summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile38
-rw-r--r--usr.sbin/Makefile.inc4
-rw-r--r--usr.sbin/ac/Makefile18
-rw-r--r--usr.sbin/ac/ac.8165
-rw-r--r--usr.sbin/ac/ac.c557
-rw-r--r--usr.sbin/accton/Makefile7
-rw-r--r--usr.sbin/accton/accton.851
-rw-r--r--usr.sbin/accton/accton.c60
-rw-r--r--usr.sbin/amd/Makefile6
-rw-r--r--usr.sbin/amd/amd/ChangeLog1169
-rw-r--r--usr.sbin/amd/amd/Makefile36
-rw-r--r--usr.sbin/amd/amd/afs_ops.c1814
-rw-r--r--usr.sbin/amd/amd/am_ops.c179
-rw-r--r--usr.sbin/amd/amd/amd.8231
-rw-r--r--usr.sbin/amd/amd/amd.c342
-rw-r--r--usr.sbin/amd/amd/amq_subr.c463
-rw-r--r--usr.sbin/amd/amd/clock.c239
-rw-r--r--usr.sbin/amd/amd/efs_ops.c133
-rw-r--r--usr.sbin/amd/amd/get_args.c334
-rw-r--r--usr.sbin/amd/amd/host_ops.c679
-rw-r--r--usr.sbin/amd/amd/ifs_ops.c193
-rw-r--r--usr.sbin/amd/amd/info_file.c274
-rw-r--r--usr.sbin/amd/amd/info_hes.c695
-rw-r--r--usr.sbin/amd/amd/info_ndbm.c121
-rw-r--r--usr.sbin/amd/amd/info_nis.c245
-rw-r--r--usr.sbin/amd/amd/info_passwd.c160
-rw-r--r--usr.sbin/amd/amd/info_union.c151
-rw-r--r--usr.sbin/amd/amd/map.c1139
-rw-r--r--usr.sbin/amd/amd/mapc.c913
-rw-r--r--usr.sbin/amd/amd/misc_rpc.c331
-rw-r--r--usr.sbin/amd/amd/mntfs.c366
-rw-r--r--usr.sbin/amd/amd/mount_fs.c271
-rw-r--r--usr.sbin/amd/amd/mtab.c106
-rw-r--r--usr.sbin/amd/amd/nfs_ops.c813
-rw-r--r--usr.sbin/amd/amd/nfs_start.c433
-rw-r--r--usr.sbin/amd/amd/nfs_subr.c550
-rw-r--r--usr.sbin/amd/amd/nfsx_ops.c514
-rw-r--r--usr.sbin/amd/amd/opts.c834
-rw-r--r--usr.sbin/amd/amd/pfs_ops.c167
-rw-r--r--usr.sbin/amd/amd/restart.c179
-rw-r--r--usr.sbin/amd/amd/rpc_fwd.c428
-rw-r--r--usr.sbin/amd/amd/sched.c323
-rw-r--r--usr.sbin/amd/amd/sfs_ops.c206
-rw-r--r--usr.sbin/amd/amd/srvr_afs.c203
-rw-r--r--usr.sbin/amd/amd/srvr_nfs.c717
-rw-r--r--usr.sbin/amd/amd/ufs_ops.c172
-rw-r--r--usr.sbin/amd/amd/umount_fs.c223
-rw-r--r--usr.sbin/amd/amd/util.c646
-rw-r--r--usr.sbin/amd/amd/wire.c279
-rw-r--r--usr.sbin/amd/amd/xutil.c489
-rw-r--r--usr.sbin/amd/amq/Makefile18
-rw-r--r--usr.sbin/amd/amq/amq.8129
-rw-r--r--usr.sbin/amd/amq/amq.c664
-rw-r--r--usr.sbin/amd/config/Configure59
-rw-r--r--usr.sbin/amd/config/Makefile.aix34
-rw-r--r--usr.sbin/amd/config/Makefile.bsd447
-rw-r--r--usr.sbin/amd/config/Makefile.config92
-rw-r--r--usr.sbin/amd/config/Makefile.hpux12
-rw-r--r--usr.sbin/amd/config/Makefile.irix9
-rw-r--r--usr.sbin/amd/config/Makefile.irix312
-rw-r--r--usr.sbin/amd/config/Makefile.irix413
-rw-r--r--usr.sbin/amd/config/Makefile.stellix9
-rw-r--r--usr.sbin/amd/config/RELEASE1
-rw-r--r--usr.sbin/amd/config/arch125
-rw-r--r--usr.sbin/amd/config/misc-aix3.h94
-rw-r--r--usr.sbin/amd/config/misc-hpux.h77
-rw-r--r--usr.sbin/amd/config/misc-irix.h48
-rw-r--r--usr.sbin/amd/config/misc-next.h42
-rw-r--r--usr.sbin/amd/config/misc-stellix.h65
-rw-r--r--usr.sbin/amd/config/misc-ultrix.h53
-rw-r--r--usr.sbin/amd/config/mount_aix.c151
-rw-r--r--usr.sbin/amd/config/mount_irix.c81
-rw-r--r--usr.sbin/amd/config/mount_stellix.c77
-rw-r--r--usr.sbin/amd/config/mtab_aix.c135
-rw-r--r--usr.sbin/amd/config/mtab_bsd.c117
-rw-r--r--usr.sbin/amd/config/mtab_file.c470
-rw-r--r--usr.sbin/amd/config/mtab_ultrix.c113
-rw-r--r--usr.sbin/amd/config/newvers.sh87
-rw-r--r--usr.sbin/amd/config/os-acis43.h82
-rw-r--r--usr.sbin/amd/config/os-aix3.h180
-rw-r--r--usr.sbin/amd/config/os-aux.h116
-rw-r--r--usr.sbin/amd/config/os-bsd44.h198
-rw-r--r--usr.sbin/amd/config/os-concentrix.h78
-rw-r--r--usr.sbin/amd/config/os-convex.h79
-rw-r--r--usr.sbin/amd/config/os-defaults.h142
-rw-r--r--usr.sbin/amd/config/os-dgux.h113
-rw-r--r--usr.sbin/amd/config/os-fpx4.h91
-rw-r--r--usr.sbin/amd/config/os-hcx.h80
-rw-r--r--usr.sbin/amd/config/os-hlh42.h88
-rw-r--r--usr.sbin/amd/config/os-hpux.h149
-rw-r--r--usr.sbin/amd/config/os-irix.h132
-rw-r--r--usr.sbin/amd/config/os-irix3.h132
-rw-r--r--usr.sbin/amd/config/os-irix4.h149
-rw-r--r--usr.sbin/amd/config/os-next.h78
-rw-r--r--usr.sbin/amd/config/os-pyrOSx.h79
-rw-r--r--usr.sbin/amd/config/os-riscix.h87
-rw-r--r--usr.sbin/amd/config/os-sos3.h78
-rw-r--r--usr.sbin/amd/config/os-sos4.h115
-rw-r--r--usr.sbin/amd/config/os-stellix.h107
-rw-r--r--usr.sbin/amd/config/os-type127
-rw-r--r--usr.sbin/amd/config/os-u2_2.h160
-rw-r--r--usr.sbin/amd/config/os-u3_0.h153
-rw-r--r--usr.sbin/amd/config/os-u4_0.h157
-rw-r--r--usr.sbin/amd/config/os-u4_2.h152
-rw-r--r--usr.sbin/amd/config/os-umax43.h78
-rw-r--r--usr.sbin/amd/config/os-utek.h48
-rw-r--r--usr.sbin/amd/config/os-utx32.h84
-rw-r--r--usr.sbin/amd/config/os-xinu43.h111
-rw-r--r--usr.sbin/amd/doc/Makefile54
-rw-r--r--usr.sbin/amd/doc/amdref.ps6429
-rw-r--r--usr.sbin/amd/doc/amdref.texinfo4556
-rw-r--r--usr.sbin/amd/doc/texinfo.tex2192
-rw-r--r--usr.sbin/amd/fsinfo/Makefile33
-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.c643
-rw-r--r--usr.sbin/amd/fsinfo/fsi_data.h234
-rw-r--r--usr.sbin/amd/fsinfo/fsi_dict.c123
-rw-r--r--usr.sbin/amd/fsinfo/fsi_gram.y392
-rw-r--r--usr.sbin/amd/fsinfo/fsi_lex.l401
-rw-r--r--usr.sbin/amd/fsinfo/fsi_util.c569
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.878
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.c273
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.h157
-rw-r--r--usr.sbin/amd/fsinfo/wr_atab.c282
-rw-r--r--usr.sbin/amd/fsinfo/wr_bparam.c99
-rw-r--r--usr.sbin/amd/fsinfo/wr_dumpset.c86
-rw-r--r--usr.sbin/amd/fsinfo/wr_exportfs.c98
-rw-r--r--usr.sbin/amd/fsinfo/wr_fstab.c301
-rw-r--r--usr.sbin/amd/include/am.h566
-rw-r--r--usr.sbin/amd/include/config.h140
-rw-r--r--usr.sbin/amd/include/fstype.h147
-rw-r--r--usr.sbin/amd/include/uwait.h81
-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/Makefile14
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.860
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.c383
-rw-r--r--usr.sbin/amd/rpcx/amq.h152
-rw-r--r--usr.sbin/amd/rpcx/amq.x184
-rw-r--r--usr.sbin/amd/rpcx/amq_clnt.c180
-rw-r--r--usr.sbin/amd/rpcx/amq_svc.c135
-rw-r--r--usr.sbin/amd/rpcx/amq_xdr.c250
-rw-r--r--usr.sbin/amd/rpcx/mount.h123
-rw-r--r--usr.sbin/amd/rpcx/mount_xdr.c205
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot.h388
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_svc.c197
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_xdr.c626
-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.ex86
-rw-r--r--usr.sbin/arp/Makefile7
-rw-r--r--usr.sbin/arp/arp.4126
-rw-r--r--usr.sbin/arp/arp.8130
-rw-r--r--usr.sbin/arp/arp.c544
-rw-r--r--usr.sbin/bad144/Makefile8
-rw-r--r--usr.sbin/bad144/bad144.8187
-rw-r--r--usr.sbin/bad144/bad144.c695
-rw-r--r--usr.sbin/bootpd/Announce63
-rw-r--r--usr.sbin/bootpd/Changes245
-rw-r--r--usr.sbin/bootpd/ConvOldTab.sh141
-rw-r--r--usr.sbin/bootpd/Installation29
-rw-r--r--usr.sbin/bootpd/Makefile13
-rw-r--r--usr.sbin/bootpd/Makefile.UNIX184
-rw-r--r--usr.sbin/bootpd/Problems47
-rw-r--r--usr.sbin/bootpd/README133
-rw-r--r--usr.sbin/bootpd/bootp.h147
-rw-r--r--usr.sbin/bootpd/bootpd.8305
-rw-r--r--usr.sbin/bootpd/bootpd.c1380
-rw-r--r--usr.sbin/bootpd/bootpd.h211
-rw-r--r--usr.sbin/bootpd/bootpef.852
-rw-r--r--usr.sbin/bootpd/bootpef.c347
-rw-r--r--usr.sbin/bootpd/bootpgw.c672
-rw-r--r--usr.sbin/bootpd/bootptab.5395
-rw-r--r--usr.sbin/bootpd/bootptab.cmu124
-rw-r--r--usr.sbin/bootpd/bootptab.mcs92
-rw-r--r--usr.sbin/bootpd/bootptest.874
-rw-r--r--usr.sbin/bootpd/bootptest.c497
-rw-r--r--usr.sbin/bootpd/bootptest.h30
-rw-r--r--usr.sbin/bootpd/bptypes.h25
-rw-r--r--usr.sbin/bootpd/dovend.c413
-rw-r--r--usr.sbin/bootpd/dovend.h13
-rw-r--r--usr.sbin/bootpd/dumptab.c382
-rw-r--r--usr.sbin/bootpd/getether.c374
-rw-r--r--usr.sbin/bootpd/getif.c146
-rw-r--r--usr.sbin/bootpd/getif.h7
-rw-r--r--usr.sbin/bootpd/hash.c425
-rw-r--r--usr.sbin/bootpd/hash.h158
-rw-r--r--usr.sbin/bootpd/hwaddr.c286
-rw-r--r--usr.sbin/bootpd/hwaddr.h39
-rw-r--r--usr.sbin/bootpd/lookup.c126
-rw-r--r--usr.sbin/bootpd/lookup.h15
-rw-r--r--usr.sbin/bootpd/patchlevel.h3
-rw-r--r--usr.sbin/bootpd/print-bootp.c493
-rw-r--r--usr.sbin/bootpd/readfile.c2097
-rw-r--r--usr.sbin/bootpd/readfile.h19
-rw-r--r--usr.sbin/bootpd/report.c154
-rw-r--r--usr.sbin/bootpd/report.h13
-rw-r--r--usr.sbin/bootpd/syslog.conf63
-rw-r--r--usr.sbin/bootpd/trygetea.c46
-rw-r--r--usr.sbin/bootpd/trygetif.c66
-rw-r--r--usr.sbin/bootpd/trylook.c50
-rw-r--r--usr.sbin/bootpd/tzone.c46
-rw-r--r--usr.sbin/bootpd/tzone.h3
-rw-r--r--usr.sbin/bootpef/Makefile15
-rw-r--r--usr.sbin/bootpgw/Makefile14
-rw-r--r--usr.sbin/bootptest/Makefile14
-rw-r--r--usr.sbin/catman/Makefile7
-rw-r--r--usr.sbin/catman/TODO2
-rw-r--r--usr.sbin/catman/catman.8100
-rw-r--r--usr.sbin/catman/catman.c268
-rw-r--r--usr.sbin/catman/pathnames.h36
-rw-r--r--usr.sbin/chown/Makefile9
-rw-r--r--usr.sbin/chown/chgrp.1137
-rw-r--r--usr.sbin/chown/chown.8150
-rw-r--r--usr.sbin/chown/chown.c244
-rw-r--r--usr.sbin/chroot/Makefile7
-rw-r--r--usr.sbin/chroot/chroot.881
-rw-r--r--usr.sbin/chroot/chroot.c73
-rw-r--r--usr.sbin/config/Makefile16
-rw-r--r--usr.sbin/config/config.8168
-rw-r--r--usr.sbin/config/config.h284
-rw-r--r--usr.sbin/config/files.c263
-rw-r--r--usr.sbin/config/gram.y421
-rw-r--r--usr.sbin/config/hash.c280
-rw-r--r--usr.sbin/config/main.c490
-rw-r--r--usr.sbin/config/mkheaders.c149
-rw-r--r--usr.sbin/config/mkioconf.c396
-rw-r--r--usr.sbin/config/mkmakefile.c368
-rw-r--r--usr.sbin/config/mkswap.c141
-rw-r--r--usr.sbin/config/pack.c521
-rw-r--r--usr.sbin/config/scan.l240
-rw-r--r--usr.sbin/config/sem.c989
-rw-r--r--usr.sbin/config/sem.h65
-rw-r--r--usr.sbin/config/util.c265
-rw-r--r--usr.sbin/cron/Makefile9
-rw-r--r--usr.sbin/cron/compat.c233
-rw-r--r--usr.sbin/cron/compat.h137
-rw-r--r--usr.sbin/cron/config.h87
-rw-r--r--usr.sbin/cron/cron.861
-rw-r--r--usr.sbin/cron/cron.c301
-rw-r--r--usr.sbin/cron/cron.h277
-rw-r--r--usr.sbin/cron/crontab.1100
-rw-r--r--usr.sbin/cron/crontab.5188
-rw-r--r--usr.sbin/cron/crontab.c624
-rw-r--r--usr.sbin/cron/database.c261
-rw-r--r--usr.sbin/cron/do_command.c501
-rw-r--r--usr.sbin/cron/entry.c507
-rw-r--r--usr.sbin/cron/env.c178
-rw-r--r--usr.sbin/cron/externs.h145
-rw-r--r--usr.sbin/cron/job.c74
-rw-r--r--usr.sbin/cron/misc.c664
-rw-r--r--usr.sbin/cron/pathnames.h81
-rw-r--r--usr.sbin/cron/popen.c167
-rw-r--r--usr.sbin/cron/user.c102
-rw-r--r--usr.sbin/dbsym/Makefile6
-rw-r--r--usr.sbin/dbsym/dbsym.846
-rw-r--r--usr.sbin/dbsym/dbsym.c241
-rw-r--r--usr.sbin/dbsym/dbtest.c58
-rw-r--r--usr.sbin/dev_mkdb/Makefile7
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.882
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.c152
-rw-r--r--usr.sbin/diskpart/Makefile7
-rw-r--r--usr.sbin/diskpart/diskpart.8144
-rw-r--r--usr.sbin/diskpart/diskpart.c475
-rw-r--r--usr.sbin/edquota/Makefile7
-rw-r--r--usr.sbin/edquota/edquota.8161
-rw-r--r--usr.sbin/edquota/edquota.c724
-rw-r--r--usr.sbin/edquota/pathnames.h40
-rw-r--r--usr.sbin/eeprom/Makefile20
-rw-r--r--usr.sbin/eeprom/defs.h109
-rw-r--r--usr.sbin/eeprom/eehandlers.c687
-rw-r--r--usr.sbin/eeprom/eeprom.8345
-rw-r--r--usr.sbin/eeprom/getdate.y971
-rw-r--r--usr.sbin/eeprom/main.c303
-rw-r--r--usr.sbin/eeprom/ophandlers.c258
-rw-r--r--usr.sbin/gettable/Makefile7
-rw-r--r--usr.sbin/gettable/gettable.8103
-rw-r--r--usr.sbin/gettable/gettable.c183
-rw-r--r--usr.sbin/grfconfig/Makefile7
-rw-r--r--usr.sbin/grfconfig/grfconfig.8135
-rw-r--r--usr.sbin/grfconfig/grfconfig.c205
-rw-r--r--usr.sbin/grfinfo/Makefile7
-rw-r--r--usr.sbin/grfinfo/grfinfo.c136
-rw-r--r--usr.sbin/gspa/Makefile3
-rw-r--r--usr.sbin/gspa/Makefile.inc4
-rw-r--r--usr.sbin/gspa/gspa/Makefile12
-rw-r--r--usr.sbin/gspa/gspa/gsp_act.c204
-rw-r--r--usr.sbin/gspa/gspa/gsp_ass.h180
-rw-r--r--usr.sbin/gspa/gspa/gsp_code.h41
-rw-r--r--usr.sbin/gspa/gspa/gsp_eval.c138
-rw-r--r--usr.sbin/gspa/gspa/gsp_gram.y122
-rw-r--r--usr.sbin/gspa/gspa/gsp_inst.c748
-rw-r--r--usr.sbin/gspa/gspa/gsp_lex.c183
-rw-r--r--usr.sbin/gspa/gspa/gsp_out.c182
-rw-r--r--usr.sbin/gspa/gspa/gsp_pseu.c148
-rw-r--r--usr.sbin/gspa/gspa/gsp_sym.c192
-rw-r--r--usr.sbin/gspa/gspa/gspa.c273
-rw-r--r--usr.sbin/gspa/gspahextoc/Makefile6
-rw-r--r--usr.sbin/gspa/gspahextoc/README19
-rw-r--r--usr.sbin/gspa/gspahextoc/gspahextoc.l123
-rw-r--r--usr.sbin/hilinfo/Makefile7
-rw-r--r--usr.sbin/hilinfo/hilinfo.c147
-rw-r--r--usr.sbin/htable/Makefile14
-rw-r--r--usr.sbin/htable/htable.8150
-rw-r--r--usr.sbin/htable/htable.c621
-rw-r--r--usr.sbin/htable/htable.h73
-rw-r--r--usr.sbin/htable/parse.y166
-rw-r--r--usr.sbin/htable/scan.l101
-rw-r--r--usr.sbin/inetd/Makefile8
-rw-r--r--usr.sbin/inetd/inetd.8280
-rw-r--r--usr.sbin/inetd/inetd.c1607
-rw-r--r--usr.sbin/inetd/pathnames.h40
-rw-r--r--usr.sbin/iostat/Makefile14
-rw-r--r--usr.sbin/iostat/iostat.8143
-rw-r--r--usr.sbin/iostat/iostat.c392
-rw-r--r--usr.sbin/iteconfig/Makefile8
-rw-r--r--usr.sbin/iteconfig/iteconfig.c286
-rw-r--r--usr.sbin/iteconfig/iteconfig_amiga.8160
-rw-r--r--usr.sbin/iteconfig/iteconfig_atari.8160
-rw-r--r--usr.sbin/iteconfig/pathnames.h35
-rw-r--r--usr.sbin/kgmon/Makefile15
-rw-r--r--usr.sbin/kgmon/kgmon.8123
-rw-r--r--usr.sbin/kgmon/kgmon.c526
-rw-r--r--usr.sbin/kvm_mkdb/Makefile8
-rw-r--r--usr.sbin/kvm_mkdb/extern.h39
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.870
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.c121
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c187
-rw-r--r--usr.sbin/kvm_mkdb/testdb.c114
-rw-r--r--usr.sbin/lpr/Makefile10
-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.c361
-rw-r--r--usr.sbin/lpr/common_source/displayq.c470
-rw-r--r--usr.sbin/lpr/common_source/lp.h127
-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.c474
-rw-r--r--usr.sbin/lpr/common_source/rmjob.c363
-rw-r--r--usr.sbin/lpr/common_source/startdaemon.c113
-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.c1140
-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.c284
-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.h59
-rw-r--r--usr.sbin/lpr/lpd/key.c270
-rw-r--r--usr.sbin/lpr/lpd/lpd.8249
-rw-r--r--usr.sbin/lpr/lpd/lpd.c511
-rw-r--r--usr.sbin/lpr/lpd/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/lpd/modes.c238
-rw-r--r--usr.sbin/lpr/lpd/printjob.c1429
-rw-r--r--usr.sbin/lpr/lpd/recvjob.c358
-rw-r--r--usr.sbin/lpr/lpd/ttcompat.c297
-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.c131
-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.c769
-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.c148
-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.c448
-rw-r--r--usr.sbin/map-mbone/Makefile11
-rw-r--r--usr.sbin/map-mbone/map-mbone.891
-rw-r--r--usr.sbin/map-mbone/mapper.c960
-rw-r--r--usr.sbin/mrinfo/Makefile13
-rw-r--r--usr.sbin/mrinfo/mrinfo.885
-rw-r--r--usr.sbin/mrinfo/mrinfo.c532
-rw-r--r--usr.sbin/mrouted/LICENSE48
-rw-r--r--usr.sbin/mrouted/Makefile11
-rw-r--r--usr.sbin/mrouted/callout.c201
-rw-r--r--usr.sbin/mrouted/cfparse.y512
-rw-r--r--usr.sbin/mrouted/config.c145
-rw-r--r--usr.sbin/mrouted/defs.h230
-rw-r--r--usr.sbin/mrouted/dvmrp.h160
-rw-r--r--usr.sbin/mrouted/igmp.c305
-rw-r--r--usr.sbin/mrouted/inet.c202
-rw-r--r--usr.sbin/mrouted/kern.c222
-rw-r--r--usr.sbin/mrouted/main.c611
-rw-r--r--usr.sbin/mrouted/mrouted.8399
-rw-r--r--usr.sbin/mrouted/pathnames.h17
-rw-r--r--usr.sbin/mrouted/prune.c2259
-rw-r--r--usr.sbin/mrouted/prune.h139
-rw-r--r--usr.sbin/mrouted/route.c1139
-rw-r--r--usr.sbin/mrouted/route.h50
-rw-r--r--usr.sbin/mrouted/rsrr.c366
-rw-r--r--usr.sbin/mrouted/rsrr.h140
-rw-r--r--usr.sbin/mrouted/snmp.c1307
-rw-r--r--usr.sbin/mrouted/snmp.h505
-rw-r--r--usr.sbin/mrouted/vif.c1373
-rw-r--r--usr.sbin/mrouted/vif.h76
-rw-r--r--usr.sbin/mtrace/Makefile14
-rw-r--r--usr.sbin/mtrace/mtrace.8498
-rw-r--r--usr.sbin/mtrace/mtrace.c1343
-rw-r--r--usr.sbin/mtree/Makefile10
-rw-r--r--usr.sbin/mtree/compare.c277
-rw-r--r--usr.sbin/mtree/create.c296
-rw-r--r--usr.sbin/mtree/extern.h46
-rw-r--r--usr.sbin/mtree/misc.c128
-rw-r--r--usr.sbin/mtree/mtree.8254
-rw-r--r--usr.sbin/mtree/mtree.c152
-rw-r--r--usr.sbin/mtree/mtree.h91
-rw-r--r--usr.sbin/mtree/spec.c286
-rw-r--r--usr.sbin/mtree/verify.c210
-rw-r--r--usr.sbin/named/Makefile27
-rw-r--r--usr.sbin/named/Makefile.dist61
-rw-r--r--usr.sbin/named/Version.c136
-rw-r--r--usr.sbin/named/Version.self1
-rw-r--r--usr.sbin/named/adb.scripts/databuf1
-rw-r--r--usr.sbin/named/adb.scripts/databufs2
-rw-r--r--usr.sbin/named/adb.scripts/namebuf2
-rw-r--r--usr.sbin/named/db.h131
-rw-r--r--usr.sbin/named/db_dump.c787
-rw-r--r--usr.sbin/named/db_glue.c227
-rw-r--r--usr.sbin/named/db_load.c969
-rw-r--r--usr.sbin/named/db_lookup.c173
-rw-r--r--usr.sbin/named/db_reload.c120
-rw-r--r--usr.sbin/named/db_save.c212
-rw-r--r--usr.sbin/named/db_update.c404
-rw-r--r--usr.sbin/named/doc/rfc1032.lpr781
-rw-r--r--usr.sbin/named/doc/rfc1033.lpr1229
-rw-r--r--usr.sbin/named/doc/rfc1034.lpr3077
-rw-r--r--usr.sbin/named/doc/rfc1035.lpr3077
-rw-r--r--usr.sbin/named/doc/rfc1101.lpr787
-rw-r--r--usr.sbin/named/doc/rfc920.lpr798
-rw-r--r--usr.sbin/named/doc/rfc974.lpr399
-rw-r--r--usr.sbin/named/named.8440
-rw-r--r--usr.sbin/named/named.reload6
-rw-r--r--usr.sbin/named/named.restart9
-rw-r--r--usr.sbin/named/ns.h285
-rw-r--r--usr.sbin/named/ns_forw.c579
-rw-r--r--usr.sbin/named/ns_init.c704
-rw-r--r--usr.sbin/named/ns_main.c1301
-rw-r--r--usr.sbin/named/ns_maint.c544
-rw-r--r--usr.sbin/named/ns_req.c1353
-rw-r--r--usr.sbin/named/ns_resp.c1704
-rw-r--r--usr.sbin/named/ns_sort.c156
-rw-r--r--usr.sbin/named/ns_stats.c157
-rw-r--r--usr.sbin/named/pathnames.h60
-rw-r--r--usr.sbin/named/storage.c167
-rw-r--r--usr.sbin/named/test/:pwedit4
-rw-r--r--usr.sbin/named/test/atod.y118
-rw-r--r--usr.sbin/named/test/hosts.mff3072
-rw-r--r--usr.sbin/named/test/ns.al23414
-rw-r--r--usr.sbin/named/test/ns.boot9
-rw-r--r--usr.sbin/named/test/ns.boot16
-rw-r--r--usr.sbin/named/test/ns.boot29
-rw-r--r--usr.sbin/named/test/ns.boot38
-rw-r--r--usr.sbin/named/test/ns.ca5
-rw-r--r--usr.sbin/named/test/ns.ca25
-rw-r--r--usr.sbin/named/test/ns.ca37
-rw-r--r--usr.sbin/named/test/ns.db17
-rw-r--r--usr.sbin/named/test/ns.db116
-rw-r--r--usr.sbin/named/test/ns.db319
-rw-r--r--usr.sbin/named/test/ns.pw21965
-rw-r--r--usr.sbin/named/testdomain/test.boot9
-rw-r--r--usr.sbin/named/testdomain/testcache5
-rw-r--r--usr.sbin/named/testdomain/testhosts17
-rw-r--r--usr.sbin/named/tools/Makefile6
-rw-r--r--usr.sbin/named/tools/nslookup/Makefile19
-rw-r--r--usr.sbin/named/tools/nslookup/commands.l197
-rw-r--r--usr.sbin/named/tools/nslookup/debug.c463
-rw-r--r--usr.sbin/named/tools/nslookup/getinfo.c800
-rw-r--r--usr.sbin/named/tools/nslookup/list.c945
-rw-r--r--usr.sbin/named/tools/nslookup/main.c1108
-rw-r--r--usr.sbin/named/tools/nslookup/nslookup.8364
-rw-r--r--usr.sbin/named/tools/nslookup/nslookup.help31
-rw-r--r--usr.sbin/named/tools/nslookup/pathnames.h37
-rw-r--r--usr.sbin/named/tools/nslookup/res.h148
-rw-r--r--usr.sbin/named/tools/nslookup/send.c564
-rw-r--r--usr.sbin/named/tools/nslookup/skip.c188
-rw-r--r--usr.sbin/named/tools/nslookup/subr.c510
-rw-r--r--usr.sbin/named/tools/nsquery/Makefile8
-rw-r--r--usr.sbin/named/tools/nsquery/nsquery.c110
-rw-r--r--usr.sbin/named/tools/nstest/Makefile8
-rw-r--r--usr.sbin/named/tools/nstest/nstest.c389
-rw-r--r--usr.sbin/named/xfer/Makefile12
-rw-r--r--usr.sbin/named/xfer/named-xfer.8148
-rw-r--r--usr.sbin/named/xfer/named-xfer.c1233
-rw-r--r--usr.sbin/netgroup_mkdb/Makefile8
-rw-r--r--usr.sbin/netgroup_mkdb/netgroup_mkdb.888
-rw-r--r--usr.sbin/netgroup_mkdb/netgroup_mkdb.c715
-rw-r--r--usr.sbin/netgroup_mkdb/str.c119
-rw-r--r--usr.sbin/netgroup_mkdb/str.h47
-rw-r--r--usr.sbin/netgroup_mkdb/util.c104
-rw-r--r--usr.sbin/netgroup_mkdb/util.h40
-rw-r--r--usr.sbin/portmap/Makefile7
-rw-r--r--usr.sbin/portmap/portmap.8111
-rw-r--r--usr.sbin/portmap/portmap.c556
-rw-r--r--usr.sbin/pppd/Makefile15
-rw-r--r--usr.sbin/pppd/auth.c934
-rw-r--r--usr.sbin/pppd/ccp.c652
-rw-r--r--usr.sbin/pppd/ccp.h51
-rw-r--r--usr.sbin/pppd/chap.c805
-rw-r--r--usr.sbin/pppd/chap.h112
-rw-r--r--usr.sbin/pppd/chat/Makefile8
-rw-r--r--usr.sbin/pppd/chat/chat.8309
-rw-r--r--usr.sbin/pppd/chat/chat.c1349
-rw-r--r--usr.sbin/pppd/fsm.c780
-rw-r--r--usr.sbin/pppd/fsm.h128
-rw-r--r--usr.sbin/pppd/ipcp.c1213
-rw-r--r--usr.sbin/pppd/ipcp.h68
-rw-r--r--usr.sbin/pppd/lcp.c1822
-rw-r--r--usr.sbin/pppd/lcp.h88
-rw-r--r--usr.sbin/pppd/magic.c90
-rw-r--r--usr.sbin/pppd/magic.h23
-rw-r--r--usr.sbin/pppd/main.c1087
-rw-r--r--usr.sbin/pppd/md5.c304
-rw-r--r--usr.sbin/pppd/md5.h58
-rw-r--r--usr.sbin/pppd/options.c1740
-rw-r--r--usr.sbin/pppd/patchlevel.h6
-rw-r--r--usr.sbin/pppd/pathnames.h22
-rw-r--r--usr.sbin/pppd/pppd.8795
-rw-r--r--usr.sbin/pppd/pppd.h255
-rw-r--r--usr.sbin/pppd/pppstats/Makefile9
-rw-r--r--usr.sbin/pppd/pppstats/pppstats.8179
-rw-r--r--usr.sbin/pppd/pppstats/pppstats.c310
-rw-r--r--usr.sbin/pppd/sys-bsd.c1135
-rw-r--r--usr.sbin/pppd/upap.c590
-rw-r--r--usr.sbin/pppd/upap.h93
-rw-r--r--usr.sbin/pstat/Makefile14
-rw-r--r--usr.sbin/pstat/pstat.8331
-rw-r--r--usr.sbin/pstat/pstat.c1159
-rw-r--r--usr.sbin/pwd_mkdb/Makefile13
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.c137
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.h36
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.8129
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c431
-rw-r--r--usr.sbin/quot/Makefile6
-rw-r--r--usr.sbin/quot/quot.896
-rw-r--r--usr.sbin/quot/quot.c583
-rw-r--r--usr.sbin/quotaon/Makefile9
-rw-r--r--usr.sbin/quotaon/quotaon.8140
-rw-r--r--usr.sbin/quotaon/quotaon.c253
-rw-r--r--usr.sbin/rarpd/Makefile14
-rw-r--r--usr.sbin/rarpd/rarpd.892
-rw-r--r--usr.sbin/rarpd/rarpd.c818
-rw-r--r--usr.sbin/rbootd/Makefile8
-rw-r--r--usr.sbin/rbootd/bpf.c425
-rw-r--r--usr.sbin/rbootd/conf.c92
-rw-r--r--usr.sbin/rbootd/defs.h186
-rw-r--r--usr.sbin/rbootd/parseconf.c361
-rw-r--r--usr.sbin/rbootd/pathnames.h53
-rw-r--r--usr.sbin/rbootd/rbootd.8158
-rw-r--r--usr.sbin/rbootd/rbootd.c449
-rw-r--r--usr.sbin/rbootd/rmp.h97
-rw-r--r--usr.sbin/rbootd/rmp_var.h246
-rw-r--r--usr.sbin/rbootd/rmpproto.c598
-rw-r--r--usr.sbin/rbootd/utils.c557
-rw-r--r--usr.sbin/rdate/Makefile8
-rw-r--r--usr.sbin/rdate/rdate.857
-rw-r--r--usr.sbin/rdate/rdate.c141
-rw-r--r--usr.sbin/rdconfig/Makefile6
-rw-r--r--usr.sbin/rdconfig/rdconfig.876
-rw-r--r--usr.sbin/rdconfig/rdconfig.c90
-rw-r--r--usr.sbin/repquota/Makefile7
-rw-r--r--usr.sbin/repquota/repquota.8104
-rw-r--r--usr.sbin/repquota/repquota.c381
-rw-r--r--usr.sbin/rmt/Makefile7
-rw-r--r--usr.sbin/rmt/rmt.8218
-rw-r--r--usr.sbin/rmt/rmt.c236
-rw-r--r--usr.sbin/rpc.bootparamd/Makefile22
-rw-r--r--usr.sbin/rpc.bootparamd/bootparamd.c383
-rw-r--r--usr.sbin/rpc.bootparamd/bootparams.578
-rw-r--r--usr.sbin/rpc.bootparamd/pathnames.h10
-rw-r--r--usr.sbin/rpc.bootparamd/rpc.bootparamd.862
-rw-r--r--usr.sbin/rpc.pcnfsd/Makefile28
-rw-r--r--usr.sbin/rpc.pcnfsd/Makefile.clnt29
-rw-r--r--usr.sbin/rpc.pcnfsd/README110
-rw-r--r--usr.sbin/rpc.pcnfsd/common.h181
-rw-r--r--usr.sbin/rpc.pcnfsd/paths.h13
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd.8217
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd.x638
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_cache.c104
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_misc.c605
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_print.c1343
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_test.c572
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_v1.c162
-rw-r--r--usr.sbin/rpc.pcnfsd/pcnfsd_v2.c569
-rw-r--r--usr.sbin/rwhod/Makefile9
-rw-r--r--usr.sbin/rwhod/rwhod.8147
-rw-r--r--usr.sbin/rwhod/rwhod.c540
-rw-r--r--usr.sbin/sa/Makefile7
-rw-r--r--usr.sbin/sa/extern.h100
-rw-r--r--usr.sbin/sa/main.c543
-rw-r--r--usr.sbin/sa/pathnames.h35
-rw-r--r--usr.sbin/sa/pdb.c419
-rw-r--r--usr.sbin/sa/sa.8246
-rw-r--r--usr.sbin/sa/usrdb.c283
-rw-r--r--usr.sbin/screenblank/Makefile9
-rw-r--r--usr.sbin/screenblank/pathnames.h38
-rw-r--r--usr.sbin/screenblank/screenblank.197
-rw-r--r--usr.sbin/screenblank/screenblank.c321
-rw-r--r--usr.sbin/sendmail/FAQ343
-rw-r--r--usr.sbin/sendmail/KNOWNBUGS131
-rw-r--r--usr.sbin/sendmail/Makefile28
-rw-r--r--usr.sbin/sendmail/READ_ME239
-rw-r--r--usr.sbin/sendmail/RELEASE_NOTES2646
-rw-r--r--usr.sbin/sendmail/cf/README1232
-rw-r--r--usr.sbin/sendmail/cf/cf/Makefile69
-rw-r--r--usr.sbin/sendmail/cf/cf/boat-anchor.mc47
-rw-r--r--usr.sbin/sendmail/cf/cf/chez.mc44
-rw-r--r--usr.sbin/sendmail/cf/cf/chimera.mc48
-rw-r--r--usr.sbin/sendmail/cf/cf/clientproto.mc49
-rw-r--r--usr.sbin/sendmail/cf/cf/netbsd-proto.mc50
-rw-r--r--usr.sbin/sendmail/cf/cf/pain.mc47
-rw-r--r--usr.sbin/sendmail/cf/cf/python.mc52
-rw-r--r--usr.sbin/sendmail/cf/cf/sun-lamp.mc52
-rw-r--r--usr.sbin/sendmail/cf/cf/tcpproto.mc50
-rw-r--r--usr.sbin/sendmail/cf/cf/trinity.mc45
-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/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/bsd4.4.m442
-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
-rw-r--r--usr.sbin/sendmail/contrib/expn.pl1365
-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/changes/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/changes/changes.me997
-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/op/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/op/op.me6921
-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/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/makemap.8128
-rw-r--r--usr.sbin/sendmail/makemap/makemap.c377
-rw-r--r--usr.sbin/sendmail/praliases/Makefile8
-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.BSD4446
-rw-r--r--usr.sbin/sendmail/src/Makefile.NetBSD42
-rw-r--r--usr.sbin/sendmail/src/READ_ME883
-rw-r--r--usr.sbin/sendmail/src/TRACEFLAGS64
-rw-r--r--usr.sbin/sendmail/src/alias.c770
-rw-r--r--usr.sbin/sendmail/src/aliases53
-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/cdefs.h123
-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.c2387
-rw-r--r--usr.sbin/sendmail/src/conf.h1197
-rw-r--r--usr.sbin/sendmail/src/convtime.c196
-rw-r--r--usr.sbin/sendmail/src/daemon.c1555
-rw-r--r--usr.sbin/sendmail/src/deliver.c2437
-rw-r--r--usr.sbin/sendmail/src/domain.c771
-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.c1510
-rw-r--r--usr.sbin/sendmail/src/makesendmail113
-rw-r--r--usr.sbin/sendmail/src/map.c1329
-rw-r--r--usr.sbin/sendmail/src/mci.c404
-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.c1685
-rw-r--r--usr.sbin/sendmail/src/recipient.c1072
-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.h974
-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/sysexits.h118
-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.c1558
-rw-r--r--usr.sbin/sendmail/src/version.c39
-rw-r--r--usr.sbin/sendmail/test/Results53
-rw-r--r--usr.sbin/sendmail/test/t_setreuid.c82
-rw-r--r--usr.sbin/sliplogin/Makefile9
-rw-r--r--usr.sbin/sliplogin/pathnames.h41
-rw-r--r--usr.sbin/sliplogin/slip.hosts11
-rw-r--r--usr.sbin/sliplogin/slip.login21
-rw-r--r--usr.sbin/sliplogin/sliplogin.8221
-rw-r--r--usr.sbin/sliplogin/sliplogin.c358
-rw-r--r--usr.sbin/slstats/Makefile12
-rw-r--r--usr.sbin/slstats/slstats.8113
-rw-r--r--usr.sbin/slstats/slstats.c261
-rw-r--r--usr.sbin/spray/Makefile7
-rw-r--r--usr.sbin/spray/spray.876
-rw-r--r--usr.sbin/spray/spray.c224
-rw-r--r--usr.sbin/sysctl/Makefile7
-rw-r--r--usr.sbin/sysctl/pathconf.c235
-rw-r--r--usr.sbin/sysctl/sysctl.8213
-rw-r--r--usr.sbin/sysctl/sysctl.c585
-rw-r--r--usr.sbin/syslogd/Makefile9
-rw-r--r--usr.sbin/syslogd/pathnames.h41
-rw-r--r--usr.sbin/syslogd/syslog.conf.5230
-rw-r--r--usr.sbin/syslogd/syslogd.8123
-rw-r--r--usr.sbin/syslogd/syslogd.c1121
-rw-r--r--usr.sbin/tcpdump/CHANGES197
-rw-r--r--usr.sbin/tcpdump/Makefile43
-rw-r--r--usr.sbin/tcpdump/README209
-rw-r--r--usr.sbin/tcpdump/addrtoname.c724
-rw-r--r--usr.sbin/tcpdump/addrtoname.h37
-rw-r--r--usr.sbin/tcpdump/appletalk.h169
-rw-r--r--usr.sbin/tcpdump/atime.awk20
-rw-r--r--usr.sbin/tcpdump/bootp.h111
-rw-r--r--usr.sbin/tcpdump/bpf_dump.c67
-rw-r--r--usr.sbin/tcpdump/decnet.h482
-rw-r--r--usr.sbin/tcpdump/ethertype.h72
-rw-r--r--usr.sbin/tcpdump/extract.h51
-rw-r--r--usr.sbin/tcpdump/fddi.h78
-rw-r--r--usr.sbin/tcpdump/interface.h152
-rw-r--r--usr.sbin/tcpdump/ipx.h31
-rw-r--r--usr.sbin/tcpdump/llc.h122
-rw-r--r--usr.sbin/tcpdump/makemib175
-rw-r--r--usr.sbin/tcpdump/md.h35
-rw-r--r--usr.sbin/tcpdump/mib.h1258
-rw-r--r--usr.sbin/tcpdump/nfsfh.h36
-rw-r--r--usr.sbin/tcpdump/nfsv2.h262
-rw-r--r--usr.sbin/tcpdump/ntp.h119
-rw-r--r--usr.sbin/tcpdump/os.h62
-rw-r--r--usr.sbin/tcpdump/ospf.h225
-rw-r--r--usr.sbin/tcpdump/packetdat.awk63
-rw-r--r--usr.sbin/tcpdump/parsenfsfh.c427
-rw-r--r--usr.sbin/tcpdump/print-arp.c123
-rw-r--r--usr.sbin/tcpdump/print-atalk.c573
-rw-r--r--usr.sbin/tcpdump/print-bootp.c359
-rw-r--r--usr.sbin/tcpdump/print-decnet.c765
-rw-r--r--usr.sbin/tcpdump/print-domain.c276
-rw-r--r--usr.sbin/tcpdump/print-egp.c358
-rw-r--r--usr.sbin/tcpdump/print-ether.c194
-rw-r--r--usr.sbin/tcpdump/print-fddi.c353
-rw-r--r--usr.sbin/tcpdump/print-icmp.c217
-rw-r--r--usr.sbin/tcpdump/print-ip.c364
-rw-r--r--usr.sbin/tcpdump/print-ipx.c214
-rw-r--r--usr.sbin/tcpdump/print-isoclns.c317
-rw-r--r--usr.sbin/tcpdump/print-llc.c198
-rw-r--r--usr.sbin/tcpdump/print-nfs.c856
-rw-r--r--usr.sbin/tcpdump/print-ntp.c287
-rw-r--r--usr.sbin/tcpdump/print-null.c113
-rw-r--r--usr.sbin/tcpdump/print-ospf.c580
-rw-r--r--usr.sbin/tcpdump/print-ppp.c104
-rw-r--r--usr.sbin/tcpdump/print-rip.c117
-rw-r--r--usr.sbin/tcpdump/print-sl.c245
-rw-r--r--usr.sbin/tcpdump/print-snmp.c1034
-rw-r--r--usr.sbin/tcpdump/print-sunrpc.c114
-rw-r--r--usr.sbin/tcpdump/print-tcp.c278
-rw-r--r--usr.sbin/tcpdump/print-tftp.c147
-rw-r--r--usr.sbin/tcpdump/print-udp.c259
-rw-r--r--usr.sbin/tcpdump/print-wb.c447
-rw-r--r--usr.sbin/tcpdump/send-ack.awk70
-rw-r--r--usr.sbin/tcpdump/stime.awk21
-rw-r--r--usr.sbin/tcpdump/tcpdump.81173
-rw-r--r--usr.sbin/tcpdump/tcpdump.c413
-rw-r--r--usr.sbin/tcpdump/util.c337
-rw-r--r--usr.sbin/tcpdump/version.c3
-rw-r--r--usr.sbin/timed/CHANGES144
-rw-r--r--usr.sbin/timed/Makefile6
-rw-r--r--usr.sbin/timed/timed/Makefile13
-rw-r--r--usr.sbin/timed/timed/acksend.c130
-rw-r--r--usr.sbin/timed/timed/byteorder.c84
-rw-r--r--usr.sbin/timed/timed/candidate.c167
-rw-r--r--usr.sbin/timed/timed/cksum.c85
-rw-r--r--usr.sbin/timed/timed/correct.c283
-rw-r--r--usr.sbin/timed/timed/globals.h186
-rw-r--r--usr.sbin/timed/timed/master.c913
-rw-r--r--usr.sbin/timed/timed/measure.c319
-rw-r--r--usr.sbin/timed/timed/networkdelta.c263
-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.c716
-rw-r--r--usr.sbin/timed/timed/timed-extern.h86
-rw-r--r--usr.sbin/timed/timed/timed.8221
-rw-r--r--usr.sbin/timed/timed/timed.c975
-rw-r--r--usr.sbin/timed/timedc/Makefile11
-rw-r--r--usr.sbin/timed/timedc/cmds.c519
-rw-r--r--usr.sbin/timed/timedc/cmdtab.c57
-rw-r--r--usr.sbin/timed/timedc/timedc-extern.h48
-rw-r--r--usr.sbin/timed/timedc/timedc.8146
-rw-r--r--usr.sbin/timed/timedc/timedc.c260
-rw-r--r--usr.sbin/timed/timedc/timedc.h66
-rw-r--r--usr.sbin/traceroute/Makefile9
-rw-r--r--usr.sbin/traceroute/mean.awk51
-rw-r--r--usr.sbin/traceroute/median.awk68
-rw-r--r--usr.sbin/traceroute/traceroute.8362
-rw-r--r--usr.sbin/traceroute/traceroute.c825
-rw-r--r--usr.sbin/trpt/Makefile9
-rw-r--r--usr.sbin/trpt/trpt.8155
-rw-r--r--usr.sbin/trpt/trpt.c411
-rw-r--r--usr.sbin/trsp/Makefile10
-rw-r--r--usr.sbin/trsp/trsp.8144
-rw-r--r--usr.sbin/trsp/trsp.c428
-rw-r--r--usr.sbin/update/Makefile7
-rw-r--r--usr.sbin/update/update.875
-rw-r--r--usr.sbin/update/update.c76
-rw-r--r--usr.sbin/videomode/Makefile7
-rw-r--r--usr.sbin/videomode/videomode.c167
-rw-r--r--usr.sbin/vipw/Makefile8
-rw-r--r--usr.sbin/vipw/pw_util.c222
-rw-r--r--usr.sbin/vipw/pw_util.h44
-rw-r--r--usr.sbin/vipw/vipw.895
-rw-r--r--usr.sbin/vipw/vipw.c129
-rw-r--r--usr.sbin/vnconfig/Makefile6
-rw-r--r--usr.sbin/vnconfig/vnconfig.8105
-rw-r--r--usr.sbin/vnconfig/vnconfig.c174
-rw-r--r--usr.sbin/ypbind/Makefile8
-rw-r--r--usr.sbin/ypbind/ypbind.8104
-rw-r--r--usr.sbin/ypbind/ypbind.c834
-rw-r--r--usr.sbin/yppoll/Makefile7
-rw-r--r--usr.sbin/yppoll/yppoll.877
-rw-r--r--usr.sbin/yppoll/yppoll.c187
-rw-r--r--usr.sbin/ypset/Makefile7
-rw-r--r--usr.sbin/ypset/ypset.887
-rw-r--r--usr.sbin/ypset/ypset.c154
-rw-r--r--usr.sbin/zdump/Makefile8
-rw-r--r--usr.sbin/zic/Makefile8
930 files changed, 271901 insertions, 0 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
new file mode 100644
index 00000000000..8282d5c27c8
--- /dev/null
+++ b/usr.sbin/Makefile
@@ -0,0 +1,38 @@
+# from: @(#)Makefile 5.6.1.2 (Berkeley) 5/8/91
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+# not yet done: catman
+
+SUBDIR= ac accton arp bootpd bootpgw bootpef bootptest \
+ chown chroot config cron dev_mkdb \
+ diskpart edquota gettable gspa htable inetd iostat kgmon \
+ kvm_mkdb lpr map-mbone mrinfo mrouted mtrace mtree named \
+ netgroup_mkdb portmap pppd pstat pwd_mkdb quot quotaon \
+ rarpd rbootd rdconfig rdate repquota rmt \
+ rpc.bootparamd rpc.pcnfsd rwhod \
+ sa sendmail sliplogin slstats spray sysctl \
+ syslogd tcpdump timed traceroute trpt trsp update \
+ vipw vnconfig ypbind yppoll ypset zdump zic
+
+# should be listed above, but doesn't work on the Alpha.
+.if (${MACHINE_ARCH} != "alpha") || make(clean) || make(cleandir)
+SUBDIR+=amd
+.endif
+
+.if make(clean) || make(cleandir)
+SUBDIR+=bad144 config.old dbsym eeprom grfinfo hilinfo iteconfig screenblank
+.elif ${MACHINE} == "amiga" || ${MACHINE} == "atari"
+SUBDIR+=grfconfig iteconfig videomode
+.elif ${MACHINE} == "hp300"
+SUBDIR+=config.old grfinfo hilinfo
+.elif ${MACHINE} == "i386"
+SUBDIR+=bad144
+.elif ${MACHINE} == "pmax"
+SUBDIR+=config.old
+.elif ${MACHINE} == "sun3"
+SUBDIR+=dbsym eeprom screenblank
+.elif ${MACHINE} == "sparc"
+SUBDIR+=eeprom screenblank
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/Makefile.inc b/usr.sbin/Makefile.inc
new file mode 100644
index 00000000000..ad23ae86678
--- /dev/null
+++ b/usr.sbin/Makefile.inc
@@ -0,0 +1,4 @@
+# from: @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
+# $Id: Makefile.inc,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile
new file mode 100644
index 00000000000..c19c952bc37
--- /dev/null
+++ b/usr.sbin/ac/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+PROG= ac
+MAN= ac.8
+
+# If "CONSOLE_TTY" is not defined, this program is compatible with the
+# traditional implementation (using SunOS 4.x as the sample traditional
+# implementation). This is the default.
+#
+# If "CONSOLE_TTY" is defined, it must be defined to the appropriate
+# console name, e.g. "vga". Additionally, the various commented-out
+# sections of the man page should be uncommented. This is not the
+# default because of the inability to detect the proper console name
+# easily, especially on m68k systems, which can share binaries.
+#
+#CFLAGS+=-DCONSOLE_TTY=\"vga\"
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8
new file mode 100644
index 00000000000..04d11d42fbc
--- /dev/null
+++ b/usr.sbin/ac/ac.8
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) 1994 Simon J. Gerraty
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: ac.8,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+.\"
+.Dd March 15, 1994
+.Dt AC 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm ac
+.Nd connect time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl dp
+.\".Op Fl c Ar console
+.Op Fl t Ar tty
+.Op Fl w Ar wtmp
+.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 login 8
+and
+.Xr init 8 ,
+respectively.
+.Nm \&Ac
+examines these records and writes the accumulated connect time
+for all logins to the standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width indentXXX
+.It Fl d
+Display the connect times in 24 hour chunks.
+.\" .It Fl c Ar console
+.\" Use
+.\" .Ar console
+.\" as the name of the device that local X sessions (ut_host of ":0.0")
+.\" originate from. If any login has been recorded on
+.\" .Ar console
+.\" then these X sessions are ignored unless COMPAT_SUNOS was defined at
+.\" compile time.
+.It Fl p
+Print individual users' totals.
+.It Fl t Ar tty
+Only do accounting logins on certain ttys. The
+.Ar tty
+specification can start with '!' to indicate not this
+.Ar tty
+and end with '*' to indicate all similarly named ttys.
+Multiple
+.Fl t
+flags may be specified.
+.It Fl w Ar wtmp
+Read connect time data from
+.Ar wtmp
+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 ac
+displays the total connect time for all
+accounts with login sessions recorded in
+.Pa wtmp .
+.Pp
+The default
+.Pa wtmp
+file will increase without bound unless it is truncated.
+It is normally truncated by the daily scripts run
+by
+.Xr cron 8 ,
+which rename and rotate the
+.Pa wtmp
+files, keeping a week's worth of data on
+hand. No login or connect time accounting is performed if
+.Pa /var/log/wtmp
+does not exist.
+.Pp
+For example,
+.Bd -literal -offset
+ac -p -t "ttyd*" > modems
+ac -p -t "!ttyd*" > other
+.Ed
+.Pp
+allows times recorded in
+.Pa modems
+to be charged out at a different rate than
+.Pa other .
+.Pp
+The
+.Nm ac
+utility exits 0 on success, and >0 if a fatal error occurs.
+.Sh FILES
+.Bl -tag -width /var/log/wtmp.[0-7] -compact
+.It Pa /var/log/wtmp
+connect time accounting file
+.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
+An
+.Nm ac
+command appeard in
+.At v6 .
+This version of
+.Nm ac
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+.\" .Sh NOTES
+.\" If COMPAT_SUNOS is defined
+.\" .Nm ac
+.\" ignores the fact that entries with ut_host of ":0.0" are not real
+.\" login sessions. Normally such entries are ignored except in the case
+.\" of a user being logged in when the
+.\" .Pa wtmp
+.\" file was rotated, in which case a login with ut_host of ":0.0" may
+.\" appear without any preceeding console logins.
+.\" If no one is logged in on the console, the user is deemed to have
+.\" logged in on at the earliest time stamp found in
+.\" .Pa wtmp .
+.\" Use of
+.\" .Pa console
+.\" allows
+.\" .Nm ac
+.\" to identify and correcty process a logout for the user. The default
+.\" value for
+.\" .Pa console
+.\" is usually correct at compile time.
diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c
new file mode 100644
index 00000000000..8c34962f641
--- /dev/null
+++ b/usr.sbin/ac/ac.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou.
+ * @(#)Copyright (c) 1994, Simon J. Gerraty.
+ *
+ * This is free software. It comes with NO WARRANTY.
+ * Permission to use, modify and distribute this source code
+ * is granted subject to the following conditions.
+ * 1/ that the above copyright notice and this notice
+ * are preserved in all copies and that due credit be given
+ * to the author.
+ * 2/ that any changes to this code are clearly commented
+ * as such so that the author does not get blamed for bugs
+ * other than his own.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ac.c,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <unistd.h>
+
+/*
+ * this is for our list of currently logged in sessions
+ */
+struct utmp_list {
+ struct utmp_list *next;
+ struct utmp usr;
+};
+
+/*
+ * this is for our list of users that are accumulating time.
+ */
+struct user_list {
+ struct user_list *next;
+ char name[UT_NAMESIZE+1];
+ time_t secs;
+};
+
+/*
+ * this is for chosing whether to ignore a login
+ */
+struct tty_list {
+ struct tty_list *next;
+ char name[UT_LINESIZE+3];
+ int len;
+ int ret;
+};
+
+/*
+ * globals - yes yuk
+ */
+#ifdef CONSOLE_TTY
+static char *Console = CONSOLE_TTY;
+#endif
+static time_t Total = 0;
+static time_t FirstTime = 0;
+static int Flags = 0;
+static struct user_list *Users = NULL;
+static struct tty_list *Ttys = NULL;
+
+#define NEW(type) (type *)malloc(sizeof (type))
+
+#define AC_W 1 /* not _PATH_WTMP */
+#define AC_D 2 /* daily totals (ignore -p) */
+#define AC_P 4 /* per-user totals */
+#define AC_U 8 /* specified users only */
+#define AC_T 16 /* specified ttys only */
+
+#ifdef DEBUG
+static int Debug = 0;
+#endif
+
+int main __P((int, char **));
+int ac __P((FILE *));
+struct tty_list *add_tty __P((char *));
+int do_tty __P((char *));
+FILE *file __P((char *));
+struct utmp_list *log_in __P((struct utmp_list *, struct utmp *));
+struct utmp_list *log_out __P((struct utmp_list *, struct utmp *));
+int on_console __P((struct utmp_list *));
+void show __P((char *, time_t));
+void show_today __P((struct user_list *, struct utmp_list *,
+ time_t));
+void show_users __P((struct user_list *));
+struct user_list *update_user __P((struct user_list *, char *, time_t));
+void usage __P((void));
+
+/*
+ * open wtmp or die
+ */
+FILE *
+file(name)
+ char *name;
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "%s", name);
+ /* in case we want to discriminate */
+ if (strcmp(_PATH_WTMP, name))
+ Flags |= AC_W;
+ return fp;
+}
+
+struct tty_list *
+add_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ register char *rcp;
+
+ Flags |= AC_T;
+
+ if ((tp = NEW(struct tty_list)) == NULL)
+ err(1, "malloc");
+ tp->len = 0; /* full match */
+ tp->ret = 1; /* do if match */
+ if (*name == '!') { /* don't do if match */
+ tp->ret = 0;
+ name++;
+ }
+ (void)strncpy(tp->name, name, sizeof (tp->name) - 1);
+ tp->name[sizeof (tp->name) - 1] = '\0';
+ if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */
+ *rcp = '\0';
+ tp->len = strlen(tp->name); /* match len bytes only */
+ }
+ tp->next = Ttys;
+ Ttys = tp;
+ return Ttys;
+}
+
+/*
+ * should we process the named tty?
+ */
+int
+do_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ int def_ret = 0;
+
+ for (tp = Ttys; tp != NULL; tp = tp->next) {
+ if (tp->ret == 0) /* specific don't */
+ def_ret = 1; /* default do */
+ if (tp->len != 0) {
+ if (strncmp(name, tp->name, tp->len) == 0)
+ return tp->ret;
+ } else {
+ if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
+ return tp->ret;
+ }
+ }
+ return def_ret;
+}
+
+#ifdef CONSOLE_TTY
+/*
+ * is someone logged in on Console?
+ */
+int
+on_console(head)
+ struct utmp_list *head;
+{
+ struct utmp_list *up;
+
+ for (up = head; up; up = up->next) {
+ if (strncmp(up->usr.ut_line, Console,
+ sizeof (up->usr.ut_line)) == 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * update user's login time
+ */
+struct user_list *
+update_user(head, name, secs)
+ struct user_list *head;
+ char *name;
+ time_t secs;
+{
+ struct user_list *up;
+
+ for (up = head; up != NULL; up = up->next) {
+ if (strncmp(up->name, name, sizeof (up->name)) == 0) {
+ up->secs += secs;
+ Total += secs;
+ return head;
+ }
+ }
+ /*
+ * not found so add new user unless specified users only
+ */
+ if (Flags & AC_U)
+ return head;
+
+ if ((up = NEW(struct user_list)) == NULL)
+ err(1, "malloc");
+ up->next = head;
+ (void)strncpy(up->name, name, sizeof (up->name) - 1);
+ up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */
+ up->secs = secs;
+ Total += secs;
+ return up;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ int c;
+
+ fp = NULL;
+ while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'D':
+ Debug++;
+ break;
+#endif
+ case 'c':
+#ifdef CONSOLE_TTY
+ Console = optarg;
+#else
+ usage(); /* XXX */
+#endif
+ break;
+ case 'd':
+ Flags |= AC_D;
+ break;
+ case 'p':
+ Flags |= AC_P;
+ break;
+ case 't': /* only do specified ttys */
+ add_tty(optarg);
+ break;
+ case 'w':
+ fp = file(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc) {
+ /*
+ * initialize user list
+ */
+ for (; optind < argc; optind++) {
+ Users = update_user(Users, argv[optind], 0L);
+ }
+ Flags |= AC_U; /* freeze user list */
+ }
+ if (Flags & AC_D)
+ Flags &= ~AC_P;
+ if (fp == NULL) {
+ /*
+ * if _PATH_WTMP does not exist, exit quietly
+ */
+ if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT)
+ return 0;
+
+ fp = file(_PATH_WTMP);
+ }
+ ac(fp);
+
+ return 0;
+}
+
+/*
+ * print login time in decimal hours
+ */
+void
+show(name, secs)
+ char *name;
+ time_t secs;
+{
+ (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
+ ((double)secs / 3600));
+}
+
+void
+show_users(list)
+ struct user_list *list;
+{
+ struct user_list *lp;
+
+ for (lp = list; lp; lp = lp->next)
+ show(lp->name, lp->secs);
+}
+
+/*
+ * print total login time for 24hr period in decimal hours
+ */
+void
+show_today(users, logins, secs)
+ struct user_list *users;
+ struct utmp_list *logins;
+ time_t secs;
+{
+ struct user_list *up;
+ struct utmp_list *lp;
+ char date[64];
+ time_t yesterday = secs - 1;
+
+ (void)strftime(date, sizeof (date), "%b %e total",
+ localtime(&yesterday));
+
+ /* restore the missing second */
+ yesterday++;
+
+ for (lp = logins; lp != NULL; lp = lp->next) {
+ secs = yesterday - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+ lp->usr.ut_time = yesterday; /* as if they just logged in */
+ }
+ secs = 0;
+ for (up = users; up != NULL; up = up->next) {
+ secs += up->secs;
+ up->secs = 0; /* for next day */
+ }
+ if (secs)
+ (void)printf("%s %11.2f\n", date, ((double)secs / 3600));
+}
+
+/*
+ * log a user out and update their times.
+ * if ut_line is "~", we log all users out as the system has
+ * been shut down.
+ */
+struct utmp_list *
+log_out(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp, *lp2, *tlp;
+ time_t secs;
+
+ for (lp = head, lp2 = NULL; lp != NULL; )
+ if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line,
+ sizeof (up->ut_line)) == 0) {
+ secs = up->ut_time - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+#ifdef DEBUG
+ if (Debug)
+ printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
+ 19, ctime(&up->ut_time),
+ sizeof (lp->usr.ut_line), lp->usr.ut_line,
+ sizeof (lp->usr.ut_name), lp->usr.ut_name,
+ secs / 3600, (secs % 3600) / 60, secs % 60);
+#endif
+ /*
+ * now lose it
+ */
+ tlp = lp;
+ lp = lp->next;
+ if (tlp == head)
+ head = lp;
+ else if (lp2 != NULL)
+ lp2->next = lp;
+ free(tlp);
+ } else {
+ lp2 = lp;
+ lp = lp->next;
+ }
+ return head;
+}
+
+
+/*
+ * if do_tty says ok, login a user
+ */
+struct utmp_list *
+log_in(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp;
+
+ /*
+ * this could be a login. if we're not dealing with
+ * the console name, say it is.
+ *
+ * If we are, and if ut_host==":0.0" we know that it
+ * isn't a real login. _But_ if we have not yet recorded
+ * someone being logged in on Console - due to the wtmp
+ * file starting after they logged in, we'll pretend they
+ * logged in, at the start of the wtmp file.
+ */
+
+#ifdef CONSOLE_TTY
+ if (up->ut_host[0] == ':') {
+ /*
+ * SunOS 4.0.2 does not treat ":0.0" as special but we
+ * do.
+ */
+ if (on_console(head))
+ return head;
+ /*
+ * ok, no recorded login, so they were here when wtmp
+ * started! Adjust ut_time!
+ */
+ up->ut_time = FirstTime;
+ /*
+ * this allows us to pick the right logout
+ */
+ (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1);
+ up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */
+ }
+#endif
+ /*
+ * If we are doing specified ttys only, we ignore
+ * anything else.
+ */
+ if (Flags & AC_T)
+ if (!do_tty(up->ut_line))
+ return head;
+
+ /*
+ * go ahead and log them in
+ */
+ if ((lp = NEW(struct utmp_list)) == NULL)
+ err(1, "malloc");
+ lp->next = head;
+ head = lp;
+ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp));
+#ifdef DEBUG
+ if (Debug) {
+ printf("%-.*s %-.*s: %-.*s logged in", 19,
+ ctime(&lp->usr.ut_time), sizeof (up->ut_line),
+ up->ut_line, sizeof (up->ut_name), up->ut_name);
+ if (*up->ut_host)
+ printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host);
+ putchar('\n');
+ }
+#endif
+ return head;
+}
+
+int
+ac(fp)
+ FILE *fp;
+{
+ struct utmp_list *lp, *head = NULL;
+ struct utmp usr;
+ struct tm *ltm;
+ time_t secs;
+ int day = -1;
+
+ while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) {
+ if (!FirstTime)
+ FirstTime = usr.ut_time;
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ day = ltm->tm_yday;
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ } else
+ day = ltm->tm_yday;
+ }
+ switch(*usr.ut_line) {
+ case '|':
+ secs = usr.ut_time;
+ break;
+ case '{':
+ secs -= usr.ut_time;
+ /*
+ * adjust time for those logged in
+ */
+ for (lp = head; lp != NULL; lp = lp->next)
+ lp->usr.ut_time -= secs;
+ break;
+ case '~': /* reboot or shutdown */
+ head = log_out(head, &usr);
+ FirstTime = usr.ut_time; /* shouldn't be needed */
+ break;
+ default:
+ /*
+ * if they came in on tty[p-y]*, then it is only
+ * a login session if the ut_host field is non-empty
+ */
+ if (*usr.ut_name) {
+ if (strncmp(usr.ut_line, "tty", 3) != 0 ||
+ strchr("pqrstuvwxy", usr.ut_line[3]) == 0 ||
+ *usr.ut_host != '\0')
+ head = log_in(head, &usr);
+ } else
+ head = log_out(head, &usr);
+ break;
+ }
+ }
+ (void)fclose(fp);
+ usr.ut_time = time((time_t *)0);
+ (void)strcpy(usr.ut_line, "~");
+
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ }
+ }
+ /*
+ * anyone still logged in gets time up to now
+ */
+ head = log_out(head, &usr);
+
+ if (Flags & AC_D)
+ show_today(Users, head, time((time_t *)0));
+ else {
+ if (Flags & AC_P)
+ show_users(Users);
+ show("total", Total);
+ }
+ return 0;
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+#ifdef CONSOLE_TTY
+ "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
+#else
+ "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");
+#endif
+ exit(1);
+}
diff --git a/usr.sbin/accton/Makefile b/usr.sbin/accton/Makefile
new file mode 100644
index 00000000000..47fc964c777
--- /dev/null
+++ b/usr.sbin/accton/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+PROG= accton
+MAN= accton.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/accton/accton.8 b/usr.sbin/accton/accton.8
new file mode 100644
index 00000000000..a5d5bb7f306
--- /dev/null
+++ b/usr.sbin/accton/accton.8
@@ -0,0 +1,51 @@
+.\" Copyright (c) 1993 Christopher G. Demetriou
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: accton.8,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+.\"
+.Dd October 18, 1993
+.Dt ACCTON 8
+.Os BSD 4
+.Sh NAME
+.Nm accton
+.Nd enable/disable system accounting
+.Sh SYNOPSIS
+.Nm accton
+.Op Ar file
+.Sh DESCRIPTION
+With an argument naming an existing
+.Ar file ,
+.Nm accton
+causes system accounting information for every process executed
+to be placed at the end of the file. If no argument is given,
+accounting is turned off.
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr acct 5
+.Sh HISTORY
+The
+.Nm accton
+command has existed nearly forever, but this man page is new.
diff --git a/usr.sbin/accton/accton.c b/usr.sbin/accton/accton.c
new file mode 100644
index 00000000000..b36b638dbc7
--- /dev/null
+++ b/usr.sbin/accton/accton.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1988 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
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/* from: static char sccsid[] = "@(#)accton.c 4.3 (Berkeley) 6/1/90"; */
+static char *rcsid = "$Id: accton.c,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc > 2) {
+ fputs("usage: accton [file]\n", stderr);
+ exit(1);
+ }
+ if (acct(argc == 2 ? argv[1] : (char *)NULL)) {
+ perror("accton");
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/usr.sbin/amd/Makefile b/usr.sbin/amd/Makefile
new file mode 100644
index 00000000000..875000f53c1
--- /dev/null
+++ b/usr.sbin/amd/Makefile
@@ -0,0 +1,6 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+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 00000000000..2cd1807260d
--- /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 00000000000..0ebf85c472a
--- /dev/null
+++ b/usr.sbin/amd/amd/Makefile
@@ -0,0 +1,36 @@
+# from: @(#)Makefile 8.2 (Berkeley) 4/22/94
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:09 deraadt Exp $
+
+.include "../config/Makefile.config"
+
+PROG= amd
+MAN= amd.8
+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
+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
+
+DPADD+= ${LIBCOMPAT}
+LDADD+= -lcompat
+
+vers.${PROG}.c: ${SRCS:.c=.o}
+ @d=${.CURDIR}/ sh ${.CURDIR}/../config/newvers.sh ${PROG} ${MACHINE} ${OS}
+
+.PATH: ${.CURDIR}/../rpcx ${.CURDIR}/../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 00000000000..e9dcf6a689d
--- /dev/null
+++ b/usr.sbin/amd/amd/afs_ops.c
@@ -0,0 +1,1814 @@
+/*
+ * 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.
+ *
+ * from: @(#)afs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: afs_ops.c,v 1.1.1.1 1995/10/18 08:47:09 deraadt 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 00000000000..c024e6a2e20
--- /dev/null
+++ b/usr.sbin/amd/amd/am_ops.c
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ *
+ * from: @(#)am_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: am_ops.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+#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 00000000000..4c52695f297
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.8
@@ -0,0 +1,231 @@
+.\"
+.\" 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.
+.\"
+.\" from: @(#)amd.8 5.10 (Berkeley) 4/19/94
+.\" $Id: amd.8,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+.\"
+.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 00000000000..90a91bfe74f
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.c
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ *
+ * from: @(#)amd.c 8.1 (Berkeley) 6/6/93
+ * $Id: amd.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+#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 00000000000..230355d0d47
--- /dev/null
+++ b/usr.sbin/amd/amd/amq_subr.c
@@ -0,0 +1,463 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq_subr.c 8.1 (Berkeley) 6/6/93
+ * $Id: amq_subr.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..b204e09d260
--- /dev/null
+++ b/usr.sbin/amd/amd/clock.c
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ *
+ * from: @(#)clock.c 8.1 (Berkeley) 6/6/93
+ * $Id: clock.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..18f17d1ce4f
--- /dev/null
+++ b/usr.sbin/amd/amd/efs_ops.c
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ * from: @(#)efs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: efs_ops.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+#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 00000000000..861a4668e59
--- /dev/null
+++ b/usr.sbin/amd/amd/get_args.c
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ *
+ * from: @(#)get_args.c 8.1 (Berkeley) 6/6/93
+ * $Id: get_args.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..89fd06a42c6
--- /dev/null
+++ b/usr.sbin/amd/amd/host_ops.c
@@ -0,0 +1,679 @@
+/*
+ * 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.
+ *
+ * from: @(#)host_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: host_ops.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt 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 00000000000..90b82fa0e50
--- /dev/null
+++ b/usr.sbin/amd/amd/ifs_ops.c
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ *
+ * from: @(#)ifs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: ifs_ops.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+#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 00000000000..698123df823
--- /dev/null
+++ b/usr.sbin/amd/amd/info_file.c
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_file.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_file.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..267e3106f08
--- /dev/null
+++ b/usr.sbin/amd/amd/info_hes.c
@@ -0,0 +1,695 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_hes.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_hes.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..6a418592df1
--- /dev/null
+++ b/usr.sbin/amd/amd/info_ndbm.c
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_ndbm.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_ndbm.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..fc88e22241c
--- /dev/null
+++ b/usr.sbin/amd/amd/info_nis.c
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_nis.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_nis.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..2f8af319fa0
--- /dev/null
+++ b/usr.sbin/amd/amd/info_passwd.c
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_passwd.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_passwd.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..f0e0c52496b
--- /dev/null
+++ b/usr.sbin/amd/amd/info_union.c
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ * from: @(#)info_union.c 8.1 (Berkeley) 6/6/93
+ * $Id: info_union.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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 00000000000..d1978715286
--- /dev/null
+++ b/usr.sbin/amd/amd/map.c
@@ -0,0 +1,1139 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)map.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: map.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $";
+#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 00000000000..422838fe0e8
--- /dev/null
+++ b/usr.sbin/amd/amd/mapc.c
@@ -0,0 +1,913 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)mapc.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: mapc.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $";
+#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 00000000000..ae38922a578
--- /dev/null
+++ b/usr.sbin/amd/amd/misc_rpc.c
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc_rpc.c 8.1 (Berkeley) 6/6/93
+ * $Id: misc_rpc.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $
+ */
+
+/*
+ * 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, (enum_t *) &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 00000000000..7662e86a39b
--- /dev/null
+++ b/usr.sbin/amd/amd/mntfs.c
@@ -0,0 +1,366 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)mntfs.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: mntfs.c,v 1.1.1.1 1995/10/18 08:47:10 deraadt Exp $";
+#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 00000000000..fd6eab45ff2
--- /dev/null
+++ b/usr.sbin/amd/amd/mount_fs.c
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount_fs.c 8.1 (Berkeley) 6/6/93
+ * $Id: mount_fs.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt 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 00000000000..f5ce98c7f98
--- /dev/null
+++ b/usr.sbin/amd/amd/mtab.c
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ *
+ * from: @(#)mtab.c 8.1 (Berkeley) 6/6/93
+ * $Id: mtab.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt Exp $
+ */
+
+#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 00000000000..d8a586fd017
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_ops.c
@@ -0,0 +1,813 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)nfs_ops.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: nfs_ops.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt Exp $";
+#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, MNTOPT_COMPRESS) != NULL)
+ nfs_args.flags |= NFSMNT_COMPRESS;
+#endif /* MNTOPT_COMPRESS */
+
+#ifdef MNTOPT_NOCONN
+ if (hasmntopt(&mnt, MNTOPT_NOCONN) != NULL)
+ nfs_args.flags |= NFSMNT_NOCONN;
+#endif /* MNTOPT_NOCONN */
+
+#ifdef MNTOPT_RESVPORT
+ if (hasmntopt(&mnt, MNTOPT_RESVPORT) != NULL)
+ nfs_args.flags |= NFSMNT_RESVPORT;
+#endif /* MNTOPT_RESVPORT */
+
+#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 00000000000..32189a3b454
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_start.c
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfs_start.c 8.1 (Berkeley) 6/6/93
+ * $Id: nfs_start.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt Exp $
+ */
+
+#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 00000000000..b4fc9a43b2b
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_subr.c
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfs_subr.c 8.1 (Berkeley) 6/6/93
+ * $Id: nfs_subr.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt Exp $
+ */
+
+#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 00000000000..cd72e89730c
--- /dev/null
+++ b/usr.sbin/amd/amd/nfsx_ops.c
@@ -0,0 +1,514 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfsx_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: nfsx_ops.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt 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 00000000000..0b81330b4b0
--- /dev/null
+++ b/usr.sbin/amd/amd/opts.c
@@ -0,0 +1,834 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)opts.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: opts.c,v 1.1.1.1 1995/10/18 08:47:11 deraadt Exp $";
+#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
+ */
+ if (!op->name) {
+ /*
+ * If it wasn't then scan the
+ * environment for that name
+ * and use any value found
+ */
+ char *env = getenv(nbuf);
+ if (env) {
+ int vlen = strlen(env);
+
+ if (BUFSPACE(ep, vlen)) {
+ strcpy(ep, env);
+ ep += vlen;
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+#ifdef DEBUG
+ Debug(D_STR)
+ plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
+#endif /* DEBUG */
+ } else {
+ plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
+ }
+ }
+ } else {
+ /*
+ * Error, error
+ */
+ plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
+ }
+ }
+
+out:
+ /*
+ * Handle common case - no expansion
+ */
+ if (cp == *p->opt) {
+ *p->opt = strdup(cp);
+ } else {
+ /*
+ * Finish off the expansion
+ */
+ if (BUFSPACE(ep, strlen(cp))) {
+ strcpy(ep, cp);
+ /*ep += strlen(ep);*/
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ }
+
+ /*
+ * Save the exansion
+ */
+ *p->opt = strdup(expbuf);
+ }
+
+ normalize_slash(*p->opt);
+
+#ifdef DEBUG
+ Debug(D_STR) {
+ plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
+ plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
+ }
+#endif /* DEBUG */
+}
+
+/*
+ * Wrapper for expand_op
+ */
+static void expand_opts P((opt_apply*, int));
+static void expand_opts(p, sel_p)
+opt_apply *p;
+int sel_p;
+{
+ if (*p->opt) {
+ expand_op(p, sel_p);
+ } else if (p->val) {
+ /*
+ * Do double expansion, remembering
+ * to free the string from the first
+ * expansion...
+ */
+ char *s = *p->opt = expand_key(p->val);
+ expand_op(p, sel_p);
+ free(s);
+ }
+}
+
+/*
+ * Apply a function to a list of options
+ */
+static void apply_opts(op, ppp, b)
+void (*op)();
+opt_apply ppp[];
+int b;
+{
+ opt_apply *pp;
+ for (pp = ppp; pp->opt; pp++)
+ (*op)(pp, b);
+}
+
+/*
+ * Free the option table
+ */
+void free_opts(fo)
+am_opts *fo;
+{
+ /*
+ * Copy in the structure we are playing with
+ */
+ fs_static = *fo;
+
+ /*
+ * Free previously allocated memory
+ */
+ apply_opts(free_op, to_free, FALSE);
+}
+
+/*
+ * Expand lookup key
+ */
+char *expand_key(key)
+char *key;
+{
+ opt_apply oa;
+
+ oa.opt = &key; oa.val = 0;
+ expand_opts(&oa, TRUE);
+
+ return key;
+}
+
+/*
+ * Remove trailing /'s from a string
+ * unless the string is a single / (Steven Glassman)
+ */
+void deslashify P((char *s));
+void deslashify(s)
+char *s;
+{
+ if (s && *s) {
+ char *sl = s + strlen(s);
+ while (*--sl == '/' && sl > s)
+ *sl = '\0';
+ }
+}
+
+int eval_fs_opts(fo, opts, g_opts, path, key, map)
+am_opts *fo;
+char *opts, *g_opts, *path, *key, *map;
+{
+ int ok = TRUE;
+
+ free_opts(fo);
+
+ /*
+ * Clear out the option table
+ */
+ bzero((voidp) &fs_static, sizeof(fs_static));
+ bzero((voidp) vars, sizeof(vars));
+ bzero((voidp) fo, sizeof(*fo));
+
+ /*
+ * Set key, map & path before expansion
+ */
+ opt_key = key;
+ opt_map = map;
+ opt_path = path;
+
+ /*
+ * Expand global options
+ */
+ fs_static.fs_glob = expand_key(g_opts);
+
+ /*
+ * Expand local options
+ */
+ fs_static.fs_local = expand_key(opts);
+
+ /*
+ * Expand default (global) options
+ */
+ if (!eval_opts(fs_static.fs_glob, key))
+ ok = FALSE;
+
+ /*
+ * Expand local options
+ */
+ if (ok && !eval_opts(fs_static.fs_local, key))
+ ok = FALSE;
+
+ /*
+ * Normalise remote host name.
+ * 1. Expand variables
+ * 2. Normalize relative to host tables
+ * 3. Strip local domains from the remote host
+ * name before using it in other expansions.
+ * This makes mount point names and other things
+ * much shorter, while allowing cross domain
+ * sharing of mount maps.
+ */
+ apply_opts(expand_opts, rhost_expansion, FALSE);
+ if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
+ host_normalize(&fs_static.opt_rhost);
+
+ /*
+ * Macro expand the options.
+ * Do this regardless of whether we are accepting
+ * this mount - otherwise nasty things happen
+ * with memory allocation.
+ */
+ apply_opts(expand_opts, expansions, FALSE);
+
+ /*
+ * Strip trailing slashes from local pathname...
+ */
+ deslashify(fs_static.opt_fs);
+
+ /*
+ * ok... copy the data back out.
+ */
+ *fo = fs_static;
+
+ /*
+ * Clear defined options
+ */
+ opt_key = opt_map = opt_path = nullstr;
+
+ return ok;
+}
diff --git a/usr.sbin/amd/amd/pfs_ops.c b/usr.sbin/amd/amd/pfs_ops.c
new file mode 100644
index 00000000000..95b7fa76deb
--- /dev/null
+++ b/usr.sbin/amd/amd/pfs_ops.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ *
+ * from: @(#)pfs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: pfs_ops.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef HAS_PFS
+
+/*
+ * Program file system
+ */
+
+/*
+ * Execute needs a mount and unmount command.
+ */
+static char *pfs_match(fo)
+am_opts *fo;
+{
+ char *prog;
+ if (!fo->opt_mount || !fo->opt_unmount) {
+ plog(XLOG_USER, "program: no mount/unmount specified");
+ return 0;
+ }
+ prog = strchr(fo->opt_mount, ' ');
+ return strdup(prog ? prog+1 : fo->opt_mount);
+}
+
+static int pfs_init(mf)
+mntfs *mf;
+{
+ /*
+ * Save unmount command
+ */
+ if (mf->mf_refc == 1) {
+ mf->mf_private = (voidp) strdup(mf->mf_fo->opt_unmount);
+ mf->mf_prfree = (void (*) ()) free;
+ }
+ return 0;
+}
+
+static int pfs_exec(info)
+char *info;
+{
+ char **xivec;
+ int error;
+ /*
+ * Split copy of command info string
+ */
+ info = strdup(info);
+ if (info == 0)
+ return ENOBUFS;
+ xivec = strsplit(info, ' ', '\'');
+ /*
+ * 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 = xivec;
+ plog(XLOG_DEBUG, "executing (un)mount command...");
+ while (*cp) {
+ plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-xivec, *cp);
+ cp++;
+ }
+ }
+#endif /* DEBUG */
+ if (xivec[0] == 0 || xivec[1] == 0) {
+ errno = EINVAL;
+ plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
+ } else {
+ (void) execv(xivec[0], xivec+1);
+ }
+ /*
+ * Save error number
+ */
+ error = errno;
+ plog(XLOG_ERROR, "exec failed: %m");
+
+ /*
+ * Free allocate memory
+ */
+ free((voidp) info);
+ free((voidp) xivec);
+ /*
+ * Return error
+ */
+ return error;
+}
+
+static int pfs_fmount(mf)
+mntfs *mf;
+{
+ return pfs_exec(mf->mf_fo->opt_mount);
+}
+
+static int pfs_fumount(mf)
+mntfs *mf;
+{
+ return pfs_exec((char *) mf->mf_private);
+}
+
+/*
+ * Ops structure
+ */
+am_ops pfs_ops = {
+ "program",
+ pfs_match,
+ pfs_init,
+ auto_fmount,
+ pfs_fmount,
+ auto_fumount,
+ pfs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* pfs_readlink */
+ 0, /* pfs_mounted */
+ 0, /* pfs_umounted */
+ find_afs_srvr,
+ FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_PFS */
diff --git a/usr.sbin/amd/amd/restart.c b/usr.sbin/amd/amd/restart.c
new file mode 100644
index 00000000000..c6b1e81ebbc
--- /dev/null
+++ b/usr.sbin/amd/amd/restart.c
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)restart.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: restart.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $";
+#endif /* not lint */
+
+#include "am.h"
+
+/*
+ * Handle an amd restart.
+ *
+ * Scan through the mount list finding all "interesting" mount points.
+ * Next hack up partial data structures and add the mounted file
+ * system to the list of known filesystems. This will leave a
+ * dangling reference to that filesystems, so when the filesystem is
+ * finally inherited, an extra "free" must be done on it.
+ *
+ * This module relies on internal details of other components. If
+ * you change something else make *sure* restart() still works.
+ */
+void restart()
+{
+ /*
+ * Read the existing mount table
+ */
+ mntlist *ml, *mlp;
+
+ /*
+ * For each entry, find nfs, ufs or auto mounts
+ * and create a partial am_node to represent it.
+ */
+ for (mlp = ml = read_mtab("restart"); mlp; mlp = mlp->mnext) {
+ struct mntent *me = mlp->mnt;
+ am_ops *fs_ops = 0;
+ if (STREQ(me->mnt_type, MTAB_TYPE_UFS)) {
+ /*
+ * UFS entry
+ */
+ fs_ops = &ufs_ops;
+ } else if (STREQ(me->mnt_type, MTAB_TYPE_NFS)) {
+ /*
+ * NFS entry, or possibly an Amd entry...
+ */
+ int au_pid;
+ char *colon = strchr(me->mnt_fsname, ':');
+ if (colon && sscanf(colon, ":(pid%d)", &au_pid) == 1) {
+ plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
+ fs_ops = &sfs_ops;
+ } else {
+ fs_ops = &nfs_ops;
+ }
+#ifdef MTAB_TYPE_MFS
+ } else if (STREQ(me->mnt_type, MTAB_TYPE_MFS)) {
+ /*
+ * MFS entry. Fake with a symlink.
+ */
+ fs_ops = &sfs_ops;
+#endif /* MTAB_TYPE_MFS */
+ } else {
+ /*
+ * Catch everything else with symlinks to
+ * avoid recursive mounts. This is debatable...
+ */
+ fs_ops = &sfs_ops;
+ }
+
+ /*
+ * If we found something to do
+ */
+ if (fs_ops) {
+ mntfs *mf;
+ am_opts mo;
+ char *cp;
+ cp = strchr(me->mnt_fsname, ':');
+ /*
+ * Partially fake up an opts structure
+ */
+ mo.opt_rhost = 0;
+ mo.opt_rfs = 0;
+ if (cp) {
+ *cp = '\0';
+ mo.opt_rhost = strdup(me->mnt_fsname);
+ mo.opt_rfs = strdup(cp+1);
+ *cp = ':';
+ } else if (fs_ops->ffserver == find_nfs_srvr) {
+ /*
+ * Prototype 4.4 BSD used to end up here -
+ * might as well keep the workaround for now
+ */
+ plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
+ mo.opt_rhost = strdup(me->mnt_fsname);
+ mo.opt_rfs = strdup("/");
+ me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
+ }
+ mo.opt_fs = me->mnt_dir;
+ mo.opt_opts = me->mnt_opts;
+
+ /*
+ * Make a new mounted filesystem
+ */
+ mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
+ me->mnt_fsname, "", me->mnt_opts, "");
+ if (mf->mf_refc == 1) {
+ mf->mf_flags |= MFF_RESTART|MFF_MOUNTED;
+ mf->mf_error = 0; /* Already mounted correctly */
+ mf->mf_fo = 0;
+ /*
+ * If the restarted type is a link then
+ * don't time out.
+ */
+ if (fs_ops == &sfs_ops || fs_ops == &ufs_ops)
+ mf->mf_flags |= MFF_RSTKEEP;
+ if (fs_ops->fs_init) {
+ /*
+ * Don't care whether this worked since
+ * it is checked again when the fs is
+ * inherited.
+ */
+ (void) (*fs_ops->fs_init)(mf);
+ }
+
+ plog(XLOG_INFO, "%s restarted fstype %s on %s",
+ me->mnt_fsname, fs_ops->fs_type, me->mnt_dir);
+ } else {
+ /* Something strange happened - two mounts at the same place! */
+ free_mntfs(mf);
+ }
+ /*
+ * Clean up mo
+ */
+ if (mo.opt_rhost)
+ free(mo.opt_rhost);
+ if (mo.opt_rfs)
+ free(mo.opt_rfs);
+ }
+ }
+
+ /*
+ * Free the mount list
+ */
+ free_mntlist(ml);
+}
diff --git a/usr.sbin/amd/amd/rpc_fwd.c b/usr.sbin/amd/amd/rpc_fwd.c
new file mode 100644
index 00000000000..bfbb821e503
--- /dev/null
+++ b/usr.sbin/amd/amd/rpc_fwd.c
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ *
+ * from: @(#)rpc_fwd.c 8.1 (Berkeley) 6/6/93
+ * $Id: rpc_fwd.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * RPC packet forwarding
+ */
+
+#include "am.h"
+#include <sys/ioctl.h>
+#ifndef F_SETFL
+#include <fcntl.h>
+#endif /* F_SETFL */
+#ifndef FNDELAY
+#include <sys/file.h>
+#endif /* FNDELAY */
+
+/*
+ * Note that the ID field in the external packet is only
+ * ever treated as a 32 bit opaque data object, so there
+ * is no need to convert to and from network byte ordering.
+ */
+
+/*
+ * Each pending reply has an rpc_forward structure
+ * associated with it. These have a 15 second lifespan.
+ * If a new structure is required, then an expired
+ * one will be re-allocated if available, otherwise a fresh
+ * one is allocated. Whenever a reply is received the
+ * structure is discarded.
+ */
+typedef struct rpc_forward rpc_forward;
+struct rpc_forward {
+ qelem rf_q; /* Linked list */
+ time_t rf_ttl; /* Time to live */
+ u_int rf_xid; /* Packet id */
+ u_int rf_oldid; /* Original packet id */
+ fwd_fun rf_fwd; /* Forwarding function */
+ voidp rf_ptr;
+ struct sockaddr_in rf_sin;
+};
+
+/*
+ * Head of list of pending replies
+ */
+extern qelem rpc_head;
+qelem rpc_head = { &rpc_head, &rpc_head };
+
+static u_int xid;
+#define XID_ALLOC() (xid++)
+
+#define MAX_PACKET_SIZE 8192 /* Maximum UDP packet size */
+
+int fwd_sock;
+
+/*
+ * Allocate a rely structure
+ */
+static rpc_forward *fwd_alloc()
+{
+ time_t now = clocktime();
+ rpc_forward *p = 0, *p2;
+
+#ifdef DEBUG
+ /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+ /*
+ * First search for an existing expired one.
+ */
+ ITER(p2, rpc_forward, &rpc_head) {
+ if (p2->rf_ttl <= now) {
+ p = p2;
+ break;
+ }
+ }
+
+ /*
+ * If one couldn't be found then allocate
+ * a new structure and link it at the
+ * head of the list.
+ */
+ if (p) {
+ /*
+ * Call forwarding function to say that
+ * this message was junked.
+ */
+#ifdef DEBUG
+ dlog("Re-using packet forwarding slot - id %#x", p->rf_xid);
+#endif /* DEBUG */
+ if (p->rf_fwd)
+ (*p->rf_fwd)(0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE);
+ rem_que(&p->rf_q);
+ } else {
+ p = ALLOC(rpc_forward);
+ }
+ ins_que(&p->rf_q, &rpc_head);
+
+ /*
+ * Set the time to live field
+ * Timeout in 43 seconds
+ */
+ p->rf_ttl = now + 43;
+
+#ifdef DEBUG
+ /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+ return p;
+}
+
+/*
+ * Free an allocated reply structure.
+ * First unlink it from the list, then
+ * discard it.
+ */
+static void fwd_free(p)
+rpc_forward *p;
+{
+#ifdef DEBUG
+ /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+ rem_que(&p->rf_q);
+#ifdef DEBUG
+ /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+ free((voidp) p);
+}
+
+/*
+ * Initialise the RPC forwarder
+ */
+int fwd_init()
+{
+ int on = 1;
+
+ /*
+ * Create ping socket
+ */
+ fwd_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fwd_sock < 0) {
+ plog(XLOG_ERROR, "Unable to create RPC forwarding socket: %m");
+ return errno;
+ }
+
+ /*
+ * Some things we talk to require a priv port - so make one here
+ */
+ if (bind_resv_port(fwd_sock, (unsigned short *) 0) < 0)
+ plog(XLOG_ERROR, "can't bind privileged port");
+
+ if (fcntl(fwd_sock, F_SETFL, FNDELAY) < 0 &&
+ ioctl(fwd_sock, FIONBIO, &on) < 0) {
+ plog(XLOG_ERROR, "Can't set non-block on forwarding socket: %m");
+ return errno;
+ }
+
+ return 0;
+}
+
+/*
+ * Locate a packet in the forwarding list
+ */
+static rpc_forward *fwd_locate(id)
+u_int id;
+{
+ rpc_forward *p;
+
+ ITER(p, rpc_forward, &rpc_head) {
+ if (p->rf_xid == id)
+ return p;
+ }
+
+ return 0;
+}
+
+/*
+ * This is called to forward a packet to another
+ * RPC server. The message id is changed and noted
+ * so that when a reply appears we can tie it up
+ * correctly. Just matching the reply's source address
+ * would not work because it might come from a
+ * different address.
+ */
+int fwd_packet(type_id, pkt, len, fwdto, replyto, i, cb)
+int type_id;
+voidp pkt;
+int len;
+struct sockaddr_in *fwdto, *replyto;
+voidp i;
+fwd_fun cb;
+{
+ rpc_forward *p;
+ u_int *pkt_int;
+ int error;
+
+ if ((int)amd_state >= (int)Finishing)
+ return ENOENT;
+
+ /*
+ * See if the type_id is fully specified.
+ * If so, then discard any old entries
+ * for this id.
+ * Otherwise make sure the type_id is
+ * fully qualified by allocating an id here.
+ */
+#ifdef DEBUG
+ switch (type_id & RPC_XID_MASK) {
+ case RPC_XID_PORTMAP: dlog("Sending PORTMAP request"); break;
+ case RPC_XID_MOUNTD: dlog("Sending MOUNTD request %#x", type_id); break;
+ case RPC_XID_NFSPING: dlog("Sending NFS ping"); break;
+ default: dlog("UNKNOWN RPC XID"); break;
+ }
+#endif /* DEBUG */
+
+ if (type_id & ~RPC_XID_MASK) {
+#ifdef DEBUG
+ /*dlog("Fully qualified rpc type provided");*/
+#endif /* DEBUG */
+ p = fwd_locate(type_id);
+ if (p) {
+#ifdef DEBUG
+ dlog("Discarding earlier rpc fwd handle");
+#endif /* DEBUG */
+ fwd_free(p);
+ }
+ } else {
+#ifdef DEBUG
+ dlog("Allocating a new xid...");
+#endif /* DEBUG */
+ type_id = MK_RPC_XID(type_id, XID_ALLOC());
+ }
+
+ p = fwd_alloc();
+ if (!p)
+ return ENOBUFS;
+
+ error = 0;
+
+ pkt_int = (u_int *) pkt;
+
+ /*
+ * Get the original packet id
+ */
+ p->rf_oldid = *pkt_int;
+
+ /*
+ * Replace with newly allocated id
+ */
+ p->rf_xid = *pkt_int = type_id;
+
+ /*
+ * The sendto may fail if, for example, the route
+ * to a remote host is lost because an intermediate
+ * gateway has gone down. Important to fill in the
+ * rest of "p" otherwise nasty things happen later...
+ */
+#ifdef DEBUG
+ { char dq[20];
+ dlog("Sending packet id %#x to %s.%d", p->rf_xid, inet_dquad(dq, fwdto->sin_addr.s_addr), ntohs(fwdto->sin_port));
+ }
+#endif /* DEBUG */
+ if (sendto(fwd_sock, (char *) pkt, len, 0,
+ (struct sockaddr *) fwdto, sizeof(*fwdto)) < 0)
+ error = errno;
+
+ /*
+ * Save callback function and return address
+ */
+ p->rf_fwd = cb;
+ if (replyto)
+ p->rf_sin = *replyto;
+ else
+ bzero((voidp) &p->rf_sin, sizeof(p->rf_sin));
+ p->rf_ptr = i;
+
+ return error;
+}
+
+/*
+ * Called when some data arrives on the forwarding socket
+ */
+void fwd_reply()
+{
+ int len;
+#ifdef DYNAMIC_BUFFERS
+ voidp pkt;
+#else
+ u_int pkt[MAX_PACKET_SIZE/sizeof(u_int)+1];
+#endif /* DYNAMIC_BUFFERS */
+ u_int *pkt_int;
+ int rc;
+ rpc_forward *p;
+ struct sockaddr_in src_addr;
+ int src_addr_len;
+
+ /*
+ * Determine the length of the packet
+ */
+#ifdef DYNAMIC_BUFFERS
+ if (ioctl(fwd_sock, FIONREAD, &len) < 0) {
+ plog(XLOG_ERROR, "Error reading packet size: %m");
+ return;
+ }
+
+ /*
+ * Allocate a buffer
+ */
+ pkt = (voidp) malloc((unsigned) len);
+ if (!pkt) {
+ plog(XLOG_ERROR, "Out of buffers in fwd_reply");
+ return;
+ }
+#else
+ len = MAX_PACKET_SIZE;
+#endif /* DYNAMIC_BUFFERS */
+
+ /*
+ * Read the packet and check for validity
+ */
+again:
+ src_addr_len = sizeof(src_addr);
+ rc = recvfrom(fwd_sock, (char *) pkt, len, 0,
+ (struct sockaddr *) &src_addr, &src_addr_len);
+ if (rc < 0 || src_addr_len != sizeof(src_addr) ||
+ src_addr.sin_family != AF_INET) {
+ if (rc < 0 && errno == EINTR)
+ goto again;
+ plog(XLOG_ERROR, "Error reading RPC reply: %m");
+ goto out;
+ }
+
+#ifdef DYNAMIC_BUFFERS
+ if (rc != len) {
+ plog(XLOG_ERROR, "Short read in fwd_reply");
+ goto out;
+ }
+#endif /* DYNAMIC_BUFFERS */
+
+ /*
+ * Do no more work if finishing soon
+ */
+ if ((int)amd_state >= (int)Finishing)
+ goto out;
+
+ /*
+ * Find packet reference
+ */
+ pkt_int = (u_int *) pkt;
+
+#ifdef DEBUG
+ switch (*pkt_int & RPC_XID_MASK) {
+ case RPC_XID_PORTMAP: dlog("Receiving PORTMAP reply"); break;
+ case RPC_XID_MOUNTD: dlog("Receiving MOUNTD reply %#x", *pkt_int); break;
+ case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", *pkt_int); break;
+ default: dlog("UNKNOWN RPC XID"); break;
+ }
+#endif /* DEBUG */
+
+ p = fwd_locate(*pkt_int);
+ if (!p) {
+#ifdef DEBUG
+ dlog("Can't forward reply id %#x", *pkt_int);
+#endif /* DEBUG */
+ goto out;
+ }
+
+ if (p->rf_fwd) {
+ /*
+ * Put the original message id back
+ * into the packet.
+ */
+ *pkt_int = p->rf_oldid;
+
+ /*
+ * Call forwarding function
+ */
+ (*p->rf_fwd)((voidp) pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE);
+ }
+
+ /*
+ * Free forwarding info
+ */
+ fwd_free(p);
+
+out:;
+#ifdef DYNAMIC_BUFFERS
+ /*
+ * Free the packet
+ */
+ free((voidp) pkt);
+#endif /* DYNAMIC_BUFFERS */
+}
diff --git a/usr.sbin/amd/amd/sched.c b/usr.sbin/amd/amd/sched.c
new file mode 100644
index 00000000000..5d6c013ef20
--- /dev/null
+++ b/usr.sbin/amd/amd/sched.c
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ *
+ * from: @(#)sched.c 8.1 (Berkeley) 6/6/93
+ * $Id: sched.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * Process scheduler
+ */
+
+#include "am.h"
+#include <sys/signal.h>
+#include WAIT
+#include <setjmp.h>
+extern jmp_buf select_intr;
+extern int select_intr_valid;
+
+typedef struct pjob pjob;
+struct pjob {
+ qelem hdr; /* Linked list */
+ int pid; /* Process ID of job */
+ cb_fun cb_fun; /* Callback function */
+ voidp cb_closure; /* Closure for callback */
+ union wait w; /* Status filled in by sigchld */
+ voidp wchan; /* Wait channel */
+};
+
+extern qelem proc_list_head;
+qelem proc_list_head = { &proc_list_head, &proc_list_head };
+extern qelem proc_wait_list;
+qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
+
+int task_notify_todo;
+
+void ins_que(elem, pred)
+qelem *elem, *pred;
+{
+ qelem *p = pred->q_forw;
+ elem->q_back = pred;
+ elem->q_forw = p;
+ pred->q_forw = elem;
+ p->q_back = elem;
+}
+
+void rem_que(elem)
+qelem *elem;
+{
+ qelem *p = elem->q_forw;
+ qelem *p2 = elem->q_back;
+ p2->q_forw = p;
+ p->q_back = p2;
+}
+
+static pjob *sched_job(cf, ca)
+cb_fun cf;
+voidp ca;
+{
+ pjob *p = ALLOC(pjob);
+
+ p->cb_fun = cf;
+ p->cb_closure = ca;
+
+ /*
+ * Now place on wait queue
+ */
+ ins_que(&p->hdr, &proc_wait_list);
+
+ return p;
+}
+
+void run_task(tf, ta, cf, ca)
+task_fun tf;
+voidp ta;
+cb_fun cf;
+voidp ca;
+{
+ pjob *p = sched_job(cf, ca);
+ int mask;
+
+ p->wchan = (voidp) p;
+
+ mask = sigblock(sigmask(SIGCHLD));
+
+ if (p->pid = background()) {
+ sigsetmask(mask);
+ return;
+ }
+
+ exit((*tf)(ta));
+ /* firewall... */
+ abort();
+}
+
+/*
+ * Schedule a task to be run when woken up
+ */
+void sched_task(cf, ca, wchan)
+cb_fun cf;
+voidp ca;
+voidp wchan;
+{
+ /*
+ * Allocate a new task
+ */
+ pjob *p = sched_job(cf, ca);
+#ifdef DEBUG_SLEEP
+ dlog("SLEEP on %#x", wchan);
+#endif
+ p->wchan = wchan;
+ p->pid = 0;
+ bzero((voidp) &p->w, sizeof(p->w));
+}
+
+static void wakeupjob(p)
+pjob *p;
+{
+ rem_que(&p->hdr);
+ ins_que(&p->hdr, &proc_list_head);
+ task_notify_todo++;
+}
+
+void wakeup(wchan)
+voidp wchan;
+{
+ pjob *p, *p2;
+#ifdef DEBUG_SLEEP
+ int done = 0;
+#endif
+ if (!foreground)
+ return;
+
+#ifdef DEBUG_SLEEP
+ /*dlog("wakeup(%#x)", wchan);*/
+#endif
+ /*
+ * Can't user ITER() here because
+ * wakeupjob() juggles the list.
+ */
+ for (p = FIRST(pjob, &proc_wait_list);
+ p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
+ p = p2) {
+ if (p->wchan == wchan) {
+#ifdef DEBUG_SLEEP
+ done = 1;
+#endif
+ wakeupjob(p);
+ }
+ }
+
+#ifdef DEBUG_SLEEP
+ if (!done)
+ dlog("Nothing SLEEPing on %#x", wchan);
+#endif
+}
+
+void wakeup_task(rc, term, cl)
+int rc;
+int term;
+voidp cl;
+{
+ wakeup(cl);
+}
+
+/*ARGSUSED*/
+
+void sigchld(sig)
+int sig;
+{
+ union wait w;
+ int pid;
+
+#ifdef SYS5_SIGNALS
+ if ((pid = wait(&w)) > 0) {
+#else
+ while ((pid = wait3((int *) &w, WNOHANG, (struct rusage *) 0)) > 0) {
+#endif /* SYS5_SIGNALS */
+ pjob *p, *p2;
+
+ if (WIFSIGNALED(w))
+ plog(XLOG_ERROR, "Process %d exited with signal %d",
+ pid, w.w_termsig);
+#ifdef DEBUG
+ else
+ dlog("Process %d exited with status %d",
+ pid, w.w_retcode);
+#endif /* DEBUG */
+
+ for (p = FIRST(pjob, &proc_wait_list);
+ p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
+ p = p2) {
+ if (p->pid == pid) {
+ p->w = w;
+ wakeupjob(p);
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (p) ; else dlog("can't locate task block for pid %d", pid);
+#endif /* DEBUG */
+ }
+
+#ifdef SYS5_SIGNALS
+ signal(sig, sigchld);
+#endif /* SYS5_SIGNALS */
+ if (select_intr_valid)
+ longjmp(select_intr, sig);
+}
+
+/*
+ * Run any pending tasks.
+ * This must be called with SIGCHLD disabled
+ */
+void do_task_notify(P_void)
+{
+ /*
+ * Keep taking the first item off the list and processing it.
+ *
+ * Done this way because the the callback can, quite reasonably,
+ * queue a new task, so no local reference into the list can be
+ * held here.
+ */
+ while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
+ pjob *p = FIRST(pjob, &proc_list_head);
+ rem_que(&p->hdr);
+ /*
+ * This job has completed
+ */
+ --task_notify_todo;
+
+ /*
+ * Do callback if it exists
+ */
+ if (p->cb_fun)
+ (*p->cb_fun)(p->w.w_retcode,
+ p->w.w_termsig, p->cb_closure);
+
+ free((voidp) p);
+ }
+}
+
+#ifdef HAS_SVR3_SIGNALS
+/*
+ * 4.2 signal library based on svr3 (4.1+ bsd) interface
+ * From Stephen C. Pope <scp@acl.lanl.gov).
+ */
+
+static int current_mask = 0;
+
+int sigblock(mask)
+int mask;
+{
+ int sig;
+ int m;
+ int oldmask;
+
+ oldmask = current_mask;
+ for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
+ if (mask & m) {
+ sighold(sig);
+ current_mask |= m;
+ }
+ }
+ return oldmask;
+}
+
+int sigsetmask(mask)
+int mask;
+{
+ int sig;
+ int m;
+ int oldmask;
+
+ oldmask = current_mask;
+ for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
+ if (mask & m) {
+ sighold(sig);
+ current_mask |= m;
+ }
+ else {
+ sigrelse(sig);
+ current_mask &= ~m;
+ }
+ }
+ return oldmask;
+}
+
+#endif /* HAS_SVR3_SIGNALS */
diff --git a/usr.sbin/amd/amd/sfs_ops.c b/usr.sbin/amd/amd/sfs_ops.c
new file mode 100644
index 00000000000..a702f0a7466
--- /dev/null
+++ b/usr.sbin/amd/amd/sfs_ops.c
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ *
+ * from: @(#)sfs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: sfs_ops.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+#include "am.h"
+
+#if defined(HAS_SFS) || defined(HAS_SFSX)
+#define NEED_SFS_MATCH
+#define NEED_SFS_UMOUNT
+#endif
+
+/*
+ * Symbol-link file system
+ */
+
+#ifdef HAS_SFSX
+#include <sys/stat.h>
+#endif
+
+#ifdef NEED_SFS_MATCH
+/*
+ * SFS needs a link.
+ */
+static char *sfs_match(fo)
+am_opts *fo;
+{
+ if (!fo->opt_fs) {
+ plog(XLOG_USER, "link: no fs specified");
+ return 0;
+ }
+
+ /*
+ * Bug report (14/12/89) from Jay Plett <jay@princeton.edu>
+ * If an automount point has the same name as an existing
+ * link type mount Amd hits a race condition and either hangs
+ * or causes a symlink loop.
+ *
+ * If fs begins with a '/' change the opt_fs & opt_sublink
+ * fields so that the fs option doesn't end up pointing at
+ * an existing symlink.
+ *
+ * If sublink is nil then set sublink to fs
+ * else set sublink to fs / sublink
+ *
+ * Finally set fs to ".".
+ */
+ if (*fo->opt_fs == '/') {
+ char *fullpath;
+ char *link = fo->opt_sublink;
+ if (link) {
+ if (*link == '/')
+ fullpath = strdup(link);
+ else
+ fullpath = str3cat((char *)0, fo->opt_fs, "/", link);
+ } else {
+ fullpath = strdup(fo->opt_fs);
+ }
+
+ if (fo->opt_sublink)
+ free(fo->opt_sublink);
+ fo->opt_sublink = fullpath;
+ fo->opt_fs = str3cat(fo->opt_fs, ".", fullpath, "");
+ }
+
+ return strdup(fo->opt_fs);
+}
+#endif
+
+#ifdef HAS_SFSX
+/*ARGUSED*/
+static int sfsx_mount P((am_node *mp));
+static int sfsx_mount(mp)
+am_node *mp;
+{
+ /*
+ * Check for existence of target.
+ */
+ struct stat stb;
+ char *ln;
+
+ if (mp->am_link)
+ ln = mp->am_link;
+ else /* should never occur */
+ ln = mp->am_mnt->mf_mount;
+
+ /*
+ * Use lstat, not stat, since we don't
+ * want to know if the ultimate target of
+ * a symlink chain exists, just the first.
+ */
+ if (lstat(ln, &stb) < 0)
+ return errno;
+
+ return 0;
+}
+#endif
+
+#ifdef HAS_SFS
+/*ARGUSED*/
+static int sfs_fmount(mf)
+mntfs *mf;
+{
+ /*
+ * Wow - this is hard to implement!
+ */
+
+ return 0;
+}
+#endif
+
+#ifdef NEED_SFS_UMOUNT
+/*ARGUSED*/
+static int sfs_fumount(mf)
+mntfs *mf;
+{
+ return 0;
+}
+#endif
+
+/*
+ * Ops structures
+ */
+#ifdef HAS_SFS
+am_ops sfs_ops = {
+ "link",
+ sfs_match,
+ 0, /* sfs_init */
+ auto_fmount,
+ sfs_fmount,
+ auto_fumount,
+ sfs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* sfs_readlink */
+ 0, /* sfs_mounted */
+ 0, /* sfs_umounted */
+ find_afs_srvr,
+#ifdef FLUSH_KERNEL_NAME_CACHE
+ FS_UBACKGROUND
+#else /* FLUSH_KERNEL_NAME_CACHE */
+ 0
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+};
+
+#endif /* HAS_SFS */
+
+#ifdef HAS_SFSX
+struct am_ops sfsx_ops = {
+ "linkx",
+ sfs_match,
+ 0, /* sfsx_init */
+ sfsx_mount,
+ 0,
+ auto_fumount,
+ sfs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* sfsx_readlink */
+ 0, /* sfsx_mounted */
+ 0, /* sfsx_umounted */
+ find_afs_srvr,
+#ifdef FLUSH_KERNEL_NAME_CACHE
+ FS_BACKGROUND
+#else /* FLUSH_KERNEL_NAME_CACHE */
+ FS_MBACKGROUND
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+};
+
+#endif /* HAS_SFSX */
diff --git a/usr.sbin/amd/amd/srvr_afs.c b/usr.sbin/amd/amd/srvr_afs.c
new file mode 100644
index 00000000000..e724f0d9c4b
--- /dev/null
+++ b/usr.sbin/amd/amd/srvr_afs.c
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ *
+ * from: @(#)srvr_afs.c 8.1 (Berkeley) 6/6/93
+ * $Id: srvr_afs.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * Automount FS server ("localhost") modeling
+ */
+
+#include "am.h"
+
+extern qelem afs_srvr_list;
+qelem afs_srvr_list = { &afs_srvr_list, &afs_srvr_list };
+
+static fserver *localhost;
+
+/*
+ * Find an nfs server for the local host
+ */
+fserver *find_afs_srvr P((mntfs *));
+fserver *find_afs_srvr(mf)
+mntfs *mf;
+{
+ fserver *fs = localhost;
+
+ if (!fs) {
+ fs = ALLOC(fserver);
+ fs->fs_refc = 0;
+ fs->fs_host = strdup("localhost");
+ fs->fs_ip = 0;
+ fs->fs_cid = 0;
+ fs->fs_pinger = 0;
+ fs->fs_flags = FSF_VALID;
+ fs->fs_type = "local";
+ fs->fs_private = 0;
+ fs->fs_prfree = 0;
+
+ ins_que(&fs->fs_q, &afs_srvr_list);
+
+ srvrlog(fs, "starts up");
+
+ localhost = fs;
+ }
+
+ fs->fs_refc++;
+
+ return fs;
+}
+
+/*------------------------------------------------------------------*/
+ /* Generic routines follow */
+
+/*
+ * Wakeup anything waiting for this server
+ */
+void wakeup_srvr P((fserver *fs));
+void wakeup_srvr(fs)
+fserver *fs;
+{
+ fs->fs_flags &= ~FSF_WANT;
+ wakeup((voidp) fs);
+}
+
+/*
+ * Called when final ttl of server has expired
+ */
+static void timeout_srvr P((fserver *fs));
+static void timeout_srvr(fs)
+fserver *fs;
+{
+ /*
+ * If the reference count is still zero then
+ * we are free to remove this node
+ */
+ if (fs->fs_refc == 0) {
+#ifdef DEBUG
+ dlog("Deleting file server %s", fs->fs_host);
+#endif /* DEBUG */
+ if (fs->fs_flags & FSF_WANT)
+ wakeup_srvr(fs);
+
+ /*
+ * Remove from queue.
+ */
+ rem_que(&fs->fs_q);
+ /*
+ * (Possibly) call the private free routine.
+ */
+ if (fs->fs_private && fs->fs_prfree)
+ (*fs->fs_prfree)(fs->fs_private);
+
+ /*
+ * Free the net address
+ */
+ if (fs->fs_ip)
+ free((voidp) fs->fs_ip);
+
+ /*
+ * Free the host name.
+ */
+ free((voidp) fs->fs_host);
+
+ /*
+ * Discard the fserver object.
+ */
+ free((voidp) fs);
+ }
+}
+
+/*
+ * Free a file server
+ */
+void free_srvr P((fserver *fs));
+void free_srvr(fs)
+fserver *fs;
+{
+ if (--fs->fs_refc == 0) {
+ /*
+ * The reference count is now zero,
+ * so arrange for this node to be
+ * removed in AM_TTL seconds if no
+ * other mntfs is referencing it.
+ */
+ int ttl = (fs->fs_flags & (FSF_DOWN|FSF_ERROR)) ? 19 : AM_TTL;
+#ifdef DEBUG
+ dlog("Last hard reference to file server %s - will timeout in %ds", fs->fs_host, ttl);
+#endif /* DEBUG */
+ if (fs->fs_cid) {
+ untimeout(fs->fs_cid);
+ /*
+ * Turn off pinging - XXX
+ */
+ fs->fs_flags &= ~FSF_PINGING;
+ }
+ /*
+ * Keep structure lying around for a while
+ */
+ fs->fs_cid = timeout(ttl, timeout_srvr, (voidp) fs);
+ /*
+ * Mark the fileserver down and invalid again
+ */
+ fs->fs_flags &= ~FSF_VALID;
+ fs->fs_flags |= FSF_DOWN;
+ }
+}
+
+/*
+ * Make a duplicate fserver reference
+ */
+fserver *dup_srvr P((fserver *fs));
+fserver *dup_srvr(fs)
+fserver *fs;
+{
+ fs->fs_refc++;
+ return fs;
+}
+
+/*
+ * Log state change
+ */
+void srvrlog P((fserver *fs, char *state));
+void srvrlog(fs, state)
+fserver *fs;
+char *state;
+{
+ plog(XLOG_INFO, "file server %s type %s %s", fs->fs_host, fs->fs_type, state);
+}
diff --git a/usr.sbin/amd/amd/srvr_nfs.c b/usr.sbin/amd/amd/srvr_nfs.c
new file mode 100644
index 00000000000..26331299e19
--- /dev/null
+++ b/usr.sbin/amd/amd/srvr_nfs.c
@@ -0,0 +1,717 @@
+/*
+ * 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.
+ *
+ * from: @(#)srvr_nfs.c 8.1 (Berkeley) 6/6/93
+ * $Id: srvr_nfs.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * NFS server modeling
+ */
+
+#include "am.h"
+#include <netdb.h>
+#include <rpc/pmap_prot.h>
+#include "mount.h"
+
+extern qelem nfs_srvr_list;
+qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
+
+typedef struct nfs_private {
+ u_short np_mountd; /* Mount daemon port number */
+ char np_mountd_inval; /* Port *may* be invalid */
+ int np_ping; /* Number of failed ping attempts */
+ time_t np_ttl; /* Time when server is thought dead */
+ int np_xid; /* RPC transaction id for pings */
+ int np_error; /* Error during portmap request */
+} nfs_private;
+
+static int np_xid; /* For NFS pings */
+#define NPXID_ALLOC() (++np_xid)
+/*#define NPXID_ALLOC() ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/
+
+/*
+ * Number of pings allowed to fail before host is declared down
+ * - three-fifths of the allowed mount time...
+#define MAX_ALLOWED_PINGS ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER)
+ */
+#define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1)
+
+/*
+ * How often to ping when starting a new server
+ */
+#define FAST_NFS_PING 3
+
+#if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME
+ #error: sanity check failed
+/*
+ you cannot do things this way...
+ sufficient fast pings must be given the chance to fail
+ within the allowed mount time
+ */
+#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */
+
+static int ping_len;
+static char ping_buf[sizeof(struct rpc_msg) + 32];
+
+/*
+ * Flush any cached data
+ */
+void flush_srvr_nfs_cache P((void));
+void flush_srvr_nfs_cache()
+{
+ fserver *fs = 0;
+
+ ITER(fs, fserver, &nfs_srvr_list) {
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ if (np) {
+ np->np_mountd_inval = TRUE;
+ np->np_error = -1;
+ }
+ }
+}
+
+/*
+ * Startup the NFS ping
+ */
+static void start_ping(P_void);
+static void start_ping()
+{
+ XDR ping_xdr;
+ struct rpc_msg ping_msg;
+
+ rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL);
+
+ /*
+ * Create an XDR endpoint
+ */
+ xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE);
+
+ /*
+ * Create the NFS ping message
+ */
+ if (!xdr_callmsg(&ping_xdr, &ping_msg)) {
+ plog(XLOG_ERROR, "Couldn't create ping RPC message");
+ going_down(3);
+ }
+
+ /*
+ * Find out how long it is
+ */
+ ping_len = xdr_getpos(&ping_xdr);
+
+ /*
+ * Destroy the XDR endpoint - we don't need it anymore
+ */
+ xdr_destroy(&ping_xdr);
+}
+
+
+/*
+ * Called when a portmap reply arrives
+ */
+/*ARGSUSED*/
+static void got_portmap P((voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done));
+static void got_portmap(pkt, len, sa, ia, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sa;
+struct sockaddr_in *ia;
+voidp idv;
+int done;
+{
+ fserver *fs2 = (fserver *) idv;
+ fserver *fs = 0;
+
+ /*
+ * Find which fileserver we are talking about
+ */
+ ITER(fs, fserver, &nfs_srvr_list)
+ if (fs == fs2)
+ break;
+
+ if (fs == fs2) {
+ u_long port = 0; /* XXX - should be short but protocol is naff */
+ int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1;
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ if (!error && port) {
+#ifdef DEBUG
+ dlog("got port (%d) for mountd on %s", port, fs->fs_host);
+#endif /* DEBUG */
+ /*
+ * Grab the port number. Portmap sends back
+ * an unsigned long in native ordering, so it
+ * needs converting to a unsigned short in
+ * network ordering.
+ */
+ np->np_mountd = htons((u_short) port);
+ np->np_mountd_inval = FALSE;
+ np->np_error = 0;
+ } else {
+#ifdef DEBUG
+ dlog("Error fetching port for mountd on %s", fs->fs_host);
+#endif /* DEBUG */
+ /*
+ * Almost certainly no mountd running on remote host
+ */
+ np->np_error = error ? error : ETIMEDOUT;
+ }
+ if (fs->fs_flags & FSF_WANT)
+ wakeup_srvr(fs);
+ } else if (done) {
+#ifdef DEBUG
+ dlog("Got portmap for old port request");
+#endif /* DEBUG */
+ } else {
+#ifdef DEBUG
+ dlog("portmap request timed out");
+#endif /* DEBUG */
+ }
+}
+
+/*
+ * Obtain portmap information
+ */
+static int call_portmap P((fserver *fs, AUTH *auth, unsigned long prog, unsigned long vers, unsigned long prot));
+static int call_portmap(fs, auth, prog, vers, prot)
+fserver *fs;
+AUTH *auth;
+unsigned long prog, vers, prot;
+{
+ struct rpc_msg pmap_msg;
+ int len;
+ char iobuf[UDPMSGSIZE];
+ int error;
+ struct pmap pmap;
+
+ rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0);
+ pmap.pm_prog = prog;
+ pmap.pm_vers = vers;
+ pmap.pm_prot = prot;
+ pmap.pm_port = 0;
+ len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT,
+ &pmap_msg, (voidp) &pmap, xdr_pmap, auth);
+ if (len > 0) {
+ struct sockaddr_in sin;
+ bzero((voidp) &sin, sizeof(sin));
+ sin = *fs->fs_ip;
+ sin.sin_port = htons(PMAPPORT);
+ error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
+ &sin, &sin, (voidp) fs, got_portmap);
+ } else {
+ error = -len;
+ }
+ return error;
+}
+
+static void nfs_keepalive P((fserver*));
+
+static void recompute_portmap P((fserver *fs));
+static void recompute_portmap(fs)
+fserver *fs;
+{
+ int error;
+
+ if (nfs_auth)
+ error = 0;
+ else
+ error = make_nfs_auth();
+
+ if (error) {
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ np->np_error = error;
+ } else {
+ call_portmap(fs, nfs_auth, MOUNTPROG,
+ MOUNTVERS, (unsigned long) IPPROTO_UDP);
+ }
+}
+
+/*
+ * This is called when we get a reply to an RPC ping.
+ * The value of id was taken from the nfs_private
+ * structure when the ping was transmitted.
+ */
+/*ARGSUSED*/
+static void nfs_pinged P((voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done));
+static void nfs_pinged(pkt, len, sp, tsp, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sp;
+struct sockaddr_in *tsp;
+voidp idv;
+int done;
+{
+ int xid = (int) idv;
+ fserver *fs;
+#ifdef DEBUG
+ int found_map = 0;
+#endif /* DEBUG */
+
+ if (!done)
+ return;
+
+ /*
+ * For each node...
+ */
+ ITER(fs, fserver, &nfs_srvr_list) {
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ if (np->np_xid == xid) {
+ /*
+ * Reset the ping counter.
+ * Update the keepalive timer.
+ * Log what happened.
+ */
+ if (fs->fs_flags & FSF_DOWN) {
+ fs->fs_flags &= ~FSF_DOWN;
+ if (fs->fs_flags & FSF_VALID) {
+ srvrlog(fs, "is up");
+ } else {
+ if (np->np_ping > 1)
+ srvrlog(fs, "ok");
+#ifdef DEBUG
+ else
+ srvrlog(fs, "starts up");
+#endif
+ fs->fs_flags |= FSF_VALID;
+ }
+
+#ifdef notdef
+ /* why ??? */
+ if (fs->fs_flags & FSF_WANT)
+ wakeup_srvr(fs);
+#endif /* notdef */
+ map_flush_srvr(fs);
+ } else {
+ if (fs->fs_flags & FSF_VALID) {
+#ifdef DEBUG
+ dlog("file server %s type nfs is still up", fs->fs_host);
+#endif /* DEBUG */
+ } else {
+ if (np->np_ping > 1)
+ srvrlog(fs, "ok");
+ fs->fs_flags |= FSF_VALID;
+ }
+ }
+
+ /*
+ * Adjust ping interval
+ */
+ untimeout(fs->fs_cid);
+ fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs);
+
+ /*
+ * Update ttl for this server
+ */
+ np->np_ttl = clocktime() +
+ (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1;
+
+ /*
+ * New RPC xid...
+ */
+ np->np_xid = NPXID_ALLOC();
+
+ /*
+ * Failed pings is zero...
+ */
+ np->np_ping = 0;
+
+ /*
+ * Recompute portmap information if not known
+ */
+ if (np->np_mountd_inval)
+ recompute_portmap(fs);
+
+#ifdef DEBUG
+ found_map++;
+#endif /* DEBUG */
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (found_map == 0)
+ dlog("Spurious ping packet");
+#endif /* DEBUG */
+}
+
+/*
+ * Called when no ping-reply received
+ */
+static void nfs_timed_out P((fserver *fs));
+static void nfs_timed_out(fs)
+fserver *fs;
+{
+ nfs_private *np = (nfs_private *) fs->fs_private;
+
+ /*
+ * Another ping has failed
+ */
+ np->np_ping++;
+
+ /*
+ * Not known to be up any longer
+ */
+ if (FSRV_ISUP(fs)) {
+ fs->fs_flags &= ~FSF_VALID;
+ if (np->np_ping > 1)
+ srvrlog(fs, "not responding");
+ }
+
+ /*
+ * If ttl has expired then guess that it is dead
+ */
+ if (np->np_ttl < clocktime()) {
+ int oflags = fs->fs_flags;
+ if ((fs->fs_flags & FSF_DOWN) == 0) {
+ /*
+ * Server was up, but is now down.
+ */
+ srvrlog(fs, "is down");
+ fs->fs_flags |= FSF_DOWN|FSF_VALID;
+ /*
+ * Since the server is down, the portmap
+ * information may now be wrong, so it
+ * must be flushed from the local cache
+ */
+ flush_nfs_fhandle_cache(fs);
+ np->np_error = -1;
+#ifdef notdef
+ /*
+ * Pretend just one ping has failed now
+ */
+ np->np_ping = 1;
+#endif
+ } else {
+ /*
+ * Known to be down
+ */
+#ifdef DEBUG
+ if ((fs->fs_flags & FSF_VALID) == 0)
+ srvrlog(fs, "starts down");
+#endif
+ fs->fs_flags |= FSF_VALID;
+ }
+ if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT))
+ wakeup_srvr(fs);
+ } else {
+#ifdef DEBUG
+ if (np->np_ping > 1)
+ dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS);
+#endif /* DEBUG */
+ }
+
+ /*
+ * Run keepalive again
+ */
+ nfs_keepalive(fs);
+}
+
+/*
+ * Keep track of whether a server is alive
+ */
+static void nfs_keepalive P((fserver *fs));
+static void nfs_keepalive(fs)
+fserver *fs;
+{
+ int error;
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ int fstimeo = -1;
+
+ /*
+ * Send an NFS ping to this node
+ */
+
+ if (ping_len == 0)
+ start_ping();
+
+ /*
+ * Queue the packet...
+ */
+ error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf,
+ ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged);
+
+ /*
+ * See if a hard error occured
+ */
+ switch (error) {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */
+ np->np_ttl = (time_t) 0;
+ /*
+ * This causes an immediate call to nfs_timed_out
+ * whenever the server was thought to be up.
+ * See +++ below.
+ */
+ fstimeo = 0;
+ break;
+
+ case 0:
+#ifdef DEBUG
+ dlog("Sent NFS ping to %s", fs->fs_host);
+#endif /* DEBUG */
+ break;
+ }
+
+#ifdef DEBUG
+ /*dlog("keepalive, ping = %d", np->np_ping);*/
+#endif /* DEBUG */
+
+ /*
+ * Back off the ping interval if we are not getting replies and
+ * the remote system is know to be down.
+ */
+ switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) {
+ case FSF_VALID: /* Up */
+ if (fstimeo < 0) /* +++ see above */
+ fstimeo = FAST_NFS_PING;
+ break;
+
+ case FSF_VALID|FSF_DOWN: /* Down */
+ fstimeo = fs->fs_pinger;
+ break;
+
+ default: /* Unknown */
+ fstimeo = FAST_NFS_PING;
+ break;
+ }
+
+#ifdef DEBUG
+ dlog("NFS timeout in %d seconds", fstimeo);
+#endif /* DEBUG */
+
+ fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs);
+}
+
+int nfs_srvr_port P((fserver *fs, u_short *port, voidp wchan));
+int nfs_srvr_port(fs, port, wchan)
+fserver *fs;
+u_short *port;
+voidp wchan;
+{
+ int error = -1;
+ if ((fs->fs_flags & FSF_VALID) == FSF_VALID) {
+ if ((fs->fs_flags & FSF_DOWN) == 0) {
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ if (np->np_error == 0) {
+ *port = np->np_mountd;
+ error = 0;
+ } else {
+ error = np->np_error;
+ }
+ /*
+ * Now go get the port mapping again in case it changed.
+ * Note that it is used even if (np_mountd_inval)
+ * is True. The flag is used simply as an
+ * indication that the mountd may be invalid, not
+ * that it is known to be invalid.
+ */
+ if (np->np_mountd_inval)
+ recompute_portmap(fs);
+ else
+ np->np_mountd_inval = TRUE;
+ } else {
+ error = EWOULDBLOCK;
+ }
+ }
+ if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
+ /*
+ * If a wait channel is supplied, and no
+ * error has yet occured, then arrange
+ * that a wakeup is done on the wait channel,
+ * whenever a wakeup is done on this fs node.
+ * Wakeup's are done on the fs node whenever
+ * it changes state - thus causing control to
+ * come back here and new, better things to happen.
+ */
+ fs->fs_flags |= FSF_WANT;
+ sched_task(wakeup_task, wchan, (voidp) fs);
+ }
+ return error;
+}
+
+static void start_nfs_pings P((fserver *fs, int pingval));
+static void start_nfs_pings(fs, pingval)
+fserver *fs;
+int pingval;
+{
+ if (!(fs->fs_flags & FSF_PINGING)) {
+ fs->fs_flags |= FSF_PINGING;
+ if (fs->fs_cid)
+ untimeout(fs->fs_cid);
+ if (pingval < 0) {
+ srvrlog(fs, "wired up");
+ fs->fs_flags |= FSF_VALID;
+ fs->fs_flags &= ~FSF_DOWN;
+ } else {
+ nfs_keepalive(fs);
+ }
+ } else {
+#ifdef DEBUG
+ dlog("Already running pings to %s", fs->fs_host);
+#endif /* DEBUG */
+ }
+}
+
+/*
+ * Find an nfs server for a host.
+ */
+fserver *find_nfs_srvr P((mntfs *mf));
+fserver *find_nfs_srvr(mf)
+mntfs *mf;
+{
+ fserver *fs;
+ struct hostent *hp = 0;
+ char *host = mf->mf_fo->opt_rhost;
+ struct sockaddr_in *ip;
+ nfs_private *np;
+ int pingval;
+
+ /*
+ * Get ping interval from mount options.
+ * Current only used to decide whether pings
+ * are required or not. < 0 = no pings.
+ */
+ { struct mntent mnt;
+ mnt.mnt_opts = mf->mf_mopts;
+ pingval = hasmntval(&mnt, "ping");
+#ifdef HAS_TCP_NFS
+ /*
+ * Over TCP mount, don't bother to do pings.
+ * This is experimental - maybe you want to
+ * do pings anyway...
+ */
+ if (pingval == 0 && hasmntopt(&mnt, "tcp"))
+ pingval = -1;
+#endif /* HAS_TCP_NFS */
+ }
+
+
+ /*
+ * lookup host address and canonical name
+ */
+ hp = gethostbyname(host);
+
+ /*
+ * New code from Bob Harris <harris@basil-rathbone.mit.edu>
+ * Use canonical name to keep track of file server
+ * information. This way aliases do not generate
+ * multiple NFS pingers. (Except when we're normalizing
+ * hosts.)
+ */
+ if (hp && !normalize_hosts) host = hp->h_name;
+
+ ITER(fs, fserver, &nfs_srvr_list) {
+ if (STREQ(host, fs->fs_host)) {
+ start_nfs_pings(fs, pingval);
+ fs->fs_refc++;
+ return fs;
+ }
+ }
+
+
+
+ /*
+ * Get here if we can't find an entry
+ */
+ if (hp) {
+ switch (hp->h_addrtype) {
+ case AF_INET:
+ ip = ALLOC(sockaddr_in);
+ bzero((voidp) ip, sizeof(*ip));
+ ip->sin_family = AF_INET;
+ bcopy((voidp) hp->h_addr, (voidp) &ip->sin_addr, sizeof(ip->sin_addr));
+
+ ip->sin_port = htons(NFS_PORT);
+ break;
+
+ default:
+ ip = 0;
+ break;
+ }
+ } else {
+ plog(XLOG_USER, "Unknown host: %s", host);
+ ip = 0;
+ }
+
+ /*
+ * Allocate a new server
+ */
+ fs = ALLOC(fserver);
+ fs->fs_refc = 1;
+ fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
+ if (normalize_hosts) host_normalize(&fs->fs_host);
+ fs->fs_ip = ip;
+ fs->fs_cid = 0;
+ if (ip) {
+ fs->fs_flags = FSF_DOWN; /* Starts off down */
+ } else {
+ fs->fs_flags = FSF_ERROR|FSF_VALID;
+ mf->mf_flags |= MFF_ERROR;
+ mf->mf_error = ENOENT;
+ }
+ fs->fs_type = "nfs";
+ fs->fs_pinger = AM_PINGER;
+ np = ALLOC(nfs_private);
+ bzero((voidp) np, sizeof(*np));
+ np->np_mountd_inval = TRUE;
+ np->np_xid = NPXID_ALLOC();
+ np->np_error = -1;
+ /*
+ * Initially the server will be deemed dead after
+ * MAX_ALLOWED_PINGS of the fast variety have failed.
+ */
+ np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
+ fs->fs_private = (voidp) np;
+ fs->fs_prfree = (void (*)()) free;
+
+ if (!(fs->fs_flags & FSF_ERROR)) {
+ /*
+ * Start of keepalive timer
+ */
+ start_nfs_pings(fs, pingval);
+ }
+
+ /*
+ * Add to list of servers
+ */
+ ins_que(&fs->fs_q, &nfs_srvr_list);
+
+ return fs;
+}
diff --git a/usr.sbin/amd/amd/ufs_ops.c b/usr.sbin/amd/amd/ufs_ops.c
new file mode 100644
index 00000000000..510f55f5391
--- /dev/null
+++ b/usr.sbin/amd/amd/ufs_ops.c
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ * from: @(#)ufs_ops.c 8.1 (Berkeley) 6/6/93
+ * $Id: ufs_ops.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef HAS_UFS
+
+#include <sys/stat.h>
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+
+#ifdef UFS_HDR
+#include UFS_HDR
+#endif /* UFS_HDR */
+
+#include <sys/mount.h>
+
+/*
+ * UN*X file system
+ */
+
+/*
+ * UFS needs local filesystem and device.
+ */
+static char *ufs_match P((am_opts *fo));
+static char *ufs_match(fo)
+am_opts *fo;
+{
+ if (!fo->opt_dev) {
+ plog(XLOG_USER, "ufs: no device specified");
+ return 0;
+ }
+
+#ifdef DEBUG
+ dlog("UFS: mounting device \"%s\" on \"%s\"",
+ fo->opt_dev, fo->opt_fs);
+#endif /* DEBUG */
+
+ /*
+ * Determine magic cookie to put in mtab
+ */
+ return strdup(fo->opt_dev);
+}
+
+static mount_ufs(dir, fs_name, opts)
+char *dir;
+char *fs_name;
+char *opts;
+{
+ struct ufs_args ufs_args;
+ struct mntent mnt;
+ int flags;
+
+ /*
+ * Figure out the name of the file system type.
+ */
+ MTYPE_TYPE type = MOUNT_TYPE_UFS;
+
+ bzero((voidp) &ufs_args, sizeof(ufs_args)); /* Paranoid */
+
+ /*
+ * Fill in the mount structure
+ */
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = fs_name;
+ mnt.mnt_type = MTAB_TYPE_UFS;
+ mnt.mnt_opts = opts;
+ mnt.mnt_freq = 1;
+ mnt.mnt_passno = 2;
+
+ flags = compute_mount_flags(&mnt);
+
+#ifdef ULTRIX_HACK
+ ufs_args.ufs_flags = flags;
+ ufs_args.ufs_pgthresh = 64; /* 64K - XXX */
+ flags &= M_RDONLY;
+#else
+ ufs_args.fspec = fs_name;
+#endif /* ULTRIX_HACK */
+
+ /*
+ * Call generic mount routine
+ */
+ return mount_fs(&mnt, flags, (caddr_t) &ufs_args, 0, type);
+}
+
+/*ARGSUSED*/
+static int ufs_fmount(mf)
+mntfs *mf;
+{
+ int error;
+
+ error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ if (error) {
+ errno = error;
+ plog(XLOG_ERROR, "mount_ufs: %m");
+ return error;
+ }
+
+ return 0;
+}
+
+static int ufs_fumount(mf)
+mntfs *mf;
+{
+ return UMOUNT_FS(mf->mf_mount);
+}
+
+/*
+ * Ops structure
+ */
+am_ops ufs_ops = {
+ "ufs",
+ ufs_match,
+ 0, /* ufs_init */
+ auto_fmount,
+ ufs_fmount,
+ auto_fumount,
+ ufs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* ufs_readlink */
+ 0, /* ufs_mounted */
+ 0, /* ufs_umounted */
+ find_afs_srvr,
+#ifdef FLUSH_KERNEL_NAME_CACHE
+ FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+#else /* FLUSH_KERNEL_NAME_CACHE */
+ FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+};
+
+#endif /* HAS_UFS */
diff --git a/usr.sbin/amd/amd/umount_fs.c b/usr.sbin/amd/amd/umount_fs.c
new file mode 100644
index 00000000000..68147ed94bc
--- /dev/null
+++ b/usr.sbin/amd/amd/umount_fs.c
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ *
+ * from: @(#)umount_fs.c 8.1 (Berkeley) 6/6/93
+ * $Id: umount_fs.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef NEED_UMOUNT_BSD
+
+int umount_fs P((char *fs_name));
+int umount_fs(fs_name)
+char *fs_name;
+{
+ int error;
+
+eintr:
+ error = unmount(fs_name, 0);
+ if (error < 0)
+ error = errno;
+
+ switch (error) {
+ case EINVAL:
+ case ENOTBLK:
+ case ENOENT:
+ plog(XLOG_WARNING, "unmount: %s is not mounted", fs_name);
+ error = 0; /* Not really an error */
+ break;
+
+ case EINTR:
+#ifdef DEBUG
+ /* not sure why this happens, but it does. ask kirk one day... */
+ dlog("%s: unmount: %m", fs_name);
+#endif /* DEBUG */
+ goto eintr;
+
+#ifdef DEBUG
+ default:
+ dlog("%s: unmount: %m", fs_name);
+ break;
+#endif /* DEBUG */
+ }
+
+ return error;
+}
+
+#endif /* NEED_UMOUNT_BSD */
+
+#ifdef NEED_UMOUNT_OSF
+
+#include <sys/mount.h> /* For MNT_NOFORCE */
+
+int umount_fs(fs_name)
+char *fs_name;
+{
+ int error;
+
+eintr:
+ error = umount(fs_name, MNT_NOFORCE);
+ if (error < 0)
+ error = errno;
+
+ switch (error) {
+ case EINVAL:
+ case ENOTBLK:
+ plog(XLOG_WARNING, "unmount: %s is not mounted", fs_name);
+ error = 0; /* Not really an error */
+ break;
+
+ case ENOENT:
+ plog(XLOG_ERROR, "mount point %s: %m", fs_name);
+ break;
+
+ case EINTR:
+#ifdef DEBUG
+ /* not sure why this happens, but it does. ask kirk one day... */
+ dlog("%s: unmount: %m", fs_name);
+#endif /* DEBUG */
+ goto eintr;
+
+#ifdef DEBUG
+ default:
+ dlog("%s: unmount: %m", fs_name);
+ break;
+#endif /* DEBUG */
+ }
+
+ return error;
+}
+
+#endif /* NEED_UMOUNT_OSF */
+
+#ifdef NEED_UMOUNT_FS
+
+int umount_fs(fs_name)
+char *fs_name;
+{
+ mntlist *mlist, *mp, *mp_save = 0;
+ int error = 0;
+
+ mp = mlist = read_mtab(fs_name);
+
+ /*
+ * Search the mount table looking for
+ * the correct (ie last) matching entry
+ */
+ while (mp) {
+ if (strcmp(mp->mnt->mnt_fsname, fs_name) == 0 ||
+ strcmp(mp->mnt->mnt_dir, fs_name) == 0)
+ mp_save = mp;
+ mp = mp->mnext;
+ }
+
+ if (mp_save) {
+#ifdef DEBUG
+ dlog("Trying unmount(%s)", mp_save->mnt->mnt_dir);
+#endif /* DEBUG */
+ /*
+ * This unmount may hang leaving this
+ * process with an exlusive lock on
+ * /etc/mtab. Therefore it is necessary
+ * to unlock mtab, do the unmount, then
+ * lock mtab (again) and reread it and
+ * finally update it.
+ */
+ unlock_mntlist();
+ if (UNMOUNT_TRAP(mp_save->mnt) < 0) {
+ switch (error = errno) {
+ case EINVAL:
+ case ENOTBLK:
+ plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir);
+ error = 0; /* Not really an error */
+ break;
+
+ case ENOENT:
+ plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
+ break;
+
+ default:
+#ifdef DEBUG
+ dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
+#endif /* DEBUG */
+ break;
+ }
+ }
+#ifdef DEBUG
+ dlog("Finished unmount(%s)", mp_save->mnt->mnt_dir);
+#endif
+
+
+#ifdef UPDATE_MTAB
+ if (!error) {
+ free_mntlist(mlist);
+ mp = mlist = read_mtab(fs_name);
+
+ /*
+ * Search the mount table looking for
+ * the correct (ie last) matching entry
+ */
+ mp_save = 0;
+ while (mp) {
+ if (strcmp(mp->mnt->mnt_fsname, fs_name) == 0 ||
+ strcmp(mp->mnt->mnt_dir, fs_name) == 0)
+ mp_save = mp;
+ mp = mp->mnext;
+ }
+
+ if (mp_save) {
+ mnt_free(mp_save->mnt);
+ mp_save->mnt = 0;
+ rewrite_mtab(mlist);
+ }
+ }
+#endif /* UPDATE_MTAB */
+ } else {
+ plog(XLOG_ERROR, "Couldn't find how to unmount %s", fs_name);
+ /*
+ * Assume it is already unmounted
+ */
+ error = 0;
+ }
+
+ free_mntlist(mlist);
+
+ return error;
+}
+
+#endif /* NEED_UMOUNT_FS */
diff --git a/usr.sbin/amd/amd/util.c b/usr.sbin/amd/amd/util.c
new file mode 100644
index 00000000000..4e790bfe545
--- /dev/null
+++ b/usr.sbin/amd/amd/util.c
@@ -0,0 +1,646 @@
+/*
+ * 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.
+ *
+ * from: @(#)util.c 8.1 (Berkeley) 6/6/93
+ * $Id: util.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * Utils
+ */
+
+#include "am.h"
+#include <ctype.h>
+#include <sys/stat.h>
+#include <netdb.h>
+
+
+char *strnsave(str, len)
+Const char *str;
+int len;
+{
+ char *sp = (char *) xmalloc(len+1);
+
+ bcopy(str, sp, len);
+ sp[len] = 0;
+
+ return sp;
+}
+
+char *strdup(s)
+Const char *s;
+{
+ return strnsave(s, strlen(s));
+}
+
+/*
+ * Concatenate three strings and store in buffer pointed to
+ * by p, making p large enough to hold the strings
+ */
+char *str3cat(p, s1, s2, s3)
+char *p;
+char *s1;
+char *s2;
+char *s3;
+{
+ int l1 = strlen(s1);
+ int l2 = strlen(s2);
+ int l3 = strlen(s3);
+ p = (char *) xrealloc(p, l1 + l2 + l3 + 1);
+ bcopy(s1, p, l1);
+ bcopy(s2, p + l1, l2);
+ bcopy(s3, p + l1 + l2, l3 + 1);
+ return p;
+}
+
+char *strealloc(p, s)
+char *p;
+char *s;
+{
+ int len = strlen(s) + 1;
+
+ p = (char *) xrealloc((voidp) p, len);
+
+ strcpy(p, s);
+#ifdef DEBUG_MEM
+ malloc_verify();
+#endif /* DEBUG_MEM */
+ return p;
+}
+
+char **strsplit P((char *s, int ch, int qc));
+char **strsplit(s, ch, qc)
+char *s;
+int ch;
+int qc;
+{
+ char **ivec;
+ int ic = 0;
+ int done = 0;
+
+ ivec = (char **) xmalloc((ic+1)*sizeof(char *));
+
+ while (!done) {
+ char *v;
+ /*
+ * skip to split char
+ */
+ while (*s && (ch == ' ' ? (isascii(*s) && isspace(*s)) : *s == ch))
+ *s++ = '\0';
+
+ /*
+ * End of string?
+ */
+ if (!*s)
+ break;
+
+ /*
+ * remember start of string
+ */
+ v = s;
+
+ /*
+ * skip to split char
+ */
+ while (*s && !(ch == ' ' ? (isascii(*s) && isspace(*s)) : *s == ch)) {
+ if (*s++ == qc) {
+ /*
+ * Skip past string.
+ */
+ s++;
+ while (*s && *s != qc)
+ s++;
+ if (*s == qc)
+ s++;
+ }
+ }
+
+ if (!*s)
+ done = 1;
+ *s++ = '\0';
+
+ /*
+ * save string in new ivec slot
+ */
+ ivec[ic++] = v;
+ ivec = (char **) xrealloc((voidp) ivec, (ic+1)*sizeof(char *));
+#ifdef DEBUG
+ Debug(D_STR)
+ plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
+#endif /* DEBUG */
+ }
+
+#ifdef DEBUG
+ Debug(D_STR)
+ plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
+#endif /* DEBUG */
+
+ ivec[ic] = 0;
+
+ return ivec;
+}
+
+/*
+ * Strip off the trailing part of a domain
+ * to produce a short-form domain relative
+ * to the local host domain.
+ * Note that this has no effect if the domain
+ * names do not have the same number of
+ * components. If that restriction proves
+ * to be a problem then the loop needs recoding
+ * to skip from right to left and do partial
+ * matches along the way -- ie more expensive.
+ */
+static void domain_strip P((char *otherdom, char *localdom));
+static void domain_strip(otherdom, localdom)
+char *otherdom, *localdom;
+{
+#ifdef PARTIAL_DOMAINS
+ char *p1 = otherdom-1;
+ char *p2 = localdom-1;
+
+ do {
+ if (p1 = strchr(p1+1, '.'))
+ if (p2 = strchr(p2+1, '.'))
+ if (strcmp(p1+1, p2+1) == 0) {
+ *p1 = '\0';
+ break;
+ }
+ } while (p1 && p2);
+#else
+ char *p1, *p2;
+
+ if ((p1 = strchr(otherdom, '.')) &&
+ (p2 = strchr(localdom, '.')) &&
+ (strcmp(p1+1, p2+1) == 0))
+ *p1 = '\0';
+#endif /* PARTIAL_DOMAINS */
+}
+
+/*
+ * Normalize a host name
+ */
+void host_normalize P((char **chp));
+void host_normalize(chp)
+char **chp;
+{
+ /*
+ * Normalize hosts is used to resolve host name aliases
+ * and replace them with the standard-form name.
+ * Invoked with "-n" command line option.
+ */
+ if (normalize_hosts) {
+ struct hostent *hp;
+ clock_valid = 0;
+ hp = gethostbyname(*chp);
+ if (hp && hp->h_addrtype == AF_INET) {
+#ifdef DEBUG
+ dlog("Hostname %s normalized to %s", *chp, hp->h_name);
+#endif /* DEBUG */
+ *chp = strealloc(*chp, hp->h_name);
+ }
+ }
+ domain_strip(*chp, hostd);
+}
+
+/*
+ * Make a dotted quad from a 32bit IP address
+ * addr is in network byte order.
+ * sizeof(buf) needs to be at least 16.
+ */
+char *inet_dquad P((char *buf, unsigned long addr));
+char *inet_dquad(buf, addr)
+char *buf;
+unsigned long addr;
+{
+ addr = ntohl(addr);
+ sprintf(buf, "%d.%d.%d.%d",
+ ((addr >> 24) & 0xff),
+ ((addr >> 16) & 0xff),
+ ((addr >> 8) & 0xff),
+ ((addr >> 0) & 0xff));
+ return buf;
+}
+
+/*
+ * Keys are not allowed to contain " ' ! or ; to avoid
+ * problems with macro expansions.
+ */
+static char invalid_keys[] = "\"'!;@ \t\n";
+int valid_key P((char *key));
+int valid_key(key)
+char *key;
+{
+ while (*key)
+ if (strchr(invalid_keys, *key++))
+ return FALSE;
+ return TRUE;
+}
+
+void going_down P((int rc));
+void going_down(rc)
+int rc;
+{
+ if (foreground) {
+ if (amd_state != Start) {
+ if (amd_state != Done)
+ return;
+ unregister_amq();
+ }
+ }
+ if (foreground) {
+ plog(XLOG_INFO, "Finishing with status %d", rc);
+ } else {
+#ifdef DEBUG
+ dlog("background process exiting with status %d", rc);
+#endif /* DEBUG */
+ }
+
+ exit(rc);
+}
+
+
+int bind_resv_port P((int so, u_short *pp));
+int bind_resv_port(so, pp)
+int so;
+u_short *pp;
+{
+ struct sockaddr_in sin;
+ int rc;
+ unsigned short port;
+
+ bzero((voidp) &sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ port = IPPORT_RESERVED;
+
+ do {
+ --port;
+ sin.sin_port = htons(port);
+ rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
+ } while (rc < 0 && port > IPPORT_RESERVED/2);
+
+ if (pp && rc == 0)
+ *pp = port;
+ return rc;
+}
+
+void forcibly_timeout_mp P((am_node *mp));
+void forcibly_timeout_mp(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ /*
+ * Arrange to timeout this node
+ */
+ if (mf && ((mp->am_flags & AMF_ROOT) ||
+ (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)))) {
+ if (!(mf->mf_flags & MFF_UNMOUNTING))
+ plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
+ } else {
+ plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ mp->am_ttl = clocktime();
+ reschedule_timeout_mp();
+ }
+}
+
+void mf_mounted P((mntfs *mf));
+void mf_mounted(mf)
+mntfs *mf;
+{
+ int quoted;
+ int wasmounted = mf->mf_flags & MFF_MOUNTED;
+
+ if (!wasmounted) {
+ /*
+ * If this is a freshly mounted
+ * filesystem then update the
+ * mntfs structure...
+ */
+ mf->mf_flags |= MFF_MOUNTED;
+ mf->mf_error = 0;
+
+ /*
+ * Do mounted callback
+ */
+ if (mf->mf_ops->mounted)
+ (*mf->mf_ops->mounted)(mf);
+
+ mf->mf_fo = 0;
+ }
+
+ /*
+ * Log message
+ */
+ quoted = strchr(mf->mf_info, ' ') != 0;
+ plog(XLOG_INFO, "%s%s%s %s fstype %s on %s",
+ quoted ? "\"" : "",
+ mf->mf_info,
+ quoted ? "\"" : "",
+ wasmounted ? "referenced" : "mounted",
+ mf->mf_ops->fs_type, mf->mf_mount);
+}
+
+void am_mounted P((am_node *mp));
+void am_mounted(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ mf_mounted(mf);
+
+ /*
+ * Patch up path for direct mounts
+ */
+ if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &dfs_ops)
+ mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
+
+ /*
+ * Check whether this mount should be cached permanently
+ */
+ if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
+ mp->am_flags |= AMF_NOTIMEOUT;
+ } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
+ mp->am_flags |= AMF_NOTIMEOUT;
+ } else {
+ struct mntent mnt;
+ if (mf->mf_mopts) {
+ mnt.mnt_opts = mf->mf_mopts;
+ if (hasmntopt(&mnt, "nounmount"))
+ mp->am_flags |= AMF_NOTIMEOUT;
+ if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
+ mp->am_timeo = am_timeo;
+ }
+ }
+
+ /*
+ * If this node is a symlink then
+ * compute the length of the returned string.
+ */
+ if (mp->am_fattr.type == NFLNK)
+ mp->am_fattr.size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
+
+ /*
+ * Record mount time
+ */
+ mp->am_fattr.mtime.seconds = mp->am_stats.s_mtime = clocktime();
+ new_ttl(mp);
+ /*
+ * Update mtime of parent node
+ */
+ if (mp->am_parent && mp->am_parent->am_mnt)
+ mp->am_parent->am_fattr.mtime.seconds = mp->am_stats.s_mtime;
+
+
+ /*
+ * Update stats
+ */
+ amd_stats.d_mok++;
+}
+
+int mount_node P((am_node *mp));
+int mount_node(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ int error;
+
+ mf->mf_flags |= MFF_MOUNTING;
+ error = (*mf->mf_ops->mount_fs)(mp);
+ mf = mp->am_mnt;
+ if (error >= 0)
+ mf->mf_flags &= ~MFF_MOUNTING;
+ if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
+ /* ...but see ifs_mount */
+ am_mounted(mp);
+ }
+
+ return error;
+}
+
+void am_unmounted P((am_node *mp));
+void am_unmounted(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ if (!foreground) /* firewall - should never happen */
+ return;
+
+#ifdef DEBUG
+ /*dlog("in am_unmounted(), foreground = %d", foreground);*/
+#endif /* DEBUG */
+
+ /*
+ * Do unmounted callback
+ */
+ if (mf->mf_ops->umounted)
+ (*mf->mf_ops->umounted)(mp);
+
+ /*
+ * Update mtime of parent node
+ */
+ if (mp->am_parent && mp->am_parent->am_mnt)
+ mp->am_parent->am_fattr.mtime.seconds = clocktime();
+
+ free_map(mp);
+}
+
+int auto_fmount P((am_node *mp));
+int auto_fmount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ return (*mf->mf_ops->fmount_fs)(mf);
+}
+
+int auto_fumount P((am_node *mp));
+int auto_fumount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ return (*mf->mf_ops->fumount_fs)(mf);
+}
+
+/*
+ * Fork the automounter
+ *
+ * TODO: Need a better strategy for handling errors
+ */
+static int dofork(P_void);
+static int dofork()
+{
+ int pid;
+top:
+ pid = fork();
+
+ if (pid < 0) {
+ sleep(1);
+ goto top;
+ }
+
+ if (pid == 0) {
+ mypid = getpid();
+ foreground = 0;
+ }
+
+ return pid;
+}
+
+int background(P_void);
+int background()
+{
+ int pid = dofork();
+ if (pid == 0) {
+#ifdef DEBUG
+ dlog("backgrounded");
+#endif
+ foreground = 0;
+ }
+
+ return pid;
+}
+
+/*
+ * Make all the directories in the path.
+ */
+int mkdirs P((char *path, int mode));
+int mkdirs(path, mode)
+char *path;
+int mode;
+{
+ /*
+ * take a copy in case path is in readonly store
+ */
+ char *p2 = strdup(path);
+ char *sp = p2;
+ struct stat stb;
+ int error_so_far = 0;
+
+ /*
+ * Skip through the string make the directories.
+ * Mostly ignore errors - the result is tested at the end.
+ *
+ * This assumes we are root so that we can do mkdir in a
+ * mode 555 directory...
+ */
+ while (sp = strchr(sp+1, '/')) {
+ *sp = '\0';
+ if (mkdir(p2, mode) < 0) {
+ error_so_far = errno;
+ } else {
+#ifdef DEBUG
+ dlog("mkdir(%s)", p2);
+#endif
+ }
+ *sp = '/';
+ }
+
+ if (mkdir(p2, mode) < 0) {
+ error_so_far = errno;
+ } else {
+#ifdef DEBUG
+ dlog("mkdir(%s)", p2);
+#endif
+ }
+
+#ifdef SUNOS4_WORKAROUND
+ /*
+ * Do a sync - if we do rmdirs() immediately
+ * and then the system crashes it leaves
+ * the filesystem in a state that fsck -p
+ * can't fix. (Observed more than once on
+ * SunOS 4 ...)
+ *
+ * The problem was caused by a bug somewhere
+ * in the UFS code which has since been fixed
+ * (at least at Berkeley).
+ *
+ * Attempted workaround - XXX.
+ */
+ sync();
+#endif /* SUNOS4_WORKAROUND */
+
+ free(p2);
+
+ return stat(path, &stb) == 0 &&
+ (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far;
+}
+
+/*
+ * Remove as many directories in the path as possible.
+ * Give up if the directory doesn't appear to have
+ * been created by Amd (not mode dr-x) or an rmdir
+ * fails for any reason.
+ */
+void rmdirs P((char *dir));
+void rmdirs(dir)
+char *dir;
+{
+ char *xdp = strdup(dir);
+ char *dp;
+
+ do {
+ struct stat stb;
+ /*
+ * Try to find out whether this was
+ * created by amd. Do this by checking
+ * for owner write permission.
+ */
+ if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) {
+ if (rmdir(xdp) < 0) {
+ if (errno != ENOTEMPTY &&
+ errno != EBUSY &&
+ errno != EEXIST &&
+ errno != EINVAL)
+ plog(XLOG_ERROR, "rmdir(%s): %m", xdp);
+ break;
+ } else {
+#ifdef DEBUG
+ dlog("rmdir(%s)", xdp);
+#endif
+ }
+ } else {
+ break;
+ }
+ dp = strrchr(xdp, '/');
+ if (dp)
+ *dp = '\0';
+ } while (dp && dp > xdp);
+ free(xdp);
+}
diff --git a/usr.sbin/amd/amd/wire.c b/usr.sbin/amd/amd/wire.c
new file mode 100644
index 00000000000..0b4395e5cdc
--- /dev/null
+++ b/usr.sbin/amd/amd/wire.c
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ *
+ * from: @(#)wire.c 8.1 (Berkeley) 6/6/93
+ * $Id: wire.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+/*
+ * This function returns the subnet (address&netmask) for the primary network
+ * interface. If the resulting address has an entry in the hosts file, the
+ * corresponding name is retuned, otherwise the address is returned in
+ * standard internet format.
+ * As a side-effect, a list of local IP/net address is recorded for use
+ * by the islocalnet() function.
+ *
+ * Derived from original by Paul Anderson (23/4/90)
+ * Updates from Dirk Grunwald (11/11/91)
+ */
+
+#include "am.h"
+
+#include <sys/ioctl.h>
+
+#define NO_SUBNET "notknown"
+
+/*
+ * List of locally connected networks
+ */
+typedef struct addrlist addrlist;
+struct addrlist {
+ addrlist *ip_next;
+ unsigned long ip_addr;
+ unsigned long ip_mask;
+};
+static addrlist *localnets = 0;
+
+#ifdef SIOCGIFFLAGS
+#ifdef STELLIX
+#include <sys/sema.h>
+#endif /* STELLIX */
+#include <net/if.h>
+#include <netdb.h>
+
+#if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK)
+#define IFF_LOOPBACK IFF_LOCAL_LOOPBACK
+#endif
+
+#define GFBUFLEN 1024
+#define clist (ifc.ifc_ifcu.ifcu_req)
+#define count (ifc.ifc_len/sizeof(struct ifreq))
+
+char *getwire P((void));
+char *getwire()
+{
+ struct hostent *hp;
+ struct netent *np;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ caddr_t cp, cplim;
+ unsigned long address, netmask, subnet;
+ char buf[GFBUFLEN], *s;
+ int sk = -1;
+ char *netname = 0;
+
+ /*
+ * Get suitable socket
+ */
+ if ((sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ goto out;
+
+ /*
+ * Fill in ifconf details
+ */
+ ifc.ifc_len = sizeof buf;
+ ifc.ifc_buf = buf;
+
+ /*
+ * Get network interface configurations
+ */
+ if (ioctl(sk, SIOCGIFCONF, (caddr_t) &ifc) < 0)
+ goto out;
+
+ /*
+ * Upper bound on array
+ */
+ cplim = buf + ifc.ifc_len;
+
+ /*
+ * This is some magic to cope with both "traditional" and the
+ * new 4.4BSD-style struct sockaddrs. The new structure has
+ * variable length and a size field to support longer addresses.
+ * AF_LINK is a new definition for 4.4BSD.
+ */
+#ifdef AF_LINK
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define size(ifr) (max((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name))
+#else
+#define size(ifr) sizeof(*ifr)
+#endif
+ /*
+ * Scan the list looking for a suitable interface
+ */
+ for (cp = buf; cp < cplim; cp += size(ifr)) {
+ addrlist *al;
+ ifr = (struct ifreq *) cp;
+
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ else
+ address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+
+ /*
+ * Get interface flags
+ */
+ if (ioctl(sk, SIOCGIFFLAGS, (caddr_t) ifr) < 0)
+ continue;
+
+ /*
+ * If the interface is a loopback, or its not running
+ * then ignore it.
+ */
+ if ((ifr->ifr_flags & IFF_LOOPBACK) != 0)
+ continue;
+ if ((ifr->ifr_flags & IFF_RUNNING) == 0)
+ continue;
+
+ /*
+ * Get the netmask of this interface
+ */
+ if (ioctl(sk, SIOCGIFNETMASK, (caddr_t) ifr) < 0)
+ continue;
+
+ netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+
+ /*
+ * Add interface to local network list
+ */
+ al = ALLOC(addrlist);
+ al->ip_addr = address;
+ al->ip_mask = netmask;
+ al->ip_next = localnets;
+ localnets = al;
+
+ if (netname == 0) {
+ unsigned long net;
+ unsigned long mask;
+ unsigned long subnetshift;
+ /*
+ * Figure out the subnet's network address
+ */
+ subnet = address & netmask;
+
+#ifdef IN_CLASSA
+ subnet = ntohl(subnet);
+
+ if (IN_CLASSA(subnet)) {
+ mask = IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(subnet)) {
+ mask = IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use.
+ * Guess at the subnet mask, assuming reasonable
+ * width subnet fields.
+ * XXX: Or-in at least 1 byte's worth of 1s to make
+ * sure the top bits remain set.
+ */
+ while (subnet &~ mask)
+ mask = (mask >> subnetshift) | 0xff000000;
+
+ net = subnet & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, net >>= 1;
+
+ /*
+ * Now get a usable name.
+ * First use the network database,
+ * then the host database,
+ * and finally just make a dotted quad.
+ */
+
+ np = getnetbyaddr(net, AF_INET);
+#else
+ /* This is probably very wrong. */
+ np = getnetbyaddr(subnet, AF_INET);
+#endif /* IN_CLASSA */
+ if (np)
+ s = np->n_name;
+ else {
+ subnet = address & netmask;
+ hp = gethostbyaddr((char *) &subnet, 4, AF_INET);
+ if (hp)
+ s = hp->h_name;
+ else
+ s = inet_dquad(buf, subnet);
+ }
+ netname = strdup(s);
+ }
+ }
+
+out:
+ if (sk >= 0)
+ (void) close(sk);
+ if (netname)
+ return netname;
+ return strdup(NO_SUBNET);
+}
+
+#else
+
+char *getwire P((void));
+char *getwire()
+{
+ return strdup(NO_SUBNET);
+}
+#endif /* SIOCGIFFLAGS */
+
+/*
+ * Determine whether a network is on a local network
+ * (addr) is in network byte order.
+ */
+int islocalnet P((unsigned long addr));
+int islocalnet(addr)
+unsigned long addr;
+{
+ addrlist *al;
+
+ for (al = localnets; al; al = al->ip_next)
+ if (((addr ^ al->ip_addr) & al->ip_mask) == 0)
+ return TRUE;
+
+#ifdef DEBUG
+ { char buf[16];
+ plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr));
+ }
+#endif
+ return FALSE;
+}
diff --git a/usr.sbin/amd/amd/xutil.c b/usr.sbin/amd/amd/xutil.c
new file mode 100644
index 00000000000..6134bb96d65
--- /dev/null
+++ b/usr.sbin/amd/amd/xutil.c
@@ -0,0 +1,489 @@
+/*
+ * 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.
+ *
+ * from: @(#)xutil.c 8.1 (Berkeley) 6/6/93
+ * $Id: xutil.c,v 1.1.1.1 1995/10/18 08:47:12 deraadt Exp $
+ */
+
+#include "config.h"
+#ifdef HAS_SYSLOG
+#include <syslog.h>
+#endif /* HAS_SYSLOG */
+#ifdef HAS_STRERROR
+#include <string.h>
+#endif
+
+FILE *logfp = stderr; /* Log errors to stderr initially */
+#ifdef HAS_SYSLOG
+int syslogging;
+#endif /* HAS_SYSLOG */
+int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS;
+int xlog_level_init = ~0;
+
+/*
+ * List of log options
+ */
+struct opt_tab xlog_opt[] = {
+ { "all", XLOG_ALL }, /* All messages */
+#ifdef DEBUG
+ { "debug", XLOG_DEBUG }, /* Debug messages */
+#endif /* DEBUG */
+ { "error", XLOG_ERROR }, /* Non-fatal system errors */
+ { "fatal", XLOG_FATAL }, /* Fatal errors */
+ { "info", XLOG_INFO }, /* Information */
+ { "map", XLOG_MAP }, /* Map errors */
+ { "stats", XLOG_STATS }, /* Additional statistical information */
+ { "user", XLOG_USER }, /* Non-fatal user errors */
+ { "warn", XLOG_WARNING }, /* Warnings */
+ { "warning", XLOG_WARNING }, /* Warnings */
+ { 0, 0 }
+};
+
+voidp xmalloc(len)
+int len;
+{
+ voidp p;
+ int retries = 600;
+
+ /*
+ * Avoid malloc's which return NULL for malloc(0)
+ */
+ if (len == 0)
+ len = 1;
+
+ do {
+ p = (voidp) malloc((unsigned) len);
+ if (p) {
+#if defined(DEBUG) && defined(DEBUG_MEM)
+ Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
+ return p;
+ }
+ if (retries > 0) {
+ plog(XLOG_ERROR, "Retrying memory allocation");
+ sleep(1);
+ }
+ } while (--retries);
+
+ plog(XLOG_FATAL, "Out of memory");
+ going_down(1);
+
+ abort();
+
+ return 0;
+}
+
+voidp xrealloc(ptr, len)
+voidp ptr;
+int len;
+{
+#if defined(DEBUG) && defined(DEBUG_MEM)
+ Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
+
+ if (len == 0)
+ len = 1;
+
+ if (ptr)
+ ptr = (voidp) realloc(ptr, (unsigned) len);
+ else
+ ptr = (voidp) xmalloc((unsigned) len);
+
+ if (!ptr) {
+ plog(XLOG_FATAL, "Out of memory in realloc");
+ going_down(1);
+ abort();
+ }
+ return ptr;
+}
+
+#if defined(DEBUG) && defined(DEBUG_MEM)
+xfree(f, l, p)
+char *f;
+int l;
+voidp p;
+{
+ Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p);
+#undef free
+ free(p);
+}
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
+#ifdef DEBUG_MEM
+static int mem_bytes;
+static int orig_mem_bytes;
+static void checkup_mem(P_void)
+{
+extern struct mallinfo __mallinfo;
+ if (mem_bytes != __mallinfo.uordbytes) {
+ if (orig_mem_bytes == 0)
+ mem_bytes = orig_mem_bytes = __mallinfo.uordbytes;
+ else {
+ fprintf(logfp, "%s[%d]: ", progname, mypid);
+ if (mem_bytes < __mallinfo.uordbytes) {
+ fprintf(logfp, "ALLOC: %d bytes",
+ __mallinfo.uordbytes - mem_bytes);
+ } else {
+ fprintf(logfp, "FREE: %d bytes",
+ mem_bytes - __mallinfo.uordbytes);
+ }
+ mem_bytes = __mallinfo.uordbytes;
+ fprintf(logfp, ", making %d missing\n",
+ mem_bytes - orig_mem_bytes);
+ }
+ }
+ malloc_verify();
+}
+#endif /* DEBUG_MEM */
+
+/*
+ * Take a log format string and expand occurences of %m
+ * with the current error code take from errno.
+ */
+INLINE
+static void expand_error(f, e)
+char *f;
+char *e;
+{
+#ifndef HAS_STRERROR
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif
+ char *p;
+ int error = errno;
+
+ for (p = f; *e = *p; e++, p++) {
+ if (p[0] == '%' && p[1] == 'm') {
+ char *errstr;
+#ifdef HAS_STRERROR
+ errstr = strerror(error);
+#else
+ if (error < 0 || error >= sys_nerr)
+ errstr = 0;
+ else
+ errstr = sys_errlist[error];
+#endif
+ if (errstr)
+ strcpy(e, errstr);
+ else
+ sprintf(e, "Error %d", error);
+ e += strlen(e) - 1;
+ p++;
+ }
+ }
+}
+
+/*
+ * Output the time of day and hostname to the logfile
+ */
+static void show_time_host_and_name(lvl)
+int lvl;
+{
+static time_t last_t = 0;
+static char *last_ctime = 0;
+ time_t t = clocktime();
+ char *sev;
+ extern char *ctime();
+
+#if defined(DEBUG) && defined(PARANOID)
+extern char **gargv;
+#endif /* defined(DEBUG) && defined(PARANOID) */
+
+ if (t != last_t) {
+ last_ctime = ctime(&t);
+ last_t = t;
+ }
+
+ switch (lvl) {
+ case XLOG_FATAL: sev = "fatal:"; break;
+ case XLOG_ERROR: sev = "error:"; break;
+ case XLOG_USER: sev = "user: "; break;
+ case XLOG_WARNING: sev = "warn: "; break;
+ case XLOG_INFO: sev = "info: "; break;
+ case XLOG_DEBUG: sev = "debug:"; break;
+ case XLOG_MAP: sev = "map: "; break;
+ case XLOG_STATS: sev = "stats:"; break;
+ default: sev = "hmm: "; break;
+ }
+ fprintf(logfp, "%15.15s %s %s[%d]/%s ",
+ last_ctime+4, hostname,
+#if defined(DEBUG) && defined(PARANOID)
+ gargv[0],
+#else
+ progname,
+#endif /* defined(DEBUG) && defined(PARANOID) */
+ mypid,
+ sev);
+}
+
+#ifdef DEBUG
+/*VARARGS1*/
+void dplog(fmt, j,s,_,p,e,n,d,r,y)
+char *fmt;
+char *j, *s, *_, *p, *e, *n, *d, *r, *y;
+{
+ plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y);
+}
+
+#endif /* DEBUG */
+/*VARARGS1*/
+void plog(lvl, fmt, j,s,_,p,e,n,d,r,y)
+int lvl;
+char *fmt;
+char *j, *s, *_, *p, *e, *n, *d, *r, *y;
+{
+ char msg[1024];
+ char efmt[1024];
+ char *ptr = msg;
+
+ if (!(xlog_level & lvl))
+ return;
+
+#ifdef DEBUG_MEM
+ checkup_mem();
+#endif /* DEBUG_MEM */
+
+ expand_error(fmt, efmt);
+ sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y);
+ ptr += strlen(ptr);
+ if (ptr[-1] == '\n')
+ *--ptr = '\0';
+#ifdef HAS_SYSLOG
+ if (syslogging) {
+ switch(lvl) { /* from mike <mcooper@usc.edu> */
+ case XLOG_FATAL: lvl = LOG_CRIT; break;
+ case XLOG_ERROR: lvl = LOG_ERR; break;
+ case XLOG_USER: lvl = LOG_WARNING; break;
+ case XLOG_WARNING: lvl = LOG_WARNING; break;
+ case XLOG_INFO: lvl = LOG_INFO; break;
+ case XLOG_DEBUG: lvl = LOG_DEBUG; break;
+ case XLOG_MAP: lvl = LOG_DEBUG; break;
+ case XLOG_STATS: lvl = LOG_INFO; break;
+ default: lvl = LOG_ERR; break;
+ }
+ syslog(lvl, "%s", msg);
+ return;
+ }
+#endif /* HAS_SYSLOG */
+
+ *ptr++ = '\n';
+ *ptr = '\0';
+
+ /*
+ * Mimic syslog header
+ */
+ show_time_host_and_name(lvl);
+ fwrite(msg, ptr - msg, 1, logfp);
+ fflush(logfp);
+}
+
+void show_opts P((int ch, struct opt_tab *opts));
+void show_opts(ch, opts)
+int ch;
+struct opt_tab *opts;
+{
+ /*
+ * Display current debug options
+ */
+ int i;
+ int s = '{';
+ fprintf(stderr, "\t[-%c {no}", ch);
+ for (i = 0; opts[i].opt; i++) {
+ fprintf(stderr, "%c%s", s, opts[i].opt);
+ s = ',';
+ }
+ fputs("}]\n", stderr);
+}
+
+int cmdoption P((char *s, struct opt_tab *optb, int *flags));
+int cmdoption(s, optb, flags)
+char *s;
+struct opt_tab *optb;
+int *flags;
+{
+ char *p = s;
+ int errs = 0;
+
+ while (p && *p) {
+ int neg;
+ char *opt;
+ struct opt_tab *dp, *dpn = 0;
+
+ s = p;
+ p = strchr(p, ',');
+ if (p)
+ *p = '\0';
+
+ if (s[0] == 'n' && s[1] == 'o') {
+ opt = s + 2;
+ neg = 1;
+ } else {
+ opt = s;
+ neg = 0;
+ }
+
+ /*
+ * Scan the array of debug options to find the
+ * corresponding flag value. If it is found
+ * then set (or clear) the flag (depending on
+ * whether the option was prefixed with "no").
+ */
+ for (dp = optb; dp->opt; dp++) {
+ if (strcmp(opt, dp->opt) == 0)
+ break;
+ if (opt != s && !dpn && strcmp(s, dp->opt) == 0)
+ dpn = dp;
+ }
+
+ if (dp->opt || dpn) {
+ if (!dp->opt) {
+ dp = dpn;
+ neg = !neg;
+ }
+ if (neg)
+ *flags &= ~dp->flag;
+ else
+ *flags |= dp->flag;
+ } else {
+ /*
+ * This will log to stderr when parsing the command line
+ * since any -l option will not yet have taken effect.
+ */
+ plog(XLOG_USER, "option \"%s\" not recognised", s);
+ errs++;
+ }
+ /*
+ * Put the comma back
+ */
+ if (p)
+ *p++ = ',';
+ }
+
+ return errs;
+}
+
+/*
+ * Switch on/off logging options
+ */
+int switch_option(opt)
+char *opt;
+{
+ int xl = xlog_level;
+ int rc = cmdoption(opt, xlog_opt, &xl);
+ if (rc) {
+ rc = EINVAL;
+ } else {
+ /*
+ * Keep track of initial log level, and
+ * don't allow options to be turned off.
+ */
+ if (xlog_level_init == ~0)
+ xlog_level_init = xl;
+ else
+ xl |= xlog_level_init;
+ xlog_level = xl;
+ }
+ return rc;
+}
+
+/*
+ * Change current logfile
+ */
+int switch_to_logfile P((char *logfile));
+int switch_to_logfile(logfile)
+char *logfile;
+{
+ FILE *new_logfp = stderr;
+
+ if (logfile) {
+#ifdef HAS_SYSLOG
+ syslogging = 0;
+#endif /* HAS_SYSLOG */
+ if (strcmp(logfile, "/dev/stderr") == 0)
+ new_logfp = stderr;
+ else if (strcmp(logfile, "syslog") == 0) {
+#ifdef HAS_SYSLOG
+ syslogging = 1;
+ new_logfp = stderr;
+#if defined(LOG_CONS) && defined(LOG_NOWAIT)
+ openlog(progname, LOG_PID|LOG_CONS|LOG_NOWAIT,
+ LOG_DAEMON);
+#else
+ /* 4.2 compat mode - XXX */
+ openlog(progname, LOG_PID);
+#endif /* LOG_CONS && LOG_NOWAIT */
+#else
+ plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
+#endif /* HAS_SYSLOG */
+ } else {
+ (void) umask(orig_umask);
+ new_logfp = fopen(logfile, "a");
+ umask(0);
+ }
+ }
+
+ /*
+ * If we couldn't open a new file, then continue using the old.
+ */
+ if (!new_logfp && logfile) {
+ plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
+ return 1;
+ }
+ /*
+ * Close the previous file
+ */
+ if (logfp && logfp != stderr)
+ (void) fclose(logfp);
+ logfp = new_logfp;
+ return 0;
+}
+
+time_t clock_valid = 0;
+time_t xclock_valid = 0;
+#ifndef clocktime
+time_t clocktime(P_void)
+{
+ time_t now = time(&clock_valid);
+ if (xclock_valid > now) {
+ /*
+ * Someone set the clock back!
+ */
+ plog(XLOG_WARNING, "system clock reset");
+ reschedule_timeouts(now, xclock_valid);
+ }
+ return xclock_valid = now;
+}
+#endif /* clocktime */
diff --git a/usr.sbin/amd/amq/Makefile b/usr.sbin/amd/amq/Makefile
new file mode 100644
index 00000000000..058aeef7aec
--- /dev/null
+++ b/usr.sbin/amd/amq/Makefile
@@ -0,0 +1,18 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+
+.include "../config/Makefile.config"
+
+PROG = amq
+SRCS = amq.c amq_clnt.c amq_xdr.c misc_rpc.c
+MAN = amq.8
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-DARCH_REP=\"${MACHINE}\"
+CFLAGS+=-DOS_REP=\"${OS}\"
+CFLAGS+=-DOS_HDR=\"os-${OS}.h\"
+.PATH: ${.CURDIR}/../rpcx ${.CURDIR}/../amd
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/amq/amq.8 b/usr.sbin/amd/amq/amq.8
new file mode 100644
index 00000000000..13f30100ebe
--- /dev/null
+++ b/usr.sbin/amd/amq/amq.8
@@ -0,0 +1,129 @@
+.\"
+.\" Copyright (c) 1990 Jan-Simon Pendry
+.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+.\" Copyright (c) 1990, 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.
+.\"
+.\" from: @(#)amq.8 8.3 (Berkeley) 4/18/94
+.\" $Id: amq.8,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt AMQ 8
+.Os
+.Sh NAME
+.Nm amq
+.Nd automounter query tool
+.Sh SYNOPSIS
+.Nm amq
+.Op Fl f
+.Op Fl h Ar hostname
+.Op Fl M Ar mountmap_entry
+.Op Fl m
+.Op Fl s
+.Op Fl u
+.Op Fl v
+.Op Ar directory
+.Ar ...
+.Sh DESCRIPTION
+.Nm Amq
+provides a simple way of determining the current state of the
+.Xr amd 8
+program.
+Communication is by
+.Tn RPC .
+Three modes of operation are supported by the current protocol.
+By default a list of mount points and auto-mounted filesystems
+is output.
+An alternative host can be specified using the
+.Fl h
+option.
+.Pp
+If directory names are given, as output by default,
+then per-filesystem information is displayed.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl f
+Request automounter to flush the internal caches.
+.It Fl h Ar hostname
+Query alternate host
+.Ar hostname .
+By default the local host is used. In an
+.Tn HP-UX
+cluster, the root server is queried by default, since
+that is the system on which the automounter is normally run.
+.It Fl m
+Request the automounter to provide a list of mounted filesystems,
+including the number of references to each filesystem and any error
+which occurred while mounting.
+.It Fl s
+Request the automounter to provide system-wide mount statistics.
+.It Fl u
+Request the automounter to unmount the named filesystems
+instead of providing information about them. Unmounts are requested,
+not forced. They merely cause the mounted filesystem to timeout,
+which will be picked up by
+.Xr amd Ns \'s
+main scheduler thus causing the normal timeout action to be taken.
+.It Fl v
+Request the automounter to provide version information. This is a subset
+of the information provided by
+.Xr amd Ns \'s Fl v
+option.
+.It Fl M
+Request automounter to add the given map entry to the root map and then
+trigger a mount request for it.
+.El
+.Sh FILES
+.Bl -tag -width amq.xxxxx -compact
+.Bl -tag -width Ds
+.It Pa amq.x
+.Tn RPC
+protocol description.
+.El
+.Sh CAVEATS
+.Nm Amq
+uses a Sun registered
+.Tn RPC
+program number (300019 decimal) which may not
+be in the
+.Pa /etc/rpc
+database.
+.Sh SEE ALSO
+.Xr amd 8
+.Sh AUTHOR
+.An Jan-Simon Pendry
+<jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
+.\" .Sh HISTORY
+.\" .Nm Amq
+.\" .At
diff --git a/usr.sbin/amd/amq/amq.c b/usr.sbin/amd/amq/amq.c
new file mode 100644
index 00000000000..8096e3894fb
--- /dev/null
+++ b/usr.sbin/amd/amq/amq.c
@@ -0,0 +1,664 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq.c 8.1 (Berkeley) 6/7/93
+ * $Id: amq.c,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+ */
+
+/*
+ * Automounter query tool
+ */
+
+#ifndef lint
+char copyright[] = "\
+@(#)Copyright (c) 1990 Jan-Simon Pendry\n\
+@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
+@(#)Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] = "$Id: amq.c,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $";
+static char sccsid[] = "@(#)amq.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+#include "am.h"
+#include "amq.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+static int privsock();
+
+char *progname;
+static int flush_flag;
+static int minfo_flag;
+static int unmount_flag;
+static int stats_flag;
+static int getvers_flag;
+static char *debug_opts;
+static char *logfile;
+static char *mount_map;
+static char *xlog_optstr;
+static char localhost[] = "localhost";
+static char *def_server = localhost;
+
+extern int optind;
+extern char *optarg;
+
+static struct timeval tmo = { 10, 0 };
+#define TIMEOUT tmo
+
+enum show_opt { Full, Stats, Calc, Short, ShowDone };
+
+/*
+ * If (e) is Calc then just calculate the sizes
+ * Otherwise display the mount node on stdout
+ */
+static void show_mti(mt, e, mwid, dwid, twid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+ switch (e) {
+ case Calc: {
+ int mw = strlen(mt->mt_mountinfo);
+ int dw = strlen(mt->mt_directory);
+ int tw = strlen(mt->mt_type);
+ if (mw > *mwid) *mwid = mw;
+ if (dw > *dwid) *dwid = dw;
+ if (tw > *twid) *twid = tw;
+ } break;
+
+ case Full: {
+ struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
+printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
+ *twid, *twid,
+ mt->mt_type,
+ *mwid, *mwid,
+ mt->mt_mountinfo,
+ mt->mt_mountpoint,
+
+ mt->mt_mountuid,
+ mt->mt_getattr,
+ mt->mt_lookup,
+ mt->mt_readdir,
+ mt->mt_readlink,
+ mt->mt_statfs,
+
+ tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+ tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ } break;
+
+ case Stats: {
+ struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
+printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
+
+ mt->mt_mountuid,
+ mt->mt_getattr,
+ mt->mt_lookup,
+ mt->mt_readdir,
+ mt->mt_readlink,
+ mt->mt_statfs,
+
+ tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+ tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ } break;
+
+ case Short: {
+ printf("%-*.*s %-*.*s %-*.*s %s\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/",
+ *twid, *twid,
+ mt->mt_type,
+ *mwid, *mwid,
+ mt->mt_mountinfo,
+ mt->mt_mountpoint);
+ } break;
+ }
+}
+
+/*
+ * Display a mount tree.
+ */
+static void show_mt(mt, e, mwid, dwid, pwid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *pwid;
+{
+ while (mt) {
+ show_mti(mt, e, mwid, dwid, pwid);
+ show_mt(mt->mt_next, e, mwid, dwid, pwid);
+ mt = mt->mt_child;
+ }
+}
+
+static void show_mi(ml, e, mwid, dwid, twid)
+amq_mount_info_list *ml;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+ int i;
+ switch (e) {
+ case Calc: {
+ for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+ amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+ int mw = strlen(mi->mi_mountinfo);
+ int dw = strlen(mi->mi_mountpt);
+ int tw = strlen(mi->mi_type);
+ if (mw > *mwid) *mwid = mw;
+ if (dw > *dwid) *dwid = dw;
+ if (tw > *twid) *twid = tw;
+ }
+ } break;
+
+ case Full: {
+ for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+ amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+ printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
+ *mwid, *mwid, mi->mi_mountinfo,
+ *dwid, *dwid, mi->mi_mountpt,
+ *twid, *twid, mi->mi_type,
+ mi->mi_refc, mi->mi_fserver,
+ mi->mi_up > 0 ? "up" :
+ mi->mi_up < 0 ? "starting" : "down");
+ if (mi->mi_error > 0) {
+#ifdef HAS_STRERROR
+ printf(" (%s)", strerror(mi->mi_error));
+#else
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ if (mi->mi_error < sys_nerr)
+ printf(" (%s)", sys_errlist[mi->mi_error]);
+ else
+ printf(" (Error %d)", mi->mi_error);
+#endif
+ } else if (mi->mi_error < 0) {
+ fputs(" (in progress)", stdout);
+ }
+ fputc('\n', stdout);
+ }
+ } break;
+ }
+}
+
+/*
+ * Display general mount statistics
+ */
+static void show_ms(ms)
+amq_mount_stats *ms;
+{
+ printf("\
+requests stale mount mount unmount\n\
+deferred fhandles ok failed failed\n\
+%-9d %-9d %-9d %-9d %-9d\n",
+ ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
+}
+
+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));
+}
+
+#ifdef hpux
+#include <cluster.h>
+static char *cluster_server()
+{
+ struct cct_entry *cp;
+
+ if (cnodeid() == 0) {
+ /*
+ * Not clustered
+ */
+ return def_server;
+ }
+
+ while (cp = getccent())
+ if (cp->cnode_type == 'r')
+ return cp->cnode_name;
+
+
+ return def_server;
+}
+#endif /* hpux */
+
+/*
+ * MAIN
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt_ch;
+ int errs = 0;
+ char *server;
+ struct sockaddr_in server_addr;
+
+ /* In order to pass the Amd security check, we must use a priv port. */
+ int s;
+
+ CLIENT *clnt;
+ struct hostent *hp;
+ int nodefault = 0;
+
+ /*
+ * Compute program name
+ */
+ if (argv[0]) {
+ progname = strrchr(argv[0], '/');
+ if (progname && progname[1])
+ progname++;
+ else
+ progname = argv[0];
+ }
+ if (!progname)
+ progname = "amq";
+
+ /*
+ * Parse arguments
+ */
+ while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:")) != EOF)
+ switch (opt_ch) {
+ case 'f':
+ flush_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'h':
+ def_server = optarg;
+ break;
+
+ case 'l':
+ logfile = optarg;
+ nodefault = 1;
+ break;
+
+ case 'm':
+ minfo_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 's':
+ stats_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'u':
+ unmount_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'v':
+ getvers_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'x':
+ xlog_optstr = optarg;
+ nodefault = 1;
+ break;
+
+ case 'D':
+ debug_opts = optarg;
+ nodefault = 1;
+ break;
+
+ case 'M':
+ mount_map = optarg;
+ nodefault = 1;
+ break;
+
+ default:
+ errs = 1;
+ break;
+ }
+
+ if (optind == argc) {
+ if (unmount_flag)
+ errs = 1;
+ }
+
+ if (errs) {
+show_usage:
+ fprintf(stderr, "\
+Usage: %s [-h host] [[-f] [-m] [-v] [-s]] | [[-u] directory ...]] |\n\
+\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n", progname);
+ exit(1);
+ }
+
+#ifdef hpux
+ /*
+ * Figure out root server of cluster
+ */
+ if (def_server == localhost)
+ server = cluster_server();
+ else
+#endif /* hpux */
+ server = def_server;
+
+ /*
+ * Get address of server
+ */
+ if ((hp = gethostbyname(server)) == 0 && strcmp(server, localhost) != 0) {
+ fprintf(stderr, "%s: Can't get address of %s\n", progname, server);
+ exit(1);
+ }
+ bzero(&server_addr, sizeof server_addr);
+ server_addr.sin_family = AF_INET;
+ if (hp) {
+ bcopy((voidp) hp->h_addr, (voidp) &server_addr.sin_addr,
+ sizeof(server_addr.sin_addr));
+ } else {
+ /* fake "localhost" */
+ server_addr.sin_addr.s_addr = htonl(0x7f000001);
+ }
+
+ /*
+ * Create RPC endpoint
+ */
+ s = privsock(SOCK_STREAM);
+ clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
+ if (clnt == 0) {
+ close(s);
+ s = privsock(SOCK_DGRAM);
+ clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, TIMEOUT, &s);
+ }
+ if (clnt == 0) {
+ fprintf(stderr, "%s: ", progname);
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+ /*
+ * Control debugging
+ */
+ if (debug_opts) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_DEBUG;
+ opt.as_str = debug_opts;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (rc && *rc < 0) {
+ fprintf(stderr, "%s: daemon not compiled for debug", progname);
+ errs = 1;
+ } else if (!rc || *rc > 0) {
+ fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Control logging
+ */
+ if (xlog_optstr) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_XLOG;
+ opt.as_str = xlog_optstr;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Control log file
+ */
+ if (logfile) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_LOGFILE;
+ opt.as_str = logfile;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, logfile);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Flush map cache
+ */
+ if (flush_flag) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_FLUSHMAPC;
+ opt.as_str = "";
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Mount info
+ */
+ if (minfo_flag) {
+ int dummy;
+ amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
+ if (ml) {
+ int mwid = 0, dwid = 0, twid = 0;
+ show_mi(ml, Calc, &mwid, &dwid, &twid);
+ mwid++; dwid++; twid++;
+ show_mi(ml, Full, &mwid, &dwid, &twid);
+
+ } else {
+ fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server);
+ }
+ }
+
+ /*
+ * Mount map
+ */
+ if (mount_map) {
+ int *rc;
+ do {
+ rc = amqproc_mount_1(&mount_map, clnt);
+ } while (rc && *rc < 0);
+ if (!rc || *rc > 0) {
+ if (rc)
+ errno = *rc;
+ else
+ errno = ETIMEDOUT;
+ fprintf(stderr, "%s: could not start new ", progname);
+ perror("autmount point");
+ }
+ }
+
+ /*
+ * Get Version
+ */
+ if (getvers_flag) {
+ amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
+ if (spp && *spp) {
+ printf("%s.\n", *spp);
+ free(*spp);
+ } else {
+ fprintf(stderr, "%s: failed to get version information\n", progname);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Apply required operation to all remaining arguments
+ */
+ if (optind < argc) {
+ do {
+ char *fs = argv[optind++];
+ if (unmount_flag) {
+ /*
+ * Unmount request
+ */
+ amqproc_umnt_1(&fs, clnt);
+ } else {
+ /*
+ * Stats request
+ */
+ amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
+ if (mtp) {
+ amq_mount_tree *mt = *mtp;
+ if (mt) {
+ int mwid = 0, dwid = 0, twid = 0;
+ show_mt(mt, Calc, &mwid, &dwid, &twid);
+ mwid++; dwid++, twid++;
+ printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
+ dwid, dwid, "What");
+ show_mt(mt, Stats, &mwid, &dwid, &twid);
+ } else {
+ fprintf(stderr, "%s: %s not automounted\n", progname, fs);
+ }
+ xdr_pri_free(xdr_amq_mount_tree_p, (caddr_t) mtp);
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ }
+ } while (optind < argc);
+ } else if (unmount_flag) {
+ goto show_usage;
+ } else if (stats_flag) {
+ amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
+ if (ms) {
+ show_ms(ms);
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ } else if (!nodefault) {
+ amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
+ if (mlp) {
+ enum show_opt e = Calc;
+ int mwid = 0, dwid = 0, pwid = 0;
+ while (e != ShowDone) {
+ int i;
+ for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
+ show_mt(mlp->amq_mount_tree_list_val[i],
+ e, &mwid, &dwid, &pwid);
+ }
+ mwid++; dwid++, pwid++;
+ if (e == Calc) e = Short;
+ else if (e == Short) e = ShowDone;
+ }
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ }
+
+ exit(errs);
+}
+
+/*
+ * udpresport creates a datagram socket and attempts to bind it to a
+ * secure port.
+ * returns: The bound socket, or -1 to indicate an error.
+ */
+static int inetresport(ty)
+int ty;
+{
+ int alport;
+ struct sockaddr_in addr;
+ int sock;
+
+ /* Use internet address family */
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if ((sock = socket(AF_INET, ty, 0)) < 0)
+ return -1;
+ for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) {
+ addr.sin_port = htons((u_short)alport);
+ if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0)
+ return sock;
+ if (errno != EADDRINUSE) {
+ close(sock);
+ return -1;
+ }
+ }
+ close(sock);
+ errno = EAGAIN;
+ return -1;
+}
+
+/*
+ * Privsock() calls inetresport() to attempt to bind a socket to a secure
+ * port. If inetresport() fails, privsock returns a magic socket number which
+ * indicates to RPC that it should make its own socket.
+ * returns: A privileged socket # or RPC_ANYSOCK.
+ */
+static int privsock(ty)
+int ty;
+{
+ int sock = inetresport(ty);
+
+ if (sock < 0) {
+ errno = 0;
+ /* Couldn't get a secure port, let RPC make an insecure one */
+ sock = RPC_ANYSOCK;
+ }
+ return sock;
+}
+
+#ifdef DEBUG
+xfree(f, l, p)
+char *f, *l;
+voidp p;
+{
+ free(p);
+}
+#endif /* DEBUG */
diff --git a/usr.sbin/amd/config/Configure b/usr.sbin/amd/config/Configure
new file mode 100644
index 00000000000..92b50d9ee5f
--- /dev/null
+++ b/usr.sbin/amd/config/Configure
@@ -0,0 +1,59 @@
+#!/bin/sh -
+#
+# 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.
+#
+# from: @(#)Configure 8.1 (Berkeley) 6/6/93
+# $Id: Configure,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+echo "Making ./arch and ./os-type executable ..."
+until chmod +x ./arch ./os-type; do echo "Error: chmod command failed" >&2; exit 1; done
+echo "Checking ./arch and ./os-type ..."
+echo ""
+arch="`sh ./arch 2>/dev/null`"
+os="`sh ./os-type 2>/dev/null`"
+case "$arch" in
+"") echo "./arch doesn't produce an answer - please check it" >&2; exit 1;;
+esac
+case "$os" in
+"") echo "./os-type doesn't produce an answer - please check it" >&2; exit 1;;
+esac
+cat << %
+This machine appears to be a "$arch" running "$os".
+If that is correct just run make.
+If those are incorrect please edit ./arch and ./os-type
+%
+exit 0
diff --git a/usr.sbin/amd/config/Makefile.aix3 b/usr.sbin/amd/config/Makefile.aix3
new file mode 100644
index 00000000000..7630c914c81
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.aix3
@@ -0,0 +1,4 @@
+# from: @(#)Makefile.aix3 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.aix3,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+SYSLIB = -lbsd
diff --git a/usr.sbin/amd/config/Makefile.bsd44 b/usr.sbin/amd/config/Makefile.bsd44
new file mode 100644
index 00000000000..c5b364b637a
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.bsd44
@@ -0,0 +1,7 @@
+# from: @(#)Makefile.bsd44 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.bsd44,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for 4.4 BSD
+#
+
+RPCLIB = -lrpc
diff --git a/usr.sbin/amd/config/Makefile.config b/usr.sbin/amd/config/Makefile.config
new file mode 100644
index 00000000000..c3e484dbdab
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.config
@@ -0,0 +1,92 @@
+# from: @(#)Makefile.config 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.config,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+
+OS = bsd44
+
+#
+# Comment/uncomment the following lines as required
+#
+
+#
+# Where local include files are stored
+#
+#XINCLUDE = -I/usr/local/athena/include
+
+#
+# Define RESOLV if your C library does not include support
+# for Hesiod and/or Named.
+#
+#RESOLV = -lhesiod -lresolv
+
+#
+# Define XLIBDIR if you have libraries not on the standard
+# search path.
+#
+#XLIBDIR = -L/usr/local/athena/lib
+
+#
+# Define DBM if your C library does not include
+# support for gdbm and/or ndbm.
+#
+#DBM = -lgdbm #-lndbm
+
+#
+# Define RPCLIB if your C library does not include
+# support for RPC
+#
+#RPCLIB = -lrpc
+
+#
+# Include support for Network Information Service (NIS)
+# Also define HAS_NIS_RELOAD to include map
+# enumeration code implementing "cache:=all"
+#
+HAS_NIS_MAPS = -DHAS_NIS_MAPS -DHAS_NIS_RELOAD
+
+#
+# Include support for file maps
+#
+HAS_FILE_MAPS = -DHAS_FILE_MAPS
+
+#
+# Include support for Hesiod
+# Also define HAS_HESIOD_RELOAD to include zone
+# transfer code implementing "cache:=all"
+#
+#HAS_HESIOD_MAPS = -DHAS_HESIOD_MAPS -DHAS_HESIOD_RELOAD
+
+#
+# Include support for /etc/passwd
+#
+HAS_PASSWD_MAPS = -DHAS_PASSWD_MAPS
+
+#
+# Include support for union maps
+#
+HAS_UNION_MAPS = -DHAS_UNION_MAPS
+
+#
+# Include support for ndbm.
+# This removes support for gdbm and is only supported
+# if your operating system supports ndbm
+#
+#HAS_NDBM_MAPS = -DHAS_NDBM_MAPS
+
+#
+# Include support for "regexp" maps
+#
+HAS_REGEXP = -DHAS_REGEXP
+
+#
+# Make sure that the hostname passed in RPC authentication packets
+# contains a fully qualified domain name. See nfs_ops.c
+#
+HAS_NFS_QUALIFIED_NAMES = -DHAS_NFS_QUALIFIED_NAMES
+
+##############################################################
+# Do NOT edit the following lines
+#
+CONFIG = ${XINCLUDE} ${HAS_NIS_MAPS} ${HAS_FILE_MAPS} ${HAS_HESIOD_MAPS} \
+ ${HAS_NDBM_MAPS} ${HAS_MOUNTD_MAPS} ${HAS_PASSWD_MAPS} ${HAS_UNION_MAPS} \
+ ${HAS_REGEXP} ${HAS_NFS_QUALIFIED_NAMES}
diff --git a/usr.sbin/amd/config/Makefile.hpux b/usr.sbin/amd/config/Makefile.hpux
new file mode 100644
index 00000000000..89fb647236c
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.hpux
@@ -0,0 +1,12 @@
+# from: @(#)Makefile.hpux 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.hpux,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for HP-UX
+#
+
+#CC = gcc ${GCCOPTS}
+# Works only on HP300
+CC = cc -Wc,-Nd2000
+SYSCC = $(CC)
+# Works only Hp800
+# CC = cc
diff --git a/usr.sbin/amd/config/Makefile.irix b/usr.sbin/amd/config/Makefile.irix
new file mode 100644
index 00000000000..612f0957c39
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix
@@ -0,0 +1,9 @@
+# from: @(#)Makefile.irix 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.irix,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for IRIX
+#
+
+DEBUG = #-g -DDEBUG
+CCOPTS = -I/usr/include/sun -I/usr/include/bsd -DIRIX
+RESOLV = -lrpcsvc -lsun -lbsd
diff --git a/usr.sbin/amd/config/Makefile.irix3 b/usr.sbin/amd/config/Makefile.irix3
new file mode 100644
index 00000000000..bcc74b1b9df
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix3
@@ -0,0 +1,12 @@
+# from: @(#)Makefile.irix3 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.irix3,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for IRIX
+#
+
+# For 3.3.x and earlier we might need to indicate the Sun and BSD include
+# paths.
+
+DEBUG = #-g -DDEBUG
+CCOPTS = -I/usr/include/sun -I/usr/include/bsd
+RESOLV = -lrpcsvc -lsun -lbsd
diff --git a/usr.sbin/amd/config/Makefile.irix4 b/usr.sbin/amd/config/Makefile.irix4
new file mode 100644
index 00000000000..5b0c50287f3
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix4
@@ -0,0 +1,13 @@
+# from: @(#)Makefile.irix4 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.irix4,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for IRIX
+#
+
+# For 4.0.X and later we need to specify the -cckr option - although amd
+# has prototypes - some of the rpc prototypes clash. The special include
+# paths are not required. -lsun always comes before -lbsd.
+
+DEBUG = -g
+CCOPTS = -cckr
+RESOLV = -lrpcsvc -lsun -lbsd
diff --git a/usr.sbin/amd/config/Makefile.stellix b/usr.sbin/amd/config/Makefile.stellix
new file mode 100644
index 00000000000..41f7ce93799
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.stellix
@@ -0,0 +1,9 @@
+# from: @(#)Makefile.stellix 8.1 (Berkeley) 6/6/93
+# $Id: Makefile.stellix,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Extra Makefile definitions for STELLIX
+#
+
+DEBUG = #-g -DDEBUG
+CCOPTS = -DSTELLIX
+RESOLV = -lrpcsvc
diff --git a/usr.sbin/amd/config/RELEASE b/usr.sbin/amd/config/RELEASE
new file mode 100644
index 00000000000..84743216ffb
--- /dev/null
+++ b/usr.sbin/amd/config/RELEASE
@@ -0,0 +1 @@
+$Revision: 1.1.1.1 $ of $Date: 1995/10/18 08:47:13 $ bsd44
diff --git a/usr.sbin/amd/config/arch b/usr.sbin/amd/config/arch
new file mode 100644
index 00000000000..d0c68953fdd
--- /dev/null
+++ b/usr.sbin/amd/config/arch
@@ -0,0 +1,125 @@
+#! /bin/sh
+#
+# 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.
+#
+# from: @(#)arch 8.1 (Berkeley) 6/6/93
+# $Id: arch,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+#
+# Figure out machine architecture
+#
+
+PATH=/bin:/usr/bin:/usr/ucb:/etc:/usr/local/bin:${PATH} export PATH
+
+#
+# First try to find a standard command
+#
+a=arch # Sun compat
+m=machine # BSD compat
+u=uname # Sys5 compat
+
+if [ -f /etc/$a -o -f /bin/$a -o -f /usr/bin/$a -o -f /usr/local/bin/$a ]
+then
+ exec $a
+elif [ -f /etc/$m -o -f /bin/$m -o -f /usr/bin/$m -o -f /usr/ucb/$m -o -f /usr/local/bin/$m ]
+then
+ exec $m
+elif [ -f /etc/$u -o -f /bin/$u -o -f /usr/bin/$u -o -f /usr/local/bin/$u ]
+then
+ ARCH="`uname`"
+ case "$ARCH" in
+ "HP-UX") echo hp9000; exit 0;;
+ AIX*) MACH="`uname -m`"
+ case "$MACH" in
+ 00*) echo ibm6000; exit 0;;
+ 10*) echo ibm032; exit 0;;
+ 20*) echo ibm032; exit 0;;
+ esac
+ ;;
+ A/UX) echo macII ; exit 0 ;;
+ dgux) MACH="`uname -m`"
+ case "$MACH" in
+ AViiON) echo aviion; exit 0;;
+ esac
+ ;;
+ *) MACH="`uname -m`"
+ case "$MACH" in
+ IP6) echo mips; exit 0;;
+ IP7) echo mips; exit 0;;
+ *) ;;
+ esac
+ ;;
+ esac
+fi
+
+#
+# Take a pot-shot at your machine architecture
+#
+echo "# ... No ARCH= option specified; dynamically determining architecture" >&2
+
+case "`exec 2>/dev/null; head -2 /etc/motd`" in
+*"HP-UX"*) ARCH=hp9000;;
+*"Iris"*) ARCH=iris4d;;
+*"Ultrix"*) ARCH=vax;;
+*"RISC iX"*) ARCH=arm;;
+*"Umax 4.2"*) ARCH=encore;;
+*"Alliant Concentrix"*) ARCH=alliant;;
+*"FPS Model 500"*) ARCH=fps500;;
+*"HCX/UX"*) ARCH=harris;;
+*) ARCH=unknown;
+ if [ -d /usr/include/caif ]; then
+ ARCH=ibm032
+ elif [ -f /bin/pyr ]; then
+ if /bin/pyr; then
+ ARCH=pyr
+ fi
+ elif [ -d /NextApps ]; then
+ ARCH=next
+ elif [ -f /etc/comply ]; then
+ # Tex 4300 is essentially a sun 3.
+ ARCH=sun3
+ fi
+ ;;
+esac
+
+echo "# ... architecture appears to be \"${ARCH}\"" >&2
+echo $ARCH
+
+case "$ARCH" in
+unknown) exit 1
+esac
+
+exit 0
diff --git a/usr.sbin/amd/config/misc-aix3.h b/usr.sbin/amd/config/misc-aix3.h
new file mode 100644
index 00000000000..52e839af7c6
--- /dev/null
+++ b/usr.sbin/amd/config/misc-aix3.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-aix3.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-aix3.h,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+ */
+
+struct ufs_args {
+ char *fspec; /* Block device */
+};
+
+struct nfs_args {
+ struct sockaddr_in addr; /* file server address */
+ fhandle_t fh; /* File handle to be mounted */
+ int flags; /* flags */
+ int wsize; /* write size in bytes */
+ int rsize; /* read size in bytes */
+ int timeo; /* initial timeout in .1 secs */
+ int retrans; /* times to retry send */
+ char *hostname; /* server's hostname */
+ int acregmin; /* attr cache file min secs */
+ int acregmax; /* attr cache file max secs */
+ int acdirmin; /* attr cache dir min secs */
+ int acdirmax; /* attr cache dir max secs */
+ char *netname; /* server's netname */
+ int biods; /* number of BIODS */
+};
+
+/*
+ * NFS mount option flags
+ */
+#define MNTOPT_RO "ro" /* read only */
+#define MNTOPT_RW "rw" /* read/write */
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_HARD "hard" /* hard mount */
+#define MNTOPT_NOSUID "nosuid"/* no set uid allowed */
+#define MNTOPT_NOAUTO "noauto"/* hide entry from mount -a */
+#define MNTOPT_INTR "intr" /* allow interrupts on hard mount */
+#define MNTOPT_SECURE "secure"/* use secure RPC for NFS */
+#define MNTOPT_GRPID "grpid" /* SysV-compatible group-id on create */
+#define MNTOPT_NOSUB "nosub" /* disallow mounts beneath this one */
+#define MNTOPT_MULTI "multi" /* Do multi-component lookup */
+#define MNTOPT_NOAC "noac" /* don't cache attributes */
+
+#define NFSMNT_SOFT 0x001 /* soft mount (hard is default) */
+#define NFSMNT_WSIZE 0x002 /* set write size */
+#define NFSMNT_RSIZE 0x004 /* set read size */
+#define NFSMNT_TIMEO 0x008 /* set initial timeout */
+#define NFSMNT_RETRANS 0x010 /* set number of request retrys */
+#define NFSMNT_HOSTNAME 0x020 /* set hostname for error printf */
+#define NFSMNT_INT 0x040 /* allow interrupts on hard mount */
+#define NFSMNT_NOAC 0x080 /* don't cache attributes */
+#define NFSMNT_ACREGMIN 0x0100 /* set min secs for file attr cache */
+#define NFSMNT_ACREGMAX 0x0200 /* set max secs for file attr cache */
+#define NFSMNT_ACDIRMIN 0x0400 /* set min secs for dir attr cache */
+#define NFSMNT_ACDIRMAX 0x0800 /* set max secs for dir attr cache */
+#define NFSMNT_SECURE 0x1000 /* secure mount */
+#define NFSMNT_BIODS 0x10000 /* Number of biods for the file system */
+
+#define DEF_BIODS 6
diff --git a/usr.sbin/amd/config/misc-hpux.h b/usr.sbin/amd/config/misc-hpux.h
new file mode 100644
index 00000000000..171a1516a9b
--- /dev/null
+++ b/usr.sbin/amd/config/misc-hpux.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-hpux.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-hpux.h,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+ */
+
+/*
+ * These definitions are from <nfs/nfs.h>
+ * Unfortunately, that file cannot be included
+ * because it contains lots of structure definitions
+ * that are not wanted (they produce name clashes).
+ * Isn't HP-UX wonderful!
+ */
+
+/*
+ * HP-UX specific definitions
+ */
+struct nfs_args {
+ struct sockaddr_in *addr; /* file server address */
+ fhandle_t *fh; /* File handle to be mounted */
+ int flags; /* flags */
+ int wsize; /* write size in bytes */
+ int rsize; /* read size in bytes */
+ int timeo; /* initial timeout in .1 secs */
+ int retrans; /* times to retry send */
+ char *hostname; /* server's name */
+#ifdef __hp9000s700 /* XXX for HPUX 8.0 */
+ char *fsname; /* server's filesystem name */
+#endif
+};
+
+/*
+ * NFS mount option flags
+ */
+#define NFSMNT_SOFT 0x001 /* soft mount (hard is default) */
+#define NFSMNT_WSIZE 0x002 /* set write size */
+#define NFSMNT_RSIZE 0x004 /* set read size */
+#define NFSMNT_TIMEO 0x008 /* set initial timeout */
+#define NFSMNT_RETRANS 0x010 /* set number of request retrys */
+#define NFSMNT_HOSTNAME 0x020 /* set hostname for error printf */
+#define NFSMNT_INT 0x040 /* set option to have interruptable mounts */
+#define NFSMNT_NODEVS 0x080 /* turn off device file access (default on) */
diff --git a/usr.sbin/amd/config/misc-irix.h b/usr.sbin/amd/config/misc-irix.h
new file mode 100644
index 00000000000..9a504179169
--- /dev/null
+++ b/usr.sbin/amd/config/misc-irix.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-irix.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-irix.h,v 1.1.1.1 1995/10/18 08:47:13 deraadt Exp $
+ */
+
+#include <sys/fs/nfs_clnt.h>
+#include <sys/fsid.h>
+#include <sys/fstyp.h>
+
+struct ufs_args {
+ char *fspec;
+};
diff --git a/usr.sbin/amd/config/misc-next.h b/usr.sbin/amd/config/misc-next.h
new file mode 100644
index 00000000000..8dc57b4f0aa
--- /dev/null
+++ b/usr.sbin/amd/config/misc-next.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-next.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-next.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include <nfs/nfs_mount.h>
diff --git a/usr.sbin/amd/config/misc-stellix.h b/usr.sbin/amd/config/misc-stellix.h
new file mode 100644
index 00000000000..214de08d38f
--- /dev/null
+++ b/usr.sbin/amd/config/misc-stellix.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-stellix.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-stellix.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include <sys/fstyp.h>
+
+struct ufs_args {
+ char *fspec;
+};
+
+struct nfs_args {
+ struct sockaddr_in *addr; /* file server address */
+ fhandle_t *fh; /* File handle to be mounted */
+ int flags; /* flags */
+ int wsize; /* write size in bytes */
+ int rsize; /* read size in bytes */
+ int timeo; /* initial timeout in .1 secs *
+/
+ int retrans; /* times to retry send */
+ char *hostname; /* server's name */
+};
+#define NFSMNT_SOFT 0x001 /* soft mount (hard is default) */
+#define NFSMNT_WSIZE 0x002 /* set write size */
+#define NFSMNT_RSIZE 0x004 /* set read size */
+#define NFSMNT_TIMEO 0x008 /* set initial timeout (= 1.6 sec) */
+#define NFSMNT_RETRANS 0x010 /* set number of request retrys */
+#define NFSMNT_HOSTNAME 0x020 /* set hostname for error printf */
+#define NFSMNT_INT 0x040 /* allow interrupts on hard mount */
diff --git a/usr.sbin/amd/config/misc-ultrix.h b/usr.sbin/amd/config/misc-ultrix.h
new file mode 100644
index 00000000000..e63de464dd0
--- /dev/null
+++ b/usr.sbin/amd/config/misc-ultrix.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * from: @(#)misc-ultrix.h 8.1 (Berkeley) 6/6/93
+ * $Id: misc-ultrix.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include <nfs/nfs_gfs.h>
+#define KERNEL
+#include <sys/fs_types.h>
+#undef KERNEL
+
+#ifndef HOSTNAMESZ
+#include <nfs/nfs_clnt.h>
+#endif
+
+#include <ufs/ufs_mount.h>
+
+#define ufs_args ufs_specific
diff --git a/usr.sbin/amd/config/mount_aix.c b/usr.sbin/amd/config/mount_aix.c
new file mode 100644
index 00000000000..6c2818ef455
--- /dev/null
+++ b/usr.sbin/amd/config/mount_aix.c
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount_aix.c 8.1 (Berkeley) 6/6/93
+ * $Id: mount_aix.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+
+/*
+ * AIX 3 Mount helper
+ */
+
+#include "misc-aix3.h"
+
+static int aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args)
+char *p;
+int gfstype;
+int flags;
+char *object;
+char *stub;
+char *host;
+char *info;
+int info_size;
+char *args;
+{
+ struct vmount *vp = (struct vmount *) p;
+ bzero((voidp) vp, sizeof(*vp));
+ /*
+ * Fill in standard fields
+ */
+ vp->vmt_revision = VMT_REVISION;
+ vp->vmt_flags = flags;
+ vp->vmt_gfstype = gfstype;
+
+#define VMT_ROUNDUP(len) (4 * ((len + 3) / 4))
+#define VMT_ASSIGN(vp, idx, data, size) \
+ vp->vmt_data[idx].vmt_off = p - (char *) vp; \
+ vp->vmt_data[idx].vmt_size = size; \
+ bcopy(data, p, size); \
+ p += VMT_ROUNDUP(size);
+
+ /*
+ * Fill in all variable length data
+ */
+ p += sizeof(*vp);
+
+ VMT_ASSIGN(vp, VMT_OBJECT, object, strlen(object) + 1);
+ VMT_ASSIGN(vp, VMT_STUB, stub, strlen(stub) + 1);
+ VMT_ASSIGN(vp, VMT_HOST, host, strlen(host) + 1);
+ VMT_ASSIGN(vp, VMT_HOSTNAME, host, strlen(host) + 1);
+ VMT_ASSIGN(vp, VMT_INFO, info, info_size);
+ VMT_ASSIGN(vp, VMT_ARGS, args, strlen(args) + 1);
+
+#undef VMT_ASSIGN
+#undef VMT_ROUNDUP
+
+ /*
+ * Return length
+ */
+ return vp->vmt_length = p - (char *) vp;
+}
+
+/*
+ * Map from conventional mount arguments
+ * to AIX 3-style arguments.
+ */
+aix3_mount(fsname, dir, flags, type, data, args)
+char *fsname;
+char *dir;
+int flags;
+int type;
+void *data;
+char *args;
+{
+ char buf[4096];
+ int size;
+
+#ifdef DEBUG
+ dlog("aix3_mount: fsname %s, dir %s, type %d", fsname, dir, type);
+#endif /* DEBUG */
+
+/* aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args) */
+
+ switch (type) {
+
+ case MOUNT_TYPE_NFS: {
+ char *host = strdup(fsname);
+ char *rfs = strchr(host, ':');
+ int free_rfs = 0;
+ if (rfs) {
+ *rfs++ = '\0';
+ } else {
+ rfs = host;
+ free_rfs = 1;
+ host = strdup(hostname);
+ }
+
+ size = aix3_mkvp(buf, type, flags, rfs, dir, host, data, sizeof(struct nfs_args), args);
+ if (free_rfs)
+ free((voidp) rfs);
+ free(host);
+
+ } break;
+
+ case MOUNT_TYPE_UFS:
+ /* Need to open block device and extract log device info from sblk. */
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+#ifdef DEBUG
+ /*dlog("aix3_mkvp: flags %#x, size %d, args %s", flags, size, args);*/
+#endif /* DEBUG */
+
+ return vmount(buf, size);
+}
diff --git a/usr.sbin/amd/config/mount_irix.c b/usr.sbin/amd/config/mount_irix.c
new file mode 100644
index 00000000000..3234317e840
--- /dev/null
+++ b/usr.sbin/amd/config/mount_irix.c
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount_irix.c 8.1 (Berkeley) 6/6/93
+ * $Id: mount_irix.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+
+/*
+ * IRIX Mount helper
+ */
+
+#include "misc-irix.h"
+
+/*
+ * Map from conventional mount arguments
+ * to IRIX style arguments.
+ */
+irix_mount(fsname, dir, flags, type, data)
+char *fsname;
+char *dir;
+int flags;
+int type;
+void *data;
+{
+ int size;
+
+#ifdef DEBUG
+ dlog("irix_mount: fsname %s, dir %s, type %d", fsname, dir, type);
+#endif /* DEBUG */
+
+ if (type == MOUNT_TYPE_NFS) {
+
+ size = sizeof (struct nfs_args);
+
+ return mount(dir, dir, (MS_FSS|MS_DATA|flags),
+ type, (struct nfs_args *) data, size);
+
+ } else if (type == MOUNT_TYPE_UFS) {
+
+ return mount(fsname, dir, (MS_FSS|flags), type);
+
+ } else {
+ return EINVAL;
+ }
+
+}
diff --git a/usr.sbin/amd/config/mount_stellix.c b/usr.sbin/amd/config/mount_stellix.c
new file mode 100644
index 00000000000..b1dbe0bd23d
--- /dev/null
+++ b/usr.sbin/amd/config/mount_stellix.c
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount_stellix.c 8.1 (Berkeley) 6/6/93
+ * $Id: mount_stellix.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+/*
+ * IRIX Mount helper
+ */
+
+#include "misc-stellix.h"
+
+/*
+ * Map from conventional mount arguments
+ * to IRIX style arguments.
+ */
+stellix_mount(fsname, dir, flags, type, data)
+char *fsname;
+char *dir;
+int flags;
+int type;
+void *data;
+{
+
+#ifdef DEBUG
+ dlog("stellix_mount: fsname %s, dir %s, type %d", fsname, dir, type);
+#endif /* DEBUG */
+
+ if (type == MOUNT_TYPE_NFS) {
+
+ return mount(dir, dir, (MS_FSS|MS_NFS|flags),
+ type, (caddr_t) data );
+
+ } else if (type == MOUNT_TYPE_UFS) {
+
+ return mount(fsname, dir, (MS_FSS|flags), type);
+
+ } else {
+ return EINVAL;
+ }
+
+}
diff --git a/usr.sbin/amd/config/mtab_aix.c b/usr.sbin/amd/config/mtab_aix.c
new file mode 100644
index 00000000000..61d65941e9a
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_aix.c
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ *
+ * from: @(#)mtab_aix.c 8.1 (Berkeley) 6/6/93
+ * $Id: mtab_aix.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_AIX3_STYLE
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+
+static struct mntent *mnt_dup(mp)
+struct vmount *mp;
+{
+ struct mntent *new_mp = ALLOC(mntent);
+
+ char *ty;
+ new_mp->mnt_fsname = strdup(vmt2dataptr(mp, VMT_OBJECT));
+ new_mp->mnt_dir = strdup(vmt2dataptr(mp, VMT_STUB));
+ new_mp->mnt_opts = strdup(vmt2dataptr(mp, VMT_ARGS));
+ switch (mp->vmt_gfstype) {
+ case MNT_JFS: ty = MTAB_TYPE_UFS; break;
+ case MNT_NFS:
+ ty = MTAB_TYPE_NFS;
+ new_mp->mnt_fsname = str3cat(new_mp->mnt_fsname,
+ vmt2dataptr(mp, VMT_HOSTNAME),
+ ":", new_mp->mnt_fsname);
+ break;
+ default: ty = "unknown"; break;
+ }
+ new_mp->mnt_type = strdup(ty);
+ new_mp->mnt_passno = mp->vmt_vfsnumber;
+ new_mp->mnt_freq = 0;
+
+ return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+ mntlist **mpp, *mhp;
+
+ int i;
+ char *mntinfo = 0, *cp;
+ struct vmount *vp;
+ int ret;
+
+ /*
+ * First figure out size of mount table
+ * and allocate space for a copy...
+ * Then get mount table for real.
+ */
+ ret = mntctl(MCTL_QUERY, sizeof(i), &i);
+ if (ret == 0) {
+ mntinfo = xmalloc(i);
+ ret = mntctl(MCTL_QUERY, i, mntinfo);
+ }
+
+ if (ret <= 0) {
+ plog(XLOG_ERROR, "mntctl: %m");
+ goto out;
+ }
+#ifdef DEBUG
+ /*dlog("mntctl returns %d structures", ret);*/
+#endif /* DEBUG */
+
+ mpp = &mhp;
+ for (i = 0, cp = mntinfo; i < ret; i++, cp += vp->vmt_length) {
+ vp = (struct vmount *) cp;
+
+ /*
+ * Allocate a new slot
+ */
+ *mpp = ALLOC(mntlist);
+
+ /*
+ * Copy the data returned by mntctl
+ */
+ (*mpp)->mnt = mnt_dup(vp);
+
+ /*
+ * Move to next pointer
+ */
+ mpp = &(*mpp)->mnext;
+ }
+
+ *mpp = 0;
+
+out:
+ if (mntinfo)
+ free(mntinfo);
+ return mhp;
+}
+
+#endif /* READ_MTAB_AIX3_STYLE */
diff --git a/usr.sbin/amd/config/mtab_bsd.c b/usr.sbin/amd/config/mtab_bsd.c
new file mode 100644
index 00000000000..8a79eb21e14
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_bsd.c
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ *
+ * from: @(#)mtab_bsd.c 8.1 (Berkeley) 6/6/93
+ * $Id: mtab_bsd.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_BSD_STYLE
+
+#include <sys/mount.h>
+
+static struct mntent *mnt_dup(mp)
+struct statfs *mp;
+{
+ struct mntent *new_mp = ALLOC(mntent);
+ char *ty;
+
+ new_mp->mnt_fsname = strdup(mp->f_mntfromname);
+ new_mp->mnt_dir = strdup(mp->f_mntonname);
+#ifndef __NetBSD__
+ switch (mp->f_type) {
+ case MOUNT_UFS: ty = MTAB_TYPE_UFS; break;
+ case MOUNT_NFS: ty = MTAB_TYPE_NFS; break;
+ case MOUNT_MFS: ty = MTAB_TYPE_MFS; break;
+ default: ty = "unknown"; break;
+ }
+#else
+ ty = mp->f_fstypename;
+#endif
+ new_mp->mnt_type = strdup(ty);
+ new_mp->mnt_opts = strdup("unset");
+ new_mp->mnt_freq = 0;
+ new_mp->mnt_passno = 0;
+
+ return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+ mntlist **mpp, *mhp;
+ struct statfs *mntbufp, *mntp;
+
+ int nloc = getmntinfo(&mntbufp, MNT_NOWAIT);
+
+ if (nloc == 0) {
+ plog(XLOG_ERROR, "Can't read mount table");
+ return 0;
+ }
+
+ mpp = &mhp;
+ for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
+ /*
+ * Allocate a new slot
+ */
+ *mpp = ALLOC(mntlist);
+
+ /*
+ * Copy the data returned by getmntent
+ */
+ (*mpp)->mnt = mnt_dup(mntp);
+
+ /*
+ * Move to next pointer
+ */
+ mpp = &(*mpp)->mnext;
+ }
+
+ /*
+ * Terminate the list
+ */
+ *mpp = 0;
+
+ return mhp;
+}
+
+#endif /* READ_MTAB_BSD_STYLE */
diff --git a/usr.sbin/amd/config/mtab_file.c b/usr.sbin/amd/config/mtab_file.c
new file mode 100644
index 00000000000..146b13497fb
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_file.c
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ *
+ * from: @(#)mtab_file.c 8.1 (Berkeley) 6/6/93
+ * $Id: mtab_file.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_FROM_FILE
+
+#ifdef USE_FCNTL
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif /* USE_FCNTL */
+
+#ifdef UPDATE_MTAB
+
+/*
+ * Do strict /etc/mtab locking
+ */
+#define MTAB_LOCKING
+
+/*
+ * Firewall mtab entries
+ */
+#define MTAB_STRIPNL
+
+#include <sys/stat.h>
+static FILE *mnt_file;
+
+/*
+ * If the system is being trashed by something, then
+ * opening mtab may fail with ENFILE. So, go to sleep
+ * for a second and try again. (Yes - this has happened to me.)
+ *
+ * Note that this *may* block the automounter, oh well.
+ * If we get to this state then things are badly wrong anyway...
+ *
+ * Give the system 10 seconds to recover but then give up.
+ * Hopefully something else will exit and free up some file
+ * table slots in that time.
+ */
+#define NFILE_RETRIES 10 /* seconds */
+
+#ifdef MTAB_LOCKING
+#ifdef LOCK_FCNTL
+static int lock(fd)
+{
+ int rc;
+ struct flock lk;
+
+ lk.l_type = F_WRLCK;
+ lk.l_whence = 0;
+ lk.l_start = 0;
+ lk.l_len = 0;
+
+again:
+ rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
+ if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
+#ifdef DEBUG
+ dlog("Blocked, trying to obtain exclusive mtab lock");
+#endif /* DEBUG */
+ sleep(1);
+ goto again;
+ }
+ return rc;
+}
+#else
+#define lock(fd) (flock((fd), LOCK_EX))
+#endif /* LOCK_FCNTL */
+#endif /* MTAB_LOCKING */
+
+static FILE *open_locked_mtab(mtab_file, mode, fs)
+char *mtab_file;
+char *mode;
+char *fs;
+{
+ FILE *mfp = 0;
+
+#ifdef UPDATE_MTAB
+ /*
+ * There is a possible race condition if two processes enter
+ * this routine at the same time. One will be blocked by the
+ * exclusive lock below (or by the shared lock in setmntent)
+ * and by the time the second process has the exclusive lock
+ * it will be on the wrong underlying object. To check for this
+ * the mtab file is stat'ed before and after all the locking
+ * sequence, and if it is a different file then we assume that
+ * it may be the wrong file (only "may", since there is another
+ * race between the initial stat and the setmntent).
+ *
+ * Simpler solutions to this problem are invited...
+ */
+ int racing = 2;
+#ifdef MTAB_LOCKING
+ int rc;
+ int retries = 0;
+ struct stat st_before, st_after;
+#endif /* MTAB_LOCKING */
+
+ if (mnt_file) {
+#ifdef DEBUG
+ dlog("Forced close on %s in read_mtab", mtab_file);
+#endif /* DEBUG */
+ endmntent(mnt_file);
+ mnt_file = 0;
+ }
+
+#ifdef MTAB_LOCKING
+again:
+ if (mfp) {
+ endmntent(mfp);
+ mfp = 0;
+ }
+
+ clock_valid = 0;
+ if (stat(mtab_file, &st_before) < 0) {
+ plog(XLOG_ERROR, "%s: stat: %m", mtab_file);
+ if (errno == ESTALE) {
+ /* happens occasionally */
+ sleep(1);
+ goto again;
+ }
+ return 0;
+ }
+#endif /* MTAB_LOCKING */
+#endif /* UPDATE_MTAB */
+
+eacces:
+ mfp = setmntent(mtab_file, mode);
+ if (!mfp) {
+ /*
+ * Since setmntent locks the descriptor, it
+ * is possible it can fail... so retry if
+ * needed.
+ */
+ if (errno == EACCES || errno == EAGAIN) {
+#ifdef DEBUG
+ dlog("Blocked, trying to obtain exclusive mtab lock");
+#endif /* DEBUG */
+ goto eacces;
+ } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+ sleep(1);
+ goto eacces;
+ }
+
+ plog(XLOG_ERROR, "setmntent(\"%s\", \"%s\"): %m", mtab_file, mode);
+ return 0;
+ }
+
+#ifdef MTAB_LOCKING
+#ifdef UPDATE_MTAB
+ /*
+ * At this point we have an exclusive lock on the mount list,
+ * but it may be the wrong one so...
+ */
+
+ /*
+ * Need to get an exclusive lock on the current
+ * mount table until we have a new copy written
+ * out, when the lock is released in free_mntlist.
+ * flock is good enough since the mount table is
+ * not shared between machines.
+ */
+ do
+ rc = lock(fileno(mfp));
+ while (rc < 0 && errno == EINTR);
+ if (rc < 0) {
+ plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab_file);
+ endmntent(mfp);
+ return 0;
+ }
+ /*
+ * Now check whether the mtab file has changed under our feet
+ */
+ if (stat(mtab_file, &st_after) < 0) {
+ plog(XLOG_ERROR, "%s: stat", mtab_file);
+ goto again;
+ }
+
+ if (st_before.st_dev != st_after.st_dev ||
+ st_before.st_ino != st_after.st_ino) {
+ struct timeval tv;
+ if (racing == 0) {
+ /* Sometimes print a warning */
+ plog(XLOG_WARNING,
+ "Possible mount table race - retrying %s", fs);
+ }
+ racing = (racing+1) & 3;
+ /*
+ * Take a nap. From: Doug Kingston <dpk@morgan.com>
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = (mypid & 0x07) << 17;
+ if (tv.tv_usec)
+ if (select(0, (voidp) 0, (voidp) 0, (voidp) 0, &tv) < 0)
+ plog(XLOG_WARNING, "mtab nap failed: %m");
+
+ goto again;
+ }
+#endif /* UPDATE_MTAB */
+#endif /* MTAB_LOCKING */
+
+ return mfp;
+}
+
+/*
+ * Unlock the mount table
+ */
+void unlock_mntlist P((void));
+void unlock_mntlist()
+{
+ /*
+ * Release file lock, by closing the file
+ */
+ if (mnt_file) {
+ endmntent(mnt_file);
+ mnt_file = 0;
+ }
+}
+
+/*
+ * Write out a mount list
+ */
+void rewrite_mtab(mp)
+mntlist *mp;
+{
+ FILE *mfp;
+ int error = 0;
+
+ /*
+ * Concoct a temporary name in the same
+ * directory as the target mount table
+ * so that rename() will work.
+ */
+ char tmpname[64];
+ int retries;
+ int tmpfd;
+ char *cp;
+ char *mcp = mtab;
+ cp = strrchr(mcp, '/');
+ if (cp) {
+ bcopy(mcp, tmpname, cp - mcp);
+ tmpname[cp-mcp] = '\0';
+ } else {
+ plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
+ tmpname[0] = '.'; tmpname[1] = '\0';
+ }
+ strcat(tmpname, "/mtabXXXXXX");
+ mktemp(tmpname);
+ retries = 0;
+enfile1:
+ if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
+ if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+ sleep(1);
+ goto enfile1;
+ }
+ plog(XLOG_ERROR, "%s: open: %m", tmpname);
+ return;
+ }
+ if (close(tmpfd) < 0)
+ plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
+
+ retries = 0;
+enfile2:
+ mfp = setmntent(tmpname, "w");
+ if (!mfp) {
+ if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+ sleep(1);
+ goto enfile2;
+ }
+ plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
+ error = 1;
+ goto out;
+ }
+
+ while (mp) {
+ if (mp->mnt) {
+ if (addmntent(mfp, mp->mnt)) {
+ plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
+ error = 1;
+ goto out;
+ }
+ }
+ mp = mp->mnext;
+ }
+
+ /*
+ * SunOS 4.1 manuals say that the return code from entmntent()
+ * is always 1 and to treat as a void. That means we need to
+ * call fflush() to make sure the new mtab file got written.
+ */
+ if (fflush(mfp)) {
+ plog(XLOG_ERROR, "flush new mtab file: %m");
+ error = 1;
+ goto out;
+ }
+
+ (void) endmntent(mfp);
+
+ /*
+ * Rename temporary mtab to real mtab
+ */
+ if (rename(tmpname, mtab) < 0) {
+ plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
+ error = 1;
+ goto out;
+ }
+
+out:
+ if (error)
+ (void) unlink(tmpname);
+}
+
+#ifdef MTAB_STRIPNL
+static void mtab_stripnl(s)
+char *s;
+{
+ do {
+ s = strchr(s, '\n');
+ if (s)
+ *s++ = ' ';
+ } while (s);
+}
+#endif /* MTAB_STRIPNL */
+
+/*
+ * Append a mntent structure to the
+ * current mount table.
+ */
+void write_mntent(mp)
+struct mntent *mp;
+{
+ int retries = 0;
+ FILE *mfp;
+enfile:
+ mfp = open_locked_mtab(mtab, "a", mp->mnt_dir);
+ if (mfp) {
+#ifdef MTAB_STRIPNL
+ mtab_stripnl(mp->mnt_opts);
+#endif /* MTAB_STRIPNL */
+ if (addmntent(mfp, mp))
+ plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
+ if (fflush(mfp))
+ plog(XLOG_ERROR, "Couldn't flush %s: %m", mtab);
+ (void) endmntent(mfp);
+ } else {
+ if (errno == ENFILE && retries < NFILE_RETRIES) {
+ sleep(1);
+ goto enfile;
+ }
+ plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
+ }
+}
+
+#endif /* UPDATE_MTAB */
+
+static struct mntent *mnt_dup(mp)
+struct mntent *mp;
+{
+ struct mntent *new_mp = ALLOC(mntent);
+
+ new_mp->mnt_fsname = strdup(mp->mnt_fsname);
+ new_mp->mnt_dir = strdup(mp->mnt_dir);
+ new_mp->mnt_type = strdup(mp->mnt_type);
+ new_mp->mnt_opts = strdup(mp->mnt_opts);
+
+ new_mp->mnt_freq = mp->mnt_freq;
+ new_mp->mnt_passno = mp->mnt_passno;
+
+#ifdef FIXUP_MNTENT_DUP
+ /*
+ * Additional fields get dup'ed here
+ */
+ FIXUP_MNTENT_DUP(new_mp, mp);
+#endif
+
+ return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+ mntlist **mpp, *mhp;
+
+ struct mntent *mep;
+ FILE *mfp = open_locked_mtab(mtab, "r+", fs);
+
+ if (!mfp)
+ return 0;
+
+ mpp = &mhp;
+
+/*
+ * XXX - In SunOS 4 there is (yet another) memory leak
+ * which loses 1K the first time getmntent is called.
+ * (jsp)
+ */
+ while (mep = getmntent(mfp)) {
+ /*
+ * Allocate a new slot
+ */
+ *mpp = ALLOC(mntlist);
+
+ /*
+ * Copy the data returned by getmntent
+ */
+ (*mpp)->mnt = mnt_dup(mep);
+
+ /*
+ * Move to next pointer
+ */
+ mpp = &(*mpp)->mnext;
+ }
+ *mpp = 0;
+
+#ifdef UPDATE_MTAB
+ /*
+ * If we are not updating the mount table then we
+ * can free the resources held here, otherwise they
+ * must be held until the mount table update is complete
+ */
+ mnt_file = mfp;
+#else
+ endmntent(mfp);
+#endif /* UPDATE_MTAB */
+
+ return mhp;
+}
+
+#endif /* READ_MTAB_FROM_FILE */
diff --git a/usr.sbin/amd/config/mtab_ultrix.c b/usr.sbin/amd/config/mtab_ultrix.c
new file mode 100644
index 00000000000..bffb5f64f38
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_ultrix.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * from: @(#)mtab_ultrix.c 8.1 (Berkeley) 6/6/93
+ * $Id: mtab_ultrix.c,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_ULTRIX_STYLE
+
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+
+static struct mntent *mnt_dup(mp)
+struct fs_data *mp;
+{
+ struct mntent *new_mp = ALLOC(mntent);
+
+ new_mp->mnt_fsname = strdup(mp->fd_devname);
+ new_mp->mnt_dir = strdup(mp->fd_path);
+ if (mp->fd_fstype >= GT_NUMTYPES)
+ mp->fd_fstype = GT_UNKWN;
+ else if (gt_names[mp->fd_fstype] == 0)
+ mp->fd_fstype = GT_UNKWN;
+ new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
+ new_mp->mnt_opts = strdup("unset");
+
+ new_mp->mnt_freq = 0;
+ new_mp->mnt_passno = mp->fd_dev;
+
+ return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+ mntlist **mpp, *mhp;
+
+/* From: Piete Brooks <pb@cl.cam.ac.uk> */
+
+ int loc=0;
+#undef NMOUNT
+#define NMOUNT 20
+ struct fs_data mountbuffer[NMOUNT], *fs_data;
+ int ret;
+
+ mpp = &mhp;
+ while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
+ for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
+ /*
+ * Allocate a new slot
+ */
+ *mpp = ALLOC(mntlist);
+
+ /*
+ * Copy the data returned by getmntent
+ */
+ (*mpp)->mnt = mnt_dup(fs_data);
+
+ /*
+ * Move to next pointer
+ */
+ mpp = &(*mpp)->mnext;
+ }
+ }
+ if (ret < 0) {
+ plog(XLOG_ERROR, "getmountent: %m");
+ return 0;
+ }
+ *mpp = 0;
+
+ return mhp;
+}
+
+#endif /* READ_MTAB_ULTRIX_STYLE */
diff --git a/usr.sbin/amd/config/newvers.sh b/usr.sbin/amd/config/newvers.sh
new file mode 100644
index 00000000000..d74de88d4a0
--- /dev/null
+++ b/usr.sbin/amd/config/newvers.sh
@@ -0,0 +1,87 @@
+#!/bin/sh -
+#
+# 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.
+#
+# from: @(#)newvers.sh 8.1 (Berkeley) 6/6/93
+# $Id: newvers.sh,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+#
+PATH=/usr/ucb:/bin:/usr/bin:$PATH
+if [ $# -ne 3 ]; then echo "Usage: newvers program arch os" >&2; exit 1; fi
+version="version.$1"
+if [ ! -r $version ]; then echo 0 > $version; chmod 444 $version; fi
+v=`cat $version`
+u=${USER-${LOGNAME-root}}
+h=`hostname`
+#h=`expr "$h" : '\([^.]*\)'`
+t=`date`
+if [ ! -s "$d../config/RELEASE" -o ! -s "$d../text/COPYRIGHT" ]; then
+ echo ERROR: config file missing >&2
+ exit 1
+fi
+rm -f vers.$1.c
+(
+cat << %%
+char copyright[] = "\\
+%%
+sed 's/$/\\n\\/' $d../text/COPYRIGHT
+cat << %%
+";
+char version[] = "\\
+%%
+cat << %%
+$1 \\
+%%
+sed \
+ -e 's/\$//g' \
+ -e 's/[A-Z][a-z]*://g' \
+ -e 's/ */ /g' \
+ -e 's/^ //' \
+ -e 's/$/\\/' \
+ $d../config/RELEASE
+cat << %%
+ #${v}: ${t}\\n\\
+Built by ${u}@${h} for \\
+%%
+case "$2" in
+[aeiou]*) echo "an \\" ;;
+*) echo "a \\";;
+esac
+echo "$2 running $3\";"
+) > vers.$1.c
+rm -f $version
+expr ${v} + 1 > $version
+chmod 444 $version
diff --git a/usr.sbin/amd/config/os-acis43.h b/usr.sbin/amd/config/os-acis43.h
new file mode 100644
index 00000000000..abcbc0444c2
--- /dev/null
+++ b/usr.sbin/amd/config/os-acis43.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-acis43.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-acis43.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * IBM RT ACIS4.3 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Need precise symlink lengths
+#define PRECISE_SYMLINKS
+ */
diff --git a/usr.sbin/amd/config/os-aix3.h b/usr.sbin/amd/config/os-aix3.h
new file mode 100644
index 00000000000..d9e6b369ff8
--- /dev/null
+++ b/usr.sbin/amd/config/os-aix3.h
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-aix3.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-aix3.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * AIX 3.1 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_AIX3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * Pick up BSD bits from include files
+ * Try for 4.4 compatibility if available (AIX 3.2 and later)
+ */
+#define _BSD 44
+
+/*
+ * No mntent info on AIX 3
+ */
+#undef MNTENT_HDR
+#define MNTENT_HDR <sys/mntctl.h>
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MNT_NFS
+#define MOUNT_TYPE_UFS MNT_JFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "jfs"
+
+/*
+ * How to unmount filesystems
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flag, mnt_data) \
+ aix3_mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data, mnt->mnt_opts)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) uvmount(mnt->mnt_passno, 0)
+
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <sys/machine.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Miscellaneous AIX 3 bits
+ */
+#define NEED_MNTOPT_PARSER
+#define SHORT_MOUNT_NAME
+
+#define MNTMAXSTR 128
+
+#define MNTTYPE_UFS "jfs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+
+#define NFS_HDR "misc-aix3.h"
+#define UFS_HDR "misc-aix3.h"
+#undef NFS_FH_DREF
+#define NFS_FH_DREF(dst, src) { (dst) = *(src); }
+#undef NFS_SA_DREF
+#define NFS_SA_DREF(dst, src) { (dst).addr = *(src); }
+#define M_RDONLY MNT_READONLY
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_AIX3_STYLE
+
+/*
+ * The data for the mount syscall needs the path in addition to the
+ * host name since that is the only source of information about the
+ * mounted filesystem.
+#define NFS_ARGS_NEEDS_PATH
+ */
+
+#define NFS_LOMAP 34
+#define NFS_HIMAP 99
+#define NFS_ERROR_MAPPING \
+static nfs_errormap[] = { 0,75,77,99,99,99, \
+ 99,99,99,99,99,78,99,99,99,79, \
+ 99,99,70,99,35,36,37,38,39,40, \
+ 41,42,43,44,45,46,47,48,49,50, \
+ 51,52,53,54,55,56,57,58,60,61, \
+ 64,65,99,67,68,62,63,66,69,68, \
+ 99,99,99,71,99,99,99,99,99,99 \
+ };
+
+#define MOUNT_HELPER_SOURCE "mount_aix.c"
+
+/*
+ * Need this too
+ */
+#include <time.h>
diff --git a/usr.sbin/amd/config/os-aux.h b/usr.sbin/amd/config/os-aux.h
new file mode 100644
index 00000000000..e630d0026b8
--- /dev/null
+++ b/usr.sbin/amd/config/os-aux.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-aux.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-aux.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * A/UX macII definitions for Amd (automounter)
+ * Contributed by Julian Onions <jpo@cs.nott.ac.uk>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * No support for ndbm
+ */
+#undef OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "5.2"
+
+#define SIGCHLD SIGCLD
+#define SYS5_SIGNALS
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+#define USE_FCNTL
+
+/*
+ * Use fcntl() rather than flock()
+ */
+#define LOCK_FCNTL
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+#define getpagesize() (2048)
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ fsmount(type, mnt->mnt_dir, flags, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) unmount(mnt->mnt_dir)
+#define NFDS 30 /* conservative */
+
+/* not included in sys/param.h */
+#include <sys/types.h>
+/* not part of sys/time.h */
+#include <time.h>
+/* for NMOUNT */
+#include <sys/config.h>
diff --git a/usr.sbin/amd/config/os-bsd44.h b/usr.sbin/amd/config/os-bsd44.h
new file mode 100644
index 00000000000..4fe2ba8637f
--- /dev/null
+++ b/usr.sbin/amd/config/os-bsd44.h
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-bsd44.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-bsd44.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * 4.4 BSD definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_44
+#define HAS_TCP_NFS
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * 4.4 doesn't provide NIS, but NetBSD does.
+ */
+#ifndef __NetBSD__
+#undef HAS_NIS_MAPS
+#endif
+
+/*
+ * OS provides strerror()
+ */
+#define HAS_STRERROR
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on 4.4 BSD
+ */
+#undef MNTENT_HDR
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+#define MTAB_TYPE_MFS "mfs"
+#ifdef __NetBSD__
+#undef MTYPE_TYPE
+#define MTYPE_TYPE char *
+#endif
+
+/*
+ * How to unmount filesystems
+ */
+#undef UNMOUNT_TRAP
+#undef NEED_UMOUNT_FS
+#define NEED_UMOUNT_BSD
+
+/*
+ * How to copy an address into an NFS filehandle
+ */
+#undef NFS_SA_DREF
+#define NFS_SA_DREF(dst, src) { \
+ (dst).addr = (struct sockaddr *) (src); \
+ (dst).addrlen = sizeof(*src); \
+ (dst).sotype = SOCK_DGRAM; \
+ (dst).proto = 0; \
+ }
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <machine/endian.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Miscellaneous 4.4 BSD bits
+ */
+#define NEED_MNTOPT_PARSER
+#define SHORT_MOUNT_NAME
+
+#define MNTMAXSTR 128
+
+#define MNTTYPE_UFS "ufs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_MFS "mfs" /* memory file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+#define M_RDONLY MNT_RDONLY
+#define M_SYNC MNT_SYNCHRONOUS
+#define M_NOEXEC MNT_NOEXEC
+#define M_NOSUID MNT_NOSUID
+#define M_NODEV MNT_NODEV
+
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_INTR "intr" /* interrupts allowed */
+#define MNTOPT_NOCONN "noconn" /* accept any responder */
+#define MNTOPT_RESVPORT "resvport" /* use reserved port */
+
+#define NFSMNT_HOSTNAME 0 /* hostname on 4.4 is not optional */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define NFS_FH_TYPE nfsv2fh_t *
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_BSD_STYLE
+
+/*
+ * The data for the mount syscall needs the path in addition to the
+ * host name since that is the only source of information about the
+ * mounted filesystem.
+ */
+#define NFS_ARGS_NEEDS_PATH
+
+/*
+ * 4.4 has RE support built in
+ */
+#undef RE_HDR
+#define RE_HDR <regexp.h>
diff --git a/usr.sbin/amd/config/os-concentrix.h b/usr.sbin/amd/config/os-concentrix.h
new file mode 100644
index 00000000000..2ffc93eb1d1
--- /dev/null
+++ b/usr.sbin/amd/config/os-concentrix.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-concentrix.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-concentrix.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * Alliant Concentrix 5.0.0 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr.sbin/amd/config/os-convex.h b/usr.sbin/amd/config/os-convex.h
new file mode 100644
index 00000000000..6ba66912473
--- /dev/null
+++ b/usr.sbin/amd/config/os-convex.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-convex.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-convex.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * Convex C220, version 7.1 definitions for Amd (automounter)
+ * from Eitan Mizrotsky <eitan@shum.huji.ac.il>
+ */
+
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+
+
+#define strrchr rindex
+#define strchr index
diff --git a/usr.sbin/amd/config/os-defaults.h b/usr.sbin/amd/config/os-defaults.h
new file mode 100644
index 00000000000..74b32587210
--- /dev/null
+++ b/usr.sbin/amd/config/os-defaults.h
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-defaults.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-defaults.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * Common OS definitions. These may be overridden in
+ * the OS specific files ("os-foo.h").
+ */
+
+/*
+ * What level of AMD are we backward compatible with?
+ * This only applies to externally visible characteristics.
+ * Rev.Minor.Branch.Patch (2 digits each)
+ */
+#define AMD_COMPAT 5000000 /* 5.0 */
+
+/*
+ * What type is free(void*) returning?
+ */
+#define FREE_RETURN_TYPE void
+
+/*
+ * Is the mount table mirrored in software
+ */
+#define UPDATE_MTAB
+
+/*
+ * Where to get union wait
+ */
+#define WAIT <sys/wait.h>
+
+/*
+ * Where to get mount entry info
+ */
+#define MNTENT_HDR <mntent.h>
+
+/*
+ * Include support for syslog()
+ */
+#define HAS_SYSLOG
+
+/*
+ * Byte ordering
+ */
+#define ARCH_ENDIAN "unknown"
+
+/*
+ * Name of filesystem types
+ */
+#define MTAB_TYPE_NFS "nfs"
+#define MTAB_TYPE_UFS "4.2"
+
+/*
+ * Name of mount & unmount system calls
+ *
+ * NOTE:
+ * UNMOUNT_TRAP takes a struct mntent *
+ */
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ mount(type, mnt->mnt_dir, flags, mnt_data)
+#define UNMOUNT_TRAP(mnt) unmount(mnt->mnt_dir)
+
+/*
+ * How to unmount filesystems.
+ * NEED_UMOUNT_FS includes code to scan the mount table
+ * to find the correct information for the unmount system
+ * call. Some systems, such as 4.4bsd, do not require
+ * this - they can just do an unmount system call directly.
+ */
+#define NEED_UMOUNT_FS
+#define UMOUNT_FS(dir) umount_fs(dir)
+
+/*
+ * Type of a file handle
+ */
+#define NFS_FH_TYPE fhandle_t *
+#define NFS_FH_DREF(dst, src) { (dst) = (src); }
+
+/*
+ * How to copy an address into an NFS filehandle
+ */
+#define NFS_SA_DREF(dst, src) { (dst).addr = (src); }
+
+/*
+ * Type of filesystem type
+ */
+#define MTYPE_TYPE int
+
+/*
+ * How to get a mount list
+ */
+#define READ_MTAB_FROM_FILE
+
+/*
+ * Make Amd automount points appear
+ * to be zero sized. undef this
+ * if the O/S has a divide by zero
+ * problem in df et al.
+ */
+#define HAS_EMPTY_AUTOMOUNTS
+
+/*
+ * For the RE matcher
+ */
+#define CHARBITS 0377
+#define STRCSPN
+#define RE_HDR "re.h"
diff --git a/usr.sbin/amd/config/os-dgux.h b/usr.sbin/amd/config/os-dgux.h
new file mode 100644
index 00000000000..5d9be43b676
--- /dev/null
+++ b/usr.sbin/amd/config/os-dgux.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-dgux.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-dgux.h,v 1.1.1.1 1995/10/18 08:47:14 deraadt Exp $
+ *
+ * dg/ux definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_4
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS "nfs"
+#define MOUNT_TYPE_UFS "dg/ux"
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "dg/ux"
+
+/*
+ * Need the following in more places than just NFS_HDR
+ */
+#include <sys/dg_mount.h>
+/*
+ * This is braindead
+ * dg/ux has nfs 4.0 but doesn't have the following options
+ */
+#define NFSMNT_HOSTNAME 0x0
+#define NFSMNT_INT 0x0
+#define M_NEWTYPE 0
+
+/*
+ * DG have their own filesystem.
+ */
+#define ufs_args dgux_args
+
+/*
+ * Byte ordering
+ */
+
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+#define _BSD_WAIT_FLAVOR
+#define _BSD_TTY_FLAVOR
+#define _BSD_SIGNAL_FLAVOR
+#define _DGUX_SOURCE
+
+/*
+ * Use fcntl() rather than flock()
+ */
+#define LOCK_FCNTL
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ ((struct nfs_args *)mnt_data)->version = !strcmp(type, MOUNT_TYPE_UFS)?\
+ DG_MOUNT_DGUX_VERSION:DG_MOUNT_NFS_VERSION, \
+ dg_mount(type, mnt->mnt_dir, flags, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
diff --git a/usr.sbin/amd/config/os-fpx4.h b/usr.sbin/amd/config/os-fpx4.h
new file mode 100644
index 00000000000..09a389aca98
--- /dev/null
+++ b/usr.sbin/amd/config/os-fpx4.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-fpx4.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-fpx4.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Celerity FPX 4.1/2 definitions for Amd (automounter)
+ * from Stephen Pope <scp@grizzly.acl.lanl.gov>
+ */
+
+/*
+ * FPX wants to include sys headers multiple times
+ */
+#define INCLUDE_HEADERS
+
+/*
+ * FPX sys/mount.h includes sys/nfs.h; prevent this
+ */
+#define INCLUDED_nfs
+
+/*
+ * FPX doesn't define NMOUNT anywhere
+ */
+#define NMOUNT 40
+
+/*
+ * Does the compiler grok void *
+ */
+/* #define VOIDP */
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+#define svc_fdset svc_fds
+#define svc_getreqset(p) svc_getreq((*p).fds_bits[0])
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr.sbin/amd/config/os-hcx.h b/usr.sbin/amd/config/os-hcx.h
new file mode 100644
index 00000000000..22356a46dc3
--- /dev/null
+++ b/usr.sbin/amd/config/os-hcx.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-hcx.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-hcx.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Harris HCX/UX Release 3.0 definitions for Amd (automounter)
+ */
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Deviant call necessary. The mount() routine in libc only works for UFS
+ * (it's a backward-compatible piece of C code which traps to mountsyscall).
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ mountsyscall(type, mnt->mnt_dir, flags, mnt_data)
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#ifdef _hcx
+#define ARCH_ENDIAN "big"
+#else
+XXX - bizarre!
+#endif
diff --git a/usr.sbin/amd/config/os-hlh42.h b/usr.sbin/amd/config/os-hlh42.h
new file mode 100644
index 00000000000..a037a34de44
--- /dev/null
+++ b/usr.sbin/amd/config/os-hlh42.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-hlh42.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-hlh42.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * HLH OTS definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(hlh)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+
+/*
+ * Miscellaneous HLH 4.2 incantations
+ */
+#define strchr index
+#define strrchr rindex
+#define sigmask(x) (1 << ((x)-1))
+
+/*
+ * HLH's 4.2 needs the extra RPC definitions.
+ */
+#define NEED_XDR_POINTER
+#define NEED_CLNT_SPERRNO
diff --git a/usr.sbin/amd/config/os-hpux.h b/usr.sbin/amd/config/os-hpux.h
new file mode 100644
index 00000000000..dcaf18b88d3
--- /dev/null
+++ b/usr.sbin/amd/config/os-hpux.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-hpux.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-hpux.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * HP/9000 HP-UX definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __GNUC__
+#define VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(hp9000s200) || defined(hp9000s300) || defined(hp9000s800)
+#define ARCH_ENDIAN "big"
+#endif
+
+#ifndef __hpux
+#define HPUX_VERSION_6
+#endif
+
+/*
+ * No support for syslog() prior to 7.0
+ */
+#ifdef HPUX_VERSION_6
+#undef HAS_SYSLOG
+#endif
+
+/*
+ * No support for ndbm
+ */
+#undef OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "hfs"
+
+/*
+ * Where to get NFS definitions
+ */
+#define NFS_HDR "misc-hpux.h"
+
+/*
+ * Where to get union wait
+ */
+#undef WAIT
+#define WAIT "uwait.h"
+#ifdef HPUX_VERSION_6
+#define SIGCHLD SIGCLD
+#endif
+#define SYS5_SIGNALS
+
+/*
+ * Miscellaneous HP-UX definitions
+ */
+
+#define NEED_XDR_POINTER
+#define NEED_CLNT_SPERRNO
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+#define USE_FCNTL
+
+/*
+ * Use fcntl() rather than flock()
+ */
+#define LOCK_FCNTL
+
+/*
+ * Additional fields in struct mntent
+ * are fixed up here
+ */
+#define FIXUP_MNTENT(mntp) { \
+ (mntp)->mnt_time = clocktime(); \
+}
+#define FIXUP_MNTENT_DUP(mntp, mp) { \
+ (mntp)->mnt_time = (mp)->mnt_time; \
+}
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+#define getpagesize() (2048)
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ vfsmount(type, mnt->mnt_dir, flags, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
+#define NFDS 30 /* conservative */
+#define MOUNTED MNT_MNTTAB
diff --git a/usr.sbin/amd/config/os-irix.h b/usr.sbin/amd/config/os-irix.h
new file mode 100644
index 00000000000..c0e94287493
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-irix.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-irix.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * IRIX 3.3 definitions for Amd (automounter)
+ * Contributed by Scott R. Presnell <srp@cgl.ucsf.edu>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Has support for syslog()
+ */
+#define HAS_SYSLOG
+
+#define M_GRPID MS_GRPID
+#define M_RDONLY MS_RDONLY
+/*
+ * Support for ndbm
+ */
+#define OS_HAS_NDBM
+
+#define UPDATE_MTAB
+
+#undef MTAB_TYPE_NFS
+#define MTAB_TYPE_NFS "nfs"
+
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "efs"
+
+#define NMOUNT 40 /* The std sun value */
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS sysfs(GETFSIND, FSID_EFS)
+#define MOUNT_TYPE_NFS sysfs(GETFSIND, FSID_NFS)
+
+#define SYS5_SIGNALS
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+/*#define USE_FCNTL*/
+
+/*
+ * Use fcntl() rather than flock()
+ */
+/*#define LOCK_FCNTL*/
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ irix_mount(mnt->mnt_fsname, mnt->mnt_dir,flags, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
+#define NFDS 30 /* conservative */
+
+#define NFS_HDR "misc-irix.h"
+#define UFS_HDR "misc-irix.h"
+
+/* not included in sys/param.h */
+#include <sys/types.h>
+
+#define MOUNT_HELPER_SOURCE "mount_irix.c"
+
+#define MNTINFO_DEV "fsid"
+#define MNTINFO_PREF "0x"
diff --git a/usr.sbin/amd/config/os-irix3.h b/usr.sbin/amd/config/os-irix3.h
new file mode 100644
index 00000000000..004494e7200
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix3.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-irix3.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-irix3.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * IRIX 3.3 definitions for Amd (automounter)
+ * Contributed by Scott R. Presnell <srp@cgl.ucsf.edu>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Has support for syslog()
+ */
+#define HAS_SYSLOG
+
+#define M_GRPID MS_GRPID
+#define M_RDONLY MS_RDONLY
+/*
+ * Support for ndbm
+ */
+#define OS_HAS_NDBM
+
+#define UPDATE_MTAB
+
+#undef MTAB_TYPE_NFS
+#define MTAB_TYPE_NFS "nfs"
+
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "efs"
+
+#define NMOUNT 40 /* The std sun value */
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS sysfs(GETFSIND, FSID_EFS)
+#define MOUNT_TYPE_NFS sysfs(GETFSIND, FSID_NFS)
+
+#define SYS5_SIGNALS
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+/*#define USE_FCNTL*/
+
+/*
+ * Use fcntl() rather than flock()
+ */
+/*#define LOCK_FCNTL*/
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ irix_mount(mnt->mnt_fsname, mnt->mnt_dir,flags, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
+#define NFDS 30 /* conservative */
+
+#define NFS_HDR "misc-irix.h"
+#define UFS_HDR "misc-irix.h"
+
+/* not included in sys/param.h */
+#include <sys/types.h>
+
+#define MOUNT_HELPER_SOURCE "mount_irix.c"
+
+#define MNTINFO_DEV "fsid"
+#define MNTINFO_PREF "0x"
diff --git a/usr.sbin/amd/config/os-irix4.h b/usr.sbin/amd/config/os-irix4.h
new file mode 100644
index 00000000000..fa2b7da81e5
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix4.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-irix4.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-irix4.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * IRIX 4.0.X definitions for Amd (automounter)
+ * Contributed by Scott R. Presnell <srp@cgl.ucsf.edu>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Has support for syslog()
+ */
+#define HAS_SYSLOG
+
+#define M_RDONLY MS_RDONLY
+#define M_GRPID MS_GRPID
+#define M_NOSUID MS_NOSUID
+#define M_NONDEV MS_NODEV
+
+/*
+ * Support for ndbm
+ */
+#define OS_HAS_NDBM
+
+#define UPDATE_MTAB
+
+#undef MTAB_TYPE_NFS
+#define MTAB_TYPE_NFS "nfs"
+
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "efs"
+
+#define NMOUNT 40 /* The std sun value */
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS sysfs(GETFSIND, FSID_EFS)
+#define MOUNT_TYPE_NFS sysfs(GETFSIND, FSID_NFS)
+
+#define SYS5_SIGNALS
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+/*#define USE_FCNTL*/
+
+/*
+ * Use fcntl() rather than flock()
+ */
+/*#define LOCK_FCNTL*/
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ irix_mount(mnt->mnt_fsname, mnt->mnt_dir,flags, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
+#define NFDS 30 /* conservative */
+
+#define NFS_HDR "misc-irix.h"
+#define UFS_HDR "misc-irix.h"
+
+/* not included in sys/param.h */
+#include <sys/types.h>
+
+#define MOUNT_HELPER_SOURCE "mount_irix.c"
+
+/*
+ * Under 4.0.X this information is in /usr/include/mntent.h
+ * Below is what is used to be for Irix 3.3.X.
+ */
+/*#define MNTINFO_DEV "fsid"*/
+/*#define MNTINFO_PREF "0x"*/
+
+#define MNTINFO_PREF ""
+
+/*
+ * Under Irix, mount type "auto" is probed by statfs() in df. A statfs() of
+ * a direct mount causes that mount to fire. So change the mount type in
+ * /etc/mtab to "ignore" to stop that (this is what SGI does for their
+ * automounter. Use the old FASCIST define for this.
+ */
+#define FASCIST_DF_COMMAND MNTTYPE_IGNORE
diff --git a/usr.sbin/amd/config/os-next.h b/usr.sbin/amd/config/os-next.h
new file mode 100644
index 00000000000..b957762c5ee
--- /dev/null
+++ b/usr.sbin/amd/config/os-next.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-next.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-next.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * NeXT OS definitions for Amd (automounter)
+ * By Bill Trost, Reed College
+ * trost%reed@cse.ogi.edu,
+ *
+ * Derived from the Sun 3.2 definitions for Amd (os-sos3.h).
+ */
+
+/*
+ * Does the compiler grok void * (NeXT uses gcc)
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "4.3"
+
+/*
+ * Where to get NFS definitions
+ */
+#define NFS_HDR "misc-next.h"
diff --git a/usr.sbin/amd/config/os-pyrOSx.h b/usr.sbin/amd/config/os-pyrOSx.h
new file mode 100644
index 00000000000..1a7de5af598
--- /dev/null
+++ b/usr.sbin/amd/config/os-pyrOSx.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-pyrOSx.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-pyrOSx.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Pyramid OSx definitions for Amd (automounter)
+ * from Stefan Petri <petri@tubsibr.UUCP>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+
+#define strchr index
+#define strrchr rindex
+
+#define hostname mnthostname
diff --git a/usr.sbin/amd/config/os-riscix.h b/usr.sbin/amd/config/os-riscix.h
new file mode 100644
index 00000000000..13d8dace309
--- /dev/null
+++ b/usr.sbin/amd/config/os-riscix.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-riscix.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-riscix.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Acorn Archimedes RISC iX definitions for Amd (automounter)
+ * Contributed by Piete Brooks.
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "little"
+
+/*
+ * Is the mount table mirrored in software
+ */
+#define UPDATE_MTAB
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS MNTTYPE_43
diff --git a/usr.sbin/amd/config/os-sos3.h b/usr.sbin/amd/config/os-sos3.h
new file mode 100644
index 00000000000..8a921c75c02
--- /dev/null
+++ b/usr.sbin/amd/config/os-sos3.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-sos3.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-sos3.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * SunOS 3.2 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(mc68010) || defined(mc68020) || defined(sparc)
+#define ARCH_ENDIAN "big"
+#endif
+#if defined(i386)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
diff --git a/usr.sbin/amd/config/os-sos4.h b/usr.sbin/amd/config/os-sos4.h
new file mode 100644
index 00000000000..de50ba7074a
--- /dev/null
+++ b/usr.sbin/amd/config/os-sos4.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-sos4.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-sos4.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * SunOS 4.0 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * What type is free(void*) returning?
+ */
+#undef FREE_RETURN_TYPE
+#define FREE_RETURN_TYPE int
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_4
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(mc68010) || defined(mc68020) || defined(sparc)
+#define ARCH_ENDIAN "big"
+#endif
+#if defined(i386)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS "nfs"
+#define MOUNT_TYPE_UFS "4.2"
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define NFS_FH_TYPE caddr_t
+
+/*
+ * Type of filesystem type
+ */
+#undef MTYPE_TYPE
+#define MTYPE_TYPE char *
+
+/*
+ * Add support for SunOS 4 automounter files
+ */
+#define SUNOS4_COMPAT
+
+/*
+ * System Vr4 / SunOS 4.1 compatibility
+ * - put dev= in the options list
+ *
+ * From: Brent Callaghan <brent@eng.sun.com>
+ */
+#define MNTINFO_DEV "dev"
+#define MNTINFO_PREF ""
diff --git a/usr.sbin/amd/config/os-stellix.h b/usr.sbin/amd/config/os-stellix.h
new file mode 100644
index 00000000000..8a3460131a1
--- /dev/null
+++ b/usr.sbin/amd/config/os-stellix.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-stellix.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-stellix.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Amd (automounter) definitions for Stellix.
+ * From Stephen C. Pope <scp@acl.lanl.gov>
+ */
+
+#define RPC_3
+
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "big"
+
+#define HAS_SYSLOG
+
+#define OS_HAS_NDBM
+
+#define UPDATE_MTAB
+
+#define USE_FCNTL
+
+#define LOCK_FCNTL
+
+/*
+ * Name of filesystem types
+ */
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "sfs"
+
+#define MOUNT_TYPE_UFS sysfs(GETFSIND, "SFS1")
+#define MOUNT_TYPE_NFS sysfs(GETFSIND, "NFS")
+
+#define SYS5_SIGNALS
+#define HAS_SVR3_SIGNALS
+
+#define MOUNT_HELPER_SOURCE "mount_stellix.c"
+
+/*
+ * Name of mount & unmount system calls
+ *
+ * NOTE:
+ * UNMOUNT_TRAP takes a struct mntent *
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+ stellix_mount(mnt->mnt_fsname, mnt->mnt_dir, flags, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_dir)
+
+/*
+ * How to unmount filesystems.
+ * NEED_UMOUNT_FS includes code to scan the mount table
+ * to find the correct information for the unmount system
+ * call. Some systems, such as 4.4bsd, do not require
+ * this - they can just do an unmount system call directly.
+ */
+/* #define NEED_UMOUNT_FS */
+/* #define UMOUNT_FS(dir) umount_fs(dir) */
+
+#define NFS_HDR "misc-stellix.h"
+#define UFS_HDR "misc-stellix.h"
+
+#define M_RDONLY 0x01 /* mount fs read only */
+
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
diff --git a/usr.sbin/amd/config/os-type b/usr.sbin/amd/config/os-type
new file mode 100644
index 00000000000..c8890b37173
--- /dev/null
+++ b/usr.sbin/amd/config/os-type
@@ -0,0 +1,127 @@
+#!/bin/sh
+#
+# 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.
+#
+# from: @(#)os-type 8.1 (Berkeley) 6/6/93
+# $Id: os-type,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+#
+
+#
+# Take a pot-shot at your os type
+#
+echo "# ... No OS= option specified; dynamically determining OS type" >&2
+
+#
+# First try poking around in /etc/motd
+#
+
+case "`exec 2>/dev/null; head -2 /etc/motd`" in
+*"Sun UNIX 4.2 Release 3."*) OS=sos3;;
+*"SunOS Release 4."*) OS=sos4;;
+*"HP-UX on the HP"*) OS=hpux;;
+*"Ultrix V2."*) OS=u2_2;;
+*"Ultrix V3."*) OS=u3_0;;
+*"Ultrix-32 V3."*) OS=u3_0;;
+*"Ultrix Worksystem V2."*) OS=u3_0;;
+*"ULTRIX V4.2"*) OS=u4_2;;
+*"ULTRIX V4."*) OS=u4_0;;
+*"HLH OTS Version 1."*) OS=hlh42;;
+*"RISC iX release 1."*) OS=riscix;;
+*"FPX 4."*) OS=fpx4;;
+*"HCX/UX"*) OS=hcx;;
+*"4.4 BSD UNIX"*) OS=bsd44;;
+*"4.3 BSD Reno UNIX"*) OS=bsd44;;
+*"4.3 BSD UNIX"*) if [ -f /etc/minidisk ]; then
+ OS=acis43
+ elif [ -f /sbin/nfsiod ]; then
+ OS=bsd44 # prototype
+ else
+ OS=xinu43
+ fi;;
+*"Alliant Concentrix"*) OS=concentrix;;
+*"Umax 4.3"*) OS=umax43;;
+*)
+#
+# Well, that didn't work so apply some heuristics
+# to the filesystem name space...
+#
+ echo "# ... inspecting File system ..." >&2
+ if [ -f /etc/comply ]; then
+ OS=utek
+ elif [ -d /usr/lib/methods -o -d /etc/methods ]; then
+ OS=aix3
+ elif [ -f /usr/bin/cat ]; then
+ OS=sos4
+ elif [ -f /etc/nd ]; then
+ OS=sos3
+ elif [ -f /etc/elcsd ]; then
+ echo "# ... Ultrix - assuming U4.0 ..." >&2
+ OS=u4_0
+ elif [ -f /hp-ux ]; then
+ OS=hpux
+ elif [ -f /etc/ttylocal ]; then
+ OS=xinu43
+ elif [ -f /etc/minidisk ]; then
+ OS=acis43
+ elif [ -f /etc/toolboxdaemon ]; then
+ OS=aux
+ elif [ -f /sbin/nfsiod ]; then
+ OS=bsd44
+ elif [ -d /vrm ]; then
+ OS=aix2
+ elif [ -f /bin/pyr ] && /bin/pyr; then
+ OS=pyrOSx
+ elif [ -d /NextApps ]; then
+ OS=next
+ elif [ -f /etc/gl/ucode ]; then
+ OS=irix3
+ elif [ -f /usr/gfx/ucode ]; then
+ OS=irix4
+ elif [ -f /stellix ]; then
+ OS=stellix
+ else
+ case "`(sh ../config/arch)2>/dev/null`" in
+ ibm032) OS=acis43;;
+ aviion) OS=dgux;;
+ *) OS=unknown;;
+ esac
+ fi;;
+esac
+
+echo "# ... OS appears to be \"${OS}\"" >&2
+echo "${OS}"
+exit 0
diff --git a/usr.sbin/amd/config/os-u2_2.h b/usr.sbin/amd/config/os-u2_2.h
new file mode 100644
index 00000000000..9c64086d666
--- /dev/null
+++ b/usr.sbin/amd/config/os-u2_2.h
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-u2_2.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-u2_2.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Ultrix 2.2 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+ */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#undef HAS_SYSLOG
+
+/*
+ * No support for ndbm
+ */
+#undef HAS_NDBM_MAPS
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS GT_NFS
+#define MOUNT_TYPE_UFS GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flag, mnt_data) \
+ mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define M_RDONLY M_RONLY
+
+#ifndef MNTMAXSTR
+#define MNTMAXSTR 128
+#endif
+
+#define MNTTYPE_UFS "ufs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+#define MNTOPT_RO "ro" /* read only */
+#define MNTOPT_RW "rw" /* read/write */
+#define MNTOPT_QUOTA "quota" /* quotas */
+#define MNTOPT_NOQUOTA "noquota" /* no quotas */
+#define MNTOPT_HARD "hard" /* hard mount */
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_INTR "intr" /* interrupts allowed */
+
+#define MNTOPT_NOSUID "nosuid" /* no set uid allowed */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+#define MOUNTED "/etc/mtab"
+
+#define NFS_HDR "misc-ultrix.h"
+#define UFS_HDR "misc-ultrix.h"
+
+#define NEED_XDR_POINTER
+#define NEED_CLNT_SPERRNO
+
+#define nfs_args nfs_gfs_mount
+#define ULTRIX_HACK /* Should be handled better than this !! */
+#define NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define PRECISE_SYMLINKS
diff --git a/usr.sbin/amd/config/os-u3_0.h b/usr.sbin/amd/config/os-u3_0.h
new file mode 100644
index 00000000000..451820b64d4
--- /dev/null
+++ b/usr.sbin/amd/config/os-u3_0.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-u3_0.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-u3_0.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Ultrix 3.0 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax) || defined(mips)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+ */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#undef HAS_SYSLOG
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS GT_NFS
+#define MOUNT_TYPE_UFS GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flag, mnt_data) \
+ mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define M_RDONLY M_RONLY
+
+#define MNTMAXSTR 128
+
+#define MNTTYPE_UFS "ufs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+#define MNTOPT_RO "ro" /* read only */
+#define MNTOPT_RW "rw" /* read/write */
+#define MNTOPT_QUOTA "quota" /* quotas */
+#define MNTOPT_NOQUOTA "noquota" /* no quotas */
+#define MNTOPT_HARD "hard" /* hard mount */
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_INTR "intr" /* interrupts allowed */
+
+#define MNTOPT_NOSUID "nosuid" /* no set uid allowed */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+#define MOUNTED "/etc/mtab"
+
+#define NFS_HDR "misc-ultrix.h"
+#define UFS_HDR "misc-ultrix.h"
+
+#define NEED_XDR_POINTER
+#define NEED_CLNT_SPERRNO
+
+#define nfs_args nfs_gfs_mount
+#define ULTRIX_HACK /* Should be handled better than this !! */
+#define NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define PRECISE_SYMLINKS
diff --git a/usr.sbin/amd/config/os-u4_0.h b/usr.sbin/amd/config/os-u4_0.h
new file mode 100644
index 00000000000..0b5e57c881c
--- /dev/null
+++ b/usr.sbin/amd/config/os-u4_0.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-u4_0.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-u4_0.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Ultrix 4.0 definitions for Amd (automounter)
+ * from Chris Lindblad <cjl@ai.mit.edu>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __STDC__
+#define VOIDP
+#else
+#undef VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax) || defined(mips)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+ */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#define HAS_SYSLOG
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS GT_NFS
+#define MOUNT_TYPE_UFS GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flag, mnt_data) \
+ mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define M_RDONLY M_RONLY
+
+#define MNTMAXSTR 128
+
+#define MNTTYPE_UFS "ufs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+#define MNTOPT_RO "ro" /* read only */
+#define MNTOPT_RW "rw" /* read/write */
+#define MNTOPT_QUOTA "quota" /* quotas */
+#define MNTOPT_NOQUOTA "noquota" /* no quotas */
+#define MNTOPT_HARD "hard" /* hard mount */
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_INTR "intr" /* interrupts allowed */
+
+#define MNTOPT_NOSUID "nosuid" /* no set uid allowed */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+#define MOUNTED "/etc/mtab"
+
+#define NFS_HDR "misc-ultrix.h"
+#define UFS_HDR "misc-ultrix.h"
+
+#define NEED_CLNT_SPERRNO
+
+#define nfs_args nfs_gfs_mount
+#define ULTRIX_HACK /* Should be handled better than this !! */
+#define NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define PRECISE_SYMLINKS
diff --git a/usr.sbin/amd/config/os-u4_2.h b/usr.sbin/amd/config/os-u4_2.h
new file mode 100644
index 00000000000..6262f1c7c8f
--- /dev/null
+++ b/usr.sbin/amd/config/os-u4_2.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-u4_2.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-u4_2.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * Ultrix 4.2 definitions for Amd (automounter)
+ * from Chris Lindblad <cjl@ai.mit.edu>
+ * and Chris Metcalf <metcalf@lcs.mit.edu>
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax) || defined(mips)
+#define ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+ */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#define HAS_SYSLOG
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS GT_NFS
+#define MOUNT_TYPE_UFS GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flag, mnt_data) \
+ mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define UNMOUNT_TRAP(mnt) umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define M_RDONLY M_RONLY
+
+#define MNTMAXSTR 128
+
+#define MNTTYPE_UFS "ufs" /* Un*x file system */
+#define MNTTYPE_NFS "nfs" /* network file system */
+#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */
+
+#define MNTOPT_RO "ro" /* read only */
+#define MNTOPT_RW "rw" /* read/write */
+#define MNTOPT_QUOTA "quota" /* quotas */
+#define MNTOPT_NOQUOTA "noquota" /* no quotas */
+#define MNTOPT_HARD "hard" /* hard mount */
+#define MNTOPT_SOFT "soft" /* soft mount */
+#define MNTOPT_INTR "intr" /* interrupts allowed */
+
+#define MNTOPT_NOSUID "nosuid" /* no set uid allowed */
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* MNTTYPE_* */
+ char *mnt_opts; /* MNTOPT* */
+ int mnt_freq; /* dump frequency, in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+#define MOUNTED "/etc/mtab"
+
+#define NFS_HDR "misc-ultrix.h"
+#define UFS_HDR "misc-ultrix.h"
+
+#define nfs_args nfs_gfs_mount
+#define ULTRIX_HACK /* Should be handled better than this !! */
+#define NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define PRECISE_SYMLINKS
diff --git a/usr.sbin/amd/config/os-umax43.h b/usr.sbin/amd/config/os-umax43.h
new file mode 100644
index 00000000000..0824ec1fef4
--- /dev/null
+++ b/usr.sbin/amd/config/os-umax43.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-umax43.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-umax43.h,v 1.1.1.1 1995/10/18 08:47:15 deraadt Exp $
+ *
+ * UMAX 4.3 definitions for Amd (automounter)
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN "little"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr.sbin/amd/config/os-utek.h b/usr.sbin/amd/config/os-utek.h
new file mode 100644
index 00000000000..918c8745d7b
--- /dev/null
+++ b/usr.sbin/amd/config/os-utek.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-utek.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-utek.h,v 1.1.1.1 1995/10/18 08:47:16 deraadt Exp $
+ *
+ * Utek 4.0 definitions for Amd (automounter)
+ * from Bill Trost <trost%reed@cse.ogi.edu>
+ */
+
+#define UTEK
+#define __NFS_HEADER__ /* prevent re-inclusion of <sys/nfs.h> */
+/* ... and fake the rest */
+#include "os-sos3.h"
diff --git a/usr.sbin/amd/config/os-utx32.h b/usr.sbin/amd/config/os-utx32.h
new file mode 100644
index 00000000000..3853e5fc307
--- /dev/null
+++ b/usr.sbin/amd/config/os-utx32.h
@@ -0,0 +1,84 @@
+/*
+ * Gould UTX/32 definitions for Amd (automounter)
+ *
+ * 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.
+ *
+ * from: @(#)os-utx32.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-utx32.h,v 1.1.1.1 1995/10/18 08:47:16 deraadt Exp $
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __GNUC__
+#define VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(gould) || defined(GOULD_PN)
+#define ARCH_ENDIAN "big"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "4.3"
diff --git a/usr.sbin/amd/config/os-xinu43.h b/usr.sbin/amd/config/os-xinu43.h
new file mode 100644
index 00000000000..d949d7dc93a
--- /dev/null
+++ b/usr.sbin/amd/config/os-xinu43.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ * from: @(#)os-xinu43.h 8.1 (Berkeley) 6/6/93
+ * $Id: os-xinu43.h,v 1.1.1.1 1995/10/18 08:47:16 deraadt Exp $
+ *
+ * mt Xinu 4.3 (MORE/bsd) definitions for Amd (automounter)
+ * Should work on both Vax and HP ...
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __GNUC__
+#define VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_4
+
+/*
+ * mt Xinu have a compatibility problem
+ * with getreq vs. getreqset. On SunOS
+ * getreqset takes a pointer to an fd_set,
+ * whereas on MORE/bsd, getreq takes a
+ * fd_set directly (cf. an integer on SunOS).
+ */
+#define svc_getreqset(p) svc_getreq(*p)
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_4
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS "nfs"
+#define MOUNT_TYPE_UFS "ufs"
+#undef MTAB_TYPE_UFS
+#define MTAB_TYPE_UFS "ufs"
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <machine/endian.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define NFS_FH_TYPE caddr_t
+
+/*
+ * Type of filesystem type
+ */
+#undef MTYPE_TYPE
+#define MTYPE_TYPE char *
diff --git a/usr.sbin/amd/doc/Makefile b/usr.sbin/amd/doc/Makefile
new file mode 100644
index 00000000000..8082fcc8bfe
--- /dev/null
+++ b/usr.sbin/amd/doc/Makefile
@@ -0,0 +1,54 @@
+#
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:16 deraadt Exp $
+#
+# Copyright (c) 1990 Jan-Simon Pendry
+# Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+# Copyright (c) 1990 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.
+#
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:16 deraadt Exp $
+
+PROG = amdref
+SRCS = amdref.texinfo
+
+${PROG}: amdref.dvi
+
+amdref.dvi: ${SRCS}
+ -tex amdref.texinfo; tex amdref.texinfo
+
+clean:
+ -rm -f amdref.aux amdref.cp amdref.cps amdref.dvi amdref.fn \
+ amdref.fns amdref.ky amdref.kys amdref.log amdref.pg amdref.pgs \
+ amdref.toc amdref.tp amdref.tps amdref.vr amdref.vrs
diff --git a/usr.sbin/amd/doc/amdref.ps b/usr.sbin/amd/doc/amdref.ps
new file mode 100644
index 00000000000..17e10f57205
--- /dev/null
+++ b/usr.sbin/amd/doc/amdref.ps
@@ -0,0 +1,6429 @@
+%!PS-Adobe-2.0
+%%Creator: dvipsk 5.512a Copyright 1986, 1993 Radical Eye Software
+%%Title: amdref.dvi
+%%Pages: 62
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%DVIPSCommandLine: dvips amdref.dvi -o
+%DVIPSSource: TeX output 1993.06.10:1525
+%%BeginProcSet: tex.pro
+/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N /X{S N}
+B /TR{translate}N /isls false N /vsize 11 72 mul N /@rigin{isls{[0 -1 1 0 0 0]
+concat}if 72 Resolution div 72 VResolution div neg scale isls{Resolution hsize
+-72 div mul 0 TR}if Resolution VResolution vsize -72 div 1 add mul TR matrix
+currentmatrix dup dup 4 get round 4 exch put dup dup 5 get round 5 exch put
+setmatrix}N /@landscape{/isls true N}B /@manualfeed{statusdict /manualfeed
+true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N
+/IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin /FontType 3 N /FontMatrix
+fntrx N /FontBBox FBB N string /base X array /BitMaps X /BuildChar{
+CharBuilder}N /Encoding IE N end dup{/foo setfont}2 array copy cvx N load 0 nn
+put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0
+0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data
+dup length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{128
+ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub get 127
+sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data dup type
+/stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N /rc 0 N /gp 0 N
+/cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup /base get 2 index get
+S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0 ch-xoff ch-yoff ch-height
+sub ch-xoff ch-width add ch-yoff setcachedevice ch-width ch-height true[1 0 0
+-1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image}imagemask restore}B /D{/cc X dup
+type /stringtype ne{]}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1
+ne{dup dup length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}
+B /I{cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin
+0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul add
+.99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore showpage userdict
+/eop-hook known{eop-hook}if}N /@start{userdict /start-hook known{start-hook}
+if pop /VResolution X /Resolution X 1000 div /DVImag X /IE 256 array N 0 1 255
+{IE S 1 string dup 0 3 index put cvn put}for 65781.76 div /vsize X 65781.76
+div /hsize X}N /p{show}N /RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N
+/ruley 0 N /v{/ruley X /rulex X V}B /V{}B /RV statusdict begin /product where{
+pop product dup length 7 ge{0 7 getinterval dup(Display)eq exch 0 4
+getinterval(NeXT)eq or}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1
+TR 1 1 scale rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1
+-.1 TR rulex ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /QV{
+gsave transform round exch round exch itransform moveto rulex 0 rlineto 0
+ruley neg rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N
+/tail{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M}
+B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{4 M}B
+/w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{p 1 w}B /r{
+p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p a}B /bos{/SS save
+N}B /eos{SS restore}B end
+%%EndProcSet
+TeXDict begin 40258431 52099146 1000 300 300 (amdref.dvi) @start
+/Fa 1 59 df<78FCFCFCFC7806067B8510>58 D E /Fb 1 59 df<60F0F06004047D830B>58
+D E /Fc 68 122 df<00FE7C0381C60603CE0E03841C03801C03801C03801C03801C03801C0380
+FFFFF01C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C0380
+1C03801C0380FF8FF0171A809916>11 D<00FE000381000601800E03801C01001C00001C00001C
+00001C00001C0000FFFF801C03801C03801C03801C03801C03801C03801C03801C03801C03801C
+03801C03801C03801C03801C0380FF8FF0141A809915>I<00FF800383800603800E03801C0380
+1C03801C03801C03801C03801C0380FFFF801C03801C03801C03801C03801C03801C03801C0380
+1C03801C03801C03801C03801C03801C03801C0380FF9FF0141A809915>I<60F0F86808080810
+102040050B7D990B>39 D<00800100020004000C00080018003000300030006000600060006000
+E000E000E000E000E000E000E000E000E000E0006000600060006000300030003000180008000C
+00040002000100008009267D9B0F>I<8000400020001000180008000C00060006000600030003
+000300030003800380038003800380038003800380038003800300030003000300060006000600
+0C0008001800100020004000800009267E9B0F>I<60F0F07010101020204040040B7D830B>44
+D<FFC0FFC00A0280880D>I<60F0F06004047D830B>I<0004000C00180018001800300030003000
+600060006000C000C000C00180018001800300030003000600060006000C000C000C0018001800
+1800300030003000600060006000C000C0000E257E9B13>I<07E01C38381C300C700E60066006
+E007E007E007E007E007E007E007E007E007E00760066006700E300C381C1C3807E010187F9713
+>I<03000700FF0007000700070007000700070007000700070007000700070007000700070007
+0007000700070007007FF80D187D9713>I<0F80106020304038803CC01CE01C401C003C003800
+380070006000C001800100020004040804100430083FF87FF8FFF80E187E9713>I<07E0183820
+1C601E700E201E001E001C001C0038007007E00038001C000E000F000FE00FE00FC00F400E601C
+183807E010187F9713>I<001800180038007800F800B801380238023804380838183810382038
+4038C038FFFF00380038003800380038003803FF10187F9713>I<30183FF03FE03F8020002000
+2000200020002FC03060203000380018001C001C401CE01CE01C80184038403030E00F800E187E
+9713>I<01F807040C06180E300E300070006000E000E3E0E418E80CF00EE006E007E007E00760
+0760077006300E180C0C3807E010187F9713>I<40007FFF7FFE7FFE4004800880108010002000
+400040008001800100030003000700060006000E000E000E000E000E00040010197E9813>I<07
+E01818300C2006600660067006780C3E181F3007C003E00CF8307C601E600FC007C003C003C003
+60022004181807E010187F9713>I<07E01C303018700C600EE006E006E007E007E0076007700F
+3017182707C700070006000E000C700C7018603030600F8010187F9713>I<60F0F06000000000
+0000000060F0F0701010102020404004177D8F0B>59 D<000C0000000C0000000C0000001E0000
+001E0000002F000000270000002700000043800000438000004380000081C0000081C0000181E0
+000100E0000100E00003FFF000020070000200700004003800040038000400380008001C000800
+1C003C001E00FF00FFC01A1A7F991D>65 D<FFFF800E00E00E00700E00380E003C0E003C0E003C
+0E003C0E003C0E00780E00700E01E00FFFC00E00F00E00780E003C0E001C0E001E0E001E0E001E
+0E001E0E001C0E003C0E00780E00F0FFFFC0171A7F991B>I<003F0201C0C603002E0E001E1C00
+0E1C0006380006780002700002700002F00000F00000F00000F00000F00000F000007000027000
+027800023800041C00041C00080E000803003001C0C0003F00171A7E991C>I<FFFF80000E00E0
+000E0070000E0038000E001C000E000E000E000E000E0007000E0007000E0007800E0007800E00
+07800E0007800E0007800E0007800E0007800E0007800E0007000E0007000E000F000E000E000E
+001C000E001C000E0078000E00E000FFFF8000191A7F991D>I<FFFFF80E00380E00180E00080E
+000C0E00040E00040E00040E01000E01000E01000E03000FFF000E03000E01000E01000E01000E
+00020E00020E00020E00060E00040E00040E000C0E003CFFFFFC171A7F991A>I<FFFFF80E0038
+0E00180E00080E000C0E00040E00040E00040E01000E01000E01000E03000FFF000E03000E0100
+0E01000E01000E00000E00000E00000E00000E00000E00000E00000E0000FFE000161A7F9919>
+I<003F020001C0C60003002E000E001E001C000E001C0006003800060078000200700002007000
+0200F0000000F0000000F0000000F0000000F0000000F001FFC070000E0070000E0078000E0038
+000E001C000E001C000E000E000E000300160001C06600003F82001A1A7E991E>I<FFE1FFC00E
+001C000E001C000E001C000E001C000E001C000E001C000E001C000E001C000E001C000E001C00
+0E001C000FFFFC000E001C000E001C000E001C000E001C000E001C000E001C000E001C000E001C
+000E001C000E001C000E001C000E001C00FFE1FFC01A1A7F991D>I<FF801C001C001C001C001C
+001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C00
+FF80091A7E990E>I<FFE01FC00E000F000E000C000E0008000E0010000E0020000E0040000E01
+80000E0200000E0400000E0C00000E1C00000E2E00000E4700000E8380000F0380000E01C0000E
+00E0000E00E0000E0070000E0038000E0038000E001C000E001E000E001F00FFE07FC01A1A7F99
+1E>75 D<FFE0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00
+000E00000E00000E00000E00000E00000E00080E00080E00080E00180E00100E00300E00700E00
+F0FFFFF0151A7F9918>I<FF0000FF0F0000F00F0000F00B8001700B80017009C0027009C00270
+09C0027008E0047008E00470087008700870087008700870083810700838107008381070081C20
+70081C2070080E4070080E4070080E40700807807008078070080300701C030070FF8307FF201A
+7F9923>I<FE007FC00F000E000F0004000B80040009C0040009C0040008E00400087004000870
+040008380400081C0400081C0400080E04000807040008038400080384000801C4000800E40008
+00E4000800740008003C0008003C0008001C0008000C001C000C00FF8004001A1A7F991D>I<00
+7F000001C1C000070070000E0038001C001C003C001E0038000E0078000F0070000700F0000780
+F0000780F0000780F0000780F0000780F0000780F0000780F000078078000F0078000F0038000E
+003C001E001C001C000E0038000700700001C1C000007F0000191A7E991E>I<FFFF800E01E00E
+00700E00780E00380E003C0E003C0E003C0E003C0E00380E00780E00700E01E00FFF800E00000E
+00000E00000E00000E00000E00000E00000E00000E00000E00000E0000FFE000161A7F991A>I<
+007F000001C1C000070070000E0038001C001C003C001E0038000E0078000F0070000700F00007
+80F0000780F0000780F0000780F0000780F0000780F0000780F00007807000070078000F003800
+0E003C1C1E001C221C000E4138000741F00001E1C000007F80800000C0800000C0800000E18000
+007F0000007F0000003E0000001C0019217E991E>I<FFFF00000E01C0000E0070000E0078000E
+003C000E003C000E003C000E003C000E003C000E0078000E0070000E01C0000FFF00000E038000
+0E00C0000E00E0000E0070000E0070000E0070000E0078000E0078000E0078000E0078400E003C
+400E001C80FFE00F001A1A7F991C>I<0FC21836200E6006C006C002C002C002E00070007E003F
+E01FF803FC007E000E00070003800380038003C002C006E004D81887E0101A7E9915>I<7FFFFF
+00701C0700401C0100401C0100C01C0180801C0080801C0080801C0080001C0000001C0000001C
+0000001C0000001C0000001C0000001C0000001C0000001C0000001C0000001C0000001C000000
+1C0000001C0000001C0000001C0000001C000003FFE000191A7F991C>I<FFE07FC00E000E000E
+0004000E0004000E0004000E0004000E0004000E0004000E0004000E0004000E0004000E000400
+0E0004000E0004000E0004000E0004000E0004000E0004000E0004000E00040006000800070008
+00030010000180200000E0C000003F00001A1A7F991D>I<FF801FC01C0007001C0006000E0004
+000E0004000E000400070008000700080003801000038010000380100001C0200001C0200000E0
+400000E0400000E040000070800000708000007980000039000000390000001E0000001E000000
+1E0000000C0000000C00001A1A7F991D>I<FF81FF07F03C007801C01C007800801C007800801C
+007800800E009C01000E009C01000E009C010007010E020007010E020007010E020003830F0400
+038207040003820704000382070C0001C403880001C403880001C403880000E801D00000E801D0
+0000E801D000007000E000007000E000007000E000003000C0000020004000241A7F9927>I<FF
+801FE01E0007001E0006000F00040007000C00078008000380100001C0100001E0200000E06000
+007040000078800000388000001D0000001F0000000E0000000E0000000E0000000E0000000E00
+00000E0000000E0000000E0000000E0000000E000000FFC0001B1A7F991D>89
+D<1FC000387000383800101C00001C00001C0003FC001E1C00381C00701C00E01C00E01C80E01C
+80E03C80705F801F8F0011107F8F13>97 D<FC00001C00001C00001C00001C00001C00001C0000
+1C00001C00001C00001CFC001D07001E03801C01C01C00C01C00E01C00E01C00E01C00E01C00E0
+1C00E01C01C01C01801E030019060010F800131A809915>I<07F81C1C381C70087000E000E000
+E000E000E000E0007000700438081C1807E00E107F8F11>I<003F000007000007000007000007
+0000070000070000070000070000070003E7000C1700180F00300700700700E00700E00700E007
+00E00700E00700E00700600700700700380F001C370007C7E0131A7F9915>I<07C01C30301870
+18600CE00CFFFCE000E000E000E0006000700438081C1807E00E107F8F11>I<01F007180E381C
+101C001C001C001C001C001C00FFC01C001C001C001C001C001C001C001C001C001C001C001C00
+1C001C00FF800D1A80990C>I<0FCF001871803030007038007038007038007038003030001860
+002FC0006000006000007000003FF0003FFC001FFE00600F00C00300C00300C00300C003006006
+00381C0007E00011187F8F13>I<FC00001C00001C00001C00001C00001C00001C00001C00001C
+00001C00001C7C001D87001E03801E03801C03801C03801C03801C03801C03801C03801C03801C
+03801C03801C03801C0380FF9FF0141A809915>I<183C3C18000000000000FC1C1C1C1C1C1C1C
+1C1C1C1C1C1C1CFF081A80990A>I<FC00001C00001C00001C00001C00001C00001C00001C0000
+1C00001C00001C1FC01C0F001C0C001C18001C20001C40001CE0001DE0001E70001C78001C3800
+1C1C001C1E001C0F001C0F80FF9FE0131A809914>107 D<FC001C001C001C001C001C001C001C
+001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A
+80990A>I<FC7C1F001D8E63801E0781C01E0781C01C0701C01C0701C01C0701C01C0701C01C07
+01C01C0701C01C0701C01C0701C01C0701C01C0701C01C0701C0FF9FE7F81D107F8F20>I<FC7C
+001D87001E03801E03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03
+801C0380FF9FF01410808F15>I<07E01C38300C700E6006E007E007E007E007E007E007600670
+0E381C1C3807E010107F8F13>I<FCFC001D07001E03801C01C01C01C01C00E01C00E01C00E01C
+00E01C00E01C00E01C01C01C01801E03001D06001CF8001C00001C00001C00001C00001C00001C
+0000FF80001317808F15>I<03E1000C1300180B00300F00700700E00700E00700E00700E00700
+E00700E00700700700700700380F001C370007C700000700000700000700000700000700000700
+003FE013177F8F14>I<FC781D9C1E1C1E081C001C001C001C001C001C001C001C001C001C001C
+00FF800E10808F0F>I<1F2060E04020C020C020F0007F003FC01FE000F080708030C030C020F0
+408F800C107F8F0F>I<0800080008000800180018003800FFC038003800380038003800380038
+003800382038203820382018201C4007800B177F960F>I<FC1F801C03801C03801C03801C0380
+1C03801C03801C03801C03801C03801C03801C03801C07800C07800E0B8003F3F01410808F15>
+I<FF0F803C07001C06001C04001C04000E08000E080007100007100007100003A00003A00001C0
+0001C00001C00000800011107F8F14>I<FE7F1F80381C07003C1C06001C0C04001C0E04000E16
+08000E1708000E170800072310000723900007A3900003C1A00003C1E0000180C0000180C00001
+80C00019107F8F1C>I<FE3F803C1E001C08000E10000F300007600003C00001C00001E00003E0
+00027000043800083800181C00381E00FC3FC012107F8F14>I<FF0F803C07001C06001C04001C
+04000E08000E080007100007100007100003A00003A00001C00001C00001C00000800000800001
+0000010000E10000E20000E4000078000011177F8F14>I E /Fd 13 119
+df<7FFFF0FFFFF8FFFFF87FFFF015047D921C>45 D<FFFF00FFFFC0FFFFE01E03F01E00F01E00
+781E007C1E003C1E003E1E001E1E001E1E001E1E000F1E000F1E000F1E000F1E000F1E000F1E00
+0F1E000F1E000F1E001F1E001E1E001E1E001E1E003C1E007C1E00781E00F81E03F0FFFFE0FFFF
+C0FFFF0018217FA01C>68 D<FFFFC0FFFFC0FFFFC001E00001E00001E00001E00001E00001E000
+01E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E000
+01E00001E00001E00001E00001E00001E00001E00001E000FFFFC0FFFFC0FFFFC012217BA01C>
+73 D<7FE0FFC0FFF1FFE07FE0FFC00F001E000F001E000F001E000F001E000F001E000F001E00
+0F001E000F001E000F001E000F001E000F001E000F001E000F001E000F001E000F001E000F001E
+000F001E000F001E000F001E000F001E000F001E000F001E0007001C0007803C0007803C0003C0
+780001E0F00000FFE000007FC000001F00001B2180A01C>85 D<0FF8001FFE003FFF803C0F8018
+03C00001E00001E00001E0003FE003FFE00FFFE03FC1E07E01E07801E0F001E0F001E0F001E0F0
+01E07803E07C0FE03FFFFF1FFEFF03F03F18177D961C>97 D<FF0000FF0000FF00000F00000F00
+000F00000F00000F00000F00000F00000F1F800F7FE00FFFF00FE0F80FC07C0F803C0F001E0F00
+1E0F000F0F000F0F000F0F000F0F000F0F000F0F000F0F001E0F801E0F803C0FC07C0FE0F80FFF
+F00F7FC0071F0018217FA01C>I<000FF0000FF0000FF00000F00000F00000F00000F00000F000
+00F00000F000F8F003FEF00FFFF01F07F03E03F03C01F07800F07800F0F000F0F000F0F000F0F0
+00F0F000F0F000F0F000F07800F07801F03C01F03E03F01F07F00FFFFF07FEFF01F8FF18217EA0
+1C>100 D<00FC0003FF000FFFC01F03E03E01E03C00F07800F0780070F00078F00078FFFFF8FF
+FFF8FFFFF8F00000F000007800007800783C00783E00F81F81F00FFFE003FFC000FE0015177D96
+1C>I<0003F8001FFC003FFE007C1E00780C00F00000F00000F00000F00000F0007FFFFCFFFFFC
+FFFFFC00F00000F00000F00000F00000F00000F00000F00000F00000F00000F00000F00000F000
+00F00000F00000F00000F00000F0007FFFE07FFFE07FFFE017217FA01C>I<FF000000FF000000
+FF0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0F80000F3FE0
+000FFFF0000FF0F0000FC078000F8078000F8078000F0078000F0078000F0078000F0078000F00
+78000F0078000F0078000F0078000F0078000F0078000F0078000F0078000F007800FFF1FF80FF
+F1FF80FFF1FF8019217FA01C>104 D<7E783C00FEFE7F007FFFFF001FCFE7801F0F87801F0F87
+801E0F07801E0F07801E0F07801E0F07801E0F07801E0F07801E0F07801E0F07801E0F07801E0F
+07801E0F07801E0F07801E0F07801E0F07807F8FC7E0FFCFE7F07F8FC7E01C1780961C>109
+D<00FC780003FF78000FFFF8001F03F8003E01F8003C00F8007800F80078007800F0007800F000
+7800F0007800F0007800F0007800F0007800F0007800780078007800F8003C01F8003E01F8001F
+07F8000FFFF80003FE780000F87800000078000000780000007800000078000000780000007800
+0000780000007800000078000007FF800007FF800007FF8019237E961C>113
+D<7FE3FF00FFE3FF807FE3FF000F0078000F0078000F80F8000780F0000780F00007C1F00003C1
+E00003C1E00003C1E00001E3C00001E3C00001E3C00000E3800000F7800000F7800000F7800000
+7F0000007F0000007F0000003E000019177F961C>118 D E /Fe 24 122
+df<FFF8FFF8FFF80D037D8C12>45 D<1FFFFFFFE07FFFFFFFF07FFFFFFFF00000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000FFFF
+FFFFC0FFFFFFFFC07FFFFFFF80240F7B942A>61 D<000001000000000180000000038000000007
+8000000007800000000F800000000FC000000013C000000013C000000023C000000023C0000000
+43E000000041E000000081E000000081E000000101E000000101F000000200F000000200F00000
+0400F000000400F000000800F00000080078000010007800003FFFF800003FFFF8000040007800
+0040007C000080003C000080003C000100003C000100003C000200003E000200001E000600001E
+001F00003E00FFC001FFF0FFC003FFE024267EA528>65 D<007F80007F8000FF0000E00000E000
+00E00000E00000E00001C00001C00001C00001C00001C00001C000038000038000038000038000
+0380000380000700000700000700000700000700000700000E00000E00000E00000E00000E0000
+0E00001C00001C00001C00001C00001C00001C0000380000380000380000380000380000380000
+700000700000700000700000700000700000E00000E00000FF0000FF0000FF000011377DA80F>
+91 D<007F80007F8000FF00000700000700000700000700000700000E00000E00000E00000E00
+000E00000E00001C00001C00001C00001C00001C00001C00003800003800003800003800003800
+00380000700000700000700000700000700000700000E00000E00000E00000E00000E00000E000
+01C00001C00001C00001C00001C00001C000038000038000038000038000038000038000070000
+070000FF0000FF0000FF0000113781A80F>93 D<01FF000701C00780E00F80F00F807807007800
+00780000780000F0003FF001F0F00780F01E00F03C00F07801E07801E1F001E1F001E1F003E1F0
+05E2700DE23C11FC0FE07818177D961B>97 D<03C0003FC0003FC00007C00007C0000780000780
+000780000780000780000780000F00000F00000F00000F00000F0FC00F30701EC0181F001C1E00
+0E1E000E1E000F1E000F3C000F3C000F3C000F3C000F3C000F3C000E78001E78001C78003C7800
+387800707800E0E401C0C3070080FC0018267BA51E>I<007FC001C0700300F00E01F01E01F01C
+00E0380000780000780000F00000F00000F00000F00000F00000F00000F00000F0000070002070
+00403800C01801000E060003F80014177C9618>I<000003C000003FC000003FC0000007C00000
+07C000000780000007800000078000000780000007800000078000000F0000000F0000000F0000
+000F00003F0F0000E0CF0003803E0006003E000E001E001C001E0038001E0078001E0078003C00
+F0003C00F0003C00F0003C00F0003C00F0003C00F0007800F0007800F0007800700078007000F8
+003801F8001802F8000E0CFF0003F0FF001A267CA51E>I<007E0001C1800700E00E00601C0070
+3C0070380070780070780070FFFFF0F00000F00000F00000F00000F00000F00000F00000700020
+7000403800801801000E060003F80014177C9618>I<0000F800038C000E1E001E3E003C3E003C
+3C00780000780000780000780000780000F00000F00000F00000F0001FFF801FFF8001E00001E0
+0001E00001E00001E00001E00003C00003C00003C00003C00003C00003C0000780000780000780
+000780000780000780000F8000FFF800FFF80017267FA510>I<003C000003FC000003FC000000
+7C0000007C000000780000007800000078000000780000007800000078000000F0000000F00000
+00F0000000F0000000F0FE0000F3070001E4038001E803C001F003C001F003C001E003C001E003
+C003C0078003C0078003C0078003C0078003C0078003C0078007800F0007800F0007800F000780
+0F0007800F0007800F000F801F00FFF1FFE0FFF1FFE01B267FA51E>104
+D<0038007C007C0078003000000000000000000000000000000000000000F00FF00FE001E001E0
+01E001E001E003C003C003C003C003C003C00780078007800780078007800F80FFF0FFF00E257F
+A40F>I<00F0FE01FC001FF307060E001FE40388070001E803D0078001F003E0078001F003E007
+8001E003C0078001E003C0078003C007800F0003C007800F0003C007800F0003C007800F0003C0
+07800F0003C007800F0007800F001E0007800F001E0007800F001E0007800F001E0007800F001E
+0007800F001E000F801F003E00FFF1FFE3FFC0FFF1FFE3FFC02A177F962D>109
+D<00F0FE000FF307001FE4038001E803C001F003C001F003C001E003C001E003C003C0078003C0
+078003C0078003C0078003C0078003C0078007800F0007800F0007800F0007800F0007800F0007
+800F000F801F00FFF1FFE0FFF1FFE01B177F961E>I<003F0001C1C00300600E00701C00381C00
+3838003C78003C78003CF0003CF0003CF0003CF0003CF00038F00078F00078F00070F000E07001
+E03801C01807000E0E0003F00016177C961B>I<003C3F0003FCC1C007FB00E0007C0070007800
+78007800380078003C0078003C00F0003C00F0003C00F0003C00F0003C00F0003C00F0007801E0
+007801E0007001E000F001E000E001E001C001E0038003D0070003CC1C0003C3F00003C0000003
+C0000003C0000007800000078000000780000007800000078000000F800000FFF00000FFF00000
+1E2281961E>I<003E0601E18603808C07005C0E007C1C003C3C003C78003C780078F00078F000
+78F00078F00078F00078F000F0F000F0F000F07000F07001F03802F01805E00E19E003E1E00001
+E00001E00001E00003C00003C00003C00003C00003C00007C0007FF8007FF817227C961C>I<00
+F1F00FF2381FE47801E87801F03001F00001E00001E00003E00003C00003C00003C00003C00003
+C0000780000780000780000780000780000780000F8000FFF800FFF80015177F9615>I<00FE20
+0381E00600C00C00401C00401C00401C00401E00001FC0001FFC000FFE0007FF0000FF80000F80
+400780400380600380600380600300600700F00600C81C0087F00013177E9615>I<0040008000
+8000800080018001800300030007000F003FFEFFFE1E001E001E001E001E001E003C003C003C00
+3C003C003C0478087808780878087808781038201C600F800F227BA115>I<07800F7F80FFFF01
+FE0F001E0F001E0F001E0F001E0F001E1E003C1E003C1E003C1E003C1E003C1E003C3C00783C00
+783C00783C00F83C00F83C01781C02F80E0CFF03F0FF18177C961E>I<0FFE1FF01FFC1FF001F8
+0F8000F00C000078080000781000003C2000003E4000001E8000001F0000000F0000000F800000
+0F8000001BC0000013C0000021E0000041E0000080F0000100F800030078001F00FC00FF81FFC0
+FF81FFC01C177F961C>120 D<07FF03FC07FF03FC00F801E000F8008000780180007801000078
+020000780200003C0400003C0400003C0800003C0800003E1000001E2000001E2000001E400000
+1F4000000F8000000F8000000F0000000E00000006000000040000000400000008000000080000
+0010000030200000F8200000F8400000F8C00000F1800000C30000003C0000001E2280961C>I
+E /Ff 28 122 df<FFFEFFFEFFFE0F037D8E14>45 D<387C7EFC7C3807067B8510>I<00000020
+0000000060000000007000000000F000000000F000000001F000000001F000000003F000000003
+F800000004F80000000CF800000008F800000010F800000010FC000000207C000000207C000000
+407C000000407C000000807E000000803E000001003E000001003E000002003E000002003F0000
+04001F000004001F000008001F00000FFFFF00001FFFFF000010001F800020000F800060000F80
+0040000F800080000F800080000FC001000007C001000007C003000007C007000007C01F80000F
+E0FFE000FFFEFFE000FFFE272A7EA92C>65 D<03FFFFFFF803FFFFFFF8001F8001F8001F000078
+001F000038001F000018001F000018001F000018003E000018003E000018003E000008003E0000
+08003E002008003E002008007C004000007C004000007C004000007C00C000007C03C000007FFF
+C00000FFFF800000F803800000F801800000F801800000F800800000F800800001F001000001F0
+01000001F000000001F000000001F000000001F000000003E000000003E000000003E000000003
+E000000003E000000003E000000007E0000000FFFF800000FFFF80000025297DA826>70
+D<03FFFC03FFFC001F80001F00001F00001F00001F00001F00003E00003E00003E00003E00003E
+00003E00007C00007C00007C00007C00007C00007C0000F80000F80000F80000F80000F80000F8
+0001F00001F00001F00001F00001F00001F00003E00003E00003E00003E00003E00003E00007E0
+00FFFF00FFFF0016297DA815>73 D<03FF8000FFF003FFC000FFF0001FC0001F800017C0000600
+0013E00004000013E00004000011F00004000011F00004000020F80008000020F800080000207C
+00080000207C00080000203E00080000203E00080000401F00100000401F00100000401F801000
+00400F80100000400FC01000004007C01000008007E02000008003E02000008003F02000008001
+F02000008001F82000008000F82000010000FC40000100007C40000100007E40000100003E4000
+0100003F40000100001F40000200001F80000200000F80000200000F8000020000078000020000
+0780000600000380001F8000030000FFF000010000FFF0000100002C297DA82C>78
+D<0001FC020007FF06001E038E003800DC0070007C00E0003C01E0001C03C0001C03C0001C0380
+000807800008078000080780000807C0000807C0000007E0000003F0000003FE000001FFE00001
+FFFC0000FFFF00003FFF800007FFC00000FFE000000FE0000003F0000001F0000001F0000001F0
+200000F0200000F0200000F0200000E0600001E0600001E0700001C0700003C0780007807C0007
+00E6001E00E3C07C00C1FFF000803FC0001F2B7DA921>83 D<003F800001C0E000020070000780
+380007C03C000F803C0007803C0002003C0000003C0000003C0000003C00003FF80001F0780007
+C078000F0078001E0078003C0078007C00F040F800F040F800F040F800F040F801F040F802F080
+7C04F0803E187F0007E03C001A1A7D991D>97 D<001FE000701801C00403803C07003E0F007C1E
+003C3E00103C00007C00007C0000F80000F80000F80000F80000F80000F80000F80000F8000078
+00107800103C00201C00400E008007070001F800171A7C991A>99 D<0000007800000FF800000F
+F8000000F0000000F0000000F0000000F0000000F0000000F0000001E0000001E0000001E00000
+01E0000001E0000001E0000003C0000FC3C0007833C001E00BC003800BC0070007C00F0007801E
+0007803E0007803C0007807C0007807C00078078000F00F8000F00F8000F00F8000F00F8000F00
+F8000F00F8001E00F8001E0078001E0078001E0038003E001C005E000E00BE0007073FE001F83F
+E01D2A7CA921>I<003F8000E0E001C0700780700F00780E00381E003C3C003C3C003C7C003C7C
+007CFFFFF8F80000F80000F80000F80000F80000F80000F800007800107800103800201C00400C
+018007060001F800161A7C991A>I<00007C0001C200070F000F1F001E1F001C0F003C04003C00
+003C0000780000780000780000780000780000780000F0001FFFC01FFFC000F00000F00000F000
+01E00001E00001E00001E00001E00001E00003C00003C00003C00003C00003C00003C000078000
+0780000780000780000780000780000F8000FFFC00FFFC00182A7EA912>I<000000780007E084
+003C3B1C00701C1C00E01E0801E01E0003E01F0003C01F0007C01F0007C01F0007C01F0007C01E
+0007C03E0007C03C0003C0780001C0700002E1E000063F000004000000040000000C0000000C00
+00000E00000007FFE00007FFF80003FFFC000E003E0018000F00380007007000070070000700E0
+000700E0000700E0000700E0000E0070001C0030003800180070000F03C00001FE00001E287F9A
+1D>I<001E000003FE000003FE0000003C0000003C0000003C0000003C0000003C0000003C0000
+00780000007800000078000000780000007800000078000000F0000000F07F0000F1838000F201
+C000F401E000F801E001F001E001F001E001E001E001E001E001E001E001E001E003C003C003C0
+03C003C003C003C003C003C003C003C003C0078007800780078007800780078007800780078007
+8007800F800F80FFF8FFF8FFF8FFF81D2A7EA921>I<0038007C00FC00FC007C00780000000000
+0000000000000000000000000000F00FF00FF001F001F001E001E001E001E001E001E003C003C0
+03C003C003C003C00780078007800780078007800F80FFF0FFF00E297EA811>I<001E000003FE
+000003FE0000003C0000003C0000003C0000003C0000003C0000003C0000007800000078000000
+78000000780000007800000078000000F0000000F00FFC00F00FFC00F007C000F0070000F00400
+01E0080001E0100001E0200001E0800001E1800001E3800003C7C00003D3C00003E3E00003C3E0
+0003C1E00003C1F0000780F0000780F8000780780007807C0007803C0007803E000F807F00FFF9
+FFE0FFF9FFE01E2A7EA91F>107 D<001E01FE03FE003C003C003C003C003C003C007800780078
+00780078007800F000F000F000F000F000F001E001E001E001E001E001E003C003C003C003C003
+C003C00780078007800780078007800F80FFF0FFF00F2A7EA911>I<00F07F007F000FF1838183
+801FF201C201C001F401E401E001F801E801E001F001F001E001F001F001E001E001E001E001E0
+01E001E001E001E001E001E001E001E003C003C003C003C003C003C003C003C003C003C003C003
+C003C003C003C003C003C003C00780078007800780078007800780078007800780078007800780
+078007800780078007800F800F800F80FFF8FFF8FFF8FFF8FFF8FFF82D1A7E9931>I<00F07F00
+0FF183801FF201C001F401E001F801E001F001E001F001E001E001E001E001E001E001E001E001
+E003C003C003C003C003C003C003C003C003C003C003C003C00780078007800780078007800780
+078007800780078007800F800F80FFF8FFF8FFF8FFF81D1A7E9921>I<001FC00070F001C03803
+801C07001E0E000E1E000F3C000F3C000F7C000F7C000F78001FF8001FF8001FF8001FF8001FF8
+003EF8003EF8003C78007C7800783800F03C01E01E03C007070001F800181A7C991D>I<003C1F
+8003FC60E007FD8078007E003C003C003C007C001E0078001F0078001F0078001F0078001F0078
+001F00F0001F00F0001F00F0001F00F0001F00F0001E00F0003E01E0003E01E0007C01E0007801
+E000F001E001E001F001C003C8078003C40E0003C3F80003C0000003C0000003C0000007800000
+07800000078000000780000007800000078000000F800000FFF80000FFF800002026809921>I<
+00F0F80FF11C0FF63E01F43E01F83C01F03C01F00001F00001E00001E00001E00003C00003C000
+03C00003C00003C00003C0000780000780000780000780000780000780000F8000FFFC00FFFC00
+171A7E9917>114 D<007F0801C0D80300380600180E00180C00101C00101E00101E00001F8000
+0FFC0007FF0003FF8000FFC0000FE00003E02001E06000E06000E06000E06000E06000C0700180
+E80300C40E0083F800151A7E9917>I<00200000200000200000600000400000C00000C00001C0
+0001C00003C0000780001FFF80FFFF800780000780000780000F00000F00000F00000F00000F00
+000F00001E00001E00001E00001E00001E01001E01003C02003C02003C02003C02003C04001C04
+001C08000E100003E00011257BA417>I<078007807F807F80FF80FF800F800F800F800F800F00
+0F000F000F000F000F000F000F000F000F000F000F001E001E001E001E001E001E001E001E001E
+001E001E001E003C003C003C003C003C003C003C007C003C007C003C00BC001C017C000E067FC0
+03F87FC01A1A7B9921>I<FFF01FF0FFF01FF00F8007800F0007000F8006000780040007800C00
+0780080007C0100003C0100003C0200003C0200003C0400001E0400001E0800001E1000001E100
+0001F2000000F2000000F4000000F4000000F80000007800000070000000600000006000001C1A
+7B991F>I<FFF3FFC3FEFFF3FF83FE1F803C00F80F003C00600F003C00400F003C00400F003C00
+8007805C008007805E010007809E010007809E020007811E060007C10E040003C20E0C0003C20F
+080003C40F100003C40F100003C807200001E807200001F007C00001F007C00001E007800001E0
+07800001C003000000C00300000080020000271A7B992A>I<07FF80FF8007FF80FF80007C003C
+000078003800007C003000003C002000003C006000003C004000003E008000001E008000001E01
+0000001E010000001E020000000F020000000F040000000F080000000F080000000F9000000007
+9000000007A000000007A000000007C000000003C0000000038000000003000000000300000000
+0200000000020000000004000000000C00000000080000007010000000F810000000F820000000
+F040000000F080000000C1000000003E00000000212680991F>121 D E
+/Fg 28 122 df<7FFFFEFFFFFFFFFFFF7FFFFE18047D931F>45 D<00000600000F00000F00001F
+00001E00003E00003C00007C0000780000F80000F00001F00001E00003E00003C00007C0000780
+000780000F80000F00001F00001E00003E00003C00007C0000780000F80000F00001F00001E000
+01E00003E00003C00007C0000780000F80000F00001F00001E00003E00003C00007C0000780000
+F80000F00000F00000600000182F7DA91F>47 D<387CFEFEFE7C38000000000000000000000000
+387CFEFEFE7C38071A74991F>58 D<7FFFFF80FFFFFFC0FFFFFFC07FFFFF800000000000000000
+000000000000000000000000000000007FFFFF80FFFFFFC0FFFFFFC07FFFFF801A0E7E981F>61
+D<001F81C0007FF1C001FFFBC003E07FC007C01FC00F800FC01F0007C01E0007C03C0003C03C00
+03C0780003C0780003C07800000070000000F0000000F0000000F0000000F0000000F0000000F0
+000000F0000000F0000000F0000000700000007800000078000000780003C03C0003C03C0003C0
+1E0003C01F0007800F800F8007C01F0003E07E0001FFFC00007FF000001FC0001A257EA41F>67
+D<7FFF8000FFFFE0007FFFF8000F00FC000F003E000F001E000F001F000F000F800F0007800F00
+07800F0003C00F0003C00F0003C00F0003E00F0001E00F0001E00F0001E00F0001E00F0001E00F
+0001E00F0001E00F0001E00F0001E00F0001E00F0003C00F0003C00F0003C00F0007C00F000780
+0F000F800F000F000F001E000F003E000F00FC007FFFF800FFFFE0007FFF80001B257FA41F>I<
+07FC00001FFF00003FFFC0003E03E0003E01F0001C00F000000078000000780000007800000078
+00003FF80001FFF80007FFF8001FE078003E0078007C00780078007800F0007800F0007800F000
+7800F00078007800F8007E03F8003FFFFFE00FFF3FE003FC0FE01B1A7D991F>97
+D<007FE001FFF807FFFC0FC07C1F007C3E00383C0000780000780000700000F00000F00000F000
+00F00000F00000F000007000007800007800003C003C3E003C1F007C0FC0F807FFF001FFE0007F
+80161A7C991F>99 D<0001FE000003FE000001FE0000001E0000001E0000001E0000001E000000
+1E0000001E0000001E0000001E00007E1E0001FF9E0007FFDE000F81FE001F00FE003E007E003C
+003E0078001E0078001E00F0001E00F0001E00F0001E00F0001E00F0001E00F0001E00F0001E00
+F0001E0078001E0078003E003C003E003C007E001E00FE000F83FE0007FFDFE003FF1FF0007C1F
+E01C257EA41F>I<007F0001FFC007FFE00F81F01F00783E00783C003C78003C78001E70001EF0
+001EFFFFFEFFFFFEFFFFFEF00000F000007800007800007800003C001E1E001E1F003E0FC0FC03
+FFF801FFF0003F80171A7D991F>I<0001FC000007FF00001FFF80003F0F80003C0F8000780700
+00780000007800000078000000780000007800007FFFFE00FFFFFE00FFFFFE0000780000007800
+000078000000780000007800000078000000780000007800000078000000780000007800000078
+000000780000007800000078000000780000007800000078000000780000007800003FFFF0007F
+FFF8003FFFF00019257FA41F>I<007C0F8001FF3FC007FFFFE00F83F1E01F01F1C01E00F0003C
+0078003C0078003C0078003C0078003C0078003C0078001E00F0001F01F0000F83E0001FFFC000
+1DFF00001C7C00003C0000003C0000003C0000001E0000001FFFE0000FFFF8000FFFFE001FFFFF
+003C003F8078000F80780007C0F00003C0F00003C0F00003C0F00003C078000780780007803E00
+1F001F807E000FFFFC0003FFF000007F80001B287E991F>I<7F800000FF8000007F8000000780
+0000078000000780000007800000078000000780000007800000078000000783F000078FFC0007
+BFFE0007FC1F0007F00F0007E0078007C0078007C0078007800780078007800780078007800780
+078007800780078007800780078007800780078007800780078007800780078007800780078007
+80078007807FF87FF8FFFCFFFC7FF87FF81E2580A41F>I<00700000F80000F80000F800007000
+0000000000000000000000000000000000000000007FF800FFF8007FF800007800007800007800
+007800007800007800007800007800007800007800007800007800007800007800007800007800
+007800007800007800007800FFFFF8FFFFF8FFFFF815267BA51F>I<7F800000FF8000007F8000
+0007800000078000000780000007800000078000000780000007800000078000000787FFC00787
+FFE00787FFC007807E000780FC000781F8000783F0000787E000078FC000079F800007BF000007
+FF000007FF800007FFC00007F3C00007E3E00007C1F0000780F0000780F80007807C0007803C00
+07801E0007801F007FF87FE0FFFCFFF07FF87FE01C257FA41F>107 D<FFF800FFF800FFF80000
+780000780000780000780000780000780000780000780000780000780000780000780000780000
+780000780000780000780000780000780000780000780000780000780000780000780000780000
+7800007800007800007800007800FFFFFCFFFFFCFFFFFC16257CA41F>I<FE3C0F00FEFE3F80FF
+FF7FC01FCFF3C01F87E1E01F07C1E01F07C1E01E0781E01E0781E01E0781E01E0781E01E0781E0
+1E0781E01E0781E01E0781E01E0781E01E0781E01E0781E01E0781E01E0781E01E0781E01E0781
+E01E0781E0FFC7F1FCFFCFF3FCFFC7F1FC1E1A80991F>I<7F83F000FF8FFC007FBFFE0007FC1F
+0007F00F0007E0078007C0078007C0078007800780078007800780078007800780078007800780
+07800780078007800780078007800780078007800780078007800780078007800780078007807F
+F87FF8FFFCFFFC7FF87FF81E1A80991F>I<00FC0003FF0007FF801F87E01E01E03C00F07C00F8
+780078780078F0003CF0003CF0003CF0003CF0003CF0003CF0003CF8007C7800787800787C00F8
+3C00F01E01E01F87E007FF8003FF0000FC00161A7C991F>I<7F83E000FF9FFC007FBFFE0007FC
+1F0007F0078007E003C007C003C0078001E0078001E0078000F0078000F0078000F0078000F007
+8000F0078000F0078000F0078000F0078001E007C001E007C003C007E007C007F00F8007F81F00
+07BFFE00079FF8000787E000078000000780000007800000078000000780000007800000078000
+000780000007800000078000007FF80000FFFC00007FF800001C2780991F>I<7FE07E00FFE1FF
+807FE3FFC001EF87C001FF07C001FC038001F8000001F8000001F0000001F0000001F0000001E0
+000001E0000001E0000001E0000001E0000001E0000001E0000001E0000001E0000001E0000001
+E0000001E000007FFFE000FFFFE0007FFFE0001A1A7E991F>114 D<03FC700FFFF03FFFF07C03
+F07001F0E000F0E000F0E000F0F000F07C00003FE0001FFF0007FFC000FFF00003F80000787000
+3CF0001CF0001CF8001CF8001CFC0038FF00F0FFFFF0E7FFC0E1FE00161A7C991F>I<00700000
+00F0000000F0000000F0000000F0000000F0000000F000007FFFFE00FFFFFE00FFFFFE0000F000
+0000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0
+000000F0000000F0000000F0078000F0078000F0078000F0078000F0078000F00F00007C1F0000
+3FFE00001FFC000007F00019217FA01F>I<7F807F80FF80FF807F807F80078007800780078007
+800780078007800780078007800780078007800780078007800780078007800780078007800780
+078007800780078007800780078007800780078007800F8007801F8003C07F8001FFFFF800FFE7
+FC003F87F81E1A80991F>I<7FF0FFE0FFF0FFF07FF0FFE00F000F0007801E0007801E0007801E
+0003C03C0003C03C0003C03C0003E07C0001E0780001E0780001E0780000F0F00000F0F00000F0
+F0000079E0000079E0000079E0000039C0000039C000003FC000003FC000001F8000001F80001C
+1A7F991F>I<FFE07FF0FFF0FFF0FFE07FF01E0007801E0007801E0007801E0007801E0007800F
+000F000F000F000F0F0F000F0F0F000F1F8F000F1F8F00071B8E00079B9E00079B9E0007BBDE00
+07BBDE0007B1DE0003B1DC0003B1DC0003F1FC0003E0FC0003E0FC0001E078001C1A7F991F>I<
+7FF1FFC07FF1FFE07FF1FFC007C07C0003E0780001E0F80000F1F00000F9E000007FE000003FC0
+00003F8000001F8000000F0000001F0000001F8000003FC0000079E00000F9E00000F0F00001E0
+F80003E07C0003C03C0007803E007FF0FFE0FFF9FFF07FF0FFE01C1A7F991F>I<7FF0FFE0FFF8
+FFF07FF0FFE00F800F0007801E0007801E0003C01E0003C03C0003C03C0001E03C0001E07C0001
+E0780000F0780000F0780000F0F0000078F0000078F0000038E0000039E000003DE000001DC000
+001DC000001FC000000FC000000F8000000F8000000F8000000F0000000F0000001F0000001E00
+00001E0000383E00007C3C00007C7C00007CF800007FF000003FE000000F8000001C277F991F>
+I E /Fh 3 110 df<00000001800000000003C00000000003C00000000007C00000000007C000
+0000000FC0000000000FE0000000001FE0000000001FE00000000037E00000000037E000000000
+67F00000000063F000000000C3F000000000C3F00000000183F00000000183F00000000303F800
+00000301F80000000601F80000000601F80000000C01F80000000C01FC0000001800FC00000018
+00FC0000003000FC0000003000FC0000006000FE000000E0007E000000C0007E000001C0007E00
+000180007E000003FFFFFE000003FFFFFF00000600003F00000600003F00000C00003F00000C00
+003F00001800003F80001800001F80003000001F80003000001F80006000001F80006000001F80
+00C000001FC001C000000FC003E000000FC00FF000003FE0FFFE0003FFFFFFFC0003FFFF30327E
+B135>65 D<00000007C0000000FFC0000000FFC00000000FC00000000FC00000000F800000000F
+800000000F800000000F800000000F800000000F800000001F000000001F000000001F00000000
+1F000000001F000000001F000000003E000000003E000003F83E00001E063E000038013E0000E0
+00BE0001C000FC000380007C000780007C000F00007C001F00007C001E00007C003E0000F8003C
+0000F8007C0000F8007C0000F8007C0000F8007C0000F800F80001F000F80001F000F80001F000
+F80001F000780001F000780001F000780003E000780003E0003C0003E0003C0007E0001C000FE0
+000E001BE000070037F00001C1C7FF00007F07FE0022327BB127>100 D<003E03F8003F800FFE
+0C1E00C1E00FFE300F0300F000FE4007840078007C8007C8007C007D0007D0007C007E0007E000
+7C007E0007E0007C007C0007C0007C007C0007C0007C00FC000FC000F800F8000F8000F800F800
+0F8000F800F8000F8000F800F8000F8000F800F8000F8000F801F0001F0001F001F0001F0001F0
+01F0001F0001F001F0001F0001F001F0001F0001F001F0001F0001F003E0003E0003E003E0003E
+0003E003E0003E0003E003E0003E0003E003E0003E0003E007E0007E0007E007E0007E0007E0FF
+FF0FFFF0FFFFFFFF0FFFF0FFFF381F7E9E3C>109 D E /Fi 49 122 df<0007FC00003FFF0000
+FE078003F007C007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC003000FC000000FC00000
+0FC000000FC07FE0FFFFFFE0FFFFFFE00FC007E00FC007E00FC007E00FC007E00FC007E00FC007
+E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC0
+07E00FC007E00FC007E00FC007E00FC007E0FFFC7FFEFFFC7FFE1F267FA522>12
+D<FFFEFFFEFFFEFFFEFFFE0F057F8E14>45 D<3C7EFFFFFFFF7E3C08087C8711>I<007F800003
+FFF00007E1F8000F807C001F003E003F003F003E001F007E001F807E001F807E001F807E001F80
+FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001F
+C0FE001FC0FE001FC0FE001FC07E001F807E001F807E001F807E001F803F003F003F003F001F00
+3E000F807C0007E1F80003FFF000007F80001A237EA21F>48 D<001C00003C0000FC00FFFC00FF
+FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000
+FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000
+FC0000FC0000FC007FFFFC7FFFFC16237CA21F>I<01FF0007FFC01E07F03803F86001FC7C00FE
+FE00FEFE00FFFE007FFE007F7C007F3800FF0000FF0000FE0000FE0001FC0001F80003F00007E0
+000780000F00001E00003C0000700000E00301C0030380070700060600060FFFFE1FFFFE3FFFFE
+7FFFFCFFFFFCFFFFFC18237DA21F>I<01FF0007FFE01E03F03801F83C01FC7E00FE7E00FE7E00
+FE3E00FE1C01FE0001FC0001FC0003F80007F0000FC001FF0001FF000007E00001F00001F80000
+FC0000FE0000FF0000FF1000FF7C00FFFE00FFFE00FFFE00FEFE00FE7C01FC7001F83E07F00FFF
+C001FF0018237DA21F>I<0000380000007800000078000000F8000001F8000003F8000007F800
+0006F800000CF800001CF8000038F8000030F8000060F80000E0F80001C0F8000180F8000300F8
+000700F8000E00F8001C00F8001800F8003000F8007000F800E000F800FFFFFFC0FFFFFFC00001
+F8000001F8000001F8000001F8000001F8000001F8000001F800007FFFC0007FFFC01A237EA21F
+>I<18000C1F007C1FFFF81FFFF01FFFE01FFFC01FFF801FFC0018000018000018000018000018
+000018FF001BFFE01F03F01C00F80800FC00007E00007E00007E00007F00007F78007FFC007FFC
+007FFC007FFC007EF8007E6000FC7000FC3801F81E07E007FFC001FE0018237DA21F>I<001FC0
+007FF001F03803E00C07803E0F807E1F007E3F007E3F007E7E003C7E00007E00007E0000FE3FC0
+FE7FF0FE80F8FF80FCFF007CFF007EFE007EFE007FFE007FFE007FFE007F7E007F7E007F7E007F
+7E007F3E007E3F007E1F007C0F80F807C1F003FFC0007F0018237DA21F>I<300000003C000000
+3FFFFFC03FFFFFC03FFFFF807FFFFF007FFFFE007FFFFC006000180060001800E0003000C00060
+00C000C00000018000000180000003000000060000000E0000000E0000001C0000001C0000003C
+0000003C0000007800000078000000F8000000F8000000F8000000F8000001F8000001F8000001
+F8000001F8000001F8000001F8000000F00000006000001A257DA41F>I<00FF8003FFE00F01F8
+1C007C38003C38001E78001E78001E7C001E7E001E7F803C7FE03C3FF8781FFDF01FFFC00FFFC0
+03FFE003FFF80FFFFC1E1FFC3C07FE7803FE7800FFF0003FF0001FF0000FF0000FF0000FF0000E
+78000E78001C3C00381F80F007FFE001FF0018237DA21F>I<00FF0003FFC00F83E01F00F03F00
+F87E007C7E007C7E007EFE007EFE007EFE007EFE007FFE007FFE007FFE007F7E007F7E00FF3E00
+FF3F01FF1F017F0FFE7F03FC7F00007F00007E00007E3C007E7E00FC7E00FC7E00F87E00F07C01
+F03003E01C0F800FFF0003F80018237DA21F>I<FFFFFFE00000FFFFFFFC000003F800FF000003
+F8001FC00003F80007E00003F80003F00003F80001F80003F80001FC0003F80000FC0003F80000
+FE0003F80000FE0003F800007F0003F800007F0003F800007F0003F800007F8003F800007F8003
+F800007F8003F800007F8003F800007F8003F800007F8003F800007F8003F800007F8003F80000
+7F8003F800007F8003F800007F0003F800007F0003F800007F0003F80000FE0003F80000FE0003
+F80001FC0003F80001F80003F80003F00003F80007E00003F8001FC00003F800FF8000FFFFFFFE
+0000FFFFFFE0000029257EA42F>68 D<FFFFFFFF00FFFFFFFF0003F8007F0003F8000F8003F800
+078003F800038003F800038003F800018003F800018003F800018003F80000C003F80600C003F8
+0600C003F806000003F806000003F80E000003F81E000003FFFE000003FFFE000003F81E000003
+F80E000003F806000003F806000003F806006003F806006003F800006003F80000C003F80000C0
+03F80000C003F80000C003F80001C003F80003C003F80003C003F8000F8003F8003F80FFFFFFFF
+80FFFFFFFF8023257EA428>I<FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003
+F800070003F800070003F800030003F800030003F800030003F800018003F803018003F8030180
+03F803000003F803000003F807000003F80F000003FFFF000003FFFF000003F80F000003F80700
+0003F803000003F803000003F803000003F803000003F800000003F800000003F800000003F800
+000003F800000003F800000003F800000003F800000003F800000003F8000000FFFFF00000FFFF
+F0000021257EA427>I<FFFFE0FFFFE0FFFFE0FFFFE003F80003F80003F80003F80003F80003F8
+0003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8
+0003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003FFFFFFF8
+0003FFFFFFF80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8
+0003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8
+0003F80003F80003F80003F80003F80003F80003F80003F800FFFFE0FFFFE0FFFFE0FFFFE02B25
+7EA430>72 D<FFFFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F800
+03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800
+03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800FFFFE0FFFFE0
+13257EA417>I<FFF8000000FFF8FFFC000001FFF803FC000001FE00037E0000037E00037E0000
+037E00037E0000037E00033F0000067E00033F0000067E00031F80000C7E00031F80000C7E0003
+0FC000187E00030FC000187E000307E000307E000307E000307E000307E000307E000303F00060
+7E000303F000607E000301F800C07E000301F800C07E000300FC01807E000300FC01807E000300
+7E03007E0003007E03007E0003007E03007E0003003F06007E0003003F06007E0003001F8C007E
+0003001F8C007E0003000FD8007E0003000FD8007E00030007F0007E00030007F0007E00030007
+F0007E00030003E0007E00078003E0007E00FFFC01C01FFFF8FFFC01C01FFFF835257EA43A>77
+D<FFF80007FFE0FFFC0007FFE003FE00003C0003FF00001800037F00001800033F80001800031F
+C0001800031FE0001800030FF00018000307F80018000303F80018000301FC0018000300FE0018
+000300FF00180003007F80180003003FC0180003001FC0180003000FE0180003000FF018000300
+07F81800030003FC1800030001FC1800030000FE18000300007F18000300007F98000300003FD8
+000300001FF8000300000FF80003000007F80003000003F80003000003F80003000001F8000300
+0000F800030000007800078000003800FFFC00001800FFFC000018002B257EA430>I<0003FF80
+00001FFFF000007F01FC0001FC007F0003F0001F8007E0000FC00FE0000FE01FC00007F01F8000
+03F03F800003F83F800003F87F800003FC7F000001FC7F000001FCFF000001FEFF000001FEFF00
+0001FEFF000001FEFF000001FEFF000001FEFF000001FEFF000001FEFF000001FE7F000001FC7F
+000001FC7F800003FC3F800003F83F800003F81FC00007F01FC00007F00FE0000FE007F0001FC0
+03F8003F8001FC007F00007F01FC00001FFFF0000003FF800027257DA42E>I<FFFFFFE000FFFF
+FFFC0003F800FF0003F8003F8003F8001FC003F8001FE003F8000FE003F8000FF003F8000FF003
+F8000FF003F8000FF003F8000FF003F8000FF003F8000FE003F8001FE003F8001FC003F8003F80
+03F800FF0003FFFFFC0003FFFFE00003F800000003F800000003F800000003F800000003F80000
+0003F800000003F800000003F800000003F800000003F800000003F800000003F800000003F800
+000003F800000003F8000000FFFFE00000FFFFE0000024257EA42A>I<00FF008007FFE3800F80
+F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC000180FC000000FF
+0000007FE000007FFE00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007FFF800003FFC0
+00003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E00003C0F00007
+C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 D<FFFFE00FFFC0FFFFE00F
+FFC003F80000780003F80000300003F80000300003F80000300003F80000300003F80000300003
+F80000300003F80000300003F80000300003F80000300003F80000300003F80000300003F80000
+300003F80000300003F80000300003F80000300003F80000300003F80000300003F80000300003
+F80000300003F80000300003F80000300003F80000300003F80000300003F80000300003F80000
+300001F80000600001FC0000600000FC0000C000007C0000C000003E00018000001F0007000000
+0FE03E00000003FFF8000000007FC000002A257EA42F>85 D<FFFF8001FFE0FFFF8001FFE007F8
+00001C0003F80000180003F80000180003FC0000380001FC0000300001FE0000700000FE000060
+0000FF00006000007F0000C000007F8000C000003F80018000003F80018000003FC0038000001F
+C0030000001FE0070000000FE0060000000FF00600000007F00C00000007F00C00000003F81800
+000003F81800000003FC3800000001FC3000000001FE7000000000FE6000000000FF6000000000
+7FC0000000007FC0000000003F80000000003F80000000003F80000000001F00000000001F0000
+0000000E00000000000E0000002B257FA42E>I<07FF00001FFFE0003E03F0003F00F8003F00FC
+003F007E001E007E0000007E0000007E0000007E00001FFE0003FE7E000FC07E001F007E003E00
+7E007E007E00FC007E00FC007E00FC007E00FC00BE007E01BE003F073E001FFE1FE007F00FE01B
+187E971E>97 D<FFC00000FFC000000FC000000FC000000FC000000FC000000FC000000FC00000
+0FC000000FC000000FC000000FC000000FC000000FC000000FC1FC000FCFFF000FFC0FC00FF007
+E00FC003F00FC003F00FC001F80FC001F80FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC0
+01FC0FC001FC0FC001FC0FC001F80FC001F80FC003F00FE003F00FF007E00F1C1F800E0FFF000C
+03F8001E267FA522>I<007FE003FFF807C07C1F80FC1F00FC3F00FC7E00787E0000FE0000FE00
+00FE0000FE0000FE0000FE0000FE0000FE00007E00007F00003F000C1F800C1FC01807E07003FF
+E0007F0016187E971B>I<0000FFC00000FFC000000FC000000FC000000FC000000FC000000FC0
+00000FC000000FC000000FC000000FC000000FC000000FC000000FC0007F0FC003FFCFC00FE0FF
+C01F803FC03F000FC03F000FC07E000FC07E000FC0FE000FC0FE000FC0FE000FC0FE000FC0FE00
+0FC0FE000FC0FE000FC0FE000FC07E000FC07E000FC03F000FC03F001FC01F803FC00FC0EFC003
+FFCFFC00FE0FFC1E267EA522>I<007F0003FFC007C1F00F80F81F00F83F007C7E007C7E007EFE
+007EFE007EFFFFFEFFFFFEFE0000FE0000FE00007E00007E00007E00063F00061F000C0F801807
+E07003FFE0007F8017187E971C>I<001FC0007FF001F8F003E1F807E1F807C1F80FC0F00FC000
+0FC0000FC0000FC0000FC0000FC0000FC000FFFF00FFFF000FC0000FC0000FC0000FC0000FC000
+0FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC000
+0FC0000FC000FFFE00FFFE0015267EA513>I<01FF07C007FFDFE00F83F1E01F01F1E03E00F800
+7E00FC007E00FC007E00FC007E00FC007E00FC007E00FC003E00F8001F01F0000F83E0000FFFC0
+0011FF00003000000030000000380000003C0000003FFFE0001FFFFC001FFFFE000FFFFF001FFF
+FF803C003F8078000FC0F80007C0F80007C0F80007C0F80007C07C000F803E001F001F807E0007
+FFF80000FFC0001B247E971F>I<FFC00000FFC000000FC000000FC000000FC000000FC000000F
+C000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC0FE000FC3FF80
+0FCE0FC00FD80FC00FD007E00FE007E00FE007E00FC007E00FC007E00FC007E00FC007E00FC007
+E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC0
+07E0FFFC7FFEFFFC7FFE1F267EA522>I<0F001F803FC03FC03FC03FC01F800F00000000000000
+00000000000000007FC07FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00F
+C00FC00FC00FC00FC00FC00FC0FFF8FFF80D277EA611>I<FFC00000FFC000000FC000000FC000
+000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC0
+00000FC01FF00FC01FF00FC007800FC00E000FC01C000FC030000FC060000FC1C0000FC380000F
+C780000FDF80000FFFC0000FE7E0000FC3F0000F81F0000F81F8000F80FC000F807E000F803F00
+0F803F000F801F800F800FC0FFF83FF8FFF83FF81D267FA520>107 D<FFC0FFC00FC00FC00FC0
+0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00F
+C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFFCFFFC0E267EA511>I<FF80FE007F
+00FF83FF81FFC00F8E0FC707E00F980FCC07E00F9007E803F00FA007F003F00FA007F003F00FC0
+07E003F00FC007E003F00FC007E003F00FC007E003F00FC007E003F00FC007E003F00FC007E003
+F00FC007E003F00FC007E003F00FC007E003F00FC007E003F00FC007E003F00FC007E003F00FC0
+07E003F00FC007E003F0FFFC7FFE3FFFFFFC7FFE3FFF30187E9733>I<FF80FE00FF83FF800F8E
+0FC00F980FC00F9007E00FA007E00FA007E00FC007E00FC007E00FC007E00FC007E00FC007E00F
+C007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E0
+FFFC7FFEFFFC7FFE1F187E9722>I<007F800003FFF00007C0F8001F807E003F003F003F003F00
+7E001F807E001F80FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001FC0FE001F
+C07E001F807E001F803F003F003F003F001F807E000FC0FC0003FFF000007F80001A187E971F>
+I<FFC1FC00FFCFFF000FFC1FC00FF007E00FC007F00FC003F00FC003F80FC001F80FC001FC0FC0
+01FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC003F80FC003F80FC003F00F
+E007F00FF00FE00FDC1F800FCFFF000FC3F8000FC000000FC000000FC000000FC000000FC00000
+0FC000000FC000000FC000000FC00000FFFC0000FFFC00001E237F9722>I<007F00C003FFC1C0
+07E0E3C01FC033C01F801FC03F001FC07F000FC07F000FC0FE000FC0FE000FC0FE000FC0FE000F
+C0FE000FC0FE000FC0FE000FC0FE000FC07E000FC07F000FC03F000FC03F801FC01F803FC00FE0
+EFC003FF8FC000FE0FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000
+000FC000000FC00000FFFC0000FFFC1E237E9720>I<FF83E0FF8FF80F8C7C0F90FC0FB0FC0FA0
+FC0FA0780FE0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0
+000FC0000FC0000FC000FFFE00FFFE0016187F9719>I<07F8C01FFFC03C07C07001C0F000C0F0
+00C0F000C0FC0000FF80007FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E0
+01E0E001C0F003C0FC0780EFFF00C3FC0013187E9718>I<00C00000C00000C00000C00001C000
+01C00001C00003C00007C0000FC0001FC000FFFFC0FFFFC00FC0000FC0000FC0000FC0000FC000
+0FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0600FC0600FC0600FC0600FC0600FC060
+07E0C007E1C001FF80007E0013237FA218>I<FFC07FE0FFC07FE00FC007E00FC007E00FC007E0
+0FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007
+E00FC007E00FC007E00FC007E00FC00FE00FC00FE007C017E007E067E003FFC7FE007F07FE1F18
+7E9722>I<FFF80FF8FFF80FF80FC001C00FC0018007E0030007E0030007F0070003F0060003F8
+0E0001F80C0001FC0C0000FC180000FE1800007E3000007E3000003F6000003F6000003FE00000
+1FC000001FC000000F8000000F800000070000000700001D187F9720>I<FFF9FFE0FF80FFF9FF
+E0FF801FC03F001C000FC01F0018000FC01F80180007E01F80300007E01F80300007F03FC07000
+03F037C0600003F037E0600001F863E0C00001F863E0C00001FCE3F1C00000FCC1F1800000FCC1
+F98000007F80FB0000007F80FB0000007F80FF0000003F007E0000003F007E0000001E003C0000
+001E003C0000001E003C0000000C0018000029187F972C>I<FFF83FF0FFF83FF00FC00F0007E0
+0E0003F01C0003F8380001FC700000FC6000007EC000003F8000003F8000001F8000000FC00000
+1FE000001FF0000033F8000061F80000E0FC0001C07E0003807F0007003F800F001F80FFC07FF8
+FFC07FF81D187F9720>I<FFF80FF8FFF80FF80FC001C00FC0018007E0030007E0030007F00700
+03F0060003F80E0001F80C0001FC0C0000FC180000FE1800007E3000007E3000003F6000003F60
+00003FE000001FC000001FC000000F8000000F800000070000000700000006000000060000000C
+0000300C0000781C0000FC180000FC300000FC70000068E000007FC000001F0000001D237F9720
+>I E /Fj 1 59 df<70F8F8F87005057C840D>58 D E /Fk 34 122 df<000700000007000000
+070000000F8000000F8000001FC000001FC000001FC000003FE0000037E0000037E0000063F000
+0063F0000063F00000C1F80000C1F80000C1F8000180FC000180FC000180FC0003007E0003FFFE
+0007FFFF0006003F0006003F000E001F800C001F800C001F801C000FC0FF80FFF8FF80FFF81D1F
+7E9E22>65 D<FFFFF000FFFFFC000F807E000F803F000F803F000F803F800F803F800F801F800F
+803F800F803F800F803F800F803F000F807E000F80FE000FFFF8000FFFFE000F803F000F801F80
+0F800FC00F800FC00F800FE00F800FE00F800FE00F800FE00F800FE00F800FC00F801FC00F801F
+800F803F80FFFFFE00FFFFF8001B1F7E9E20>I<000FF010007FFC7001FC0EF003E003F00FC001
+F01F8000F01F8000F03F0000703F0000707E0000307E000030FE000030FE000000FE000000FE00
+0000FE000000FE000000FE000000FE000000FE0000007E0000307E0000303F0000303F0000701F
+8000601F8000E00FC000C003E0038001FC0F00007FFC00000FF0001C1F7E9E21>I<FFFFF000FF
+FFFE000FC07F000FC01F800FC007C00FC007E00FC003F00FC003F00FC001F80FC001F80FC001F8
+0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001FC0FC001
+F80FC001F80FC001F80FC003F00FC003F00FC003E00FC007E00FC00FC00FC03F00FFFFFE00FFFF
+F0001E1F7E9E23>I<FFFFFF00FFFFFF000FC01F000FC00F000FC007000FC003000FC003800FC0
+01800FC001800FC181800FC181800FC180000FC180000FC380000FFF80000FFF80000FC380000F
+C180000FC180000FC180C00FC180C00FC000C00FC001800FC001800FC001800FC003800FC00380
+0FC007800FC03F00FFFFFF00FFFFFF001A1F7E9E1E>I<FFFFFEFFFFFE0FC03E0FC00E0FC00E0F
+C0060FC0070FC0030FC0030FC1830FC1830FC1800FC1800FC3800FFF800FFF800FC3800FC1800F
+C1800FC1800FC1800FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC000FFFE00FFFE0018
+1F7E9E1D>I<FFFCFFFC0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00F
+C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFFCFFFC0E1F7E9E12>73
+D<FFC0000FFCFFE0001FFC0FE0001FC00FE0001FC00DF00037C00DF00037C00DF00037C00CF800
+67C00CF80067C00C7C00C7C00C7C00C7C00C7C00C7C00C3E0187C00C3E0187C00C3E0187C00C1F
+0307C00C1F0307C00C1F0307C00C0F8607C00C0F8607C00C07CC07C00C07CC07C00C07CC07C00C
+03F807C00C03F807C00C03F807C00C01F007C00C01F007C00C00E007C0FFC0E07FFCFFC0E07FFC
+261F7E9E2B>77 D<FFC007FEFFC007FE0FE000600FF000600DF800600DF800600CFC00600C7E00
+600C7E00600C3F00600C1F80600C0FC0600C0FC0600C07E0600C03F0600C03F8600C01F8600C00
+FC600C007E600C007E600C003F600C001FE00C000FE00C000FE00C0007E00C0003E00C0003E00C
+0001E00C0000E0FFC00060FFC000601F1F7E9E24>I<003FE00000FFF80003F07E0007C01F000F
+800F801F800FC03F0007E03F0007E07F0007F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8
+FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F87E0003F07E0003F07F0007F03F0007
+E03F0007E01F800FC00FC01F8007E03F0003F07E0000FFF800003FE0001D1F7E9E22>I<03F040
+0FFDC01C0FC03803C07001C07001C0F000C0F000C0F000C0F80000FC0000FF80007FF8003FFE00
+3FFF801FFFC007FFC000FFE0000FE00003F00001F00000F0C000F0C000F0C000F0E000E0E001E0
+F801C0FE0380EFFF0081FC00141F7E9E19>83 D<FFFC0FFCFFFC0FFC0FC000C00FC000C00FC000
+C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC0
+00C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C00FC000C007
+C0018007E0018003E0030001F0070000F81E00003FF800000FE0001E1F7E9E23>85
+D<FFF803FEFFF803FE0FC000700FC000600FC0006007E000C007E000C007F001C003F0018003F0
+018001F8030001F8030001FC070000FC060000FC0600007E0C00007E0C00007E0C00003F180000
+3F1800003FB800001FB000001FB000000FE000000FE000000FE0000007C0000007C0000007C000
+00038000000380001F1F7F9E22>I<7FFC3FF87FFC3FF807E0070007F0060003F00E0001F80C00
+01FC1C0000FC180000FE3000007E7000003F6000003FC000001FC000001FC000000FC0000007E0
+000007F000000FF000000FF8000019F8000038FC000030FE0000607E0000E07F0000C03F000180
+1F8003801FC003000FC007000FE0FFE07FFEFFE07FFE1F1F7F9E22>88 D<0FF0003FFC007E1E00
+7E1F007E0F807E0F80180F80000F8000FF800FFF801F0F807C0F807C0F80F80F80F80F80F80F80
+F817807C37803FE3F00F81F014147F9316>97 D<03F8000FFE001F3F003E3F007E3F007C3F007C
+0C00FC0000FC0000FC0000FC0000FC0000FC00007C00007C00007E01803E03801F87000FFE0003
+F80011147F9314>99 D<001FE0001FE00003E00003E00003E00003E00003E00003E00003E00003
+E00003E00003E003F3E00FFFE01F0FE03E03E07C03E07C03E07C03E0FC03E0FC03E0FC03E0FC03
+E0FC03E0FC03E0FC03E07C03E07C03E03E07E01F0FE00FFBFC03F3FC16207F9F19>I<03F8000F
+FE001F0F003E07803C07807C07C07C07C0FC07C0FFFFC0FFFFC0FC0000FC0000FC00007C00007C
+00003E00C03E00C01F038007FF0001FC0012147F9315>I<007F0001FF8007C7C00F8FC00F0FC0
+1F0FC01F07801F00001F00001F00001F00001F0000FFF000FFF0001F00001F00001F00001F0000
+1F00001F00001F00001F00001F00001F00001F00001F00001F00001F00001F00001F0000FFF000
+FFF00012207F9F0E>I<03F0E00FFDF01E1EF03C0FF07C0F807C0F807C0F807C0F807C0F803C0F
+001E1E001FFC0033F0003000003000003800003FFE003FFF801FFFC03FFFE07803F07000F0F000
+F0F000F0F000F0F000F07801E03E07C01FFF8003FC00141E7F9317>I<FF0000FF00001F00001F
+00001F00001F00001F00001F00001F00001F00001F00001F00001F1F001F3FC01F63C01F83E01F
+83E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F
+03E0FFE7FCFFE7FC16207E9F19>I<1C003E007F007F007F003E001C0000000000000000000000
+0000FF00FF001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F00FF
+E0FFE00B217FA00C>I<FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F00
+001F00001F00001F0FF01F0FF01F03801F06001F0C001F18001F30001F70001FF0001FF8001F7C
+001E3C001E1E001E1F001E0F001E0F801E07801E03C0FFCFF8FFCFF815207F9F18>107
+D<FF00FF001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F00
+1F001F001F001F001F001F001F001F001F001F001F00FFE0FFE00B207F9F0C>I<FE0F80F800FE
+3FC3FC001E63E63E001EC1FC1F001E81F81F001F01F01F001F01F01F001F01F01F001F01F01F00
+1F01F01F001F01F01F001F01F01F001F01F01F001F01F01F001F01F01F001F01F01F001F01F01F
+001F01F01F00FFE7FE7FE0FFE7FE7FE023147E9326>I<FE1F00FE3FC01E63C01E83E01E83E01F
+03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E0FF
+E7FCFFE7FC16147E9319>I<01F8000FFF001F0F803E07C07C03E07C03E07C03E0FC03F0FC03F0
+FC03F0FC03F0FC03F0FC03F0FC03F07C03E07C03E03E07C01F0F800FFF0003FC0014147F9317>
+I<FE3C00FE7F001EDF801E9F801F9F801F1F801F06001F00001F00001F00001F00001F00001F00
+001F00001F00001F00001F00001F0000FFF000FFF0001114809313>114
+D<0FD83FF87038E018E018E018F800FF807FF03FF81FFC03FE003EC00EC00EE00EE00CF81CFFF8
+C7E00F147F9312>I<0300030003000300070007000F000F003F00FFF8FFF81F001F001F001F00
+1F001F001F001F001F001F001F0C1F0C1F0C1F0C1F0C0F9807F003E00E1D7F9C12>I<FF1FE0FF
+1FE01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F03E01F
+03E01F03E01F07E00F0FE007FBFC03F3FC16147E9319>I<FFCFF1FCFFCFF1FC1F03C0701F03C0
+601F07E0600F87E0C00F87E0C00F8CF0C007CCF18007CCF18007D8798003F87B0003F87B0003F8
+7F0003F03F0001F03E0001F03E0001E01E0000E01C0000C00C001E147F9321>119
+D<FFCFF0FFCFF01F03800F830007860007CE0003FC0001F80001F00000F80000780000FC0001FE
+00039E00031F00060F800E07800C07C0FF1FF8FF1FF815147F9318>I<FFC3F8FFC3F81F00C01F
+00C00F81800F81800F818007C30007C30007E70003E60003E60001FC0001FC0001FC0000F80000
+F80000F80000700000700000600000600078E000FCC000FCC000C18000E380007F00003C000015
+1D7F9318>I E /Fl 92 126 df<70F8F8F8F8F8F8F8F8F8F8F8F8F8F8F8F870000000000070F8
+F8F870051C779B18>33 D<4010E038F078E038E038E038E038E038E038E038E038E038E0386030
+0D0E7B9C18>I<030600078F00078F00078F00078F00078F00078F007FFFC0FFFFE0FFFFE07FFF
+C00F1E000F1E000F1E000F1E000F1E000F1E007FFFC0FFFFE0FFFFE07FFFC01E3C001E3C001E3C
+001E3C001E3C001E3C000C1800131C7E9B18>I<00C00001C00001C00001C00003F0000FFC003F
+FE007DCF0071C700E1C380E1C780E1C780E1C780F1C00079C0003FC0001FE0000FF80001FC0001
+DE0001CF0001C70061C380F1C380F1C380E1C380E1C70071C70079DE003FFE001FF80007E00001
+C00001C00001C00000C00011247D9F18>I<3803007C07807C0780EE0F80EE0F00EE0F00EE1F00
+EE1E00EE1E00EE3E007C3C007C3C00387C0000780000780000F80000F00001F00001E00001E000
+03E00003C00003C00007C0000783800787C00F87C00F0EE00F0EE01F0EE01E0EE01E0EE03E0EE0
+3C07C03C07C018038013247E9F18>I<01C00007E0000FF0000E70001C38001C38001C38001C38
+001C73F81CF3F81CE3F80FC1C00FC3800F83800F03801F07003F87007B8E0071CE00E1FC00E0FC
+00E07C00E07870E0787070FE707FFFE03FC7E00F03C0151C7F9B18>I<387C7C7E3E0E0E0E1C1C
+38F8F0C0070E789B18>I<007000F001E003C007800F001E001C00380038007000700070007000
+E000E000E000E000E000E000E000E0007000700070007000380038001C001E000F00078003C001
+F000F000700C24799F18>I<6000F00078003C001E000F000780038001C001C000E000E000E000
+E00070007000700070007000700070007000E000E000E000E001C001C0038007800F001E003C00
+7800F00060000C247C9F18>I<01C00001C00001C00001C00041C100F1C780FDDF807FFF001FFC
+0007F00007F0001FFC007FFF00FDDF80F1C78041C10001C00001C00001C00001C00011147D9718
+>I<00600000F00000F00000F00000F00000F00000F00000F0007FFFC0FFFFE0FFFFE07FFFC000
+F00000F00000F00000F00000F00000F00000F00000600013147E9718>I<1C3E7E7F3F1F070E1E
+7CF860080C788518>I<7FFFC0FFFFE0FFFFE07FFFC013047E8F18>I<3078FCFC78300606778518
+>I<000300000780000780000F80000F00001F00001E00001E00003E00003C00007C0000780000
+780000F80000F00001F00001E00003E00003C00003C00007C0000780000F80000F00000F00001F
+00001E00003E00003C00003C00007C0000780000F80000F00000F0000060000011247D9F18>I<
+01F00007FC000FFE001F1F001C07003803807803C07001C07001C0E000E0E000E0E000E0E000E0
+E000E0E000E0E000E0E000E0E000E0F001E07001C07001C07803C03803801C07001F1F000FFE00
+07FC0001F000131C7E9B18>I<01800380038007800F803F80FF80FB8043800380038003800380
+0380038003800380038003800380038003800380038003807FFCFFFE7FFC0F1C7B9B18>I<03F0
+000FFE003FFF007C0F807003C0E001C0F000E0F000E06000E00000E00000E00001C00001C00003
+C0000780000F00001E00003C0000780000F00001E00007C0000F80001E00E03C00E07FFFE0FFFF
+E07FFFE0131C7E9B18>I<07F8001FFE003FFF007807807803C07801C03001C00001C000038000
+0380000F0003FF0003FE0003FF000007800003C00001C00000E00000E00000E0F000E0F000E0F0
+01C0F003C07C07803FFF001FFE0003F800131C7E9B18>I<001F00003F0000770000770000E700
+01E70001C7000387000787000707000E07001E07003C0700380700780700F00700FFFFF8FFFFF8
+FFFFF8000700000700000700000700000700000700007FF0007FF0007FF0151C7F9B18>I<3FFF
+803FFF803FFF803800003800003800003800003800003800003800003800003BF8003FFE003FFF
+003C07803003C00001C00000E00000E06000E0F000E0F000E0E001C07003C07C0F803FFF001FFC
+0003F000131C7E9B18>I<007E0001FF0007FF800F83C01E03C01C03C038018038000070000070
+0000E1F800E7FE00FFFF00FE0780F803C0F001C0F000E0E000E0F000E07000E07000E07000E038
+01C03C03C01E07800FFF0007FE0001F800131C7E9B18>I<E00000FFFFE0FFFFE0FFFFC0E00380
+E00700000F00001E00001C0000380000380000700000F00000E00000E00001C00001C00001C000
+038000038000038000038000070000070000070000070000070000070000070000131D7E9C18>
+I<03F8000FFE001FFF003E0F803803807001C07001C07001C07001C03803803C07801FFF0007FC
+000FFE001F1F003C07807001C0F001E0E000E0E000E0E000E0E000E07001C07803C03E0F801FFF
+000FFE0003F800131C7E9B18>I<03F0000FFC001FFE003C0F00780780700380E001C0E001C0E0
+01C0E001E0E001E07001E07803E03C0FE01FFFE00FFEE003F0E00000E00001C00001C00001C030
+0380780780780F00783E003FFC001FF00007C000131C7E9B18>I<3078FCFC7830000000000000
+00003078FCFC78300614779318>I<183C7E7E3C180000000000000000183C7E7E3E1E0E1C3C78
+F060071A789318>I<0000C00003E00007E0001FC0003F8000FE0001FC0007F0000FE0003F8000
+7F0000FC0000FC00007F00003F80000FE00007F00001FC0000FE00003F80001FC00007E00003E0
+0000C013187E9918>I<7FFFC0FFFFE0FFFFE0FFFFE0000000000000000000000000FFFFE0FFFF
+E0FFFFE07FFFC0130C7E9318>I<600000F80000FC00007F00003F80000FE00007F00001FC0000
+FE00003F80001FC00007E00007E0001FC0003F8000FE0001FC0007F0000FE0003F80007F0000FC
+0000F8000060000013187E9918>I<007C0001FE0007FF000F87801E03C03C1DC0387FC070FFE0
+71E3E071C1E0E1C1E0E380E0E380E0E380E0E380E0E380E0E380E0E1C1C071C1C071E3C070FF80
+387F003C1C001E00E00F83E007FFC001FF80007E00131C7E9B18>64 D<00700000F80000F80000
+D80000D80001DC0001DC0001DC00018C00038E00038E00038E00038E0007070007070007070007
+07000707000FFF800FFF800FFF800E03801C01C01C01C01C01C07F07F0FF07F87F07F0151C7F9B
+18>I<7FFC00FFFF007FFF801C03C01C01C01C00E01C00E01C00E01C00E01C01E01C01C01C07C0
+1FFF801FFF001FFFC01C03C01C00E01C00F01C00701C00701C00701C00701C00F01C00E01C03E0
+7FFFC0FFFF807FFE00141C7F9B18>I<00F8E003FEE007FFE00F07E01E03E03C01E03800E07000
+E07000E0700000E00000E00000E00000E00000E00000E00000E00000E000007000007000E07000
+E03800E03C00E01E01C00F07C007FF8003FE0000F800131C7E9B18>I<7FF800FFFE007FFF001C
+0F801C03C01C03C01C01E01C00E01C00E01C00F01C00701C00701C00701C00701C00701C00701C
+00701C00701C00F01C00E01C00E01C01E01C01C01C03C01C0F807FFF00FFFE007FF800141C7F9B
+18>I<FFFFF0FFFFF0FFFFF01C00701C00701C00701C00701C00001C00001C0E001C0E001C0E00
+1FFE001FFE001FFE001C0E001C0E001C0E001C00001C00001C00381C00381C00381C00381C0038
+FFFFF8FFFFF8FFFFF8151C7F9B18>I<FFFFF8FFFFF8FFFFF81C00381C00381C00381C00381C00
+001C00001C07001C07001C07001FFF001FFF001FFF001C07001C07001C07001C00001C00001C00
+001C00001C00001C00001C0000FFC000FFC000FFC000151C7F9B18>I<01F1C003FDC00FFFC01F
+0FC01C03C03803C03801C07001C07001C0700000E00000E00000E00000E00000E00000E00FF0E0
+1FF0E00FF07001C07001C07003C03803C03803C01C07C01F0FC00FFFC003FDC001F1C0141C7E9B
+18>I<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C0
+1FFFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C0
+7F07F0FF8FF87F07F0151C7F9B18>I<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0
+0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0
+0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<01FFC001FFC001FFC000
+0E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0000
+0E00000E00000E00000E00000E00000E00F00E00F00E00F03C007FFC003FF0000FC000121C7D9B
+18>I<7F07F0FF87F87F07F01C03C01C07801C07001C0E001C1E001C3C001C38001C70001CF000
+1DF0001DF0001FB8001FB8001F1C001E1C001C0E001C0E001C07001C07001C03801C03801C01C0
+7F03F0FF87F87F03F0151C7F9B18>I<FFC000FFC000FFC0001C00001C00001C00001C00001C00
+001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00
+E01C00E01C00E01C00E01C00E0FFFFE0FFFFE0FFFFE0131C7E9B18>I<FC01F8FE03F8FE03F83B
+06E03B06E03B06E03B06E03B8EE03B8EE0398CE0398CE039DCE039DCE039DCE038D8E038D8E038
+F8E03870E03870E03800E03800E03800E03800E03800E03800E0FE03F8FE03F8FE03F8151C7F9B
+18>I<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1C0
+1C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0DC0
+7F07C0FF87C07F03C0151C7F9B18>I<0FFE003FFF807FFFC07803C07001C0F001E0E000E0E000
+E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000
+E0E000E0F001E07001C07C07C07FFFC03FFF800FFE00131C7E9B18>I<FFFE00FFFF80FFFFC01C
+03C01C01E01C00E01C00701C00701C00701C00701C00701C00E01C01E01C03C01FFFC01FFF801F
+FE001C00001C00001C00001C00001C00001C00001C00001C0000FF8000FF8000FF8000141C7F9B
+18>I<0FFE003FFF807FFFC07803C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0
+E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E070E0E070E0F079E07039C0783FC0
+7FFFC03FFF800FFE00000F000007800007800003C00001C00001C013227E9B18>I<7FF800FFFE
+007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C0F801FFF001FFE001FFE
+001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C039C7F01F8FF81F87F00
+F0161C7F9B18>I<03F1C01FFFC03FFFC07C0FC07003C0E001C0E001C0E001C0E0000070000078
+00003F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E001E0F0
+01C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FFFFF8E07038E07038E07038
+E07038007000007000007000007000007000007000007000007000007000007000007000007000
+00700000700000700000700000700000700007FF0007FF0007FF00151C7F9B18>I<FF83FEFF83
+FEFF83FE1C00701C00701C00701C00701C00701C00701C00701C00701C00701C00701C00701C00
+701C00701C00701C00701C00701C00701C00701C00700E00E00F01E00783C003FF8001FF00007C
+00171C809B18>I<FE03F8FF07F8FE03F83C01E01C01C01C01C01C01C01E03C00E03800E03800E
+03800E0380070700070700070700070700038E00038E00038E00038E00018C0001DC0001DC0001
+DC0000D80000F80000F800007000151C7F9B18>I<FE03F8FE03F8FE03F8700070700070700070
+3800E03800E03800E03800E03800E038F8E039FCE039DCE039DCE019DCC019DCC019DCC0198CC0
+198CC01D8DC01D8DC01D8DC01D05C00D05800F07800F07800E0380151C7F9B18>I<7F0FE07F9F
+E07F0FE00E07000F0700070E00078E00039C0003DC0001F80001F80000F80000F00000700000F0
+0000F80001FC0001DC00039E00038E00070F000707000E07800E03801E03C07F07F0FF07F87F07
+F0151C7F9B18>I<FE03F8FF07F8FE03F81C01C01E03C00E03800F0780070700070700038E0003
+8E0001DC0001DC0001DC0000F80000F80000700000700000700000700000700000700000700000
+700000700001FC0003FE0001FC00151C7F9B18>I<3FFFE07FFFE07FFFE07001C07003C0700780
+700700000F00001E00001C00003C0000780000700000F00001E00001C00003C000078000070000
+0F00001E00E01C00E03C00E07800E07000E0FFFFE0FFFFE0FFFFE0131C7E9B18>I<FFF8FFF8FF
+F8E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000
+E000E000E000E000E000E000E000E000E000E000E000FFF8FFF8FFF80D24779F18>I<600000F0
+0000F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F00000F800007
+800007C00003C00003C00003E00001E00001F00000F00000F800007800007800007C00003C0000
+3E00001E00001E00001F00000F00000F8000078000078000030011247D9F18>I<FFF8FFF8FFF8
+003800380038003800380038003800380038003800380038003800380038003800380038003800
+380038003800380038003800380038003800380038FFF8FFF8FFF80D247F9F18>I<018007C01F
+F07EFCF83EE00E0F067C9B18>I<7FFFC0FFFFE0FFFFE07FFFC013047E7F18>I<061E3E387070E0
+E0E0F8FC7C7C38070E789E18>I<0FF0001FFC003FFE003C0F0018070000038000038000FF8007
+FF801FFF807F0380780380E00380E00380E00380F00780780F803FFFF81FFDF807F0F815147E93
+18>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF800FFFC00FC1E0
+0F80E00F00700E00700E00380E00380E00380E00380E00380E00380F00700F00700F80E00FC1E0
+0FFFC00EFF80063E00151C809B18>I<01FE0007FF001FFF803E0780380300700000700000E000
+00E00000E00000E00000E00000E000007000007001C03801C03E03C01FFF8007FF0001FC001214
+7D9318>I<001F80003F80001F8000038000038000038000038000038003E3800FFB801FFF803C
+1F80380F80700780700380E00380E00380E00380E00380E00380E00380700780700780380F803C
+1F801FFFF00FFBF803E3F0151C7E9B18>I<01F00007FC001FFE003E0F00380780700380700380
+E001C0E001C0FFFFC0FFFFC0FFFFC0E000007000007001C03801C03E07C01FFF8007FF0001F800
+12147D9318>I<001F80007FC000FFE000E1E001C0C001C00001C00001C0007FFFC0FFFFC0FFFF
+C001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0
+0001C0007FFF007FFF007FFF00131C7F9B18>I<01E1F007FFF80FFFF81E1E301C0E0038070038
+07003807003807003807001C0E001E1E001FFC001FF80039E0003800001C00001FFE001FFFC03F
+FFE07801F0700070E00038E00038E00038E000387800F07E03F01FFFC00FFF8001FC00151F7F93
+18>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF800FFFC00FC1C0
+0F80E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E0
+7FC7FCFFE7FE7FC7FC171C809B18>I<038007C007C007C0038000000000000000007FC0FFC07F
+C001C001C001C001C001C001C001C001C001C001C001C001C001C001C0FFFFFFFFFFFF101D7C9C
+18>I<0038007C007C007C003800000000000000000FFC0FFC0FFC001C001C001C001C001C001C
+001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C6038F078FFF07F
+E03F800E277E9C18>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3FF00E3F
+F00E3FF00E07800E0F000E1E000E3C000E78000EF0000FF8000FFC000F9C000F0E000E0F000E07
+000E03800E03C07FC7F8FFC7F87FC7F8151C7F9B18>I<FFC000FFC000FFC00001C00001C00001
+C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001
+C00001C00001C00001C00001C00001C00001C000FFFF80FFFF80FFFF80111C7D9B18>I<F9C1C0
+FFF7F0FFFFF03E3E383C3C383C3C38383838383838383838383838383838383838383838383838
+383838383838383838FE3E3EFE7E7EFE3E3E1714809318>I<7E3E00FEFF807FFFC00FC1C00F80
+E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E07FC7
+FCFFE7FE7FC7FC1714809318>I<01F0000FFE001FFF003E0F803803807001C07001C0E000E0E0
+00E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE0001F00013147E93
+18>I<7E3E00FEFF807FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E0038
+0E00380F00700F00700F80E00FC1E00FFFC00EFF800E3E000E00000E00000E00000E00000E0000
+0E00000E00007FC000FFE0007FC000151E809318>I<01F38007FB801FFF803E1F80380F807007
+80700780E00380E00380E00380E00380E00380E00380700780700780380F803C1F801FFF800FFB
+8003E380000380000380000380000380000380000380000380001FF0003FF8001FF0151E7E9318
+>I<FF0FC0FF3FE0FF7FF007F0F007E06007C00007800007800007000007000007000007000007
+0000070000070000070000070000FFFC00FFFE00FFFC0014147E9318>I<07F7003FFF007FFF00
+780F00E00700E00700E007007C00007FE0001FFC0003FE00001F00600780E00380E00380F00380
+F80F00FFFF00FFFC00E7F00011147D9318>I<0180000380000380000380000380007FFFC0FFFF
+C0FFFFC00380000380000380000380000380000380000380000380000380000380400380E00380
+E00380E001C1C001FFC000FF80003E0013197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E
+00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E01E00F03E007FFFC03
+FFFE01FCFC1714809318>I<7F8FF0FF8FF87F8FF01C01C00E03800E03800E0380070700070700
+070700078F00038E00038E00038E0001DC0001DC0001DC0000F80000F80000700015147F9318>
+I<FF07F8FF8FF8FF07F83800E03800E03800E03800E01C01C01C71C01CF9C01CF9C01CD9C01DDD
+C00DDD800DDD800DDD800D8D800F8F800F8F8007070015147F9318>I<7F8FF07F9FF07F8FF00F
+0700078E00039E0001DC0001F80000F80000700000F00000F80001DC00039E00038E000707000E
+07807F8FF0FF8FF87F8FF015147F9318>I<7F8FF0FF8FF87F8FF00E01C00E03800E0380070380
+070700070700038700038700038E0001CE0001CE0001CC0000CC0000DC00007800007800007800
+00700000700000700000F00000E00079E0007BC0007F80003F00001E0000151E7F9318>I<3FFF
+F07FFFF07FFFF07001E07003C0700780000F00001E00003C0000F80001F00003C0000780000F00
+701E00703C0070780070FFFFF0FFFFF0FFFFF014147F9318>I<0007E0001FE0007FE000780000
+E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00001E0007FC000FF
+8000FF80007FC00001E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000
+E00000E000007800007FE0001FE00007E013247E9F18>I<60F0F0F0F0F0F0F0F0F0F0F0F0F0F0
+F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0600424769F18>I<7C0000FF0000FFC00003C0
+0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000F000007F
+C0003FE0003FE0007FC000F00000E00000E00000E00000E00000E00000E00000E00000E00000E0
+0000E00000E00003C000FFC000FF00007C000013247E9F18>I E /Fm 46
+122 df<00003F000000000000FF800000000003E0C00000000007C060000000000F8070000000
+001F8030000000003F0038000000003F0038000000003F0038000000007F0038000000007F0038
+000000007F0070000000007F0060000000007F80E0000000007F80C0000000007F818000000000
+7F8300000000003F8600000000003FCC0000FFFE003FD80000FFFE003FF00000FFFE001FE00000
+0780001FE000000700001FF000000E00000FF000001C00000FF800001C00000FF800003800001F
+FC000038000033FE000070000063FE0000E00001C1FF0000E00003C1FF8001C00007C0FF800380
+000F807FC00700001F807FE00700003F803FF00E00007F801FF81C00007F800FFC380000FF8007
+FC700000FF8003FEE00000FF8001FFC00000FFC000FF800000FFC0007FC0000E7FC0003FF0000E
+7FE0007FF8001C3FF001F7FE003C1FF80FE1FF81F807FFFF807FFFF001FFFE001FFFC0003FE000
+01FE0037327DB13F>38 D<FFFFF8FFFFF8FFFFF8FFFFF8FFFFF8FFFFF8FFFFF815077F921B>45
+D<0001C0000003C000000FC000007FC0001FFFC000FFFFC000FFBFC000E03FC000003FC000003F
+C000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00000
+3FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000
+003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC0
+00003FC000003FC000003FC000003FC0007FFFFFF07FFFFFF07FFFFFF01C2E7AAD28>49
+D<003FE00001FFFE0007FFFF800F80FFC01E003FE038001FF07C000FF87E0007FCFF0007FCFF80
+07FEFF8007FEFF8003FEFF8003FE7F0003FE3E0007FE000007FE000007FC000007FC00000FF800
+000FF800000FF000001FE000001FC000003F8000007F0000007E000000F8000001F0000003E000
+0007C000000F0000001E000E003C000E0038000E0070001E00E0001C01C0001C0300003C07FFFF
+FC0FFFFFFC1FFFFFFC3FFFFFFC7FFFFFF8FFFFFFF8FFFFFFF8FFFFFFF81F2E7CAD28>I<001FF8
+000000FFFF000003FFFFC00007E01FF0000F0007F8001F8007FC003FC007FC003FC003FE003FC0
+03FE003FC003FE003FC003FE001F8003FE000F0007FE00000007FC00000007FC00000007F80000
+000FF00000001FE00000003F80000000FF0000003FF80000003FFF800000001FE00000000FF000
+000007F800000003FC00000003FE00000001FF00000001FF00000001FF80000001FF80000001FF
+801C0001FF803E0001FF807F0001FF80FF8001FF80FF8001FF00FF8001FF00FF8003FE007F0003
+FE007E0007FC003C0007F8001FC01FF0000FFFFFC00003FFFF0000003FF80000212E7DAD28>I<
+0000007000000000F000000001F000000003F000000007F00000000FF00000000FF00000001FF0
+0000003FF000000077F0000000F7F0000000E7F0000001C7F000000387F000000707F000000F07
+F000000E07F000001C07F000003807F000007007F00000F007F00000E007F00001C007F0000380
+07F000070007F0000F0007F0000E0007F0001C0007F000380007F000700007F000E00007F000FF
+FFFFFFE0FFFFFFFFE0FFFFFFFFE000000FF00000000FF00000000FF00000000FF00000000FF000
+00000FF00000000FF00000000FF00000000FF000000FFFFFE0000FFFFFE0000FFFFFE0232E7EAD
+28>I<0C0000300FC007F00FFFFFE00FFFFFC00FFFFF800FFFFF000FFFFE000FFFF8000FFFF000
+0FFF80000E0000000E0000000E0000000E0000000E0000000E0000000E0000000E0000000E1FF0
+000EFFFE000FE03F800F000FC00E0007E00C0007F0000007F8000003F8000003FC000003FC0000
+03FE000003FE180003FE3E0003FE7F0003FEFF0003FEFF0003FEFF0003FCFF0003FCFE0003FC78
+0007F8780007F03C000FE01E001FC00FC07F8007FFFF0001FFFC00003FE0001F2E7CAD28>I<00
+00FF00000007FFE000001FFFF000007F80F80000FE003C0001F8007C0003F000FE0007F001FE00
+0FE001FE000FE001FE001FC001FE003FC000FC003FC00078003FC00000007F800000007F800000
+007F80000000FF83FC0000FF8FFF8000FF9C0FC000FFB003F000FFB001F800FFE001FC00FFC001
+FE00FFC000FE00FFC000FF00FFC000FF00FF8000FF80FF8000FF80FF8000FF80FF8000FF807F80
+00FF807F8000FF807F8000FF807F8000FF803F8000FF003FC000FF001FC000FF001FC000FE000F
+C001FC0007E001FC0003F003F80001FC0FE00000FFFFC000003FFF0000000FFC0000212E7DAD28
+>I<38000000003E000000003FFFFFFFC03FFFFFFFC03FFFFFFFC03FFFFFFF807FFFFFFF007FFF
+FFFE007FFFFFFC007FFFFFF80078000038007000007000700000E000F00001C000E000038000E0
+00070000E00007000000000E000000001C00000000380000000078000000007000000000F00000
+0001E000000001E000000003E000000003C000000007C000000007C00000000FC00000000FC000
+00001FC00000001F800000001F800000003F800000003F800000003F800000003F800000007F80
+0000007F800000007F800000007F800000007F800000007F800000007F800000007F800000003F
+000000001E00000022307CAF28>I<000FFC0000007FFF800001FFFFE00003F00FF00007C003F8
+000F8000FC001F0000FC001F00007E003F00007E003F00007E003F00007E003F80007E003FC000
+7E003FF000FC003FFC00F8001FFE01F8001FFF81F0000FFFE3C00007FFFF800003FFFE000001FF
+FF000000FFFFC000003FFFE00000FFFFF00003E3FFF80007C1FFFC000F807FFE001F001FFF003E
+000FFF007E0003FF807E0000FF80FC00007F80FC00003F80FC00001F80FC00001F80FC00001F80
+FC00001F00FE00001F007E00001F007E00003E003F00007C001FC000F8000FF007F00003FFFFE0
+0000FFFF8000001FF80000212E7DAD28>I<000FF80000007FFF000001FFFF800003F80FC00007
+E007E0000FC003F0001FC001F8003FC001FC007F8001FC007F8001FE007F8000FE00FF8000FF00
+FF8000FF00FF8000FF00FF8000FF00FF8000FF80FF8000FF80FF8000FF80FF8000FF807F8001FF
+807F8001FF803F8001FF803FC001FF801FC003FF800FC006FF8007E006FF8001F81CFF8000FFF8
+FF80001FE0FF80000000FF00000000FF00000000FF00000000FF000F0001FE001F8001FE003FC0
+01FC003FC001FC003FC003F8003FC003F0003F8007E0001F000FC0001E001F80000F807F000007
+FFFE000001FFF80000007FC00000212E7DAD28>I<0000007800000000000078000000000000FC
+000000000000FC000000000000FC000000000001FE000000000001FE000000000003FF00000000
+0003FF000000000007FF800000000007FF800000000007FF80000000000FFFC0000000000E7FC0
+000000001E7FE0000000001C3FE0000000001C3FE000000000383FF000000000381FF000000000
+781FF800000000700FF800000000700FF800000000E00FFC00000000E007FC00000001E007FE00
+000001C003FE00000001C003FE000000038001FF000000038001FF000000078001FF8000000700
+00FF8000000F0000FFC000000FFFFFFFC000000FFFFFFFC000001FFFFFFFE000001C00003FE000
+003C00003FF000003800001FF000003800001FF000007000001FF800007000000FF80000F00000
+0FFC0000E0000007FC0000E0000007FC0001C0000007FE0003E0000003FE00FFFF0001FFFFFCFF
+FF0001FFFFFCFFFF0001FFFFFC36317DB03D>65 D<000003FF80018000003FFFF003800001FFFF
+FC07800007FF003F0F80001FF800079F80003FC00001FF8000FF800000FF8001FE0000007F8003
+FC0000003F8007FC0000001F8007F80000000F800FF00000000F801FF000000007801FF0000000
+07803FE000000007803FE000000003807FE000000003807FE000000003807FC000000000007FC0
+0000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC000000000
+00FFC00000000000FFC00000000000FFC00000000000FFC000000000007FC000000000007FC000
+000000007FE000000000007FE000000003803FE000000003803FE000000003801FF00000000380
+1FF000000007800FF0000000070007F8000000070007FC0000000E0003FC0000001E0001FE0000
+001C0000FF8000007800003FC00000F000001FF80003E0000007FF003F80000001FFFFFE000000
+003FFFF80000000003FF80000031317CB03A>67 D<FFFFFFFFF00000FFFFFFFFFF0000FFFFFFFF
+FFC00000FF8000FFF00000FF80000FF80000FF800003FE0000FF800001FF0000FF800000FF8000
+FF8000007FC000FF8000003FC000FF8000001FE000FF8000001FF000FF8000000FF000FF800000
+0FF800FF8000000FF800FF80000007FC00FF80000007FC00FF80000007FC00FF80000007FC00FF
+80000007FE00FF80000007FE00FF80000007FE00FF80000007FE00FF80000007FE00FF80000007
+FE00FF80000007FE00FF80000007FE00FF80000007FE00FF80000007FE00FF80000007FE00FF80
+000007FC00FF80000007FC00FF80000007FC00FF80000007FC00FF8000000FF800FF8000000FF8
+00FF8000000FF000FF8000001FF000FF8000001FE000FF8000003FE000FF8000007FC000FF8000
+007F8000FF800001FF0000FF800003FE0000FF80000FFC0000FF80007FF000FFFFFFFFFFC000FF
+FFFFFFFF0000FFFFFFFFF0000037317EB03E>I<FFFFFFFFFFF0FFFFFFFFFFF0FFFFFFFFFFF000
+FF80003FF000FF800007F800FF800003F800FF800000F800FF800000F800FF8000007800FF8000
+007800FF8000003800FF8000003800FF8000003800FF8000001C00FF8007001C00FF8007001C00
+FF8007001C00FF8007000000FF8007000000FF800F000000FF801F000000FF803F000000FFFFFF
+000000FFFFFF000000FFFFFF000000FF803F000000FF801F000000FF800F000000FF8007000000
+FF8007000000FF8007000700FF8007000700FF8007000700FF8000000E00FF8000000E00FF8000
+000E00FF8000000E00FF8000001E00FF8000001E00FF8000003C00FF8000003C00FF8000007C00
+FF800000FC00FF800001FC00FF800007FC00FF80003FFCFFFFFFFFFFF8FFFFFFFFFFF8FFFFFFFF
+FFF830317EB035>I<FFFFFFFFFFE0FFFFFFFFFFE0FFFFFFFFFFE000FF80007FE000FF80000FF0
+00FF800003F000FF800001F000FF800001F000FF800000F000FF800000F000FF8000007000FF80
+00007000FF8000007000FF8000003800FF8000003800FF8007003800FF8007003800FF80070000
+00FF8007000000FF8007000000FF800F000000FF801F000000FF803F000000FFFFFF000000FFFF
+FF000000FFFFFF000000FF803F000000FF801F000000FF800F000000FF8007000000FF80070000
+00FF8007000000FF8007000000FF8007000000FF8000000000FF8000000000FF8000000000FF80
+00000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80000000
+00FF8000000000FF80000000FFFFFFC00000FFFFFFC00000FFFFFFC000002D317EB033>I<FFFF
+FF80FFFFFF80FFFFFF8000FF800000FF800000FF800000FF800000FF800000FF800000FF800000
+FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF8000
+00FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF80
+0000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF
+800000FF800000FF800000FF800000FF800000FF800000FF8000FFFFFF80FFFFFF80FFFFFF8019
+317EB01E>73 D<FFFFFF800000FFFFFF800000FFFFFF80000001FF0000000001FF0000000001FF
+0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF000000
+0001FF0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF
+0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF000000
+0001FF0000000001FF0000000001FF0000000001FF0000000001FF0000000001FF0000038001FF
+0000038001FF0000038001FF0000038001FF0000078001FF0000070001FF0000070001FF00000F
+0001FF00000F0001FF00000F0001FF00001F0001FF00003F0001FF00007F0001FF0000FF0001FF
+0001FE0001FF000FFE00FFFFFFFFFE00FFFFFFFFFE00FFFFFFFFFE0029317DB030>76
+D<FFFFC000000003FFFFFFFFC000000003FFFFFFFFE000000007FFFF00FFE000000007FF0000EF
+F00000000EFF0000EFF00000000EFF0000EFF00000000EFF0000E7F80000001CFF0000E7F80000
+001CFF0000E3FC00000038FF0000E3FC00000038FF0000E1FE00000070FF0000E1FE00000070FF
+0000E0FF000000E0FF0000E0FF000000E0FF0000E07F800001C0FF0000E07F800001C0FF0000E0
+3FC0000380FF0000E03FC0000380FF0000E03FC0000380FF0000E01FE0000700FF0000E01FE000
+0700FF0000E00FF0000E00FF0000E00FF0000E00FF0000E007F8001C00FF0000E007F8001C00FF
+0000E003FC003800FF0000E003FC003800FF0000E001FE007000FF0000E001FE007000FF0000E0
+00FF00E000FF0000E000FF00E000FF0000E000FF00E000FF0000E0007F81C000FF0000E0007F81
+C000FF0000E0003FC38000FF0000E0003FC38000FF0000E0001FE70000FF0000E0001FE70000FF
+0000E0000FFE0000FF0000E0000FFE0000FF0000E00007FC0000FF0000E00007FC0000FF0000E0
+0007FC0000FF0000E00003F80000FF0001F00003F80000FF00FFFFE001F000FFFFFFFFFFE001F0
+00FFFFFFFFFFE000E000FFFFFF48317EB04D>I<00000FFF0000000000FFFFF000000007FC03FE
+0000001FE0007F8000003F80001FC000007F00000FE00001FE000007F80003FC000003FC0007F8
+000001FE0007F8000001FE000FF0000000FF001FF0000000FF801FE00000007F803FE00000007F
+C03FE00000007FC03FE00000007FC07FC00000003FE07FC00000003FE07FC00000003FE0FFC000
+00003FF0FFC00000003FF0FFC00000003FF0FFC00000003FF0FFC00000003FF0FFC00000003FF0
+FFC00000003FF0FFC00000003FF0FFC00000003FF0FFC00000003FF0FFC00000003FF07FC00000
+003FE07FE00000007FE07FE00000007FE07FE00000007FE03FE00000007FC03FE00000007FC01F
+F0000000FF801FF0000000FF800FF8000001FF0007F8000001FE0007FC000003FE0003FC000003
+FC0001FE000007F80000FF00000FF000003FC0003FC000001FE0007F80000007FC03FE00000000
+FFFFF0000000000FFF00000034317CB03D>79 D<FFFFFFFFE000FFFFFFFFFE00FFFFFFFFFF8000
+FF8000FFE000FF80003FF000FF80000FF800FF800007FC00FF800007FC00FF800003FE00FF8000
+03FE00FF800003FF00FF800003FF00FF800003FF00FF800003FF00FF800003FF00FF800003FF00
+FF800003FF00FF800003FE00FF800003FE00FF800007FC00FF800007F800FF80000FF800FF8000
+3FE000FF8000FFC000FFFFFFFF0000FFFFFFF80000FF8000000000FF8000000000FF8000000000
+FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000
+000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000
+FF8000000000FF8000000000FF8000000000FF80000000FFFFFF800000FFFFFF800000FFFFFF80
+000030317EB037>I<FFFFFFFF80000000FFFFFFFFF8000000FFFFFFFFFE00000000FF8003FF80
+000000FF80007FE0000000FF80001FF0000000FF80000FF8000000FF80000FF8000000FF80000F
+FC000000FF800007FC000000FF800007FE000000FF800007FE000000FF800007FE000000FF8000
+07FE000000FF800007FE000000FF800007FE000000FF800007FC000000FF80000FFC000000FF80
+000FF8000000FF80001FF0000000FF80003FE0000000FF80007FC0000000FF8003FF00000000FF
+FFFFF800000000FFFFFFE000000000FF8007F800000000FF8001FC00000000FF8000FE00000000
+FF80007F00000000FF80007F80000000FF80003FC0000000FF80003FC0000000FF80003FE00000
+00FF80003FE0000000FF80003FE0000000FF80003FE0000000FF80003FE0000000FF80003FF000
+0000FF80003FF0000000FF80003FF0000000FF80003FF0000000FF80003FF0038000FF80003FF8
+038000FF80001FF8038000FF80001FF8030000FF80000FFC0700FFFFFF8003FE0E00FFFFFF8001
+FFFC00FFFFFF80001FF00039317EB03C>82 D<001FF8018000FFFF038003FFFFC78007F007EF80
+0F8000FF801F00007F803E00001F803E00000F807C00000F807C00000780FC00000780FC000007
+80FC00000380FE00000380FE00000380FF00000000FFC00000007FF00000007FFF8000003FFFF8
+00003FFFFF80001FFFFFF0000FFFFFF80007FFFFFC0003FFFFFF0000FFFFFF00003FFFFF800001
+FFFFC000001FFFE0000001FFE00000003FE00000001FF00000000FF000000007F060000007F0E0
+000003F0E0000003F0E0000003F0E0000003E0F0000003E0F0000003E0F8000007C0FC000007C0
+FF00000F80FFC0001F00FBFC00FE00F1FFFFF800E03FFFF000C003FF800024317CB02D>I<7FFF
+FFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007FC00FF801FF007E000FF8003F007C000FF8001F
+0078000FF8000F0078000FF8000F0070000FF8000700F0000FF8000780F0000FF8000780F0000F
+F8000780E0000FF8000380E0000FF8000380E0000FF8000380E0000FF8000380E0000FF8000380
+00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8
+00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000
+000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800
+000000000FF800000000000FF800000000000FF800000000000FF800000000000FF80000000000
+0FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF80000
+00007FFFFFFF0000007FFFFFFF0000007FFFFFFF000031307DAF38>I<00FFF0000003FFFF0000
+0F803F80000FC00FE0001FE007F0001FE007F0001FE003F8000FC003FC00078003FC00000003FC
+00000003FC00000003FC00000003FC000000FFFC00001FFFFC0000FFE3FC0003FC03FC000FF003
+FC001FC003FC003FC003FC007F8003FC007F8003FC00FF0003FC00FF0003FC00FF0003FC00FF00
+07FC00FF0007FC007F800DFC003FC01DFE001FE078FFF007FFE07FF000FF803FF024207E9F27>
+97 D<01F8000000FFF8000000FFF8000000FFF80000000FF800000007F800000007F800000007
+F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8000000
+07F800000007F800000007F800000007F83FE00007F8FFFC0007FBE07F0007FF001F8007FE000F
+C007FC000FE007F80007F007F80007F807F80007F807F80003FC07F80003FC07F80003FC07F800
+03FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F8
+0003FC07F80003FC07F80003FC07F80007F807F80007F807F80007F007FC000FE007FE000FC007
+E7003F8007C3C0FE000780FFF80007003FC00027327EB12D>I<000FFF00007FFFC001FC01F003
+F003F007E007F80FE007F81FC007F83FC003F03FC001E07F8000007F8000007F800000FF800000
+FF800000FF800000FF800000FF800000FF800000FF800000FF8000007F8000007F8000007F8000
+003FC0001C3FC0001C1FC000380FE0003807E0007003F001E001FC07C0007FFF00000FF8001E20
+7D9F24>I<0000000FC0000007FFC0000007FFC0000007FFC00000007FC00000003FC00000003F
+C00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0000000
+3FC00000003FC00000003FC00000003FC00007F83FC0003FFF3FC000FE07BFC003F801FFC007E0
+007FC00FE0007FC01FC0003FC03FC0003FC03FC0003FC07F80003FC07F80003FC07F80003FC0FF
+80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0
+7F80003FC07F80003FC07F80003FC03FC0003FC03FC0003FC01FC0003FC00FE0007FC007E000FF
+C003F003FFE001FC0F3FFE007FFE3FFE000FF03FFE27327DB12D>I<000FFC00007FFF8001FC0F
+C003F003E007E001F00FE001F81FC000FC3FC000FE3FC000FE7F80007E7F80007F7F80007FFF80
+007FFF80007FFFFFFFFFFFFFFFFFFF800000FF800000FF800000FF8000007F8000007F8000007F
+8000003FC000071FC000071FC0000E0FE0000E07F0001C03F8007800FE03E0003FFFC00007FE00
+20207E9F25>I<0001FE00000FFF80001FC3C0007F07E000FE0FF001FE0FF001FC0FF003FC0FF0
+03FC07E003FC018003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00
+00FFFFFC00FFFFFC00FFFFFC0003FC000003FC000003FC000003FC000003FC000003FC000003FC
+000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003
+FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC0000
+7FFFF0007FFFF0007FFFF0001C327EB119>I<001FF007C000FFFE3FE001F83F79F007E00FC3F0
+0FE00FE1F00FC007E0E01FC007F0001FC007F0003FC007F8003FC007F8003FC007F8003FC007F8
+003FC007F8001FC007F0001FC007F0000FC007E0000FE00FE00007E00FC00003F83F000006FFFE
+00000E1FF000000E000000001E000000001E000000001F000000001F800000001FFFFF80000FFF
+FFF0000FFFFFFC0007FFFFFE0003FFFFFF0003FFFFFF800FFFFFFFC03F00007FC07E00001FE07C
+00000FE0FC000007E0FC000007E0FC000007E0FC000007E07E00000FC03E00000F803F00001F80
+0FC0007E0007F803FC0001FFFFF000001FFF0000242F7E9F28>I<03C00007E0000FF0001FF800
+1FF8001FF8001FF8000FF00007E00003C000000000000000000000000000000000000000000000
+00000000000001F8007FF8007FF8007FF80007F80007F80007F80007F80007F80007F80007F800
+07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800
+07F80007F80007F80007F80007F800FFFF80FFFF80FFFF8011337DB217>105
+D<01F8000000FFF8000000FFF8000000FFF80000000FF800000007F800000007F800000007F800
+000007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8
+00000007F800000007F800000007F800FFF807F800FFF807F800FFF807F8003F0007F8003C0007
+F800780007F800F00007F803C00007F807800007F80F000007F81E000007F878000007F8FC0000
+07F9FE000007FBFE000007FFFF000007FE7F800007FC7FC00007F83FC00007F01FE00007F00FF0
+0007F00FF80007F007FC0007F003FC0007F001FE0007F000FF0007F000FF8007F0007F8007F000
+7FC0FFFF81FFFEFFFF81FFFEFFFF81FFFE27327EB12B>107 D<01F800FFF800FFF800FFF8000F
+F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007
+F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007
+F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007
+F80007F80007F80007F800FFFFC0FFFFC0FFFFC012327DB117>I<03F007F8001FE000FFF03FFE
+00FFF800FFF0783F01E0FC00FFF0C03F8300FE000FF1801FC6007F0007F3001FCC007F0007F600
+1FF8007F8007FC001FF0007F8007FC001FF0007F8007FC001FF0007F8007F8001FE0007F8007F8
+001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007
+F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F80
+07F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F
+8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F80FFFFC3FFFF0FFFFCFFFFC3FFFF0F
+FFFCFFFFC3FFFF0FFFFC3E207D9F43>I<03F007F800FFF03FFE00FFF0783F00FFF0C03F800FF1
+801FC007F3001FC007F6001FE007FC001FE007FC001FE007FC001FE007F8001FE007F8001FE007
+F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0
+07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F
+E007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF28207D9F2D>I<0007FC0000007FFFC00001
+FC07F00003F001F80007E000FC000FC0007E001FC0007F003FC0007F803F80003F807F80003FC0
+7F80003FC07F80003FC0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003F
+E0FF80003FE0FF80003FE07F80003FC07F80003FC07F80003FC03FC0007F803FC0007F801FC000
+7F000FE000FE0007E000FC0003F803F80001FE0FF000007FFFC0000007FC000023207E9F28>I<
+01F83FE000FFF8FFFC00FFFBE07F00FFFF003F8007FE001FC007FC000FE007F8000FF007F80007
+F807F80007F807F80007FC07F80003FC07F80003FC07F80003FE07F80003FE07F80003FE07F800
+03FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FC07F80007FC07F80007FC07F8
+0007F807F80007F807F8000FF007FC000FE007FE001FC007FF003F8007FBC0FE0007F8FFF80007
+F83FC00007F800000007F800000007F800000007F800000007F800000007F800000007F8000000
+07F800000007F800000007F800000007F8000000FFFFC00000FFFFC00000FFFFC00000272E7E9F
+2D>I<03F03F00FFF07FC0FFF1C3E0FFF187E00FF30FF007F60FF007F60FF007FC07E007FC03C0
+07FC000007FC000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F800
+0007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8
+0000FFFFE000FFFFE000FFFFE0001C207E9F21>114 D<01FF860007FFFE001F00FE003C003E00
+78001E0078000E00F8000E00F8000E00F8000E00FC000000FF800000FFFC00007FFFC0003FFFF0
+003FFFF8001FFFFC0007FFFE0001FFFF00003FFF000000FF8000003F8060001F80E0000F80E000
+0F80F0000F80F0000F00F8000F00FC001E00FE001C00FF807800F3FFF000C07F800019207D9F20
+>I<001C0000001C0000001C0000001C0000001C0000003C0000003C0000003C0000007C000000
+7C000000FC000001FC000003FC000007FC00001FFFFE00FFFFFE00FFFFFE0003FC000003FC0000
+03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00
+0003FC000003FC000003FC000003FC000003FC038003FC038003FC038003FC038003FC038003FC
+038003FC038001FC038001FC070000FE0700007F0E00003FFC000007F000192E7FAD1F>I<01F8
+0007E0FFF803FFE0FFF803FFE0FFF803FFE00FF8003FE007F8001FE007F8001FE007F8001FE007
+F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0
+07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F
+E007F8003FE007F8003FE003F8007FE003F8007FE001FC00DFF000FE039FFF007FFF1FFF000FFC
+1FFF28207D9F2D>I<FFFF001FFCFFFF001FFCFFFF001FFC0FF80003C007F800038007FC000780
+03FC00070003FE00070001FE000E0001FF000E0000FF001C0000FF001C0000FF803C00007F8038
+00007FC07800003FC07000003FE0F000001FE0E000001FF1E000000FF1C000000FF9C0000007FB
+80000007FB80000007FF80000003FF00000003FF00000001FE00000001FE00000000FC00000000
+FC00000000780000000078000026207E9F2B>I<FFFF1FFFE03FF8FFFF1FFFE03FF8FFFF1FFFE0
+3FF80FF000FE0007800FF800FE00038007F800FF00070007F8007F00070007FC007F000F0003FC
+00FF800E0003FC00FF800E0001FE01FFC01C0001FE01DFC01C0001FF01DFC03C0000FF038FE038
+0000FF038FE03800007F878FF07000007F8707F07000007FC707F0F000003FCF07F8E000003FCE
+03F8E000001FFE03F9C000001FFC01FDC000001FFC01FFC000000FFC01FF8000000FF800FF8000
+000FF800FF80000007F0007F00000007F0007F00000003F0007E00000003E0003E00000003E000
+3E00000001C0001C000035207E9F3A>I<7FFF807FFC7FFF807FFC7FFF807FFC03FC000F0001FE
+001E0000FF003C0000FF803800007FC07800003FC0F000001FE1E000000FF3C000000FFF800000
+07FF00000003FE00000001FE00000000FF00000000FF80000000FFC0000001FFC0000003DFE000
+00078FF00000078FF800000F07FC00001E03FE00003C01FE00007800FF0000F000FF8001E0007F
+C003E0003FE0FFFC01FFFFFFFC01FFFFFFFC01FFFF28207F9F2B>I<FFFF001FFCFFFF001FFCFF
+FF001FFC0FF80003C007F800038007FC00078003FC00070003FE00070001FE000E0001FF000E00
+00FF001C0000FF001C0000FF803C00007F803800007FC07800003FC07000003FE0F000001FE0E0
+00001FF1E000000FF1C000000FF9C0000007FB80000007FB80000007FF80000003FF00000003FF
+00000001FE00000001FE00000000FC00000000FC00000000780000000078000000007000000000
+7000000000F000000000E000000001E000007C01C00000FE03C00000FE03800000FE07000000FE
+0F000000FC1E000000787C0000003FF00000000FC0000000262E7E9F2B>I
+E /Fn 2 16 df<0000FF00000007FFE000001F00F8000078001E0000E000070001800001800300
+0000C006000000600C000000300C000000301800000018300000000C300000000C600000000660
+0000000660000000066000000006C000000003C000000003C000000003C000000003C000000003
+C000000003C000000003C000000003C00000000360000000066000000006600000000660000000
+06300000000C300000000C18000000180C000000300C00000030060000006003000000C0018000
+018000E00007000078001E00001F00F8000007FFE0000000FF0000282B7EA02D>13
+D<03F0000FFC001FFE003FFF007FFF807FFF80FFFFC0FFFFC0FFFFC0FFFFC0FFFFC0FFFFC07FFF
+807FFF803FFF001FFE000FFC0003F00012127E9317>15 D E /Fo 82 125
+df<001F83E000F06E3001C078780380F8780300F0300700700007007000070070000700700007
+0070000700700007007000FFFFFF80070070000700700007007000070070000700700007007000
+070070000700700007007000070070000700700007007000070070000700700007007000070070
+0007007000070070003FE3FF001D20809F1B>11 D<003F0000E0C001C0C00381E00701E00701E0
+070000070000070000070000070000070000FFFFE00700E00700E00700E00700E00700E00700E0
+0700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E03FC3FC
+1620809F19>I<003FE000E0E001C1E00381E00700E00700E00700E00700E00700E00700E00700
+E00700E0FFFFE00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700
+E00700E00700E00700E00700E00700E00700E00700E03FE7FC1620809F19>I<001F81F80000F0
+4F040001C07C06000380F80F000300F00F000700F00F0007007000000700700000070070000007
+0070000007007000000700700000FFFFFFFF000700700700070070070007007007000700700700
+070070070007007007000700700700070070070007007007000700700700070070070007007007
+000700700700070070070007007007000700700700070070070007007007003FE3FE3FE0232080
+9F26>I<7038F87CFC7EFC7E743A0402040204020804080410081008201040200F0E7F9F17>34
+D<0078000000840000018400000302000007020000070200000702000007020000070400000704
+000007080000070800000390000003A00FFC03C001E003C000C001C0008001C0010002E0010004
+E00200087002001878040030380800703C0800701C1000F00E1000F00F2000F007C000F0038004
+7001C0047802E008380470181C183C3007E00FC01E227EA023>38 D<70F8FCFC74040404080810
+102040060E7C9F0D>I<0040008001000300060004000C00180018003800300030007000600060
+0060006000E000E000E000E000E000E000E000E000E000E000E000E00060006000600060007000
+300030003800180018000C000400060003000100008000400A2E7BA112>I<8000400020003000
+180008000C00060006000700030003000380018001800180018001C001C001C001C001C001C001
+C001C001C001C001C001C001800180018001800380030003000700060006000C00080018003000
+2000400080000A2E7EA112>I<70F0F8F878080808101010202040050E7C840D>44
+D<FFF0FFF00C02808A0F>I<70F8F8F87005057C840D>I<0000400000C000018000018000018000
+0300000300000300000600000600000C00000C00000C0000180000180000180000300000300000
+600000600000600000C00000C00000C00001800001800001800003000003000006000006000006
+00000C00000C00000C0000180000180000300000300000300000600000600000600000C00000C0
+0000122D7EA117>I<03F0000E1C001C0E00180600380700700380700380700380700380F003C0
+F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0700380
+7003807003807807803807001806001C0E000E1C0003F000121F7E9D17>I<008003800F80F380
+038003800380038003800380038003800380038003800380038003800380038003800380038003
+80038003800380038007C0FFFE0F1E7C9D17>I<03F0000C1C00100E00200700400780800780F0
+07C0F803C0F803C0F803C02007C00007C0000780000780000F00000E00001C0000380000700000
+600000C0000180000300000600400C00401800401000803FFF807FFF80FFFF80121E7E9D17>I<
+03F0000C1C00100E00200F00780F80780780780780380F80000F80000F00000F00001E00001C00
+00700007F000003C00000E00000F000007800007800007C02007C0F807C0F807C0F807C0F00780
+400780400F00200E00183C0007F000121F7E9D17>I<000600000600000E00000E00001E00002E
+00002E00004E00008E00008E00010E00020E00020E00040E00080E00080E00100E00200E00200E
+00400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E0000FFE0141E7F9D17
+>I<1803001FFE001FFC001FF8001FE00010000010000010000010000010000010000011F00016
+1C00180E001007001007800003800003800003C00003C00003C07003C0F003C0F003C0E0038040
+0380400700200600100C0008380007E000121F7E9D17>I<007C000182000701000E03800C0780
+180780380300380000780000700000700000F1F000F21C00F40600F80700F80380F80380F003C0
+F003C0F003C0F003C0F003C07003C07003C07003803803803807001807000C0E00061C0001F000
+121F7E9D17>I<4000007FFFE07FFFC07FFFC04000808001008001008002000004000004000008
+0000100000100000200000200000600000600000E00000C00001C00001C00001C00001C00003C0
+0003C00003C00003C00003C00003C00003C000018000131F7E9D17>I<03F0000C0C0010060030
+03002001806001806001806001807001807803003E03003F06001FC8000FF00003F80007FC000C
+7E00103F00300F806007806001C0C001C0C000C0C000C0C000C0C000806001802001001002000C
+0C0003F000121F7E9D17>I<03F0000E18001C0C00380600380700700700700380F00380F00380
+F003C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C003E3C0000380000380
+000380000700300700780600780E00700C002018001070000FC000121F7E9D17>I<70F8F8F870
+0000000000000000000070F8F8F87005147C930D>I<70F8F8F8700000000000000000000070F0
+F8F878080808101010202040051D7C930D>I<000100000003800000038000000380000007C000
+0007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F00000207800002078
+000020780000403C0000403C0000C03E0000801E0000801E0001FFFF0001000F0001000F000200
+07800200078002000780040003C0040003C00C0003C01E0003E0FF801FFE1F207F9F22>65
+D<FFFFE0000F0078000F001E000F001E000F000F000F000F800F000F800F000F800F000F800F00
+0F800F000F000F001F000F001E000F007C000FFFF0000F007C000F001F000F000F800F0007C00F
+0003C00F0003E00F0003E00F0003E00F0003E00F0003E00F0003C00F0007C00F0007800F000F00
+0F003E00FFFFF0001B1F7E9E20>I<000FE01000381C3000E0027003C00170078000F00F000070
+1E0000701E0000303C0000303C0000107C00001078000010F8000000F8000000F8000000F80000
+00F8000000F8000000F8000000F8000000F8000000780000007C0000103C0000103C0000101E00
+00201E0000200F0000200780004003C0008000E0030000380C00000FF0001C217E9F21>I<FFFF
+F80007801E0007800780078003C0078001E0078000F00780007007800078078000780780003C07
+80003C0780003C0780003E0780003E0780003E0780003E0780003E0780003E0780003E0780003E
+0780003C0780003C0780007C0780007807800078078000F0078001E0078003C00780078007801E
+00FFFFF8001F1F7F9E23>I<FFFFFF800F000F800F0003800F0001800F0000800F0000C00F0000
+400F0000400F0000400F0040400F0040000F0040000F00C0000F01C0000FFFC0000F01C0000F00
+C0000F0040000F0040000F0040000F0000200F0000200F0000200F0000400F0000400F0000400F
+0000C00F0001C00F0003800F000F80FFFFFF801B1F7E9E1F>I<FFFFFF80078007800780018007
+80018007800080078000C007800040078000400780004007800040078020000780200007802000
+078060000780E00007FFE0000780E0000780600007802000078020000780200007800000078000
+0007800000078000000780000007800000078000000780000007C00000FFFE00001A1F7F9E1E>
+I<000FE01000381C3000E0027003C00170078000F00F0000701E0000701E0000303C0000303C00
+00107C00001078000010F8000000F8000000F8000000F8000000F8000000F8000000F8000000F8
+003FFEF80001F0780000F07C0000F03C0000F03C0000F01E0000F01E0000F00F0000F0078000F0
+03C0017000E0023000380C10000FF0001F217E9F24>I<FFF07FF80F0007800F0007800F000780
+0F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007
+800FFFFF800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F00
+07800F0007800F0007800F0007800F0007800F0007800F000780FFF07FF81D1F7E9E22>I<FFF0
+0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F
+000F000F000F000F000F000F000F000F000F00FFF00C1F7E9E10>I<07FFC0003E00001E00001E
+00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E
+00001E00001E00001E00001E00001E00001E00201E00F81E00F81E00F81E00F01C00403C006038
+001070000FC00012207F9E17>I<FFF007FC0F0003E00F0001800F0001000F0002000F0004000F
+0008000F0010000F0020000F0040000F0080000F0100000F0300000F0780000F0F80000F13C000
+0F21E0000F41E0000F80F0000F0078000F0078000F003C000F001E000F001E000F000F000F0007
+800F0007800F0003C00F0003E00F0003F0FFF01FFE1F1F7E9E23>I<FFF8000F80000F00000F00
+000F00000F00000F00000F00000F00000F00000F00000F00000F00000F00000F00000F00000F00
+000F00000F00000F00000F00020F00020F00020F00020F00060F00040F00040F000C0F001C0F00
+7CFFFFFC171F7E9E1C>I<FF800007FE07800007C007800007C005C0000BC005C0000BC004E000
+13C004E00013C004E00013C004700023C004700023C004380043C004380043C004380043C0041C
+0083C0041C0083C0040E0103C0040E0103C0040E0103C004070203C004070203C004070203C004
+038403C004038403C00401C803C00401C803C00401C803C00400F003C00400F003C004006003C0
+1F006003C0FFE0607FFE271F7F9E2A>I<FF000FF80F8003E00F8000800BC0008009E0008009E0
+008008F000800878008008780080083C0080081E0080081E0080080F0080080780800807808008
+03C0800801E0800801E0800800F080080078800800788008003C8008001E8008001E8008000F80
+080007800800078008000380080001803E000180FF8000801D1F7E9E22>I<001FE00000703800
+01C00E0003800700070003800F0003C01E0001E03C0000F03C0000F07C0000F87C0000F8780000
+78F800007CF800007CF800007CF800007CF800007CF800007CF800007CF800007CF800007C7800
+00787C0000F87C0000F83C0000F03E0001F01E0001E00F0003C0070003800380070001E01E0000
+703800001FE0001E217E9F23>I<FFFFE0000F007C000F001E000F000F000F0007800F0007800F
+0007C00F0007C00F0007C00F0007C00F0007800F0007800F000F000F001E000F007C000FFFE000
+0F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000
+000F0000000F0000000F0000000F000000FFF000001A1F7E9E1F>I<001FE0000070380001C00E
+0003800700070003800F0003C01E0001E03E0001F03C0000F07C0000F87C0000F878000078F800
+007CF800007CF800007CF800007CF800007CF800007CF800007CF800007CF800007C780000787C
+0000F87C0000F83C0000F03E0781F01E0841E00F1023C0071023800390170001D01E0000783804
+001FF80400001C0400000C0C00000E1C00000FF800000FF8000007F8000007F0000001E01E297E
+9F23>I<FFFF80000F00F0000F003C000F001E000F000F000F000F000F000F800F000F800F000F
+800F000F800F000F000F000F000F001E000F003C000F00F0000FFF80000F01C0000F0070000F00
+70000F0038000F003C000F003C000F003C000F003E000F003E000F003E000F003E040F003F040F
+001F040F000F08FFF00788000001F01E207E9E21>I<03F0400C0CC01803C03001C06000C06000
+C0E000C0E00040E00040E00040F00000F800007C00007F80003FF8001FFF0007FF8000FFC0001F
+E00003E00001E00000F0000070800070800070800070800070C00060C000E0E000C0F80180C603
+0081FC0014217E9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010
+800F0010800F0010800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F00
+00000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F
+0000000F0000000F0000001F800003FFFC001C1F7E9E21>I<FFF00FF80F0003E00F0000800F00
+00800F0000800F0000800F0000800F0000800F0000800F0000800F0000800F0000800F0000800F
+0000800F0000800F0000800F0000800F0000800F0000800F0000800F0000800F0000800F000080
+0F0000800700010007800100038001000380020001C0040000E0080000383000000FC0001D207E
+9E22>I<FFF003FE1F8000F80F0000600F00002007800040078000400780004003C0008003C000
+8003E0018001E0010001E0010000F0020000F0020000F802000078040000780400003C0800003C
+0800003C0800001E1000001E1000001F1000000F2000000F20000007C0000007C0000007C00000
+0380000003800000038000000100001F207F9E22>I<FFF07FF81FF01F000FC007C00F00078001
+800F00078001000F0007C001000F8007C00300078007C00200078009E0020007C009E0020003C0
+09E0040003C019F0040003C010F0040001E010F0080001E010F0080001E02078080000F0207810
+0000F02078100000F0403C10000078403C20000078403C20000078801E2000007C801E6000003C
+801E4000003D000F4000003F000F4000001F000F8000001F000F8000001E00078000000E000700
+00000E00070000000C000300000004000200002C207F9E2F>I<7FF81FF80FE007C007C0030003
+C0020003E0060001F0040000F0080000F8180000781000003C2000003E6000001E4000000F8000
+000F8000000780000003C0000007E0000005E0000008F0000018F8000010780000207C0000603E
+0000401E0000801F0001000F8001000780020007C0060003C01F0007E0FFC01FFE1F1F7F9E22>
+I<FFF001FF1F8000780F8000600780006007C0004003C0008003E0008001F0010000F0010000F8
+0200007C0600003C0400003E0800001E0800001F1000000FB0000007A0000007E0000003C00000
+03C0000003C0000003C0000003C0000003C0000003C0000003C0000003C0000003C0000003C000
+0003C000003FFC00201F7F9E22>I<FFFFC0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0
+C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0FFFF082D7CA10D>91 D<08041008201020104020
+4020804080408040B85CFC7EFC7E7C3E381C0F0E7A9F17>I<FFFF030303030303030303030303
+0303030303030303030303030303030303030303030303030303030303FFFF082D80A10D>I<08
+1020204040808080B8FCFC7C38060E7D9F0D>96 D<1FE000303000781800781C00300E00000E00
+000E00000E0000FE00078E001E0E00380E00780E00F00E10F00E10F00E10F01E10781E10386720
+0F83C014147E9317>I<1C0000FC00001C00001C00001C00001C00001C00001C00001C00001C00
+001C00001C00001C7C001D87001E01801E00C01C00E01C00701C00701C00781C00781C00781C00
+781C00781C00781C00701C00F01C00E01E00C01A0180198700107C0015207E9F19>I<01FC0007
+06001C0F00380F00380600780000700000F00000F00000F00000F00000F00000F0000070000078
+00003800803800801C010007060001F80011147F9314>I<0001C0000FC00001C00001C00001C0
+0001C00001C00001C00001C00001C00001C00001C001F1C0070DC00C03C01801C03801C07801C0
+7001C0F001C0F001C0F001C0F001C0F001C0F001C07001C07001C03801C01803C00C03C0070DC0
+01F1F815207F9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FFFF
+80F00000F00000F000007000007000003800803800801C010007060001F80011147F9314>I<00
+7C01C6030F070F0E060E000E000E000E000E000E000E00FFF00E000E000E000E000E000E000E00
+0E000E000E000E000E000E000E000E000E000E000E007FE01020809F0E>I<0000E003E3300E3C
+301C1C30380E00780F00780F00780F00780F00780F00380E001C1C001E380033E0002000002000
+003000003000003FFE001FFF801FFFC03001E0600070C00030C00030C00030C000306000603000
+C01C038003FC00141F7F9417>I<1C0000FC00001C00001C00001C00001C00001C00001C00001C
+00001C00001C00001C00001C7C001C86001D03001E03801E03801C03801C03801C03801C03801C
+03801C03801C03801C03801C03801C03801C03801C03801C03801C0380FF8FF014207E9F19>I<
+38007C007C007C0038000000000000000000000000001C00FC001C001C001C001C001C001C001C
+001C001C001C001C001C001C001C001C001C001C00FF80091F7F9E0C>I<00E001F001F001F000
+E0000000000000000000000000007007F000F00070007000700070007000700070007000700070
+007000700070007000700070007000700070007000706070F060F0C061803F000C28829E0E>I<
+1C0000FC00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C1FE0
+1C07801C06001C04001C08001C10001C20001C60001CE0001DF0001E70001C38001C3C001C1C00
+1C0E001C0F001C07001C07801C07C0FF9FF014207E9F18>I<1C00FC001C001C001C001C001C00
+1C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C
+001C001C001C001C00FF8009207F9F0C>I<1C3E03E000FCC30C30001D039038001E01E01C001E
+01E01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C00
+1C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C00FF8FF8FF
+8021147E9326>I<1C7C00FC86001D03001E03801E03801C03801C03801C03801C03801C03801C
+03801C03801C03801C03801C03801C03801C03801C03801C0380FF8FF014147E9319>I<01F800
+070E001C03803801C03801C07000E07000E0F000F0F000F0F000F0F000F0F000F0F000F07000E0
+7000E03801C03801C01C0380070E0001F80014147F9317>I<1C7C00FD87001E01801E01C01C00
+E01C00F01C00701C00781C00781C00781C00781C00781C00781C00701C00F01C00E01E01C01E03
+801D87001C7C001C00001C00001C00001C00001C00001C00001C00001C0000FF8000151D7E9319
+>I<01F040070CC00E02C01C03C03801C07801C07001C0F001C0F001C0F001C0F001C0F001C0F0
+01C07001C07801C03801C01C03C00C05C00709C001F1C00001C00001C00001C00001C00001C000
+01C00001C00001C0000FF8151D7F9318>I<1CF0FD181E3C1E3C1E181C001C001C001C001C001C
+001C001C001C001C001C001C001C001C00FFC00E147E9312>I<0FC830386018C008C008C008E0
+007C003FE01FF007F8003C800E8006C006C006C004E00CD81887E00F147F9312>I<0200020002
+00060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E000E000E000E040E04
+0E040E040E040708030801F00E1C7F9B12>I<1C0380FC1F801C03801C03801C03801C03801C03
+801C03801C03801C03801C03801C03801C03801C03801C03801C03801C07800C0780061B8003E3
+F014147E9319>I<FF83F83E00E01C00C00E00800E00800E008007010007010007830003820003
+820001C40001C40001E40000E80000E80000700000700000700000200015147F9318>I<FF9FE1
+FC3C0780701C0300601C0380200E0380400E0380400E03C0400704C0800704E0800704E0800388
+6100038871000388710001D0320001D03A0001D03E0000E01C0000E01C0000601800004008001E
+147F9321>I<FF87F81E03C00E01800E030007020003840001C80001D80000F000007000007800
+00F800009C00010E00020E000607000403800C03C03C03E0FE07FC16147F9318>I<FF83F83E00
+E01C00C00E00800E00800E008007010007010007830003820003820001C40001C40001E40000E8
+0000E800007000007000007000002000002000004000004000004000F08000F08000F100006200
+003C0000151D7F9318>I<7FFF700E600E401C40384078407000E001E001C00380078007010E01
+1E011C0338027006700EFFFE10147F9314>I<FFFFFC1601808C17>I<FFFFFFFFFFF02C01808C2D
+>I E /Fp 41 123 df<0003F07C001E0DC600380F0F00701E0F00E01E0E00E00C0001C01C0001
+C01C0001C01C0001C01C0001C01C00038038007FFFFFC003803800038038000380380003803800
+0700700007007000070070000700700007007000070070000E00E0000E00E0000E00E0000E00E0
+000E00E0000E00E0001C01C0001E01E000FF8FFC0020207E9F1B>11 D<0003E0001C1800381800
+703C00E03C00E03801C00001C00001C00001C00001C0000380007FFFF003807003807003807003
+80700700E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C
+03801E03C0FF0FF016207E9F19>I<0006000C00100030006000C0008001800300030006000E00
+0C000C0018001800380038003000300070007000600060006000E000E000E000E000E000E000E0
+00E00060006000600060006000300030001000180008000C00040002000F2E7AA112>40
+D<008000C00040002000300030001800180018000C000C000C000C000C000C000C000C000C000C
+000C000C000C001C001C001C0018001800380038003000300070006000E000C000C00180010003
+0006000400080018003000400080000E2E80A112>I<FFF0FFF00C027E8A0F>45
+D<3078F8787005057C840D>I<0018003801F80E700070007000700070007000E000E000E000E0
+00E000E001C001C001C001C001C001C003800380038003800380038007000780FFFC0E1E7B9D17
+>49 D<1FFFFFFE3FFFFFFF00000000000000000000000000000000000000000000000000000000
+00000000FFFFFFFC7FFFFFF8200C7D9023>61 D<0000080000000C0000001C0000003C0000003C
+0000007C0000007E0000009E0000009E0000011E0000011E0000021E0000020F0000040F000004
+0F0000080F0000080F0000100F80001007800020078000200780007FFF80004007C0008003C000
+8003C0010003C0010003C0020003C0020001E0060001E01F0003E0FF801FFE1F207F9F22>65
+D<07FFFFF800F80078007800380078001800F0001800F0000800F0000800F0000800F0000800F0
+000801E0080001E0080001E0080001E0180001E0380001FFF80003C0300003C0100003C0100003
+C0100003C0100003C000000780000007800000078000000780000007800000078000000F000000
+0F800000FFFC00001D1F7E9E1E>70 D<07FF83FFC000F8007C000078003C000078003C0000F000
+780000F000780000F000780000F000780000F000780000F000780001E000F00001E000F00001E0
+00F00001E000F00001FFFFF00001E000F00003C001E00003C001E00003C001E00003C001E00003
+C001E00003C001E000078003C000078003C000078003C000078003C000078003C000078003C000
+0F000780000F8007C000FFF07FF800221F7E9E22>72 D<07FF8000F80000780000780000F00000
+F00000F00000F00000F00000F00001E00001E00001E00001E00001E00001E00003C00003C00003
+C00003C00003C00003C0000780000780000780000780000780000780000F00000F8000FFF00011
+1F7E9E10>I<07F8007FC0007C001F00007C000C00005E000400009E000800008F000800008F00
+0800008780080000878008000083C008000103C010000101E010000101E010000100F010000100
+F010000100781000020078200002003C200002003C200002001E200002001E200002000F200004
+000F4000040007C000040007C000040003C000040003C000040001C0000C000180001E00008000
+FF80008000221F7E9E22>78 D<001F8200706600C01E01800E03000E07000C0600040E00040E00
+040E00040F00000F00000F800007F00007FF0003FFC001FFE0003FF00003F80000F80000780000
+3C00003C400038400038400038400030600070600060F000C0E80180C6030081FC0017217E9F19
+>83 D<00FF01FE0180018001800180018003000300030003000300030006000600060006000600
+06000C000C000C000C000C000C0018001800180018001800180030003000300030003000300060
+0060006000600060006000FF00FF00102D7EA10D>91 D<00FF01FE00060006000600060006000C
+000C000C000C000C000C0018001800180018001800180030003000300030003000300060006000
+6000600060006000C000C000C000C000C000C0018001800180018001800180FF00FF00102D82A1
+0D>93 D<07F8000C0C001E06001E07001C070000070000070000070000FF0007C7001E07003C0E
+00780E00F00E10F00E10F00E10F01E10F02E20784F401F878014147D9317>97
+D<0700003F00000F00000700000700000E00000E00000E00000E00000E00000E00001C00001C7C
+001D83001E01801C01C01C00E03800E03800F03800F03800F03800F03800F07001E07001E07001
+C07003C0700380700700E80E00CC380083E00014207B9F19>I<00FE000383000E07801C078038
+0700380000780000F00000F00000F00000F00000E00000E00000E00000F00000F0010070020038
+04001C180007E00011147D9314>I<0000380001F8000078000038000038000070000070000070
+0000700000700000700000E000FCE00382E00601E01C01E03C00E03801C07801C0F001C0F001C0
+F001C0F001C0E00380E00380E00380E00380F00380700780380F001C378007C7E015207D9F19>
+I<00F800070E000E07001C0700380380780380700380F00380F00380FFFF80F00000E00000E000
+00E00000E00000F001007002003004001C180007E00011147D9314>I<0007C0001C600030F000
+60F000E0E000C00001C00001C00001C00001C00001C0000380003FFC0003800003800003800003
+80000700000700000700000700000700000700000E00000E00000E00000E00000E00000E00001C
+00001E0000FFC00014207F9F0E>I<00000E003E1100E1A301C1C20381E00780E00701E00F01E0
+0F01E00F01E00703C007038007870004FC000800000800001800001C00000FFF000FFFC00FFFE0
+1800F0300030600030C00030C00030C000306000603000C01C070007FC00181F809417>I<00E0
+0007E00001E00000E00000E00001C00001C00001C00001C00001C00001C000038000038F800390
+E003A0E003C0600380600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01
+C00E01C00E01C01C03801E03C0FF8FF014207E9F19>I<01C003E003E003C00180000000000000
+00000000000003801F800780038003800700070007000700070007000E000E000E000E000E000E
+001C001E00FF800B1F7F9E0C>I<00E00007E00001E00000E00000E00001C00001C00001C00001
+C00001C00001C0000380000381FC0380F00380C003818003810007040007080007180007380007
+7C00071C000E1C000E0E000E0E000E0F000E07000E07801C03801E07C0FF8FF016207E9F18>
+107 D<00E007E001E000E000E001C001C001C001C001C001C00380038003800380038003800700
+070007000700070007000E000E000E000E000E000E001C001E00FF800B207F9F0C>I<0387C07C
+001F9861860007A072070003C03403000380380300078078070007007007000700700700070070
+0700070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00
+E00E001C01C01C001E01E01E00FFCFFCFFC022147E9326>I<038F801F90E007A0E003C0600380
+600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C03
+801E03C0FF8FF014147E9319>I<00FC000387000E01801C00C03800E03800E07000F0F000F0F0
+00F0F000F0F000F0E001E0E001E0E001C0E003C0F00380700700380E001C1C0007E00014147D93
+17>I<00E3E00007EC380000F01C0000E00E0000E00F0001C0070001C0078001C0078001C00780
+01C0078001C0078003800F0003800F0003800E0003801E0003801C0003803800074070000761C0
+00071F00000700000007000000070000000E0000000E0000000E0000000E0000001E000000FFC0
+0000191D809319>I<00FC200382600702601E01E03C01E03801C07801C0F001C0F001C0F001C0
+F001C0E00380E00380F00380F00380F00780700780380F001C370007C700000700000700000700
+000E00000E00000E00000E00001E0000FFC0131D7D9318>I<038E001FB38007C78003C7800383
+000780000700000700000700000700000700000E00000E00000E00000E00000E00000E00001C00
+001E0000FFC00011147E9312>I<01F9060708031803180138023C001F001FF007FC01FE001F40
+074003400360036006F004C81887E010147F9312>I<0080010001000100030007000F001E00FF
+F80E000E000E000E001C001C001C001C001C001C00380038103810381038103820382018400F80
+0D1C7C9B12>I<1C0380FC1F803C07801C03801C03803807003807003807003807003807003807
+00700E00700E00700E00700E00701E00701E00703C00305E001F9F8011147B9319>I<FF83F81E
+00E01C00C01C00801E00800E01000E03000E02000E040007040007080007080007100003900003
+A00003E00003C00003800001800001000015147C9318>I<FF9FE1FC3C0780701C0300601C0380
+601C0380401C0380800E0780800E0D81000E0981000E19C2000E11C2000F21C4000720C4000740
+C8000740E8000780F0000780F0000300E00003006000020040001E147C9321>I<1FF0FF03C078
+01C07001C04000E0C000E180007300007600003C00003C00001C00002E00004E00008700010700
+0203800403800C01C03C03E0FE07FC18147F9318>I<0FF83F8001E00E0001C00C0001C0080001
+E0080000E0100000E0300000E0200000E040000070400000708000007080000071000000390000
+003A0000003E0000003C0000003800000018000000100000001000000020000000200000004000
+0070C00000F0800000F1000000E600000078000000191D809318>I<0FFFE00E01E00C01C00803
+80080700100E00101C0000380000700000700000E00001C0000380800700800E00801C01001C01
+00380300700E00FFFE0013147F9314>I E /Fq 63 122 df<0001FF0000001FFFC000007F81E0
+0000FC01E00001F807F00003F807F00007F007F00007F007F00007F007F00007F007F00007F001
+C00007F000000007F000000007F000000007F03FF800FFFFFFF800FFFFFFF800FFFFFFF80007F0
+03F80007F003F80007F003F80007F003F80007F003F80007F003F80007F003F80007F003F80007
+F003F80007F003F80007F003F80007F003F80007F003F80007F003F80007F003F80007F003F800
+07F003F80007F003F80007F003F80007F003F80007F003F8007FFF3FFF807FFF3FFF807FFF3FFF
+80212A7FA925>12 D<0003F0000000000FF8000000001F1C000000003C0E000000007C06000000
+00FC0700000000F80700000001F80700000001F80700000001F80600000001F80E00000001FC0C
+00000001FC1800000001FC3800000001FC3000000000FE6000FFF800FEC000FFF800FF8000FFF8
+00FF00000E00007F00000E00007F00001C00007F80003800007FC000380000FFC0007000019FE0
+00E000038FE000E000070FF001C0000F07F80380001E07FC0380003E03FE0700007E01FE0E0000
+FE00FF1C0000FE007FB80000FE003FF00000FE001FE00000FF000FF000707F0007F800707F801F
+FE00E03FC0FEFF83E01FFFF87FFFC007FFE00FFF8000FF0001FE002D2A7DA934>38
+D<3C007F00FF80FF80FFC0FFC0FFC07FC03EC000C000C00180018001800300030006000E001C00
+380010000A157BA913>I<0006000C00180038007000E001E003C003C0078007800F800F001F00
+1F003E003E003E007E007E007E007C007C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC
+00FC00FC00FC007C007C007E007E007E003E003E003E001F001F000F000F800780078003C003C0
+01E000E0007000380018000C00060F3C7AAC1A>I<C0006000300038001C000E000F0007800780
+03C003C003E001E001F001F000F800F800F800FC00FC00FC007C007C007E007E007E007E007E00
+7E007E007E007E007E007E007E007E007E007C007C00FC00FC00FC00F800F800F801F001F001E0
+03E003C003C0078007800F000E001C00380030006000C0000F3C7CAC1A>I<FFFF80FFFF80FFFF
+80FFFF80FFFF80FFFF8011067F9016>45 D<1C007F007F00FF80FF80FF807F007F001C0009097B
+8813>I<003F800001FFF00007E0FC000FC07E001F803F001F001F003F001F803E000F807E000F
+C07E000FC07E000FC07E000FC0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE00
+0FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE07E000FC07E
+000FC07E000FC07E000FC03F001F803F001F801F001F001F803F000FC07E0007E0FC0001FFF000
+003F80001B277DA622>48 D<000E00001E00007E0007FE00FFFE00FFFE00F8FE0000FE0000FE00
+00FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE00
+00FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE00
+00FE00FFFFFEFFFFFEFFFFFE17277BA622>I<00FF800007FFF0000FFFFC001E03FE003800FF80
+7C003F80FE003FC0FF001FC0FF001FE0FF000FE0FF000FE07E000FE03C001FE000001FE000001F
+C000001FC000003F8000003F0000007E000000FC000000F8000001F0000003E00000078000000F
+0000001E0000003C00E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFFC03F
+FFFFC07FFFFFC0FFFFFF80FFFFFF80FFFFFF801B277DA622>I<007F800003FFF00007FFFC000F
+81FE001F007F003F807F003F803F803F803F803F803F801F803F801F003F8000007F0000007F00
+00007E000000FC000001F8000007F00000FFC00000FFC0000001F80000007E0000003F0000003F
+8000001FC000001FC000001FE000001FE03C001FE07E001FE0FF001FE0FF001FE0FF001FC0FF00
+3FC0FE003F807C007F003F01FE001FFFFC0007FFF00000FF80001B277DA622>I<00000F000000
+0F0000001F0000003F0000007F000000FF000001FF000001FF000003BF0000073F00000E3F0000
+1C3F00003C3F0000383F0000703F0000E03F0001C03F0003803F0007803F0007003F000E003F00
+1C003F0038003F0070003F00F0003F00FFFFFFF8FFFFFFF8FFFFFFF800007F0000007F0000007F
+0000007F0000007F0000007F0000007F0000007F00001FFFF8001FFFF8001FFFF81D277EA622>
+I<180003001F801F001FFFFE001FFFFC001FFFF8001FFFF0001FFFC0001FFF00001C0000001C00
+00001C0000001C0000001C0000001C0000001C0000001C7FC0001DFFF8001F80FC001E003F0008
+003F0000001F8000001FC000001FC000001FE000001FE018001FE07C001FE0FE001FE0FE001FE0
+FE001FE0FE001FC0FC001FC078003F8078003F803C007F001F01FE000FFFFC0003FFF00000FF80
+001B277DA622>I<0007F800003FFE0000FFFF0001FC078003F00FC007C01FC00F801FC01F801F
+C01F001FC03F000F803F0000007E0000007E0000007E000000FE020000FE1FF000FE3FFC00FE60
+3E00FE801F00FF801F80FF000FC0FF000FC0FE000FE0FE000FE0FE000FE0FE000FE07E000FE07E
+000FE07E000FE07E000FE03E000FE03F000FC01F000FC01F001F800F801F0007E07E0003FFFC00
+01FFF800003FC0001B277DA622>I<380000003E0000003FFFFFF03FFFFFF03FFFFFF07FFFFFE0
+7FFFFFC07FFFFF807FFFFF0070000E0070000E0070001C00E0003800E0007000E000E0000001C0
+000001C000000380000007800000070000000F0000001F0000001E0000003E0000003E0000007E
+0000007C0000007C000000FC000000FC000000FC000000FC000001FC000001FC000001FC000001
+FC000001FC000001FC000001FC000000F80000007000001C297CA822>I<003FC00001FFF00003
+FFFC0007C07E000F003F001E001F001E000F803E000F803E000F803F000F803F800F803FC00F00
+3FF01F001FFC1E001FFE3C000FFFF80007FFE00003FFF00001FFFC0001FFFE0007FFFF000F0FFF
+801E07FFC03E01FFC07C007FE07C001FE0F8000FE0F80007E0F80003E0F80003E0F80003E0F800
+03C07C0003C07E0007803F000F001FC03F000FFFFC0003FFF800007FC0001B277DA622>I<007F
+800001FFF00007FFF8000FC0FC001F803E003F001F007E001F807E001F807E000F80FE000FC0FE
+000FC0FE000FC0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE07E001FE07E001FE03F003FE0
+1F002FE00F80CFE007FF8FE001FF0FE000080FE000000FC000000FC000000FC000001F803E001F
+807F001F807F003F007F003E007F007E007E00FC003E03F8001FFFE0000FFF800001FE00001B27
+7DA622>I<00000780000000000780000000000FC0000000000FC0000000000FC0000000001FE0
+000000001FE0000000003FF0000000003FF0000000003FF00000000077F80000000077F8000000
+00F7FC00000000E3FC00000000E3FC00000001C1FE00000001C1FE00000003C1FF0000000380FF
+0000000380FF00000007007F80000007007F8000000F007FC000000E003FC000000E003FC00000
+1C001FE000001C001FE000003FFFFFF000003FFFFFF000003FFFFFF00000700007F80000700007
+F80000F00007FC0000E00003FC0001E00003FE0001C00001FE0001C00001FE0003C00001FF00FF
+FE003FFFFCFFFE003FFFFCFFFE003FFFFC2E297EA833>65 D<FFFFFFF800FFFFFFFF00FFFFFFFF
+C003F8001FE003F8000FF003F80007F803F80003F803F80003FC03F80003FC03F80001FC03F800
+01FC03F80001FC03F80003FC03F80003F803F80003F803F80007F003F8000FF003F8001FC003F8
+00FF8003FFFFFE0003FFFFFFC003F8000FF003F80003F803F80001FC03F80001FE03F80000FE03
+F80000FE03F80000FF03F80000FF03F80000FF03F80000FF03F80000FF03F80000FF03F80000FE
+03F80001FE03F80003FC03F80007FC03F8001FF8FFFFFFFFE0FFFFFFFFC0FFFFFFFE0028297DA8
+30>I<00007FE0030007FFFC07001FFFFF0F007FF00F9F00FF0001FF01FC0000FF03F800007F07
+F000003F0FE000001F1FC000001F1FC000000F3F8000000F3F800000077F800000077F80000007
+7F00000000FF00000000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000
+00FF00000000FF000000007F000000007F800000007F800000073F800000073F800000071FC000
+00071FC000000E0FE000000E07F000001C03F800003C01FC00007800FF0001F0007FF007C0001F
+FFFF800007FFFE0000007FF00028297CA831>I<FFFFFFFC0000FFFFFFFF8000FFFFFFFFE00003
+FC001FF80003FC0003FC0003FC0000FE0003FC00007F0003FC00003F8003FC00001FC003FC0000
+1FC003FC00000FE003FC00000FE003FC000007F003FC000007F003FC000007F003FC000007F003
+FC000007F803FC000007F803FC000007F803FC000007F803FC000007F803FC000007F803FC0000
+07F803FC000007F803FC000007F803FC000007F803FC000007F003FC000007F003FC000007F003
+FC00000FE003FC00000FE003FC00000FC003FC00001FC003FC00003F8003FC00007F0003FC0000
+FF0003FC0003FC0003FC001FF800FFFFFFFFF000FFFFFFFF8000FFFFFFFC00002D297EA834>I<
+FFFFFFFFE0FFFFFFFFE0FFFFFFFFE003FC001FE003FC0007F003FC0001F003FC0001F003FC0000
+F003FC00007003FC00007003FC00007003FC01C07803FC01C03803FC01C03803FC01C03803FC03
+C00003FC03C00003FC0FC00003FFFFC00003FFFFC00003FFFFC00003FC0FC00003FC03C00003FC
+03C00003FC01C00E03FC01C00E03FC01C00E03FC01C01C03FC00001C03FC00001C03FC00001C03
+FC00003C03FC00003803FC00007803FC0000F803FC0001F803FC0003F803FC001FF8FFFFFFFFF0
+FFFFFFFFF0FFFFFFFFF027297EA82C>I<FFFFFFFFC0FFFFFFFFC0FFFFFFFFC003FC003FC003FC
+000FE003FC0003E003FC0001E003FC0001E003FC0000E003FC0000E003FC0000E003FC0000F003
+FC01C07003FC01C07003FC01C07003FC01C00003FC03C00003FC03C00003FC0FC00003FFFFC000
+03FFFFC00003FFFFC00003FC0FC00003FC03C00003FC03C00003FC01C00003FC01C00003FC01C0
+0003FC01C00003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00
+000003FC00000003FC000000FFFFFC0000FFFFFC0000FFFFFC000024297EA82A>I<00007FE003
+000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F0007F0
+00003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80000007
+007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF0000000000FF00
+00000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F8000FFFF
+F87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF0007F0
+0000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007FFFE0F
+0000007FF003002D297CA835>I<FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF03FC00003FC003
+FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000
+3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003
+FC00003FC003FFFFFFFFC003FFFFFFFFC003FFFFFFFFC003FC00003FC003FC00003FC003FC0000
+3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003
+FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000
+3FC003FC00003FC0FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF30297EA835>I<FFFFF0FFFFF0
+FFFFF003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC00
+03FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC00
+03FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC0003FC00FFFFF0FFFFF0FFFFF0
+14297EA819>I<00FFFFF800FFFFF800FFFFF80000FF000000FF000000FF000000FF000000FF00
+0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF
+000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+FF000000FF000000FF001800FF007E00FF00FF00FF00FF00FF00FF00FF00FF00FE007E01FC007C
+01F8003E07F0000FFFE00003FF00001D297EA823>I<FFFFF000FFFEFFFFF000FFFEFFFFF000FF
+FE03FC00000F0003FC00001E0003FC00003C0003FC0000780003FC0000E00003FC0003C00003FC
+0007800003FC000F000003FC001E000003FC003C000003FC00F0000003FC01E0000003FC03C000
+0003FC07C0000003FC0FC0000003FC1FE0000003FC7FF0000003FCFFF8000003FDE7F8000003FF
+C3FC000003FF83FE000003FE01FF000003FC00FF000003FC007F800003FC007FC00003FC003FE0
+0003FC001FE00003FC000FF00003FC000FF80003FC0007F80003FC0003FC0003FC0001FE0003FC
+0001FF0003FC0000FF0003FC00007F80FFFFF00FFFFEFFFFF00FFFFEFFFFF00FFFFE2F297EA835
+>I<FFFFFC0000FFFFFC0000FFFFFC000003FC00000003FC00000003FC00000003FC00000003FC
+00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003
+FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000
+03FC00000003FC0001C003FC0001C003FC0001C003FC0001C003FC0003C003FC00038003FC0003
+8003FC00078003FC00078003FC000F8003FC000F8003FC001F8003FC007F8003FC01FF00FFFFFF
+FF00FFFFFFFF00FFFFFFFF0022297EA828>I<FFFE0000003FFF80FFFE0000003FFF80FFFF0000
+007FFF8003FF0000007FE00003FF0000007FE00003BF800000EFE00003BF800000EFE000039FC0
+0001CFE000039FC00001CFE000038FE000038FE000038FE000038FE000038FE000038FE0000387
+F000070FE0000387F000070FE0000383F8000E0FE0000383F8000E0FE0000381FC001C0FE00003
+81FC001C0FE0000381FC001C0FE0000380FE00380FE0000380FE00380FE00003807F00700FE000
+03807F00700FE00003803F80E00FE00003803F80E00FE00003803F80E00FE00003801FC1C00FE0
+0003801FC1C00FE00003800FE3800FE00003800FE3800FE000038007F7000FE000038007F7000F
+E000038007F7000FE000038003FE000FE000038003FE000FE000038001FC000FE000038001FC00
+0FE000038000F8000FE000FFFE00F803FFFF80FFFE00F803FFFF80FFFE007003FFFF8039297DA8
+40>I<FFFC00007FFFFFFE00007FFFFFFF00007FFF03FF800001C003FFC00001C003BFE00001C0
+039FE00001C0039FF00001C0038FF80001C00387FC0001C00383FE0001C00381FF0001C00380FF
+8001C003807F8001C003807FC001C003803FE001C003801FF001C003800FF801C0038007FC01C0
+038003FC01C0038003FE01C0038001FF01C0038000FF81C00380007FC1C00380003FE1C0038000
+1FF1C00380000FF1C00380000FF9C003800007FDC003800003FFC003800001FFC003800000FFC0
+038000007FC0038000007FC0038000003FC0038000001FC0038000000FC00380000007C0FFFE00
+0003C0FFFE000001C0FFFE000001C030297EA835>I<0000FFC00000000FFFFC0000003F807F00
+0000FE001FC00001F80007E00003F00003F00007E00001F8000FE00001FC001FC00000FE001FC0
+0000FE003F8000007F003F8000007F007F8000007F807F0000003F807F0000003F807F0000003F
+80FF0000003FC0FF0000003FC0FF0000003FC0FF0000003FC0FF0000003FC0FF0000003FC0FF00
+00003FC0FF0000003FC0FF0000003FC0FF0000003FC07F0000003F807F8000007F807F8000007F
+803F8000007F003F8000007F001FC00000FE001FC00000FE000FE00001FC0007F00003F80003F8
+0007F00001FC000FE00000FE001FC000003FC0FF0000000FFFFC00000000FFC000002A297CA833
+>I<FFFFFFF800FFFFFFFF00FFFFFFFFC003FC003FE003FC0007F003FC0003F803FC0003FC03FC
+0001FC03FC0001FE03FC0001FE03FC0001FE03FC0001FE03FC0001FE03FC0001FE03FC0001FE03
+FC0001FC03FC0003FC03FC0003F803FC0007F003FC003FE003FFFFFF8003FFFFFE0003FC000000
+03FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0000
+0003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000FFFFF0
+0000FFFFF00000FFFFF0000027297EA82E>I<FFFFFFE00000FFFFFFFE0000FFFFFFFF800003FC
+003FE00003FC000FF00003FC0007F80003FC0003FC0003FC0001FC0003FC0001FE0003FC0001FE
+0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FC0003FC0003F80003FC
+0007F80003FC000FE00003FC003FC00003FFFFFE000003FFFFFE000003FC00FF800003FC003FC0
+0003FC001FE00003FC000FF00003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC
+0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80E03FC0007F8
+0E03FC0003F80E03FC0001FC1CFFFFF000FE1CFFFFF0007FF8FFFFF0000FE02F297EA832>82
+D<00FF806003FFF0E00FFFF8E01F80FDE03F001FE03E0007E07C0003E07C0003E0FC0001E0FC00
+01E0FC0000E0FE0000E0FE0000E0FF000000FFC000007FFC00007FFFE0003FFFF8001FFFFE001F
+FFFF0007FFFF8003FFFFC000FFFFC0000FFFE000007FE000001FF000000FF0000007F0E00003F0
+E00003F0E00003F0E00003F0F00003E0F00003E0F80007E0FC0007C0FF000F80FFE03F80E3FFFE
+00E1FFFC00C01FF0001C297CA825>I<7FFFFFFFFF807FFFFFFFFF807FFFFFFFFF807F807F807F
+807C007F800F8078007F80078078007F80078070007F800380F0007F8003C0F0007F8003C0E000
+7F8001C0E0007F8001C0E0007F8001C0E0007F8001C0E0007F8001C000007F80000000007F8000
+0000007F80000000007F80000000007F80000000007F80000000007F80000000007F8000000000
+7F80000000007F80000000007F80000000007F80000000007F80000000007F80000000007F8000
+0000007F80000000007F80000000007F80000000007F80000000007F80000000007F8000000000
+7F80000000FFFFFFC00000FFFFFFC00000FFFFFFC0002A287EA72F>I<FFFFF000FFFEFFFFF000
+FFFEFFFFF000FFFE03FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003
+FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000
+038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003
+FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000
+038003FC0000038003FC0000038003FC0000038001FC0000070001FE0000070000FE00000E0000
+7F00000E00003F00003C00001FC0007800000FF003F0000007FFFFE0000000FFFF800000001FFC
+00002F297EA834>I<FFFFF0007FFFFFFFF0007FFFFFFFF0007FFF03FE000001C001FE00000380
+01FE0000038001FF0000078000FF0000070000FF80000F00007F80000E00007FC0000E00003FC0
+001C00003FC0001C00003FE0003C00001FE0003800001FF0007800000FF0007000000FF8007000
+0007F800E0000007F800E0000003FC01C0000003FC01C0000003FE03C0000001FE0380000001FF
+0780000000FF0700000000FF87000000007F8E000000007F8E000000007FDE000000003FDC0000
+00003FFC000000001FF8000000001FF8000000000FF0000000000FF0000000000FF00000000007
+E00000000007E00000000003C00000000003C0000030297FA833>I<FFFFE07FFFE01FFFC0FFFF
+E07FFFE01FFFC0FFFFE07FFFE01FFFC003FC0003FC0000700003FC0003FC0000700003FE0001FE
+0000700001FE0001FE0000E00001FE0001FE0000E00001FF0001FF0001E00000FF0001FF0001C0
+0000FF0003FF8001C00000FF8003FF8003C000007F8003FF80038000007F8007FFC0038000003F
+C0073FC0070000003FC0073FC0070000003FE00E1FE00F0000001FE00E1FE00E0000001FE00E1F
+F00E0000001FF01C0FF01E0000000FF01C0FF01C0000000FF03C0FF81C00000007F83807F83800
+000007F83807F83800000007F87807FC3800000003FC7003FC7000000003FC7003FC7000000003
+FEE001FEF000000001FEE001FEE000000001FFE001FFE000000001FFC000FFE000000000FFC000
+FFC000000000FFC000FFC0000000007F80007F80000000007F80007F80000000007F80007F8000
+0000003F00003F00000000003F00003F00000000003E00001F00000000001E00001E0000000000
+1E00001E00000042297FA845>I<020007000E001C00180030003000600060006000C000C000DF
+00FF80FFC0FFC0FFC07FC07FC03F800F000A157CA913>96 D<03FF80000FFFF0001F01FC003F80
+FE003F807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001
+FC3F800FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F80
+7E00DF803F839FFC1FFE0FFC03FC03FC1E1B7E9A21>I<FFE00000FFE00000FFE000000FE00000
+0FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000
+000FE000000FE1FE000FEFFF800FFE07E00FF803F00FF001F80FE000FC0FE000FC0FE0007E0FE0
+007E0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007E0F
+E0007E0FE0007E0FE000FC0FE000FC0FF001F80FF803F00F9C0FE00F0FFF800E01FC00202A7EA9
+25>I<003FF00001FFFC0003F03E000FC07F001F807F003F007F003F007F007F003E007E000000
+7E000000FE000000FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000
+007F0000003F0003803F8003801F8007000FE00E0003F83C0001FFF800003FC000191B7E9A1E>
+I<00007FF000007FF000007FF0000007F0000007F0000007F0000007F0000007F0000007F00000
+07F0000007F0000007F0000007F0000007F0000007F0003F87F001FFF7F007F03FF00FC00FF01F
+8007F03F0007F03F0007F07E0007F07E0007F07E0007F0FE0007F0FE0007F0FE0007F0FE0007F0
+FE0007F0FE0007F0FE0007F0FE0007F07E0007F07E0007F03F0007F03F0007F01F800FF00FC01F
+F007E07FFF01FFE7FF007F87FF202A7EA925>I<003FC00001FFF00003E07C000F803E001F801F
+001F001F003F000F807E000F807E000FC07E000FC0FE0007C0FE0007C0FFFFFFC0FFFFFFC0FE00
+0000FE000000FE0000007E0000007E0000007F0000003F0001C01F0001C00F80038007C0070003
+F01E0000FFFC00003FE0001A1B7E9A1F>I<0007F8003FFC007E3E01FC7F03F87F03F07F07F07F
+07F03E07F00007F00007F00007F00007F00007F00007F000FFFFC0FFFFC0FFFFC007F00007F000
+07F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F000
+07F00007F00007F00007F00007F00007F0007FFF807FFF807FFF80182A7EA915>I<00FF80F003
+FFE3F80FC1FE1C1F007C7C3F007E7C3E003E107E003F007E003F007E003F007E003F007E003F00
+7E003F003E003E003F007E001F007C000FC1F8000BFFE00018FF80001800000038000000380000
+003C0000003FFFF8003FFFFF001FFFFFC00FFFFFE007FFFFF01FFFFFF03C0007F07C0001F8F800
+00F8F80000F8F80000F8F80000F87C0001F07C0001F03F0007E00FC01F8007FFFF00007FF0001E
+287E9A22>I<FFE00000FFE00000FFE000000FE000000FE000000FE000000FE000000FE000000F
+E000000FE000000FE000000FE000000FE000000FE000000FE000000FE07E000FE1FF800FE30FC0
+0FE40FE00FE807E00FF807F00FF007F00FF007F00FE007F00FE007F00FE007F00FE007F00FE007
+F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE0
+07F00FE007F0FFFE3FFFFFFE3FFFFFFE3FFF202A7DA925>I<07000F801FC03FE03FE03FE01FC0
+0F8007000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00F
+E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>
+I<FFE00000FFE00000FFE000000FE000000FE000000FE000000FE000000FE000000FE000000FE0
+00000FE000000FE000000FE000000FE000000FE000000FE01FFC0FE01FFC0FE01FFC0FE007800F
+E00F000FE01E000FE03C000FE078000FE0E0000FE3C0000FE7C0000FEFE0000FFFF0000FFFF800
+0FF3F8000FE1FC000FC0FE000FC07F000FC07F000FC03F800FC01FC00FC00FE00FC00FE00FC007
+F0FFFC1FFFFFFC1FFFFFFC1FFF202A7FA923>107 D<FFE0FFE0FFE00FE00FE00FE00FE00FE00F
+E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0
+0FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2A7EA912>I<FFC07F00
+1FC000FFC1FFC07FF000FFC307E0C1F8000FC407F101FC000FC803F200FC000FD803FE00FE000F
+D003FC00FE000FD003FC00FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800
+FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE0
+03F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE
+000FE003F800FE00FFFE3FFF8FFFE0FFFE3FFF8FFFE0FFFE3FFF8FFFE0331B7D9A38>I<FFC07E
+00FFC1FF80FFC30FC00FC40FE00FC807E00FD807F00FD007F00FD007F00FE007F00FE007F00FE0
+07F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00F
+E007F00FE007F00FE007F00FE007F0FFFE3FFFFFFE3FFFFFFE3FFF201B7D9A25>I<003FE00001
+FFFC0003F07E000FC01F801F800FC03F0007E03F0007E07E0003F07E0003F07E0003F0FE0003F8
+FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F87E0003F07E0003F03F0007
+E03F0007E01F800FC00FC01F8007F07F0001FFFC00003FE0001D1B7E9A22>I<FFE1FE00FFEFFF
+80FFFE0FE00FF803F00FF001F80FE001FC0FE000FC0FE000FE0FE000FE0FE0007F0FE0007F0FE0
+007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007E0FE000FE0FE000FE0FE000FC0F
+E001FC0FF001F80FF807F00FFC0FE00FEFFF800FE1FC000FE000000FE000000FE000000FE00000
+0FE000000FE000000FE000000FE000000FE00000FFFE0000FFFE0000FFFE000020277E9A25>I<
+FFC1F0FFC7FCFFC63E0FCC7F0FD87F0FD07F0FD07F0FF03E0FE0000FE0000FE0000FE0000FE000
+0FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE000FFFF00FFFF00
+FFFF00181B7F9A1B>114 D<03FE300FFFF03E03F07800F07000F0F00070F00070F80070FE0000
+FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF80007FC0000FCE0007CE0003CF0003CF00038
+F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B>I<00E00000E00000E00000E00001E00001E0
+0001E00003E00003E00007E0000FE0001FFFE0FFFFE0FFFFE00FE0000FE0000FE0000FE0000FE0
+000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0700FE0700FE0700FE0700FE0
+700FE0700FE07007F0E003F0C001FF80007F0014267FA51A>I<FFE07FF0FFE07FF0FFE07FF00F
+E007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F0
+0FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE00FF00FE00F
+F007E017F003F067FF01FFC7FF007F87FF201B7D9A25>I<FFFC03FFFFFC03FFFFFC03FF0FF000
+F007F000E007F800E003F801C003F801C003FC03C001FC038001FE078000FE070000FF0700007F
+0E00007F0E00007F9E00003F9C00003FFC00001FF800001FF800000FF000000FF000000FF00000
+07E0000007E0000003C0000003C000201B7F9A23>I<FFFC7FFC1FFCFFFC7FFC1FFCFFFC7FFC1F
+FC0FE00FE001C007F007E0038007F007E0038007F807F0078003F807F0070003F80FF8070003FC
+0FF80F0001FC0FF80E0001FC1FFC0E0000FE1CFC1C0000FE1CFE1C0000FF387E3C00007F387E38
+00007F787F3800003FF03F7000003FF03FF000003FE01FF000001FE01FE000001FE01FE000000F
+C00FC000000FC00FC000000F8007C0000007800780000007800780002E1B7F9A31>I<FFFC1FFE
+FFFC1FFEFFFC1FFE07F0038003F8078003FC0F0001FE1E0000FE3C00007F3800007FF800003FF0
+00001FE000000FE000000FF0000007F800000FF800001FFC00003CFE000038FF0000787F0000F0
+3F8001E01FC003C01FE003800FE0FFF03FFFFFF03FFFFFF03FFF201B7F9A23>I<FFFC03FFFFFC
+03FFFFFC03FF0FF000F007F000E007F800E003F801C003F801C003FC03C001FC038001FE078000
+FE070000FF0700007F0E00007F0E00007F9E00003F9C00003FFC00001FF800001FF800000FF000
+000FF000000FF0000007E0000007E0000003C0000003C000000380000003800000078000380700
+007C0F0000FE0E0000FE1E0000FE1C0000FE38000074F000003FE000000F80000020277F9A23>
+I E /Fr 22 118 df<0F003FC07FE07FE0FFF0FFF0FFF0FFF07FE07FE03FC00F000C0C798B1B>
+46 D<0000000F80000000000F80000000001F80000000003F80000000007F8000000000FF8000
+000000FF8000000001FF8000000003FF8000000007FF8000000007FF800000000FFF800000001E
+FF800000003EFF800000007CFF8000000078FF80000000F0FF80000001E0FF80000003E0FF8000
+0003C0FF8000000780FF8000000F00FF8000001F00FF8000003E00FF8000003C00FF8000007800
+FF800000F000FF800001F000FF800001E000FF800003C000FF8000078000FF80000F8000FF8000
+1F0000FF80001E0000FF80003C0000FF8000780000FF8000F80000FF8000FFFFFFFFFF80FFFFFF
+FFFF80FFFFFFFFFF80FFFFFFFFFF80000001FF8000000001FF8000000001FF8000000001FF8000
+000001FF8000000001FF8000000001FF8000000001FF8000000001FF8000000001FF80000003FF
+FFFF800003FFFFFF800003FFFFFF800003FFFFFF8029377DB630>52 D<00000001E00000000000
+000003F00000000000000003F00000000000000007F80000000000000007F80000000000000007
+F8000000000000000FFC000000000000000FFC000000000000001FFE000000000000001FFE0000
+00000000001FFE000000000000003FFF000000000000003FFF000000000000007FFF8000000000
+00007BFF800000000000007BFF80000000000000F3FFC0000000000000F1FFC0000000000001F1
+FFE0000000000001E0FFE0000000000003E0FFF0000000000003C0FFF0000000000003C07FF000
+0000000007C07FF8000000000007803FF800000000000F803FFC00000000000F001FFC00000000
+000F001FFC00000000001F001FFE00000000001E000FFE00000000003E000FFF00000000003C00
+07FF00000000003C0007FF0000000000780007FF8000000000780003FF8000000000F80003FFC0
+00000000F00001FFC000000000F00001FFC000000001FFFFFFFFE000000001FFFFFFFFE0000000
+03FFFFFFFFF000000003FFFFFFFFF000000007C000007FF8000000078000007FF8000000078000
+003FF80000000F8000003FFC0000000F0000001FFC0000001F0000001FFE0000001E0000000FFE
+0000001E0000000FFE0000003E0000000FFF0000003C00000007FF0000007C00000007FF800000
+7800000003FF800000FC00000003FF8000FFFFF00003FFFFFFC0FFFFF00003FFFFFFC0FFFFF000
+03FFFFFFC0FFFFF00003FFFFFFC0423B7DBA49>65 D<FFFFFFFFFF800000FFFFFFFFFFF80000FF
+FFFFFFFFFF0000FFFFFFFFFFFF8000007FE00003FFE000007FE00000FFF000007FE000003FF800
+007FE000001FFC00007FE000001FFC00007FE000000FFE00007FE000000FFE00007FE000000FFF
+00007FE0000007FF00007FE0000007FF00007FE0000007FF00007FE0000007FF00007FE0000007
+FF00007FE0000007FF00007FE000000FFE00007FE000000FFE00007FE000000FFE00007FE00000
+1FFC00007FE000003FF800007FE000003FF000007FE00000FFE000007FE00001FFC000007FE000
+0FFF0000007FFFFFFFFC0000007FFFFFFFFC0000007FFFFFFFFF8000007FE00000FFE000007FE0
+00003FF800007FE000000FFC00007FE000000FFE00007FE0000007FF00007FE0000003FF80007F
+E0000003FF80007FE0000001FFC0007FE0000001FFC0007FE0000001FFE0007FE0000001FFE000
+7FE0000001FFE0007FE0000001FFE0007FE0000001FFE0007FE0000001FFE0007FE0000001FFE0
+007FE0000001FFE0007FE0000001FFC0007FE0000003FFC0007FE0000003FF80007FE0000007FF
+80007FE000000FFF00007FE000001FFE00007FE000003FFC00007FE00001FFF800FFFFFFFFFFFF
+F000FFFFFFFFFFFFC000FFFFFFFFFFFF0000FFFFFFFFFFF000003B3B7CBA45>I<FFFFFFFFFF80
+0000FFFFFFFFFFF80000FFFFFFFFFFFF0000FFFFFFFFFFFFC000007FF00007FFE000007FF00000
+7FF800007FF000001FFC00007FF000000FFE00007FF0000003FF00007FF0000001FF80007FF000
+0000FFC0007FF00000007FE0007FF00000007FE0007FF00000003FF0007FF00000003FF8007FF0
+0000001FF8007FF00000001FF8007FF00000001FFC007FF00000001FFC007FF00000000FFE007F
+F00000000FFE007FF00000000FFE007FF00000000FFE007FF00000000FFE007FF00000000FFF00
+7FF00000000FFF007FF00000000FFF007FF00000000FFF007FF00000000FFF007FF00000000FFF
+007FF00000000FFF007FF00000000FFF007FF00000000FFF007FF00000000FFF007FF00000000F
+FF007FF00000000FFF007FF00000000FFE007FF00000000FFE007FF00000000FFE007FF0000000
+0FFE007FF00000000FFC007FF00000001FFC007FF00000001FFC007FF00000001FF8007FF00000
+003FF8007FF00000003FF0007FF00000007FF0007FF00000007FE0007FF0000000FFC0007FF000
+0001FFC0007FF0000003FF80007FF0000007FF00007FF000001FFE00007FF000007FF800007FF0
+0007FFF000FFFFFFFFFFFFC000FFFFFFFFFFFF0000FFFFFFFFFFF80000FFFFFFFFFF800000403B
+7CBA4A>68 D<FFFFF00000000003FFFFE0FFFFF80000000007FFFFE0FFFFF80000000007FFFFE0
+FFFFFC000000000FFFFFE0007FFC000000000FFFC000007FFC000000000FFFC000007BFE000000
+001EFFC000007BFE000000001EFFC0000079FF000000003CFFC0000079FF000000003CFFC00000
+78FF8000000078FFC0000078FF8000000078FFC0000078FF8000000078FFC00000787FC0000000
+F0FFC00000787FC0000000F0FFC00000783FE0000001E0FFC00000783FE0000001E0FFC0000078
+1FF0000003C0FFC00000781FF0000003C0FFC00000781FF0000003C0FFC00000780FF800000780
+FFC00000780FF800000780FFC000007807FC00000F00FFC000007807FC00000F00FFC000007803
+FE00001E00FFC000007803FE00001E00FFC000007803FE00001E00FFC000007801FF00003C00FF
+C000007801FF00003C00FFC000007800FF80007800FFC000007800FF80007800FFC0000078007F
+C000F000FFC0000078007FC000F000FFC0000078007FC000F000FFC0000078003FE001E000FFC0
+000078003FE001E000FFC0000078001FF003C000FFC0000078001FF003C000FFC0000078000FF8
+078000FFC0000078000FF8078000FFC00000780007FC0F0000FFC00000780007FC0F0000FFC000
+00780007FC0F0000FFC00000780003FE1E0000FFC00000780003FE1E0000FFC00000780001FF3C
+0000FFC00000780001FF3C0000FFC00000780000FFF80000FFC00000780000FFF80000FFC00000
+780000FFF80000FFC000007800007FF00000FFC000007800007FF00000FFC000007800003FE000
+00FFC000007800003FE00000FFC00000FC00001FC00000FFC000FFFFFC001FC001FFFFFFE0FFFF
+FC001FC001FFFFFFE0FFFFFC000F8001FFFFFFE0FFFFFC00070001FFFFFFE0533B7CBA5C>77
+D<FFFFFFFFF800000000FFFFFFFFFFC0000000FFFFFFFFFFF8000000FFFFFFFFFFFE000000007F
+F0001FFF000000007FF00003FFC00000007FF00000FFE00000007FF000007FF00000007FF00000
+3FF80000007FF000003FF80000007FF000003FFC0000007FF000001FFC0000007FF000001FFC00
+00007FF000001FFE0000007FF000001FFE0000007FF000001FFE0000007FF000001FFE0000007F
+F000001FFE0000007FF000001FFE0000007FF000001FFC0000007FF000001FFC0000007FF00000
+3FFC0000007FF000003FF80000007FF000007FF00000007FF000007FE00000007FF00001FFC000
+00007FF00003FF800000007FF0001FFE000000007FFFFFFFF8000000007FFFFFFFC0000000007F
+FFFFFFC0000000007FF0007FF0000000007FF0001FF8000000007FF0000FFC000000007FF00007
+FE000000007FF00003FF000000007FF00003FF800000007FF00001FF800000007FF00001FF8000
+00007FF00001FFC00000007FF00001FFC00000007FF00001FFC00000007FF00001FFC00000007F
+F00001FFC00000007FF00001FFE00000007FF00001FFE00000007FF00001FFE00000007FF00001
+FFE00000007FF00001FFE00000007FF00001FFE001E0007FF00001FFE001E0007FF00000FFF001
+E0007FF00000FFF001E0007FF00000FFF003C0007FF000007FF803C0FFFFFFF8003FFC0780FFFF
+FFF8001FFE0F80FFFFFFF80007FFFF00FFFFFFF80001FFFC000000000000001FF000433C7CBA48
+>82 D<0003FF000300001FFFE0070000FFFFFC0F0001FFFFFE1F0003FE00FF3F0007F0001FFF00
+0FE00007FF001FC00001FF003F800000FF003F800000FF007F0000007F007F0000003F007F0000
+003F00FF0000001F00FF0000001F00FF0000001F00FF8000000F00FF8000000F00FFC000000F00
+FFC000000F00FFF0000000007FFC000000007FFF800000003FFFF80000003FFFFFC000001FFFFF
+FC00001FFFFFFF00000FFFFFFFC00007FFFFFFF00003FFFFFFF80000FFFFFFFC00007FFFFFFE00
+001FFFFFFE000003FFFFFF0000001FFFFF80000001FFFF800000000FFFC000000003FFC0000000
+00FFC0000000007FE0000000007FE0700000003FE0F00000003FE0F00000001FE0F00000001FE0
+F00000001FE0F80000001FE0F80000001FC0F80000001FC0FC0000001FC0FC0000003F80FE0000
+003F80FF0000003F00FFC000007F00FFE00000FE00FFFC0001FC00FDFFC00FF800F87FFFFFF000
+F01FFFFFC000E003FFFF0000C0003FF800002B3D7BBB36>I<3FFFFFFFFFFFFFC03FFFFFFFFFFF
+FFC03FFFFFFFFFFFFFC03FFFFFFFFFFFFFC03FF8007FF001FFC07FC0007FF0003FE07F80007FF0
+001FE07F00007FF0000FE07E00007FF00007E07C00007FF00003E07C00007FF00003E07C00007F
+F00003E07800007FF00001E07800007FF00001E07800007FF00001E07800007FF00001E0F00000
+7FF00000F0F000007FF00000F0F000007FF00000F0F000007FF00000F0F000007FF00000F00000
+007FF00000000000007FF00000000000007FF00000000000007FF00000000000007FF000000000
+00007FF00000000000007FF00000000000007FF00000000000007FF00000000000007FF0000000
+0000007FF00000000000007FF00000000000007FF00000000000007FF00000000000007FF00000
+000000007FF00000000000007FF00000000000007FF00000000000007FF00000000000007FF000
+00000000007FF00000000000007FF00000000000007FF00000000000007FF00000000000007FF0
+0000000000007FF00000000000007FF00000000000007FF00000000000007FF00000000000007F
+F00000000000007FF00000000000007FF00000000000007FF0000000000FFFFFFFFF8000000FFF
+FFFFFF8000000FFFFFFFFF8000000FFFFFFFFF80003C3A7DB943>I<003FFE00000001FFFFE000
+0007FFFFF800000FE007FC00000FF001FE00001FF800FF00001FF8007F80001FF8007FC0001FF8
+003FC0000FF0003FE00007E0003FE00003C0003FE0000000003FE0000000003FE0000000003FE0
+000000003FE0000000FFFFE000001FFFFFE000007FF83FE00003FF803FE00007FC003FE0000FF0
+003FE0001FE0003FE0003FE0003FE0007FC0003FE0007FC0003FE000FF80003FE000FF80003FE0
+00FF80003FE000FF80003FE000FF80007FE0007FC0007FE0007FC000DFE0003FE0039FF0001FF8
+0F0FFFE007FFFE0FFFE001FFFC07FFE0003FE000FFE02B267DA52F>97 D<0001FFF000000FFFFE
+00003FFFFF8000FF801FC001FE003FC003FC007FE007F8007FE00FF0007FE01FF0007FE03FE000
+3FC03FE0001F807FE0000F007FC00000007FC0000000FFC0000000FFC0000000FFC0000000FFC0
+000000FFC0000000FFC0000000FFC0000000FFC0000000FFC0000000FFC00000007FC00000007F
+E00000007FE00000003FE00000003FF00000F01FF00000F00FF80001E007F80001E003FC0003C0
+01FF000F8000FFC03F00003FFFFE00000FFFF8000001FFC00024267DA52B>99
+D<000000003F800000003FFF800000003FFF800000003FFF800000003FFF8000000001FF800000
+0000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF
+8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF800000
+0000FF8000000000FF8000000000FF800000FF80FF80000FFFF0FF80003FFFFCFF8000FFC03FFF
+8001FE000FFF8003FC0003FF8007F80001FF800FF00000FF801FF00000FF803FE00000FF803FE0
+0000FF807FE00000FF807FC00000FF807FC00000FF807FC00000FF80FFC00000FF80FFC00000FF
+80FFC00000FF80FFC00000FF80FFC00000FF80FFC00000FF80FFC00000FF80FFC00000FF80FFC0
+0000FF807FC00000FF807FC00000FF807FC00000FF803FE00000FF803FE00000FF801FE00000FF
+800FF00001FF8007F80003FF8003F80007FF8001FE001FFFC000FF807EFFFE007FFFF8FFFE000F
+FFE0FFFE0001FF00FFFE2F3C7DBB36>I<0001FF8000000FFFF000007FFFFC0000FF81FE0003FE
+007F8007F8003F800FF0001FC00FF0000FE01FE0000FE03FE0000FF03FE00007F07FC00007F07F
+C00007F87FC00007F8FFC00007F8FFC00007F8FFFFFFFFF8FFFFFFFFF8FFFFFFFFF8FFC0000000
+FFC0000000FFC0000000FFC00000007FC00000007FC00000007FC00000003FE00000003FE00000
+781FE00000781FF00000780FF00000F007F80001F003FC0003E001FE000FC000FFC07F80003FFF
+FE00000FFFF8000000FFC00025267DA52C>I<00001FF0000000FFFC000003FFFF00000FF83F80
+001FE07F80003FC0FFC0007F80FFC000FF80FFC000FF80FFC001FF007F8001FF003F0001FF001E
+0001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00
+000001FF00000001FF000000FFFFFF8000FFFFFF8000FFFFFF8000FFFFFF800001FF00000001FF
+00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001
+FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF000000
+01FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF00000001FF0000
+0001FF00000001FF00000001FF00000001FF00000001FF0000007FFFFE00007FFFFE00007FFFFE
+00007FFFFE0000223C7DBB1E>I<00FE00000000FFFE00000000FFFE00000000FFFE00000000FF
+FE0000000007FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000
+000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003
+FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE00FF800003FE03FF
+F00003FE0FFFF80003FE1E03FC0003FE3801FE0003FE6001FF0003FEC000FF0003FFC000FF8003
+FF8000FF8003FF0000FF8003FF0000FF8003FF0000FF8003FE0000FF8003FE0000FF8003FE0000
+FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003
+FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000
+FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF80FF
+FFF83FFFFEFFFFF83FFFFEFFFFF83FFFFEFFFFF83FFFFE2F3C7CBB36>104
+D<00FE00FFFE00FFFE00FFFE00FFFE0007FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE
+0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE
+0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE
+0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE
+0003FE0003FE0003FE0003FE00FFFFF8FFFFF8FFFFF8FFFFF8153C7DBB1A>108
+D<01FC007FC0000FF80000FFFC03FFF8007FFF0000FFFC0FFFFC01FFFF8000FFFC1F03FE03E07F
+C000FFFC3800FF07001FE00007FC7000FF8E001FF00003FCC0007F98000FF00003FDC0007FF800
+0FF80003FD80007FF0000FF80003FF00007FE0000FF80003FF00007FE0000FF80003FF00007FE0
+000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007F
+C0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE0000
+7FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00
+007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE
+00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF80003
+FE00007FC0000FF80003FE00007FC0000FF80003FE00007FC0000FF800FFFFF81FFFFF03FFFFE0
+FFFFF81FFFFF03FFFFE0FFFFF81FFFFF03FFFFE0FFFFF81FFFFF03FFFFE04B267CA552>I<01FC
+00FF8000FFFC03FFF000FFFC0FFFF800FFFC1E03FC00FFFC3801FE0007FC6001FF0003FCC000FF
+0003FDC000FF8003FD8000FF8003FF0000FF8003FF0000FF8003FF0000FF8003FE0000FF8003FE
+0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF
+8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE
+0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF
+8003FE0000FF80FFFFF83FFFFEFFFFF83FFFFEFFFFF83FFFFEFFFFF83FFFFE2F267CA536>I<00
+01FFC00000000FFFF80000007FFFFF000000FF80FF800003FE003FE00007F8000FF0000FF00007
+F8000FF00007F8001FE00003FC003FE00003FE003FE00003FE007FC00001FF007FC00001FF007F
+C00001FF007FC00001FF00FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001
+FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF807FC00001FF007FC00001FF007F
+C00001FF003FE00003FE003FE00003FE001FE00003FC001FF00007FC000FF00007F80007F8000F
+F00003FE003FE00000FF80FF8000007FFFFF0000000FFFF800000001FFC0000029267DA530>I<
+01FC03F000FFFC0FFC00FFFC1FFF00FFFC3C3F80FFFC707F8007FCE0FFC003FCC0FFC003FD80FF
+C003FD80FFC003FF807F8003FF003F0003FF001E0003FF00000003FE00000003FE00000003FE00
+000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE
+00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003
+FE00000003FE00000003FE000000FFFFFC0000FFFFFC0000FFFFFC0000FFFFFC000022267DA528
+>114 D<000F0000000F0000000F0000000F0000000F0000001F0000001F0000001F0000001F00
+00003F0000003F0000007F0000007F000000FF000001FF000003FF000007FF00001FFFFFF0FFFF
+FFF0FFFFFFF0FFFFFFF001FF000001FF000001FF000001FF000001FF000001FF000001FF000001
+FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF0000
+01FF000001FF000001FF003C01FF003C01FF003C01FF003C01FF003C01FF003C01FF003C01FF00
+3C00FF007800FF8078007F80F0003FC1E0001FFFC0000FFF800001FE001E377EB626>116
+D<00FE00003F80FFFE003FFF80FFFE003FFF80FFFE003FFF80FFFE003FFF8007FE0001FF8003FE
+0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF
+8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE
+0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF8003FE0000FF
+8003FE0000FF8003FE0000FF8003FE0001FF8003FE0001FF8003FE0003FF8001FE0003FF8001FE
+0006FF8000FF000CFFC0007F8078FFFE003FFFF0FFFE001FFFE0FFFE0003FF80FFFE2F267CA536
+>I E end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 300dpi
+TeXDict begin
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 871 1042 a Fr(Amd)399 1229 y(The)33 b(4.4)g(BSD)f(Automoun)m(ter)592
+1415 y(Reference)h(Man)m(ual)702 1602 y Fq(Jan-Simon)24 b(P)n(endry)937
+1727 y Fp(and)767 1851 y Fq(Nic)n(k)f(Williams)719 2163 y Fo(Last)15
+b(up)q(dated)h(Marc)o(h)e(1991)510 2225 y(Do)q(cumen)o(tation)h(for)g(soft)o
+(w)o(are)e(revision)k(5.3)d(Alpha)p eop
+%%Page: 2 2
+2 1 bop 0 295 a Fo(Cop)o(yrigh)o(t)226 294 y(c)214 295 y Fn(\015)15
+b Fo(1989)f(Jan-Simon)j(P)o(endry)0 370 y(Cop)o(yrigh)o(t)226
+369 y(c)214 370 y Fn(\015)e Fo(1989)f(Imp)q(erial)j(College)f(of)f(Science,)i
+(T)l(ec)o(hnology)e(&)h(Medicine)0 445 y(Cop)o(yrigh)o(t)226
+444 y(c)214 445 y Fn(\015)f Fo(1989)f(The)i(Regen)o(ts)f(of)g(the)g(Univ)o
+(ersit)o(y)h(of)f(California.)0 582 y(All)h(Righ)o(ts)g(Reserv)o(ed.)0
+738 y(P)o(ermission)k(to)g(cop)o(y)f(this)i(do)q(cumen)o(t,)g(or)e(an)o(y)g
+(p)q(ortion)i(of)e(it,)i(as)e(necessary)h(for)g(use)g(of)f(this)h(soft)o(w)o
+(are)e(is)0 801 y(gran)o(ted)d(pro)o(vided)h(this)f(cop)o(yrigh)o(t)g(notice)
+h(and)f(statemen)o(t)f(of)h(p)q(ermission)i(are)e(included.)p
+eop
+%%Page: 1 3
+1 2 bop 0 -83 a Fo(Source)16 b(Distribution)1357 b(SMM:13-1)0
+158 y Fm(Preface)62 299 y Fo(This)11 b(man)o(ual)g(do)q(cumen)o(ts)g(the)f
+(use)h(of)f(the)h(4.4)f(BSD)g(automoun)o(ter|)p Fp(Amd)p Fo(.)18
+b(This)11 b(is)g(primarily)h(a)e(reference)0 349 y(man)o(ual.)20
+b(Unfortunately)l(,)15 b(no)g(tutorial)h(exists.)62 419 y(This)22
+b(man)o(ual)f(comes)f(in)i(t)o(w)o(o)e(forms:)30 b(the)21 b(published)i(form)
+d(and)h(the)g(Info)g(form.)36 b(The)21 b(Info)g(form)f(is)0
+469 y(for)f(on-line)i(p)q(erusal)f(with)g(the)g(INF)o(O)f(program)g(whic)o(h)
+h(is)g(distributed)h(along)e(with)h(GNU)f(Emacs.)32 b(Both)0
+519 y(forms)16 b(con)o(tain)h(substan)o(tially)h(the)f(same)f(text)h(and)g
+(are)f(generated)h(from)f(a)h(common)f(source)h(\014le,)h(whic)o(h)f(is)0
+569 y(distributed)g(with)e(the)h Fp(Amd)h Fo(source.)0 783
+y Fm(License)62 924 y Fp(Amd)f Fo(is)f(not)e(in)i(the)f(public)i(domain;)e
+(it)g(is)h(cop)o(yrigh)o(ted)f(and)g(there)g(are)f(restrictions)i(on)f(its)g
+(distribution.)62 994 y(Redistribution)k(and)d(use)g(in)h(source)f(and)g
+(binary)h(forms)e(are)g(p)q(ermitted)i(pro)o(vided)g(that:)j(\(1\))14
+b(source)h(dis-)0 1044 y(tributions)f(retain)g(this)g(en)o(tire)h(cop)o
+(yrigh)o(t)e(notice)h(and)g(commen)o(t,)f(and)h(\(2\))f(distributions)i
+(including)i(binaries)0 1094 y(displa)o(y)e(the)e(follo)o(wing)h(ac)o(kno)o
+(wledgemen)o(t:)19 b(\\This)14 b(pro)q(duct)g(includes)h(soft)o(w)o(are)d
+(dev)o(elop)q(ed)j(b)o(y)e(The)h(Univ)o(er-)0 1144 y(sit)o(y)f(of)g
+(California,)h(Berk)o(eley)g(and)f(its)h(Con)o(tributors")e(in)i(the)f(do)q
+(cumen)o(tation)g(or)g(other)g(materials)g(pro)o(vided)0 1193
+y(with)18 b(the)f(distribution)i(and)e(in)h(all)g(adv)o(ertising)g(materials)
+f(men)o(tioning)i(features)d(or)h(use)h(of)e(this)i(soft)o(w)o(are.)0
+1243 y(neither)h(the)e(name)h(of)f(the)g(Univ)o(ersit)o(y)i(nor)e(the)g
+(names)h(of)f(its)h(Con)o(tributors)f(ma)o(y)f(b)q(e)j(used)f(to)f(endorse)g
+(or)0 1293 y(promote)d(pro)q(ducts)i(deriv)o(ed)g(from)f(this)g(soft)o(w)o
+(are)f(without)h(sp)q(eci\014c)i(prior)e(written)g(p)q(ermission.)62
+1364 y(THIS)h(SOFTW)-5 b(ARE)15 b(IS)g(PR)o(O)o(VIDED)g(\\AS)g(IS")g(AND)g
+(WITHOUT)g(ANY)g(EXPRESS)h(OR)g(IMPLIED)0 1413 y(W)-5 b(ARRANTIES,)21
+b(INCLUDING,)e(WITHOUT)h(LIMIT)l(A)l(TION,)i(THE)d(IMPLIED)h(W)-5
+b(ARRANTIES)21 b(OF)0 1463 y(MER)o(CHANT)l(ABILITY)c(AND)e(FITNESS)g(F)o(OR)h
+(A)f(P)l(AR)l(TICULAR)i(PURPOSE.)0 1678 y Fm(Source)e(Distribution)62
+1818 y Fo(If)g(y)o(ou)f(ha)o(v)o(e)h(access)f(to)g(the)h(In)o(ternet,)g(y)o
+(ou)f(can)h(get)f(the)g(latest)h(distribution)h(v)o(ersion)f(of)f
+Fp(Amd)j Fo(from)c(host)0 1868 y(`)p Fl(usc.edu)p Fo(')g(using)i(anon)o
+(ymous)g(FTP)l(.)e(Mo)o(v)o(e)h(to)g(the)h(directory)g(`)p
+Fl(/pub/amd)p Fo(')e(on)h(that)g(host)h(and)g(fetc)o(h)f(the)h(\014le)0
+1918 y(`)p Fl(amd.tar.Z)p Fo('.)62 1988 y(If)23 b(y)o(ou)e(are)h(in)h(the)g
+(UK,)f(y)o(ou)g(can)g(get)g(the)g(latest)g(distribution)i(v)o(ersion)e(of)g
+Fp(Amd)i Fo(from)d(the)h(UKnet)0 2038 y(info-serv)o(er.)e(Start)14
+b(b)o(y)i(sending)g(email)g(to)f(`)p Fl(info-server@doc.ic.ac)o(.uk)p
+Fo('.)62 2109 y(Sites)g(on)f(the)g(UK)g(JANET)g(net)o(w)o(ork)f(can)h(get)g
+(the)g(latest)f(distribution)j(b)o(y)e(using)g(anon)o(ymous)g(NIFTP)g(to)0
+2159 y(fetc)o(h)h(the)g(\014le)i(`)p Fl(<AMD>amd.tar.Z)p Fo(')12
+b(from)j(host)f(`)p Fl(uk.ac.imperial.doc.src)p Fo('.)62 2229
+y(Revision)j(5.2)d(w)o(as)h(part)f(of)h(the)g(4.3)g(BSD)g(Reno)h
+(distribution.)62 2300 y(Revision)c(5.3bsdnet,)f(a)f(late)g(alpha)h(v)o
+(ersion)f(of)g(5.3,)g(w)o(as)g(part)f(of)h(the)g(BSD)h(net)o(w)o(ork)e(v)o
+(ersion)h(2)g(distribution)0 2504 y Fq(Bug)15 b(Rep)r(orts)62
+2595 y Fo(Send)i(all)f(bug)g(rep)q(orts)f(to)f(`)p Fl(jsp@doc.ic.ac.uk)p
+Fo(')f(quoting)j(the)f(details)i(of)e(the)g(release)h(and)g(y)o(our)f
+(con\014g-)0 2645 y(uration.)20 b(These)15 b(can)h(b)q(e)g(obtained)g(b)o(y)f
+(running)h(the)f(command)g(`)p Fl(amd)g(-v)p Fo('.)p eop
+%%Page: 2 4
+2 3 bop 15 -83 a Fo(SMM:13-2)912 b(4.4)15 b(BSD)g(Automoun)o(ter)f(Reference)
+j(Man)o(ual)0 158 y Fq(Mailing)g(List)62 250 y Fo(There)11
+b(is)g(a)f(mailing)i(list)f(for)f(p)q(eople)i(in)o(terested)f(in)h(k)o
+(eeping)f(upto)q(date)g(with)f(dev)o(elopmen)o(ts.)19 b(T)l(o)11
+b(subscrib)q(e,)0 299 y(send)16 b(a)f(note)g(to)f(`)p Fl
+(amd-workers-request@acl.l)o(anl.gov)o Fo('.)0 533 y Fm(In)n(tro)r(duction)62
+674 y Fo(An)e Fp(automoun)o(ter)i Fo(main)o(tains)e(a)f(cac)o(he)h(of)g(moun)
+o(ted)f(\014lesystems.)20 b(Filesystems)12 b(are)f(moun)o(ted)h(on)f(demand)0
+724 y(when)16 b(they)f(are)g(\014rst)g(referenced,)g(and)h(unmoun)o(ted)f
+(after)g(a)g(p)q(erio)q(d)h(of)f(inactivit)o(y)l(.)62 795 y
+Fp(Amd)k Fo(ma)o(y)d(b)q(e)h(used)g(as)g(a)f(replacemen)o(t)h(for)f(Sun's)h
+(automoun)o(ter.)23 b(The)17 b(c)o(hoice)h(of)e(whic)o(h)h(\014lesystem)h(to)
+0 844 y(moun)o(t)10 b(can)h(b)q(e)h(con)o(trolled)f(dynamically)i(with)e
+Fp(selectors)p Fo(.)19 b(Selectors)11 b(allo)o(w)g(decisions)h(of)f(the)g
+(form)f(\\hostname)0 894 y(is)15 b Fp(this)p Fo(,")f(or)f(\\arc)o(hitecture)h
+(is)h(not)e Fp(that)p Fo(.")19 b(Selectors)c(ma)o(y)e(b)q(e)i(com)o(bined)g
+(arbitrarily)l(.)20 b Fp(Amd)c Fo(also)e(supp)q(orts)g(a)0
+944 y(v)m(ariet)o(y)e(of)f(\014lesystem)i(t)o(yp)q(es,)f(including)i(NFS,)e
+(UFS)f(and)h(the)g(no)o(v)o(el)g Fp(program)f Fo(\014lesystem.)19
+b(The)12 b(com)o(bination)0 994 y(of)22 b(selectors)h(and)g(m)o(ultiple)h
+(\014lesystem)f(t)o(yp)q(es)g(allo)o(ws)g(iden)o(tical)h(con\014guration)f
+(\014les)g(to)f(b)q(e)h(used)h(on)e(all)0 1044 y(mac)o(hines)16
+b(so)f(reducing)h(the)g(administrativ)o(e)f(o)o(v)o(erhead.)62
+1114 y Fp(Amd)h Fo(ensures)f(that)f(it)g(will)i(not)e(hang)g(if)g(a)g(remote)
+g(serv)o(er)g(go)q(es)g(do)o(wn.)19 b(Moreo)o(v)o(er,)12 b
+Fp(Amd)17 b Fo(can)d(determine)0 1164 y(when)f(a)f(remote)g(serv)o(er)g(has)g
+(b)q(ecome)h(inaccessible)i(and)d(then)h(moun)o(t)f(replacemen)o(t)h
+(\014lesystems)g(as)f(and)g(when)0 1214 y(they)j(b)q(ecome)h(a)o(v)m
+(ailable.)62 1284 y Fp(Amd)h Fo(con)o(tains)f(no)f(proprietary)g(source)g(co)
+q(de)h(and)f(has)g(b)q(een)i(p)q(orted)e(to)g(n)o(umerous)g(\015a)o(v)o(ours)
+f(of)h(Unix.)0 1516 y Fm(1)41 b(Ov)n(erview)62 1658 y Fp(Amd)20
+b Fo(main)o(tains)e(a)g(cac)o(he)g(of)f(moun)o(ted)h(\014lesystems.)28
+b(Filesystems)18 b(are)f Fp(demand-moun)o(ted)k Fo(when)d(they)0
+1708 y(are)12 b(\014rst)g(referenced,)i(and)e(unmoun)o(ted)h(after)f(a)g(p)q
+(erio)q(d)i(of)e(inactivit)o(y)l(.)20 b Fp(Amd)14 b Fo(ma)o(y)e(b)q(e)h(used)
+g(as)f(a)g(replacemen)o(t)0 1757 y(for)17 b(Sun's)g Fk(automoun)o(t)p
+Fo(\(8\))f(program.)25 b(It)18 b(con)o(tains)f(no)g(proprietary)h(source)f
+(co)q(de)h(and)f(has)h(b)q(een)g(p)q(orted)g(to)0 1807 y(n)o(umerous)d(\015a)
+o(v)o(ours)f(of)h(Unix.)21 b(See)16 b(Section)g(2.1)e([Supp)q(orted)i(Op)q
+(erating)g(Systems],)e(page)30 b(SMM:13-6.)62 1878 y Fp(Amd)25
+b Fo(w)o(as)c(designed)j(as)e(the)h(basis)g(for)f(exp)q(erimen)o(ting)i(with)
+e(\014lesystem)i(la)o(y)o(out)d(and)i(managemen)o(t.)0 1928
+y(Although)15 b Fp(Amd)i Fo(has)e(man)o(y)g(direct)g(applications)i(it)e(is)g
+(loaded)h(with)f(additional)i(features)d(whic)o(h)i(ha)o(v)o(e)f(little)0
+1977 y(practical)h(use.)21 b(A)o(t)15 b(some)g(p)q(oin)o(t)h(the)g(infrequen)
+o(tly)h(used)f(comp)q(onen)o(ts)f(ma)o(y)g(b)q(e)h(remo)o(v)o(ed)f(to)g
+(streamline)h(the)0 2027 y(pro)q(duction)g(system.)0 2234 y
+Fq(1.1)33 b(F)-6 b(undamen)n(tals)62 2325 y Fo(The)15 b(fundamen)o(tal)g
+(concept)f(b)q(ehind)j Fp(Amd)f Fo(is)f(the)f(abilit)o(y)i(to)d(separate)h
+(the)g(name)h(used)g(to)e(refer)h(to)g(a)g(\014le)0 2375 y(from)d(the)g(name)
+g(used)h(to)f(refer)g(to)g(its)g(ph)o(ysical)i(storage)d(lo)q(cation.)19
+b(This)12 b(allo)o(ws)g(the)f(same)g(\014les)i(to)d(b)q(e)i(accessed)0
+2425 y(with)g(the)h(same)f(name)g(regardless)g(of)g(where)g(in)h(the)f(net)o
+(w)o(ork)g(the)g(name)g(is)h(used.)19 b(This)13 b(is)f(v)o(ery)g(di\013eren)o
+(t)h(from)0 2475 y(placing)i(`)p Fl(/n/hostname)p Fo(')10 b(in)k(fron)o(t)f
+(of)f(the)i(pathname)f(since)h(that)f(includes)i(lo)q(cation)f(dep)q(enden)o
+(t)h(information)0 2525 y(whic)o(h)h(ma)o(y)f(c)o(hange)g(if)g(\014les)i(are)
+e(mo)o(v)o(ed)f(to)h(another)g(mac)o(hine.)62 2595 y(By)i(placing)i(the)e
+(required)h(mappings)f(in)h(a)e(cen)o(trally)i(administered)g(database,)f
+(\014lesystems)g(can)g(b)q(e)h(re-)0 2645 y(organised)d(without)h(requiring)g
+(c)o(hanges)f(to)g(con\014guration)g(\014les,)h(shell)h(scripts)e(and)h(so)e
+(on.)p eop
+%%Page: 3 5
+3 4 bop 0 -83 a Fo(Chapter)15 b(1:)k(Ov)o(erview)1328 b(SMM:13-3)0
+158 y Fq(1.2)33 b(Filesystems)15 b(and)h(V)-6 b(olumes)62 250
+y Fp(Amd)19 b Fo(views)e(the)g(w)o(orld)g(as)g(a)f(set)h(of)f(\014leserv)o
+(ers,)i(eac)o(h)f(con)o(taing)g(one)g(or)f(more)g(\014lesystems)i(where)f
+(eac)o(h)0 299 y(\014lesystem)g(con)o(tains)f(one)h(or)f(more)g
+Fp(v)o(olumes)p Fo(.)23 b(Here)17 b(the)f(term)g Fp(v)o(olume)j
+Fo(is)e(used)g(to)f(refer)g(to)g(a)g(coheren)o(t)g(set)0 349
+y(of)f(\014les)h(suc)o(h)f(as)g(a)g(user's)g(home)g(directory)h(or)e(a)h(T)
+899 359 y(E)925 349 y(X)g(distribution.)62 420 y(In)i(order)e(to)h(access)g
+(the)g(con)o(ten)o(ts)f(of)g(a)h(v)o(olume,)g Fp(Amd)i Fo(m)o(ust)d(b)q(e)i
+(told)f(in)g(whic)o(h)h(\014lesystem)g(the)f(v)o(olume)0 470
+y(resides)j(and)g(whic)o(h)g(host)g(o)o(wns)e(the)i(\014lesystem.)30
+b(By)19 b(default)g(the)g(host)f(is)h(assumed)f(to)g(b)q(e)i(lo)q(cal)f(and)g
+(the)0 519 y(v)o(olume)c(is)f(assumed)g(to)g(b)q(e)h(the)f(en)o(tire)h
+(\014lesystem.)20 b(If)14 b(a)g(\014lesystem)h(con)o(tains)f(more)g(than)g
+(one)g(v)o(olume,)h(then)0 569 y(a)e Fp(sublink)18 b Fo(is)13
+b(used)h(to)f(refer)g(to)f(the)h(sub-directory)h(within)h(the)e(\014lesystem)
+h(where)f(the)g(v)o(olume)h(can)f(b)q(e)h(found.)0 722 y Fq(1.3)33
+b(V)-6 b(olume)15 b(Naming)62 814 y Fo(V)l(olume)23 b(names)g(are)f
+(de\014ned)h(to)f(b)q(e)h(unique)g(across)f(the)g(en)o(tire)h(net)o(w)o(ork.)
+40 b(A)22 b(v)o(olume)h(name)f(is)h(the)0 864 y(pathname)17
+b(to)g(the)h(v)o(olume's)f(ro)q(ot)g(as)g(kno)o(wn)g(b)o(y)h(the)g(users)f
+(of)g(that)g(v)o(olume.)27 b(Since)19 b(this)f(name)g(uniquely)0
+913 y(iden)o(ti\014es)g(the)e(v)o(olume)h(con)o(ten)o(ts,)e(all)i(v)o(olumes)
+g(can)f(b)q(e)h(named)f(and)h(accessed)f(from)g(eac)o(h)g(host,)g(sub)s(ject)
+g(to)0 963 y(administrativ)o(e)g(con)o(trols.)62 1034 y(V)l(olumes)k(ma)o(y)e
+(b)q(e)h(replicated)h(or)e(duplicated.)32 b(Replicated)21 b(v)o(olumes)e(con)
+o(tain)g(iden)o(tical)h(copies)g(of)e(the)0 1084 y(same)11
+b(data)g(and)g(reside)i(at)d(t)o(w)o(o)g(or)h(more)g(lo)q(cations)h(in)h(the)
+e(net)o(w)o(ork.)18 b(Eac)o(h)11 b(of)g(the)g(replicated)i(v)o(olumes)f(can)f
+(b)q(e)0 1133 y(used)16 b(in)o(terc)o(hangeably)l(.)22 b(Duplicated)17
+b(v)o(olumes)f(eac)o(h)f(ha)o(v)o(e)g(the)h(same)f(name)g(but)h(con)o(tain)g
+(di\013eren)o(t,)f(though)0 1183 y(functionally)21 b(iden)o(tical,)h(data.)32
+b(F)l(or)19 b(example,)i(`)p Fl(/vol/tex)p Fo(')d(migh)o(t)h(b)q(e)h(the)g
+(name)f(of)g(a)g(T)1638 1193 y(E)1664 1183 y(X)g(distribution)0
+1233 y(whic)o(h)d(v)m(aried)g(for)f(eac)o(h)g(mac)o(hine)h(arc)o(hitecture.)
+62 1304 y Fp(Amd)k Fo(pro)o(vides)e(facilities)h(to)e(tak)o(e)g(adv)m(an)o
+(tage)g(of)g(b)q(oth)g(replicated)i(and)f(duplicated)h(v)o(olumes.)27
+b(Con\014g-)0 1353 y(uration)18 b(options)g(allo)o(w)f(a)h(single)h(set)e(of)
+h(con\014guration)f(data)g(to)h(b)q(e)g(shared)g(across)f(an)g(en)o(tire)h
+(net)o(w)o(ork)f(b)o(y)0 1403 y(taking)e(adv)m(an)o(tage)g(of)g(replicated)h
+(and)g(duplicated)h(v)o(olumes.)62 1474 y Fp(Amd)d Fo(can)f(tak)o(e)e(adv)m
+(an)o(tage)h(of)f(replacemen)o(t)i(v)o(olumes)f(b)o(y)h(moun)o(ting)f(them)g
+(as)f(required)j(should)f(an)f(activ)o(e)0 1524 y(\014leserv)o(er)k(b)q
+(ecome)g(una)o(v)m(ailable.)0 1670 y Fq(1.4)33 b(V)-6 b(olume)15
+b(Binding)62 1761 y Fo(Unix)22 b(implemen)o(ts)h(a)d(namespace)i(of)e
+(hierarc)o(hically)k(moun)o(ted)d(\014lesystems.)38 b(Tw)o(o)20
+b(forms)g(of)h(binding)0 1811 y(b)q(et)o(w)o(een)15 b(names)g(and)g(\014les)g
+(are)g(pro)o(vided.)20 b(A)15 b Fp(hard)g(link)k Fo(completes)c(the)g
+(binding)h(when)g(the)e(name)h(is)g(added)0 1861 y(to)f(the)h(\014lesystem.)
+20 b(A)15 b Fp(soft)f(link)19 b Fo(dela)o(ys)c(the)g(binding)i(un)o(til)f
+(the)f(name)f(is)i(accessed.)k(An)15 b Fp(automoun)o(ter)i
+Fo(adds)0 1911 y(a)e(further)g(form)f(in)i(whic)o(h)g(the)g(binding)h(of)e
+(name)g(to)f(\014lesystem)i(is)g(dela)o(y)o(ed)g(un)o(til)g(the)f(name)h(is)f
+(accessed.)62 1981 y(The)h(target)f(v)o(olume,)g(in)i(its)f(general)g(form,)f
+(is)h(a)f(tuple)i(\(host,)d(\014lesystem,)i(sublink\))i(whic)o(h)e(can)g(b)q
+(e)g(used)0 2031 y(to)f(name)g(the)g(ph)o(ysical)i(lo)q(cation)f(of)e(an)o(y)
+h(v)o(olume)h(in)g(the)f(net)o(w)o(ork.)62 2102 y(When)22 b(a)f(target)f(is)i
+(referenced,)h Fp(Amd)g Fo(ignores)e(the)h(sublink)h(elemen)o(t)f(and)f
+(determines)h(whether)g(the)0 2152 y(required)c(\014lesystem)f(is)g(already)g
+(moun)o(ted.)25 b(This)17 b(is)g(done)g(b)o(y)g(computing)g(the)g(lo)q(cal)g
+(moun)o(t)g(p)q(oin)o(t)g(for)f(the)0 2201 y(\014lesystem)g(and)g(c)o(hec)o
+(king)h(for)e(an)h(existing)h(\014lesystem)f(moun)o(ted)g(at)f(the)h(same)g
+(place.)23 b(If)16 b(suc)o(h)g(a)f(\014lesystem)0 2251 y(already)i(exists)h
+(then)f(it)h(is)f(assumed)h(to)e(b)q(e)i(functionally)h(iden)o(tical)g(to)e
+(the)g(target)f(\014lesystem.)26 b(By)17 b(default)0 2301 y(there)d(is)g(a)f
+(one-to-one)g(mapping)i(b)q(et)o(w)o(een)e(the)h(pair)g(\(host,)f
+(\014lesystem\))g(and)h(the)g(lo)q(cal)g(moun)o(t)f(p)q(oin)o(t)h(so)g(this)0
+2351 y(assumption)h(is)h(v)m(alid.)0 2504 y Fq(1.5)33 b(Op)r(erational)15
+b(Principl)q(es)62 2595 y Fp(Amd)e Fo(op)q(erates)e(b)o(y)f(in)o(tro)q
+(ducing)j(new)e(moun)o(t)f(p)q(oin)o(ts)h(in)o(to)g(the)g(namespace.)19
+b(These)11 b(are)g(called)h Fp(automoun)o(t)0 2645 y Fo(p)q(oin)o(ts.)22
+b(The)16 b(k)o(ernel)h(sees)f(these)g(automoun)o(t)e(p)q(oin)o(ts)j(as)e(NFS)
+h(\014lesystems)g(b)q(eing)h(serv)o(ed)f(b)o(y)g Fp(Amd)p Fo(.)22
+b(Ha)o(ving)p eop
+%%Page: 4 6
+4 5 bop 15 -83 a Fo(SMM:13-4)912 b(4.4)15 b(BSD)g(Automoun)o(ter)f(Reference)
+j(Man)o(ual)0 158 y(attac)o(hed)f(itself)h(to)f(the)h(namespace,)g
+Fp(Amd)h Fo(is)f(no)o(w)f(able)i(to)e(con)o(trol)g(the)g(view)i(the)e(rest)g
+(of)g(the)h(system)f(has)0 208 y(of)f(those)g(moun)o(t)f(p)q(oin)o(ts.)21
+b(RPC)15 b(calls)h(are)f(receiv)o(ed)i(from)d(the)h(k)o(ernel)h(one)g(at)e(a)
+h(time.)62 279 y(When)k(a)e Fp(lo)q(okup)j Fo(call)f(is)g(receiv)o(ed)g
+Fp(Amd)h Fo(c)o(hec)o(ks)e(whether)g(the)g(name)g(is)h(already)f(kno)o(wn.)28
+b(If)18 b(it)g(is)h(not,)0 329 y(the)g(required)h(v)o(olume)f(is)g(moun)o
+(ted.)30 b(A)19 b(sym)o(b)q(olic)h(link)g(p)q(oin)o(ting)g(to)e(the)h(v)o
+(olume)g(ro)q(ot)f(is)h(then)g(returned.)0 378 y(Once)g(the)e(sym)o(b)q(olic)
+i(link)g(is)f(returned,)g(the)g(k)o(ernel)g(will)i(send)e(all)g(other)g
+(requests)f(direct)h(to)f(the)h(moun)o(ted)0 428 y(\014lesystem.)62
+499 y(If)d(a)f(v)o(olume)g(is)h(not)f(y)o(et)g(moun)o(ted,)g
+Fp(Amd)i Fo(consults)f(a)f(con\014guration)g Fp(moun)o(t-map)h
+Fo(corresp)q(onding)g(to)f(the)0 549 y(automoun)o(t)h(p)q(oin)o(t.)24
+b Fp(Amd)19 b Fo(then)e(mak)o(es)f(a)g(run)o(time)h(decision)h(on)e(what)g
+(and)h(where)f(to)g(moun)o(t)g(a)g(\014lesystem)0 598 y(based)g(on)f(the)g
+(information)g(obtained)h(from)f(the)g(map.)62 669 y Fp(Amd)21
+b Fo(do)q(es)e(not)g(implemen)o(t)h(all)g(the)f(NFS)g(requests;)h(only)g
+(those)e(relev)m(an)o(t)i(to)e(name)h(binding)i(suc)o(h)e(as)0
+719 y Fp(lo)q(okup)p Fo(,)g Fp(readlink)j Fo(and)c Fp(readdir)p
+Fo(.)28 b(Some)18 b(other)g(calls)g(are)g(also)g(implemen)o(ted)h(but)f(most)
+f(simply)i(return)f(an)0 769 y(error)c(co)q(de;)i(for)e(example)j
+Fp(mkdir)h Fo(alw)o(a)o(ys)d(returns)g(\\read-only)h(\014lesystem".)0
+933 y Fq(1.6)33 b(Moun)n(ting)16 b(a)f(V)-6 b(olume)62 1024
+y Fo(Eac)o(h)21 b(automoun)o(t)e(p)q(oin)o(t)i(has)g(a)f(corresp)q(onding)i
+(moun)o(t)e(map.)36 b(The)20 b(moun)o(t)h(map)f(con)o(tains)h(a)f(list)h(of)0
+1074 y(k)o(ey{v)m(alue)15 b(pairs.)20 b(The)15 b(k)o(ey)f(is)h(the)f(name)h
+(of)f(the)g(v)o(olume)h(to)e(b)q(e)j(moun)o(ted.)j(The)c(v)m(alue)g(is)g(a)f
+(list)h(of)f(lo)q(cations)0 1124 y(describing)i(where)d(the)h(\014lesystem)h
+(is)f(stored)f(in)i(the)e(net)o(w)o(ork.)19 b(In)14 b(the)g(source)g(for)f
+(the)g(map)h(the)g(v)m(alue)h(w)o(ould)0 1173 y(lo)q(ok)g(lik)o(e)120
+1244 y(lo)q(cation1)31 b(lo)q(cation2)g Fj(:)8 b(:)g(:)28 b
+Fo(lo)q(cationN)62 1335 y Fp(Amd)14 b Fo(examines)f(eac)o(h)f(lo)q(cation)g
+(in)h(turn.)19 b(Eac)o(h)12 b(lo)q(cation)g(ma)o(y)f(con)o(tain)h
+Fp(selectors)i Fo(whic)o(h)f(con)o(trol)f(whether)0 1385 y
+Fp(Amd)19 b Fo(can)e(use)h(that)e(lo)q(cation.)27 b(F)l(or)16
+b(example,)i(the)g(lo)q(cation)g(ma)o(y)e(b)q(e)i(restricted)f(to)g(use)g(b)o
+(y)g(certain)h(hosts.)0 1435 y(Those)d(lo)q(cations)h(whic)o(h)g(cannot)f(b)q
+(e)h(used)g(are)f(ignored.)62 1506 y Fp(Amd)23 b Fo(attempts)d(to)g(moun)o(t)
+g(the)h(\014lesystem)g(describ)q(ed)i(b)o(y)d(eac)o(h)h(remaining)h(lo)q
+(cation)f(un)o(til)h(a)e(moun)o(t)0 1555 y(succeeds)c(or)f
+Fp(Amd)i Fo(can)f(no)f(longer)g(pro)q(ceed.)21 b(The)15 b(latter)g(can)g(o)q
+(ccur)h(in)g(three)f(w)o(a)o(ys:)37 1626 y Fn(\017)30 b Fo(If)16
+b(none)h(of)e(the)i(lo)q(cations)f(could)i(b)q(e)e(used,)h(or)e(if)i(all)g
+(of)f(the)g(lo)q(cations)h(caused)f(an)g(error,)f(then)i(the)f(last)90
+1676 y(error)e(is)i(returned.)37 1738 y Fn(\017)30 b Fo(If)17
+b(a)f(lo)q(cation)i(could)f(b)q(e)g(used)h(but)e(w)o(as)g(b)q(eing)i(moun)o
+(ted)f(in)g(the)g(bac)o(kground)f(then)h Fp(Amd)i Fo(marks)d(that)90
+1788 y(moun)o(t)k(as)f(b)q(eing)j(\\in)f(progress")e(and)h(con)o(tin)o(ues)h
+(with)g(the)f(next)g(request;)j(no)d(reply)h(is)f(sen)o(t)g(to)g(the)90
+1838 y(k)o(ernel.)37 1900 y Fn(\017)30 b Fo(Lastly)l(,)23 b(one)e(or)g(more)f
+(of)h(the)g(moun)o(ts)g(ma)o(y)f(ha)o(v)o(e)h(b)q(een)h Fp(deferred)p
+Fo(.)38 b(A)21 b(moun)o(t)g(is)g(deferred)h(if)g(extra)90 1950
+y(information)11 b(is)h(required)g(b)q(efore)f(the)h(moun)o(t)e(can)h(pro)q
+(ceed.)20 b(When)11 b(the)g(information)h(b)q(ecomes)f(a)o(v)m(ailable)90
+1999 y(the)k(moun)o(t)e(will)k(tak)o(e)c(place,)i(but)g(in)g(the)g(mean)f
+(time)h(no)f(reply)i(is)e(sen)o(t)h(to)e(the)i(k)o(ernel.)20
+b(If)15 b(the)g(moun)o(t)e(is)90 2049 y(deferred,)i Fp(Amd)j
+Fo(con)o(tin)o(ues)d(to)g(try)f(an)o(y)h(remaining)i(lo)q(cations.)62
+2141 y(Once)g(a)d(v)o(olume)i(has)f(b)q(een)i(moun)o(ted,)e
+Fp(Amd)i Fo(establishes)f(a)f Fp(v)o(olume)h(mapping)k Fo(whic)o(h)c(is)g
+(used)g(to)e(satisfy)0 2190 y(subsequen)o(t)i(requests.)0 2355
+y Fq(1.7)33 b(Automatic)15 b(Unmoun)n(ting)62 2446 y Fo(T)l(o)e(a)o(v)o(oid)f
+(an)g(ev)o(er)h(increasing)h(n)o(um)o(b)q(er)e(of)h(\014lesystem)g(moun)o
+(ts,)f Fp(Amd)i Fo(remo)o(v)o(es)e(v)o(olume)h(mappings)g(whic)o(h)0
+2496 y(ha)o(v)o(e)19 b(not)g(b)q(een)h(used)g(recen)o(tly)l(.)33
+b(A)19 b(time-to-liv)o(e)i(in)o(terv)m(al)f(is)g(asso)q(ciated)f(with)h(eac)o
+(h)f(mapping)h(and)f(when)0 2545 y(that)g(expires)i(the)e(mapping)i(is)f
+(remo)o(v)o(ed.)32 b(When)20 b(the)g(last)g(reference)g(to)f(a)g
+(\014lesystem)i(is)f(remo)o(v)o(ed,)g(that)0 2595 y(\014lesystem)14
+b(is)h(unmoun)o(ted.)k(If)14 b(the)g(unmoun)o(t)g(fails,)g(for)f(example)i
+(the)f(\014lesystem)g(is)g(still)h(busy)l(,)f(the)g(mapping)0
+2645 y(is)k(re-instated)f(and)g(its)h(time-to-liv)o(e)g(in)o(terv)m(al)g(is)g
+(extended.)26 b(The)18 b(global)g(default)f(for)g(this)g(grace)g(p)q(erio)q
+(d)h(is)p eop
+%%Page: 5 7
+5 6 bop 0 -83 a Fo(Chapter)15 b(1:)k(Ov)o(erview)1328 b(SMM:13-5)0
+158 y(con)o(trolled)14 b(b)o(y)g(the)f(\\-w")g(command-line)i(option)f(\(see)
+f(Section)h(4.11)e([-w)h(Option],)h(page)27 b(SMM:13-19\).)17
+b(It)c(is)0 208 y(also)i(p)q(ossible)i(to)e(set)g(this)g(v)m(alue)i(on)e(a)g
+(p)q(er-moun)o(t)g(basis)h(\(see)f(Section)h(3.3.4.3)d([opts],)g(page)31
+b(SMM:13-15\).)62 279 y(Filesystems)20 b(can)g(b)q(e)f(forcefully)i(timed)f
+(out)f(using)h(the)f Fp(Amq)h Fo(command.)32 b(See)20 b(Chapter)f(6)g
+([Run-time)0 329 y(Administration],)d(page)30 b(SMM:13-27.)0
+513 y Fq(1.8)j(Keep-aliv)n(es)62 604 y Fo(Use)14 b(of)g(some)g(\014lesystem)g
+(t)o(yp)q(es)g(requires)h(the)f(presence)h(of)e(a)h(serv)o(er)g(on)f(another)
+h(mac)o(hine.)20 b(If)14 b(a)g(mac)o(hine)0 654 y(crashes)19
+b(then)g(it)g(is)h(of)e(no)h(concern)g(to)f(pro)q(cesses)i(on)e(that)h(mac)o
+(hine)g(that)f(the)h(\014lesystem)h(is)f(una)o(v)m(ailable.)0
+704 y(Ho)o(w)o(ev)o(er,)14 b(to)h(pro)q(cesses)h(on)f(a)h(remote)f(host)g
+(using)h(that)f(mac)o(hine)h(as)f(a)g(\014leserv)o(er)i(this)e(ev)o(en)o(t)h
+(is)g(imp)q(ortan)o(t.)0 753 y(This)h(situation)f(is)h(most)e(widely)i
+(recognised)g(when)g(an)f(NFS)g(serv)o(er)g(crashes)g(and)g(the)g(b)q(eha)o
+(viour)h(observ)o(ed)0 803 y(on)h(clien)o(t)i(mac)o(hines)f(is)g(that)f(more)
+g(and)h(more)f(pro)q(cesses)h(hang.)29 b(In)19 b(order)f(to)g(pro)o(vide)h
+(the)g(p)q(ossibilit)o(y)h(of)0 853 y(reco)o(v)o(ery)l(,)f
+Fp(Amd)h Fo(implemen)o(ts)g(a)e Fp(k)o(eep-aliv)o(e)23 b Fo(in)o(terv)m(al)c
+(timer)g(for)f(some)g(\014lesystem)i(t)o(yp)q(es.)30 b(Curren)o(tly)18
+b(only)0 903 y(NFS)d(mak)o(es)g(use)g(of)g(this)h(service.)62
+973 y(The)k(basis)h(of)e(the)h(NFS)g(k)o(eep-aliv)o(e)i(implemen)o(tation)f
+(is)f(the)h(observ)m(ation)f(that)f(most)g(sites)h(main)o(tain)0
+1023 y(replicated)j(copies)e(of)g(common)g(system)f(data)h(suc)o(h)g(as)g
+(man)o(ual)g(pages,)h(most)e(or)h(all)g(programs,)g(system)0
+1073 y(source)c(co)q(de)g(and)g(so)f(on.)24 b(If)17 b(one)g(of)f(those)h
+(serv)o(ers)f(go)q(es)h(do)o(wn)f(it)h(w)o(ould)g(b)q(e)g(reasonable)g(to)f
+(moun)o(t)h(one)f(of)0 1123 y(the)f(others)g(as)g(a)g(replacemen)o(t.)62
+1193 y(The)j(\014rst)g(part)f(of)h(the)g(pro)q(cess)g(is)h(to)e(k)o(eep)h
+(trac)o(k)f(of)h(whic)o(h)g(\014leserv)o(ers)h(are)f(up)g(and)g(whic)o(h)h
+(are)f(do)o(wn.)0 1243 y Fp(Amd)j Fo(do)q(es)e(this)g(b)o(y)g(sending)h(RPC)f
+(requests)f(to)h(the)f(serv)o(ers')g(NFS)h Fl(NullProc)f Fo(and)h(c)o(hec)o
+(king)g(whether)g(a)0 1293 y(reply)13 b(is)f(returned.)19 b(While)13
+b(the)f(serv)o(er)f(state)g(is)h(uncertain)h(the)f(requests)g(are)f
+(re-transmitted)h(at)f(three)g(second)0 1343 y(in)o(terv)m(als)19
+b(and)g(if)f(no)h(reply)g(is)f(receiv)o(ed)i(after)d(four)h(attempts)f(the)i
+(serv)o(er)f(is)g(mark)o(ed)g(do)o(wn.)29 b(If)18 b(a)g(reply)h(is)0
+1393 y(receiv)o(ed)f(the)g(\014leserv)o(er)f(is)h(mark)o(ed)f(up)g(and)h(sta)
+o(ys)e(in)i(that)e(state)h(for)f(30)h(seconds)g(at)g(whic)o(h)h(time)f
+(another)0 1442 y(NFS)e(ping)h(is)g(sen)o(t.)62 1513 y(Once)21
+b(a)f(\014leserv)o(er)g(is)h(mark)o(ed)e(do)o(wn,)h(requests)g(con)o(tin)o
+(ue)h(to)e(b)q(e)h(sen)o(t)g(ev)o(ery)g(30)f(seconds)h(in)h(order)f(to)0
+1563 y(determine)c(when)g(the)f(\014leserv)o(er)h(comes)f(bac)o(k)g(up.)21
+b(During)15 b(this)h(time)f(an)o(y)g(reference)h(through)f
+Fp(Amd)i Fo(to)e(the)0 1613 y(\014lesystems)h(on)f(that)g(serv)o(er)g(fail)h
+(with)g(the)f(error)g(\\Op)q(eration)h(w)o(ould)g(blo)q(c)o(k".)21
+b(If)15 b(a)h(replacemen)o(t)g(v)o(olume)f(is)0 1662 y(a)o(v)m(ailable)i
+(then)e(it)h(will)h(b)q(e)f(moun)o(ted,)e(otherwise)i(the)f(error)g(is)g
+(returned)h(to)e(the)i(user.)62 1733 y(Although)g(this)g(action)g(do)q(es)g
+(not)f(protect)g(user)g(\014les,)h(whic)o(h)h(are)e(unique)i(on)e(the)h(net)o
+(w)o(ork,)e(or)h(pro)q(cesses)0 1783 y(whic)o(h)g(do)g(not)f(access)h
+(\014les)g(via)g Fp(Amd)h Fo(or)e(already)h(ha)o(v)o(e)f(op)q(en)i(\014les)f
+(on)f(the)h(h)o(ung)g(\014lesystem,)g(it)f(can)h(prev)o(en)o(t)0
+1833 y(most)f(new)i(pro)q(cesses)f(from)g(hanging.)62 1903
+y(By)k(default,)g(\014leserv)o(er)h(state)d(is)i(not)f(main)o(tained)i(for)e
+(NFS/TCP)f(moun)o(ts.)30 b(The)18 b(remote)g(\014leserv)o(er)h(is)0
+1953 y(alw)o(a)o(ys)14 b(assumed)i(to)e(b)q(e)i(up.)0 2135
+y Fq(1.9)33 b(Non-blo)r(c)n(king)16 b(Op)r(eration)62 2226
+y Fo(Since)e(there)f(is)g(only)g(one)g(instance)g(of)f Fp(Amd)j
+Fo(for)d(eac)o(h)g(automoun)o(t)g(p)q(oin)o(t,)h(and)f(usually)i(only)f(one)g
+(instance)0 2276 y(on)18 b(eac)o(h)g(mac)o(hine,)h(it)g(is)f(imp)q(ortan)o(t)
+g(that)f(it)h(is)h(alw)o(a)o(ys)e(a)o(v)m(ailable)j(to)d(service)i(k)o(ernel)
+g(calls.)30 b Fp(Amd)20 b Fo(go)q(es)e(to)0 2325 y(great)12
+b(lengths)h(to)g(ensure)g(that)f(it)h(do)q(es)g(not)g(blo)q(c)o(k)g(in)h(a)f
+(system)f(call.)20 b(As)13 b(a)g(last)f(resort)g Fp(Amd)j Fo(will)f(fork)f(b)
+q(efore)0 2375 y(it)j(attempts)e(a)i(system)f(call)i(that)d(ma)o(y)h(blo)q(c)
+o(k)i(inde\014nitely)l(,)h(suc)o(h)e(as)f(moun)o(ting)h(an)f(NFS)h
+(\014lesystem.)22 b(Other)0 2425 y(tasks)12 b(suc)o(h)g(as)h(obtaining)g
+(\014lehandle)i(information)d(for)g(an)g(NFS)h(\014lesystem,)g(are)f(done)h
+(using)g(a)f(purp)q(ose)i(built)0 2475 y(non-blo)q(c)o(king)i(RPC)f(library)g
+(whic)o(h)g(is)g(in)o(tegrated)f(with)h Fp(Amd)r Fo('s)f(task)g(sc)o
+(heduler.)21 b(This)15 b(library)g(is)g(also)f(used)0 2525
+y(to)h(implemen)o(t)h(NFS)f(k)o(eep-aliv)o(es)i(\(see)e(Section)h(1.8)e
+([Keep-aliv)o(es],)i(page)30 b(SMM:13-5\).)62 2595 y(Whenev)o(er)11
+b(a)f(moun)o(t)g(is)g(deferred)h(or)f(bac)o(kgrounded,)h Fp(Amd)i
+Fo(m)o(ust)c(w)o(ait)h(for)g(it)g(to)g(complete)h(b)q(efore)g(replying)0
+2645 y(to)f(the)i(k)o(ernel.)19 b(Ho)o(w)o(ev)o(er,)10 b(this)i(w)o(ould)f
+(cause)h Fp(Amd)h Fo(to)d(blo)q(c)o(k)i(w)o(aiting)f(for)f(a)h(reply)h(to)f
+(b)q(e)g(constructed.)19 b(Rather)p eop
+%%Page: 6 8
+6 7 bop 15 -83 a Fo(SMM:13-6)912 b(4.4)15 b(BSD)g(Automoun)o(ter)f(Reference)
+j(Man)o(ual)0 158 y(than)h(do)g(this,)h Fp(Amd)h Fo(simply)f
+Fp(drops)h Fo(the)e(call)h(under)g(the)f(assumption)g(that)f(the)h(k)o(ernel)
+h(RPC)f(mec)o(hanism)0 208 y(will)f(automatically)e(retry)g(the)g(request.)0
+445 y Fm(2)41 b(Supp)r(orted)15 b(Platforms)62 590 y Fp(Amd)20
+b Fo(has)e(b)q(een)g(p)q(orted)g(to)f(a)h(wide)h(v)m(ariet)o(y)e(of)h(mac)o
+(hines)g(and)g(op)q(erating)g(systems.)27 b(The)18 b(table)g(b)q(elo)o(w)0
+640 y(lists)e(those)f(platforms)g(supp)q(orted)g(b)o(y)g(the)h(curren)o(t)f
+(release.)0 852 y Fq(2.1)33 b(Supp)r(orted)16 b(Op)r(erating)g(Systems)62
+943 y Fo(The)j(follo)o(wing)g(op)q(erating)f(systems)g(are)g(curren)o(tly)g
+(supp)q(orted)h(b)o(y)f Fp(Amd)p Fo(.)30 b Fp(Amd)r Fo('s)17
+b(con)o(v)o(en)o(tional)i(name)0 993 y(for)c(eac)o(h)g(system)g(is)g(giv)o
+(en.)0 1064 y Fl(acis43)96 b Fo(4.3)14 b(BSD)i(for)e(IBM)i(R)l(T.)f(Con)o
+(tributed)g(b)o(y)g(Jan-Simon)i(P)o(endry)e Fl(<jsp@doc.ic.ac.uk>)0
+1132 y(aix3)144 b Fo(AIX)16 b(3.1.)j(Con)o(tributed)c(b)o(y)g(Jan-Simon)i(P)o
+(endry)e Fl(<jsp@doc.ic.ac.uk>)0 1200 y(aux)168 b Fo(System)15
+b(V)g(for)g(Mac-I)q(I.)h(Con)o(tributed)f(b)o(y)g(Julian)i(Onions)f
+Fl(<jpo@cs.nott.ac.uk>)0 1269 y(bsd44)120 b Fo(4.4)14 b(BSD.)h(Con)o
+(tributed)h(b)o(y)f(Jan-Simon)h(P)o(endry)f Fl(<jsp@doc.ic.ac.uk>)0
+1337 y(concentrix)240 1405 y Fo(Concen)o(trix)g(5.0.)k(Con)o(tributed)d(b)o
+(y)f(Sjo)q(erd)g(Mullender)j Fl(<sjoerd@cwi.nl>)0 1473 y(convex)96
+b Fo(Con)o(v)o(ex)15 b(OS)g(7.1.)k(Con)o(tributed)d(b)o(y)f(Eitan)g
+(Mizrotsky)g Fl(<eitan@shumuji.ac.il>)0 1542 y(dgux)144 b Fo(Data)14
+b(General)i(DG/UX.)e(Con)o(tributed)h(b)o(y)g(Mark)g(Da)o(vies)g
+Fl(<mark@comp.vuw.ac.nz>)0 1610 y(fpx4)144 b Fo(Celerit)o(y)16
+b(FPX)f(4.1/2.)j(Con)o(tributed)d(b)o(y)h(Stephen)g(P)o(op)q(e)f
+Fl(<scp@grizzly.acl.lanl.gov>)0 1678 y(hcx)168 b Fo(Harris)15
+b(HCX/UX.)g(Con)o(tributed)g(b)o(y)g(Chris)h(Metcalf)f Fl
+(<metcalf@masala.lcs.mit.edu)o(>)0 1746 y(hlh42)120 b Fo(HLH)16
+b(OTS)f(1.)p Fp(x)j Fo(\(4.2)c(BSD\).)g(Con)o(tributed)i(b)o(y)f(Jan-Simon)h
+(P)o(endry)g Fl(<jsp@doc.ic.ac.uk>)0 1815 y(hpux)144 b Fo(HP-UX)16
+b(6.)p Fp(x)h Fo(or)e(7.0.)k(Con)o(tributed)c(b)o(y)g(Jan-Simon)i(P)o(endry)e
+Fl(<jsp@doc.ic.ac.uk>)0 1883 y(irix)144 b Fo(SGI)15 b(Irix.)21
+b(Con)o(tributed)16 b(b)o(y)f(Scott)f(R.)i(Presnell)g Fl(<srp@cgl.ucsf.edu>)0
+1951 y(next)144 b Fo(Mac)o(h)15 b(for)f(NeXT.)h(Con)o(tributed)h(b)o(y)f
+(Bill)i(T)l(rost)d Fl(<trost\045reed@cse.ogi.edu>)0 2019 y(pyrOSx)96
+b Fo(Pyramid)15 b(OSx.)21 b(Con)o(tributed)15 b(b)o(y)g(Stefan)h(P)o(etri)f
+Fl(<petri@tubsibr.UUCP>)0 2088 y(riscix)96 b Fo(Acorn)15 b(RISC)h(iX.)g(Con)o
+(tributed)f(b)o(y)g(Piete)h(Bro)q(oks)f Fl(<pb@cam.cl.ac.uk>)0
+2156 y(sos3)144 b Fo(SunOS)17 b(3.4)d(&)h(3.5.)k(Con)o(tributed)d(b)o(y)f
+(Jan-Simon)h(P)o(endry)f Fl(<jsp@doc.ic.ac.uk>)0 2224 y(sos4)144
+b Fo(SunOS)17 b(4.)p Fp(x)p Fo(.)i(Con)o(tributed)c(b)o(y)g(Jan-Simon)i(P)o
+(endry)e Fl(<jsp@doc.ic.ac.uk>)0 2292 y(u2_2)144 b Fo(Ultrix)16
+b(2.2.)j(Con)o(tributed)c(b)o(y)g(Piete)h(Bro)q(oks)f Fl(<pb@cam.cl.ac.uk>)0
+2361 y(u3_0)144 b Fo(Ultrix)16 b(3.)k(Con)o(tributed)15 b(b)o(y)g(Piete)h
+(Bro)q(oks)f Fl(<pb@cam.cl.ac.uk>)0 2429 y(u4_0)144 b Fo(Ultrix)16
+b(4.0.)j(Con)o(tributed)c(b)o(y)g(Chris)h(Lindblad)i Fl(<cjl@ai.mit.edu>)0
+2497 y(umax43)96 b Fo(Umax)15 b(4.3)f(BSD.)h(Con)o(tributed)g(b)o(y)h(Sjo)q
+(erd)f(Mullender)i Fl(<sjoerd@cwi.nl>)0 2565 y(utek)144 b Fo(Utek)15
+b(4.0.)k(Con)o(tributed)c(b)o(y)h(Bill)h(T)l(rost)d Fl
+(<trost\045reed@cse.ogi.edu>)0 2634 y(xinu43)96 b Fo(m)o(t)14
+b(Xin)o(u)j(MORE/bsd.)j(Con)o(tributed)15 b(b)o(y)h(Jan-Simon)g(P)o(endry)f
+Fl(<jsp@doc.ic.ac.uk>)p eop
+%%Page: 7 9
+7 8 bop 0 -83 a Fo(Chapter)15 b(3:)k(Moun)o(t)c(Maps)1258 b(SMM:13-7)0
+158 y Fq(2.2)33 b(Supp)r(orted)16 b(Mac)n(hine)g(Arc)n(hitectures)0
+250 y Fl(alliant)72 b Fo(Allian)o(t)17 b(FX/4)0 313 y Fl(arm)168
+b Fo(Acorn)15 b(ARM)0 377 y Fl(aviion)96 b Fo(Data)14 b(General)i(A)-5
+b(ViiON)0 440 y Fl(encore)96 b Fo(Encore)0 504 y Fl(fps500)g
+Fo(FPS)15 b(Mo)q(del)h(500)0 567 y Fl(hp9000)96 b Fo(HP)15
+b(9000/300)e(family)0 631 y Fl(hp9k8)120 b Fo(HP)15 b(9000/800)e(family)0
+694 y Fl(ibm032)96 b Fo(IBM)15 b(R)l(T)0 758 y Fl(ibm6000)72
+b Fo(IBM)15 b(RISC)i(System/6000)0 821 y Fl(iris4d)96 b Fo(SGI)15
+b(Iris)h(4D)0 885 y Fl(macII)120 b Fo(Apple)17 b(Mac)d(I)q(I)0
+948 y Fl(mips)144 b Fo(MIPS)15 b(RISC)0 1012 y Fl(multimax)48
+b Fo(Encore)15 b(Multimax)0 1075 y Fl(orion105)48 b Fo(HLH)16
+b(Orion)g(1/05)0 1139 y Fl(sun3)144 b Fo(Sun-3)16 b(family)0
+1202 y Fl(sun4)144 b Fo(Sun-4)16 b(family)0 1266 y Fl(tahoe)120
+b Fo(T)l(aho)q(e)15 b(family)0 1329 y Fl(vax)168 b Fo(DEC)15
+b(V)l(ax)0 1513 y Fm(3)41 b(Moun)n(t)15 b(Maps)62 1639 y Fp(Amd)k
+Fo(has)f(no)f(built-in)i(kno)o(wledge)f(of)f(mac)o(hines)h(or)e
+(\014lesystems.)27 b(External)17 b Fp(moun)o(t-maps)i Fo(are)e(used)h(to)0
+1688 y(pro)o(vide)12 b(the)g(required)h(information.)19 b(Sp)q(eci\014cally)l
+(,)c Fp(Amd)f Fo(needs)e(to)f(kno)o(w)g(when)h(and)g(under)h(what)e
+(conditions)0 1738 y(it)k(should)i(moun)o(t)d(\014lesystems.)62
+1809 y(The)k(map)e(en)o(try)h(corresp)q(onding)h(to)e(the)h(requested)h(name)
+f(con)o(tains)g(a)g(list)h(of)e(p)q(ossible)j(lo)q(cations)f(from)0
+1859 y(whic)o(h)e(to)f(resolv)o(e)h(the)f(request.)21 b(Eac)o(h)15
+b(lo)q(cation)i(sp)q(eci\014es)g(\014lesystem)f(t)o(yp)q(e,)f(information)h
+(required)g(b)o(y)g(that)0 1908 y(\014lesystem)11 b(\(for)f(example)h(the)g
+(blo)q(c)o(k)g(sp)q(ecial)h(device)g(in)g(the)e(case)h(of)f(UFS\),)g(and)g
+(some)g(information)h(describing)0 1958 y(where)k(to)f(moun)o(t)h(the)g
+(\014lesystem)g(\(see)g(Section)h(3.3.4.2)c([fs)j(Option],)g(page)29
+b(SMM:13-14\).)18 b(A)d(lo)q(cation)h(ma)o(y)0 2008 y(also)f(con)o(tain)h
+Fp(selectors)h Fo(\(see)e(Section)h(3.3.3)e([Selectors],)g(page)31
+b(SMM:13-13\).)0 2184 y Fq(3.1)i(Map)15 b(T)n(yp)r(es)62 2276
+y Fo(A)k(moun)o(t-map)f(pro)o(vides)i(the)f(run-time)g(con\014guration)g
+(information)g(to)f Fp(Amd)p Fo(.)31 b(Maps)19 b(can)g(b)q(e)g(imple-)0
+2325 y(men)o(ted)f(in)h(man)o(y)f(w)o(a)o(ys.)27 b(Some)18
+b(of)g(the)g(forms)f(supp)q(orted)i(b)o(y)f Fp(Amd)i Fo(are)e(regular)g
+(\014les,)h(ndbm)g(databases,)0 2375 y(NIS)d(maps)f(the)g Fp(Hesio)q(d)j
+Fo(name)d(serv)o(er)g(and)h(ev)o(en)f(the)g(passw)o(ord)g(\014le.)62
+2446 y(A)g(moun)o(t-map)f Fp(name)k Fo(is)d(a)f(sequence)i(of)f(c)o
+(haracters.)k(When)c(an)f(automoun)o(t)g(p)q(oin)o(t)h(is)g(created)g(a)g
+(handle)0 2496 y(on)j(the)h(moun)o(t-map)f(is)g(obtained.)31
+b(F)l(or)17 b(eac)o(h)i(map)f(t)o(yp)q(e)g(con\014gured)h Fp(Amd)i
+Fo(attempts)c(to)h(reference)h(the)f(a)0 2545 y(map)g(of)g(the)h(appropriate)
+f(t)o(yp)q(e.)29 b(If)19 b(a)f(map)g(is)h(found,)g Fp(Amd)i
+Fo(notes)d(the)g(t)o(yp)q(e)h(for)e(future)i(use)f(and)h(deletes)0
+2595 y(the)14 b(reference,)g(for)f(example)i(closing)g(an)o(y)e(op)q(en)h
+(\014le)h(descriptors.)20 b(The)14 b(a)o(v)m(ailable)h(maps)f(are)f
+(con\014gure)h(when)0 2645 y Fp(Amd)j Fo(is)f(built)g(and)g(can)f(b)q(e)h
+(displa)o(y)o(ed)h(b)o(y)e(running)h(the)f(command)g(`)p Fl(amd)g(-v)p
+Fo('.)p eop
+%%Page: 8 10
+8 9 bop 15 -83 a Fo(SMM:13-8)912 b(4.4)15 b(BSD)g(Automoun)o(ter)f(Reference)
+j(Man)o(ual)62 158 y(By)i(default,)g Fp(Amd)h Fo(cac)o(hes)f(data)f(in)h(a)f
+(mo)q(de)g(dep)q(enden)o(t)i(on)e(the)h(t)o(yp)q(e)f(of)g(map.)29
+b(This)19 b(is)g(the)f(same)g(as)0 208 y(sp)q(ecifying)g(`)p
+Fl(cache:=mapdefault)p Fo(')13 b(and)k(selects)f(a)g(suitable)i(default)e
+(cac)o(he)h(mo)q(de)f(dep)q(ending)j(on)d(the)g(map)0 258 y(t)o(yp)q(e.)j
+(The)12 b(individual)k(defaults)c(are)g(describ)q(ed)i(b)q(elo)o(w.)20
+b(The)12 b Fp(cac)o(he)j Fo(option)e(can)f(b)q(e)h(sp)q(eci\014ed)h(on)e
+(automoun)o(t)0 308 y(p)q(oin)o(ts)j(to)f(alter)g(the)h(cac)o(hing)g(b)q(eha)
+o(viour)g(\(see)g(Section)g(5.8)f([Automoun)o(t)f(Filesystem],)i(page)28
+b(SMM:13-24\).)62 378 y(The)13 b(follo)o(wing)f(map)g(t)o(yp)q(es)g(ha)o(v)o
+(e)g(b)q(een)h(implemen)o(ted,)h(though)e(some)g(are)f(not)h(a)o(v)m(ailable)
+i(on)e(all)h(mac)o(hines.)0 428 y(Run)j(the)f(command)g(`)p
+Fl(amd)g(-v)p Fo(')f(to)h(obtain)g(a)g(list)h(of)f(map)g(t)o(yp)q(es)g
+(con\014gured)h(on)f(y)o(our)g(mac)o(hine.)0 582 y Fi(3.1.1)30
+b(File)15 b(maps)62 673 y Fo(When)i Fp(Amd)i Fo(searc)o(hes)e(a)f(\014le)i
+(for)e(a)g(map)g(en)o(try)h(it)g(do)q(es)f(a)h(simple)h(scan)f(of)f(the)h
+(\014le)g(and)g(supp)q(orts)g(b)q(oth)0 723 y(commen)o(ts)e(and)g(con)o(tin)o
+(uation)h(lines.)62 794 y(Con)o(tin)o(uation)g(lines)h(are)e(indicated)i(b)o
+(y)e(a)g(bac)o(kslash)h(c)o(haracter)e(\(`)p Fl(\\)p Fo('\))g(as)h(the)g
+(last)h(c)o(haracter)e(of)h(a)g(line)i(in)0 843 y(the)h(\014le.)30
+b(The)18 b(bac)o(kslash,)h(newline)h(c)o(haracter)e Fp(and)g(an)o(y)g
+(leading)i(white)e(space)h(on)f(the)g(follo)o(wing)h(line)j
+Fo(are)0 893 y(discarded.)g(A)16 b(maxim)o(um)g(line)h(length)f(of)g(2047)e
+(c)o(haracters)h(is)h(enforced)g(after)f(con)o(tin)o(uation)h(lines)i(are)d
+(read)0 943 y(but)h(b)q(efore)h(commen)o(ts)f(are)g(stripp)q(ed.)24
+b(Eac)o(h)16 b(line)i(m)o(ust)e(end)h(with)g(a)f(newline)i(c)o(haracter;)e
+(that)f(is)i(newlines)0 993 y(are)e(terminators,)f(not)h(separators.)j(The)e
+(follo)o(wing)g(examples)g(illustrate)g(this:)120 1063 y Fl(key)119
+b(valA)71 b(valB;)g(\\)359 1113 y(valC)62 1205 y Fo(sp)q(eci\014es)17
+b Fp(three)h Fo(lo)q(cations,)e(and)f(is)h(iden)o(tical)h(to)120
+1275 y Fl(key)119 b(valA)71 b(valB;)g(valC)62 1366 y Fo(Ho)o(w)o(ev)o(er,)120
+1437 y Fl(key)119 b(valA)71 b(valB;\\)359 1487 y(valC)62 1578
+y Fo(sp)q(eci\014es)17 b(only)f Fp(t)o(w)o(o)g Fo(lo)q(cations,)g(and)f(is)h
+(iden)o(tical)h(to)120 1649 y Fl(key)119 b(valA)71 b(valB;valC)62
+1740 y Fo(After)20 b(a)h(complete)g(line)h(has)f(b)q(een)g(read)g(from)f(the)
+h(\014le,)h(including)h(con)o(tin)o(uations,)f Fp(Amd)h Fo(determines)0
+1790 y(whether)d(there)g(is)h(a)e(commen)o(t)h(on)f(the)i(line.)35
+b(A)20 b(commen)o(t)g(b)q(egins)h(with)f(a)g(hash)g(\(\\`)p
+Fl(#)p Fo('"\))e(c)o(haracter)h(and)0 1840 y(con)o(tin)o(ues)12
+b(to)g(the)f(end)i(of)e(the)h(line.)21 b(There)12 b(is)g(no)g(w)o(a)o(y)e(to)
+i(escap)q(e)g(or)f(c)o(hange)h(the)g(commen)o(t)f(lead-in)j(c)o(haracter.)62
+1910 y(Note)f(that)g(con)o(tin)o(uation)h(lines)h(and)f(commen)o(t)f(supp)q
+(ort)g Fp(only)18 b Fo(apply)d(to)e(\014le)h(maps,)f(or)g(ndbm)h(maps)g
+(built)0 1960 y(with)i(the)f Fl(mk-amd-map)f Fo(program.)62
+2031 y(When)e(cac)o(hing)f(is)h(enabled,)h(\014le)f(maps)e(ha)o(v)o(e)h(a)f
+(default)i(cac)o(he)f(mo)q(de)g(of)g Fl(all)f Fo(\(see)h(Section)h(5.8)e
+([Automoun)o(t)0 2080 y(Filesystem],)15 b(page)30 b(SMM:13-24\).)0
+2234 y Fi(3.1.2)g(ndbm)15 b(maps)62 2325 y Fo(An)20 b(ndbm)f(map)g(ma)o(y)g
+(b)q(e)h(used)f(as)g(a)g(fast)f(access)h(form)g(of)f(a)h(\014le)h(map.)32
+b(The)19 b(program,)g Fl(mk-amd-map)p Fo(,)0 2375 y(con)o(v)o(erts)c(a)g
+(normal)g(map)g(\014le)h(in)o(to)g(an)f(ndbm)h(database.)k(This)c(program)e
+(supp)q(orts)h(the)h(same)f(con)o(tin)o(uation)0 2425 y(and)f(commen)o(t)f
+(con)o(v)o(en)o(tions)h(that)f(are)g(pro)o(vided)i(for)e(\014le)h(maps.)19
+b(Note)14 b(that)f(ndbm)h(format)e(\014les)j(ma)o(y)e Fp(not)h
+Fo(b)q(e)0 2475 y(sharable)h(across)f(mac)o(hine)i(arc)o(hitectures.)j(The)c
+(notion)g(of)f(sp)q(eed)i(generally)g(only)f(applies)h(to)e(large)h(maps;)f
+(a)0 2525 y(small)i(map,)f(less)g(than)g(a)g(single)i(disk)f(blo)q(c)o(k,)f
+(is)h(almost)f(certainly)h(b)q(etter)f(implemen)o(ted)i(as)e(a)g(\014le)h
+(map.)62 2595 y(ndbm)e(maps)e(do)h(not)f(supp)q(ort)h(cac)o(he)g(mo)q(de)f(`)
+p Fl(all)p Fo(')g(and,)h(when)g(cac)o(hing)g(is)h(enabled,)g(ha)o(v)o(e)e(a)g
+(default)i(cac)o(he)0 2645 y(mo)q(de)h(of)g(`)p Fl(inc)p Fo(')f(\(see)h
+(Section)h(5.8)f([Automoun)o(t)f(Filesystem],)h(page)30 b(SMM:13-24\).)p
+eop
+%%Page: 9 11
+9 10 bop 0 -83 a Fo(Chapter)15 b(3:)k(Moun)o(t)c(Maps)1258
+b(SMM:13-9)0 158 y Fi(3.1.3)30 b(NIS)15 b(maps)62 250 y Fo(When)j(using)h
+(NIS)f(\(formerly)f(YP\),)g(an)g Fp(Amd)j Fo(map)d(is)h(implemen)o(ted)i
+(directly)f(b)o(y)e(the)h(underlying)h(NIS)0 299 y(map.)f(Commen)o(ts)11
+b(and)h(con)o(tin)o(uation)g(lines)h(are)f Fp(not)g Fo(supp)q(orted)g(in)g
+(the)g(automoun)o(ter)f(and)g(m)o(ust)g(b)q(e)i(stripp)q(ed)0
+349 y(when)j(constructing)f(the)g(NIS)h(serv)o(er's)f(database.)62
+420 y(NIS)j(maps)e(do)h(not)f(supp)q(ort)h(cac)o(he)f(mo)q(de)h
+Fl(all)f Fo(and,)h(when)g(cac)o(hing)h(is)f(enabled,)h(ha)o(v)o(e)e(a)g
+(default)i(cac)o(he)0 470 y(mo)q(de)d(of)g Fl(inc)g Fo(\(see)g(Section)h(5.8)
+e([Automoun)o(t)h(Filesystem],)g(page)30 b(SMM:13-24\).)62
+540 y(The)15 b(follo)o(wing)h(rule)f(illustrates)h(what)e(could)h(b)q(e)h
+(added)f(to)f(y)o(our)g(NIS)i(`)p Fl(Makefile)p Fo(',)c(in)k(this)f(case)f
+(causing)0 590 y(the)h(`)p Fl(amd.home)p Fo(')f(map)h(to)f(b)q(e)i(rebuilt:)
+120 661 y Fl($\(YPTSDIR\)/amd.home.time:)k($\(ETCDIR\)/amd.home)311
+710 y(-@sed)j(-e)h("s/#.*$$//")e(-e)i("/^$$/d")e($\(ETCDIR\)/amd.home)g(|)i
+(\\)359 760 y(awk)f('{)48 b(\\)526 810 y(for)23 b(\(i)h(=)f(1;)h(i)g(<=)f
+(NF;)h(i++\))f(\\)621 860 y(if)h(\(i)f(==)h(NF\))f({)h(\\)717
+910 y(if)f(\(substr\($$i,)f(length\($$i\),)h(1\))g(==)h("\\\\"\))f(\\)812
+959 y(printf\("\045s",)f(substr\($$i,)h(1,)g(length\($$i\))g(-)g(1\)\);)120
+1009 y(\\)717 1059 y(else)g(\\)812 1109 y(printf\("\045s\\n",)f($$i\);)h(\\)
+621 1159 y(})h(\\)621 1209 y(else)f(\\)717 1258 y(printf\("\045s)f(",)i
+($$i\);)f(\\)430 1308 y(}')h(|)g(\\)311 1358 y($\(MAKEDBM\))e(-)i
+($\(YPDBDIR\)/amd.home;)d(\\)311 1408 y(touch)i($\(YPTSDIR\)/amd.home.time;)e
+(\\)311 1458 y(echo)i("updated)g(amd.home";)f(\\)311 1507 y(if)h([)h(!)g
+($\(NOPUSH\))f(];)g(then)g(\\)502 1557 y($\(YPPUSH\))f(amd.home;)h(\\)502
+1607 y(echo)g("pushed)g(amd.home";)g(\\)311 1657 y(else)g(\\)502
+1707 y(:)h(;)f(\\)311 1757 y(fi)62 1848 y Fo(Here)16 b Fl($\(YPTSDIR\))e
+Fo(con)o(tains)h(the)g(time)h(stamp)e(\014les,)i(and)f Fl($\(YPDBDIR\))f
+Fo(con)o(tains)i(the)f(dbm)g(format)f(NIS)0 1898 y(\014les.)0
+2083 y Fi(3.1.4)30 b(Hesio)r(d)15 b(maps)62 2174 y Fo(When)f(the)g(map)g
+(name)f(b)q(egins)i(with)f(the)g(string)g(`)p Fl(hesiod.)p
+Fo(')e(lo)q(okups)i(are)f(made)h(using)h(the)e Fp(Hesio)q(d)k
+Fo(name)0 2224 y(serv)o(er.)i(The)13 b(string)g(follo)o(wing)g(the)g(dot)g
+(is)g(used)h(as)e(a)h(name)g(quali\014er)h(and)f(is)h(prep)q(ended)h(with)e
+(the)g(k)o(ey)g(b)q(eing)0 2274 y(lo)q(cated.)24 b(The)16 b(en)o(tire)h
+(string)f(is)h(then)g(resolv)o(ed)g(in)g(the)f Fl(automount)f
+Fo(con)o(text.)23 b(F)l(or)15 b(example,)j(if)e(the)h(the)f(k)o(ey)0
+2324 y(is)f(`)p Fl(jsp)p Fo(')e(and)h(map)h(name)f(is)h(`)p
+Fl(hesiod.homes)p Fo(')d(then)i Fp(Hesio)q(d)k Fo(is)c(ask)o(ed)h(to)e
+(resolv)o(e)i(`)p Fl(jsp.homes.automount)p Fo(')o(.)62 2394
+y(Hesio)q(d)21 b(maps)e(do)g(not)g(supp)q(ort)g(cac)o(he)g(mo)q(de)h(`)p
+Fl(all)p Fo(')e(and,)i(when)g(cac)o(hing)g(is)f(enabled,)j(ha)o(v)o(e)c(a)h
+(default)0 2444 y(cac)o(he)c(mo)q(de)h(of)f(`)p Fl(inc)p Fo(')f(\(see)h
+(Section)h(5.8)e([Automoun)o(t)g(Filesystem],)h(page)31 b(SMM:13-24\).)62
+2515 y(The)16 b(follo)o(wing)g(is)f(an)g(example)h(of)f(a)g
+Fp(Hesio)q(d)j Fo(map)d(en)o(try:)120 2585 y Fl(jsp.homes.automount)21
+b(HS)j(TXT)f("rfs:=/home/charm;rhost:=cha)o(rm;subli)o(nk:=jsp)o(")120
+2635 y(njw.homes.automount)e(HS)j(TXT)f("rfs:=/home/dylan/dk2;rhost:)o
+(=dylan;s)o(ublink:)o(=njw")p eop
+%%Page: 10 12
+10 11 bop 15 -83 a Fo(SMM:13-10)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fi(3.1.5)30 b(P)n(assw)n(ord)16
+b(maps)62 250 y Fo(The)g(passw)o(ord)g(map)f(supp)q(ort)i(is)f(unlik)o(e)i
+(the)e(four)f(previous)i(map)f(t)o(yp)q(es.)22 b(When)16 b(the)h(map)e(name)h
+(is)h(the)0 299 y(string)g(`)p Fl(/etc/passwd)p Fo(')d Fp(Amd)19
+b Fo(can)e(lo)q(okup)h(a)e(user)h(name)g(in)h(the)f(passw)o(ord)f(\014le)i
+(and)f(re-arrange)f(the)h(home)0 349 y(directory)e(\014eld)i(to)d(pro)q(duce)
+j(a)d(usable)j(map)e(en)o(try)l(.)62 420 y Fp(Amd)20 b Fo(assumes)e(the)g
+(home)g(directory)g(has)g(the)g(format)f(`)p Fl(/)p Fp(an)o(ydir)s
+Fl(/)p Fp(dom1)t Fl(/../)p Fp(domN)5 b Fl(/)p Fp(login)p Fo('.)27
+b(It)18 b(breaks)0 470 y(this)d(string)g(in)o(to)g(a)f(map)g(en)o(try)h
+(where)g Fl(${rfs})f Fo(has)g(the)h(v)m(alue)h(`)p Fl(/)p Fp(an)o(ydir)s
+Fl(/)p Fp(domN)5 b Fo(',)14 b Fl(${rhost})f Fo(has)i(the)g(v)m(alue)0
+519 y(`)p Fp(domN)5 b Fl(.)p Fp(...)p Fl(.)p Fp(dom1)t Fo(',)12
+b(and)j Fl(${sublink})f Fo(has)h(the)g(v)m(alue)i(`)p Fl(login)p
+Fo('.)62 590 y(Th)o(us)e(if)h(the)f(passw)o(ord)g(\014le)h(en)o(try)f(w)o(as)
+120 661 y Fl(/home/achilles/jsp)62 752 y Fo(the)h(map)f(en)o(try)f(used)i(b)o
+(y)f Fp(Amd)i Fo(w)o(ould)f(b)q(e)120 823 y Fl(rfs:=/home/achilles;rhost:)o
+(=achill)o(es;subli)o(nk:=jsp)62 914 y Fo(Similarly)l(,)h(if)f(the)f(passw)o
+(ord)g(\014le)h(en)o(try)f(w)o(as)120 984 y Fl(/home/cc/sugar/mjh)62
+1076 y Fo(the)h(map)f(en)o(try)f(used)i(b)o(y)f Fp(Amd)i Fo(w)o(ould)f(b)q(e)
+120 1146 y Fl(rfs:=/home/sugar;rhost:=su)o(gar.cc;)o(sublink:)o(=jsp)0
+1279 y Fi(3.1.6)30 b(Union)15 b(maps)62 1371 y Fo(The)d(union)h(map)e(supp)q
+(ort)g(is)h(pro)o(vided)h(sp)q(eci\014cally)h(for)d(use)h(with)f(the)h(union)
+h(\014lesystem,)f(see)g(Section)g(5.10)0 1420 y([Union)k(Filesystem],)f(page)
+30 b(SMM:13-25.)62 1491 y(It)17 b(is)g(iden)o(ti\014ed)h(b)o(y)e(the)h
+(string)f(`)p Fl(union:)p Fo(')f(whic)o(h)i(is)g(follo)o(w)o(ed)g(b)o(y)f(a)g
+(colon)h(separated)f(list)h(of)f(directories.)0 1541 y(The)e(directories)g
+(are)f(read)g(in)i(order,)e(and)g(the)h(names)f(of)g(all)h(en)o(tries)g(are)f
+(recorded)h(in)g(the)f(map)h(cac)o(he.)19 b(Later)0 1591 y(directories)f(tak)
+o(e)e(precedence)j(o)o(v)o(er)d(earlier)i(ones.)25 b(The)18
+b(union)g(\014lesystem)f(t)o(yp)q(e)g(then)h(uses)f(the)g(map)g(cac)o(he)0
+1640 y(to)e(determine)h(the)f(union)h(of)f(the)g(names)h(in)g(all)g(the)f
+(directories.)0 1790 y Fq(3.2)33 b(Ho)n(w)14 b(k)n(eys)h(are)g(lo)r(ok)n(ed)h
+(up)62 1881 y Fo(The)g(k)o(ey)f(is)h(lo)q(cated)g(in)g(the)g(map)f(whose)g(t)
+o(yp)q(e)g(w)o(as)g(determined)i(when)e(the)h(automoun)o(t)e(p)q(oin)o(t)i(w)
+o(as)e(\014rst)0 1931 y(created.)19 b(In)14 b(general)g(the)f(k)o(ey)g(is)h
+(a)f(pathname)g(comp)q(onen)o(t.)19 b(In)14 b(some)f(circumstances)h(this)f
+(ma)o(y)g(b)q(e)h(mo)q(di\014ed)0 1981 y(b)o(y)h(v)m(ariable)i(expansion)f
+(\(see)f(Section)h(3.3.2)e([V)l(ariable)i(Expansion],)f(page)31
+b(SMM:13-12\))13 b(and)j(pre\014xing.)21 b(If)0 2031 y(the)13
+b(automoun)o(t)e(p)q(oin)o(t)i(has)g(a)f(pre\014x,)h(sp)q(eci\014ed)i(b)o(y)e
+(the)f Fp(pref)22 b Fo(option,)13 b(then)g(that)f(is)h(prep)q(ended)h(to)e
+(the)h(searc)o(h)0 2081 y(k)o(ey)i(b)q(efore)h(the)f(map)g(is)h(searc)o(hed.)
+62 2151 y(If)e(the)f(map)g(cac)o(he)h(is)g(a)e(`)p Fl(regexp)p
+Fo(')g(cac)o(he)i(then)f(the)h(k)o(ey)f(is)h(treated)e(as)h(an)g(egrep-st)o
+(yle)h(regular)f(expression,)0 2201 y(otherwise)i(a)g(normal)g(string)h
+(comparison)f(is)h(made.)62 2271 y(If)k(the)f(k)o(ey)h(cannot)f(b)q(e)h
+(found)g(then)f(a)g Fp(wildcard)k Fo(matc)o(h)c(is)h(attempted.)31
+b Fp(Amd)22 b Fo(rep)q(eatedly)e(strips)g(the)0 2321 y(basename)15
+b(from)f(the)h(k)o(ey)l(,)f(app)q(ends)i(`)p Fl(/*)p Fo(')e(and)h(attempts)e
+(a)i(lo)q(okup.)20 b(Finally)l(,)c Fp(Amd)h Fo(attempts)d(to)g(lo)q(cate)h
+(the)0 2371 y(sp)q(ecial)i(k)o(ey)e(`)p Fl(*)p Fo('.)62 2421
+y(F)l(or)g(example,)g(the)h(follo)o(wing)g(sequence)g(w)o(ould)g(b)q(e)g(c)o
+(hec)o(k)o(ed)f(if)h(`)p Fl(home/dylan/dk2)p Fo(')c(w)o(as)j(b)q(eing)h(lo)q
+(cated:)192 2492 y Fl(home/dylan/dk2)192 2541 y(home/dylan/*)192
+2591 y(home/*)192 2641 y(*)p eop
+%%Page: 11 13
+11 12 bop 0 -83 a Fo(Chapter)15 b(3:)k(Moun)o(t)c(Maps)1236
+b(SMM:13-11)62 158 y(A)o(t)14 b(an)o(y)f(p)q(oin)o(t)h(when)h(a)e(wildcard)i
+(is)g(found,)f Fp(Amd)i Fo(pro)q(ceeds)e(as)g(if)g(an)g(exact)f(matc)o(h)h
+(had)g(b)q(een)h(found)f(and)0 208 y(the)19 b(v)m(alue)h(\014eld)g(is)f(then)
+g(used)g(to)f(resolv)o(e)h(the)g(moun)o(t)f(request,)h(otherwise)g(an)f
+(error)g(co)q(de)h(is)h(propagated)0 258 y(bac)o(k)15 b(to)g(the)g(k)o
+(ernel.)21 b(\(see)15 b(Chapter)g(5)f([Filesystem)i(T)o(yp)q(es],)f(page)30
+b(SMM:13-20\).)0 437 y Fq(3.3)j(Lo)r(cation)15 b(F)-6 b(ormat)62
+528 y Fo(The)17 b(v)m(alue)h(\014eld)f(from)f(the)h(lo)q(okup)g(pro)o(vides)g
+(the)f(information)h(required)h(to)d(moun)o(t)h(a)g(\014lesystem.)25
+b(The)0 578 y(information)15 b(is)h(parsed)f(according)h(to)f(the)g(syn)o
+(tax)f(sho)o(wn)h(b)q(elo)o(w.)120 648 y Fp(lo)q(cation-list)q
+Fo(:)393 698 y Fp(lo)q(cation-selection)393 748 y(lo)q(cation-list)j
+(white-space)g Fl(||)d Fp(white-space)k(lo)q(cation-selection)120
+798 y(lo)q(cation-selection)p Fo(:)393 848 y Fp(lo)q(cation)393
+897 y(lo)q(cation-selection)e(white-space)i(lo)q(cation)120
+947 y(lo)q(cation)p Fo(:)393 997 y Fp(lo)q(cation-info)393
+1047 y Fl(-)p Fp(lo)q(cation-info)393 1097 y Fl(-)120 1147
+y Fp(lo)q(cation-info)r Fo(:)393 1196 y Fp(sel-or-opt)393 1246
+y(lo)q(cation-info)r Fl(;)p Fp(sel-or-opt)393 1296 y Fl(;)120
+1346 y Fp(sel-or-opt)q Fo(:)393 1396 y Fp(selection)393 1445
+y(opt-ass)120 1495 y(selection)p Fo(:)393 1545 y(selector)p
+Fl(==)p Fp(v)m(alue)393 1595 y Fo(selector)p Fl(!=)p Fp(v)m(alue)120
+1645 y(opt-ass)r Fo(:)393 1694 y(option)p Fl(:=)p Fp(v)m(alue)120
+1744 y(white-space)s Fo(:)393 1794 y(space)393 1844 y(tab)62
+1935 y(Note)g(that)f(unquoted)h(whitespace)h(is)f(not)f(allo)o(w)o(ed)h(in)h
+(a)e(lo)q(cation)i(description.)32 b(White)19 b(space)g(is)g(only)0
+1985 y(allo)o(w)o(ed,)c(and)h(is)f(mandatory)l(,)f(where)i(sho)o(wn)f(with)g
+(non-terminal)i(`)p Fl(white-space)p Fo('.)62 2056 y(A)j Fp(lo)q
+(cation-selection)h Fo(is)f(a)f(list)h(of)f(p)q(ossible)i(v)o(olumes)f(with)f
+(whic)o(h)i(to)d(satisfy)h(the)h(request.)32 b Fp(lo)q(cation-)0
+2105 y(selection)p Fo(s)23 b(are)f(separated)f(b)o(y)h(the)g(`)p
+Fl(||)p Fo(')f(op)q(erator.)39 b(The)22 b(e\013ect)f(of)h(this)g(op)q(erator)
+f(is)h(to)g(prev)o(en)o(t)f(use)h(of)0 2155 y(lo)q(cation-selections)d(to)c
+(its)i(righ)o(t)f(if)h(an)o(y)f(of)g(the)g(lo)q(cation-selections)j(on)d(its)
+h(left)f(w)o(ere)g(selected)i(whether)e(or)0 2205 y(not)f(an)o(y)g(of)f(them)
+i(w)o(ere)f(successfully)i(moun)o(ted)e(\(see)g(Section)h(3.3.3)e
+([Selectors],)g(page)31 b(SMM:13-13\).)62 2276 y(The)17 b(lo)q
+(cation-selection,)h(and)e(singleton)h Fp(lo)q(cation-list)p
+Fo(,)h(`)p Fl(type:=ufs;dev:=/dev/)o(xd1g)p Fo(')12 b(w)o(ould)17
+b(inform)0 2325 y Fp(Amd)g Fo(to)e(moun)o(t)f(a)h(UFS)g(\014lesystem)h(from)f
+(the)g(blo)q(c)o(k)h(sp)q(ecial)h(device)g(`)p Fl(/dev/xd1g)p
+Fo('.)62 2396 y(The)h Fp(sel-or-opt)g Fo(comp)q(onen)o(t)f(is)h(either)f(the)
+h(name)f(of)f(an)h(option)h(required)g(b)o(y)f(a)g(sp)q(eci\014c)i
+(\014lesystem,)e(or)0 2446 y(it)h(is)g(the)g(name)f(of)h(a)f(built-in,)j
+(prede\014ned)f(selector)f(suc)o(h)g(as)g(the)f(arc)o(hitecture)h(t)o(yp)q
+(e.)28 b(The)17 b(v)m(alue)i(ma)o(y)e(b)q(e)0 2496 y(quoted)g(with)g(double)h
+(quotes)f(`)p Fl(")p Fo(',)f(for)g(example)i(`)p Fl(type:="ufs";dev:="/dev/)o
+(xd1g")p Fo(')o(.)k(These)c(quotes)e(are)0 2545 y(stripp)q(ed)k(when)g(the)g
+(v)m(alue)g(is)g(parsed)f(and)h(there)f(is)h(no)f(w)o(a)o(y)f(to)h(get)g(a)g
+(double)h(quote)f(in)o(to)h(a)f(v)m(alue)h(\014eld.)0 2595
+y(Double)h(quotes)g(are)f(used)h(to)f(get)h(white)g(space)g(in)o(to)f(a)h(v)m
+(alue)h(\014eld,)h(whic)o(h)e(is)g(needed)h(for)e(the)h(program)0
+2645 y(\014lesystem)16 b(\(see)f(Section)h(5.5)e([Program)g(Filesystem],)h
+(page)30 b(SMM:13-23\).)p eop
+%%Page: 12 14
+12 13 bop 15 -83 a Fo(SMM:13-12)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fi(3.3.1)30 b(Map)15 b(Defaults)62
+250 y Fo(A)h(lo)q(cation)h(b)q(eginning)h(with)e(a)g(dash)g(`)p
+Fl(-)p Fo(')f(is)h(used)h(to)e(sp)q(ecify)i(default)g(v)m(alues)g(for)e
+(subsequen)o(t)i(lo)q(cations.)0 299 y(An)o(y)12 b(previously)i(sp)q
+(eci\014ed)g(defaults)f(in)g(the)f(lo)q(cation-list)i(are)e(discarded.)20
+b(The)13 b(default)g(string)f(can)g(b)q(e)h(empt)o(y)0 349
+y(in)j(whic)o(h)g(case)f(no)g(defaults)h(apply)l(.)62 420 y(The)c(lo)q
+(cation)h(`)p Fl(-fs:=/mnt;opts:=ro)p Fo(')8 b(w)o(ould)k(set)g(the)f(lo)q
+(cal)i(moun)o(t)e(p)q(oin)o(t)h(to)f(`)p Fl(/mnt)p Fo(')g(and)h(cause)g(moun)
+o(ts)0 470 y(to)h(b)q(e)g(read-only)h(b)o(y)f(default.)20 b(Defaults)13
+b(sp)q(eci\014ed)i(this)f(w)o(a)o(y)e(are)h(app)q(ended)i(to,)d(and)i(so)e(o)
+o(v)o(erride,)i(an)o(y)e(global)0 519 y(map)j(defaults)h(giv)o(en)f(with)h(`)
+p Fl(/defaults)p Fo('\).)0 805 y Fi(3.3.2)30 b(V)-5 b(ariable)15
+b(Expansion)62 896 y Fo(T)l(o)g(allo)o(w)g(generic)h(lo)q(cation)g(sp)q
+(eci\014cations)h Fp(Amd)g Fo(do)q(es)e(v)m(ariable)i(expansion)f(on)f(eac)o
+(h)g(lo)q(cation)h(and)f(also)0 946 y(on)f(some)f(of)g(the)h(option)g
+(strings.)19 b(An)o(y)13 b(option)h(or)f(selector)h(app)q(earing)h(in)f(the)g
+(form)f Fl($)p Fp(v)m(ar)j Fo(is)e(replaced)h(b)o(y)f(the)0
+996 y(curren)o(t)f(v)m(alue)i(of)e(that)g(option)h(or)f(selector.)19
+b(F)l(or)13 b(example,)h(if)g(the)g(v)m(alue)h(of)e Fl(${key})f
+Fo(w)o(as)h(`)p Fl(bin)p Fo(',)f Fl(${autodir})0 1046 y Fo(w)o(as)k(`)p
+Fl(/a)p Fo(')f(and)i Fl(${fs})f Fo(w)o(as)g(`)p Fl(${autodir}/local/${key})p
+Fo(')d(then)k(after)f(expansion)i Fl(${fs})e Fo(w)o(ould)h(ha)o(v)o(e)f(the)0
+1095 y(v)m(alue)g(`)p Fl(/a/local/bin)p Fo('.)i(An)o(y)d(en)o(vironmen)o(t)h
+(v)m(ariable)g(can)f(b)q(e)h(accessed)g(in)g(a)f(similar)h(w)o(a)o(y)l(.)62
+1166 y(Tw)o(o)f(pathname)g(op)q(erators)g(are)g(a)o(v)m(ailable)i(when)f
+(expanding)h(a)e(v)m(ariable.)23 b(If)16 b(the)f(v)m(ariable)i(name)f(b)q
+(egins)0 1216 y(with)h(`)p Fl(/)p Fo(')g(then)g(only)h(the)f(last)g(comp)q
+(onen)o(t)g(of)g(then)g(pathname)g(is)h(substituted.)26 b(F)l(or)16
+b(example,)i(if)g Fl(${path})0 1266 y Fo(w)o(as)f(`)p Fl(/foo/bar)p
+Fo(')e(then)j Fl(${/path})e Fo(w)o(ould)i(b)q(e)g(expanded)h(to)d(`)p
+Fl(bar)p Fo('.)26 b(Similarly)l(,)20 b(if)e(the)f(v)m(ariable)i(name)e(ends)0
+1315 y(with)f(`)p Fl(/)p Fo(')e(then)h(all)i(but)e(the)g(last)g(comp)q(onen)o
+(t)h(of)f(the)g(pathname)g(is)h(substituted.)k(In)c(the)g(previous)f
+(example,)0 1365 y Fl(${path/})f Fo(w)o(ould)i(b)q(e)g(expanded)g(to)e(`)p
+Fl(/foo)p Fo('.)62 1436 y(Tw)o(o)i(domain)g(name)h(op)q(erators)e(are)h(also)
+g(pro)o(vided.)24 b(If)16 b(the)h(v)m(ariable)g(name)f(b)q(egins)i(with)f(`)p
+Fl(.)p Fo(')e(then)h(only)0 1486 y(the)h(domain)g(part)f(of)g(the)g(name)h
+(is)g(substituted.)25 b(F)l(or)16 b(example,)h(if)g Fl(${rhost})e
+Fo(w)o(as)h(`)p Fl(swan.doc.ic.ac.uk)p Fo(')0 1535 y(then)g
+Fl(${.rhost})f Fo(w)o(ould)i(b)q(e)f(expanded)h(to)f(`)p Fl(doc.ic.ac.uk)p
+Fo('.)k(Similarly)l(,)e(if)e(the)h(v)m(ariable)g(name)f(ends)h(with)0
+1585 y(`)p Fl(.)p Fo(')h(then)h(only)g(the)g(host)f(comp)q(onen)o(t)h(is)g
+(substituted.)31 b(In)19 b(the)g(previous)g(example,)h Fl(${rhost.})d
+Fo(w)o(ould)i(b)q(e)0 1635 y(expanded)d(to)f(`)p Fl(swan)p
+Fo('.)62 1706 y(V)l(ariable)k(expansion)f(is)g(a)f(t)o(w)o(o)f(phase)h(pro)q
+(cess.)26 b(Before)18 b(a)f(lo)q(cation)h(is)f(parsed,)h(all)g(references)g
+(to)f(selec-)0 1755 y(tors,)f Fp(eg)k Fl(${path})p Fo(,)c(are)g(expanded.)25
+b(The)17 b(lo)q(cation)g(is)g(then)g(parsed,)g(selections)h(are)e(ev)m
+(aluated)i(and)f(option)0 1805 y(assignmen)o(ts)h(recorded.)31
+b(If)19 b(there)g(w)o(ere)f(no)h(selections)h(or)e(they)g(all)i(succeeded)g
+(the)f(lo)q(cation)g(is)h(used)f(and)0 1855 y(the)c(v)m(alues)h(of)f(the)g
+(follo)o(wing)h(options)f(are)g(expanded)h(in)g(the)f(order)g(giv)o(en:)20
+b Fp(sublink)p Fo(,)d Fp(rfs)p Fo(,)d Fp(fs)p Fo(,)h Fp(opts)p
+Fo(,)f Fp(remopts)p Fo(,)0 1905 y Fp(moun)o(t)i Fo(and)f Fp(unmoun)o(t)p
+Fo(.)62 1975 y(Note)f(that)f(expansion)h(of)g(option)f(v)m(alues)i(is)g(done)
+f(after)f Fp(all)j Fo(assignmen)o(ts)e(ha)o(v)o(e)f(b)q(een)i(completed)f
+(and)g(not)0 2025 y(in)20 b(a)f(purely)h(left)g(to)e(righ)o(t)h(order)g(as)g
+(is)g(done)h(b)o(y)f(the)g(shell.)33 b(This)20 b(generally)g(has)f(the)h
+(desired)g(e\013ect)f(but)0 2075 y(care)14 b(m)o(ust)g(b)q(e)h(tak)o(en)f(if)
+g(one)h(of)f(the)g(options)h(references)g(another,)e(in)i(whic)o(h)h(case)e
+(the)g(ordering)h(can)f(b)q(ecome)0 2125 y(signi\014can)o(t.)62
+2195 y(There)i(are)f(t)o(w)o(o)e(sp)q(ecial)k(cases)f(concerning)g(v)m
+(ariable)h(expansion:)25 2266 y(1.)29 b(b)q(efore)12 b(a)f(map)h(is)g
+(consulted,)h(an)o(y)e(selectors)h(in)g(the)g(name)g(receiv)o(ed)h(from)d
+(the)i(k)o(ernel)h(are)e(expanded.)20 b(F)l(or)90 2316 y(example,)f(if)f(the)
+f(request)h(from)e(the)i(k)o(ernel)g(w)o(as)f(for)g(`)p Fl(${arch}.bin)p
+Fo(')e(and)j(the)f(mac)o(hine)i(arc)o(hitecture)90 2366 y(w)o(as)14
+b(`)p Fl(vax)p Fo(',)g(the)h(v)m(alue)i(giv)o(en)e(to)g Fl(${key})f
+Fo(w)o(ould)i(b)q(e)g(`)p Fl(vax.bin)p Fo('.)25 2446 y(2.)29
+b(the)13 b(v)m(alue)h(of)e Fl(${rhost})g Fo(is)h(expanded)h(and)f(normalized)
+i(b)q(efore)e(the)g(other)f(options)h(are)g(expanded.)20 b(The)90
+2496 y(normalization)g(pro)q(cess)g(strips)g(an)o(y)f(lo)q(cal)i(sub-domain)g
+(comp)q(onen)o(ts.)33 b(F)l(or)19 b(example,)i(if)f Fl(${domain})90
+2545 y Fo(w)o(as)12 b(`)p Fl(Berkeley.EDU)p Fo(')e(and)j Fl(${rhost})f
+Fo(w)o(as)g(initially)j(`)p Fl(snow.Berkeley.EDU)p Fo(',)10
+b(after)i(the)h(normalization)90 2595 y(it)21 b(w)o(ould)g(simply)h(b)q(e)g
+(`)p Fl(snow)p Fo('.)35 b(Hostname)21 b(normalization)g(is)h(curren)o(tly)f
+(done)g(in)h(a)e Fp(case-dep)q(enden)o(t)90 2645 y Fo(manner.)p
+eop
+%%Page: 13 15
+13 14 bop 0 -83 a Fo(Chapter)15 b(3:)k(Moun)o(t)c(Maps)1236
+b(SMM:13-13)0 158 y Fi(3.3.3)30 b(Selectors)62 250 y Fo(Selectors)15
+b(are)g(used)g(to)f(con)o(trol)g(the)h(use)g(of)f(a)h(lo)q(cation.)20
+b(It)15 b(is)g(p)q(ossible)h(to)e(share)h(a)f(moun)o(t)g(map)h(b)q(et)o(w)o
+(een)0 299 y(man)o(y)c(mac)o(hines)h(in)g(suc)o(h)g(a)f(w)o(a)o(y)g(that)f
+(\014lesystem)i(lo)q(cation,)h(arc)o(hitecture)f(and)f(op)q(erating)h(system)
+f(di\013erences)0 349 y(are)18 b(hidden)j(from)d(the)h(users.)31
+b(A)18 b(selector)h(of)g(the)g(form)f(`)p Fl(arch==sun3;os==sos4)p
+Fo(')d(w)o(ould)k(only)g(apply)h(on)0 399 y(Sun-3s)c(running)g(SunOS)h(4.x.)
+62 470 y(Selectors)22 b(are)f(ev)m(aluated)h(left)g(to)e(righ)o(t.)38
+b(If)21 b(a)g(selector)g(fails)h(then)g(that)e(lo)q(cation)i(is)g(ignored.)38
+b(Th)o(us)0 519 y(the)21 b(selectors)h(form)f(a)g(conjunction)h(and)g(the)f
+(lo)q(cations)h(form)f(a)g(disjunction.)40 b(If)21 b(all)i(the)e(lo)q
+(cations)h(are)0 569 y(ignored)17 b(or)f(otherwise)h(fail)h(then)f
+Fp(Amd)h Fo(uses)f(the)g Fp(error)i Fo(\014lesystem)e(\(see)g(Section)g(5.11)
+f([Error)f(Filesystem],)0 619 y(page)43 b(SMM:13-26\).)38 b(This)22
+b(is)g(equiv)m(alen)o(t)i(to)d(ha)o(ving)h(a)f(lo)q(cation)i(`)p
+Fl(type:=error)p Fo(')c(at)i(the)h(end)h(of)e(eac)o(h)0 669
+y(moun)o(t-map)15 b(en)o(try)l(.)62 739 y(The)h(selectors)f(curren)o(tly)h
+(implemen)o(ted)h(are:)0 823 y(`)p Fl(arch)p Fo(')118 b(the)19
+b(mac)o(hine)g(arc)o(hitecture)g(whic)o(h)g(w)o(as)e(automatically)i
+(determined)h(at)e(compile)i(time.)30 b(The)240 873 y(arc)o(hitecture)16
+b(t)o(yp)q(e)f(can)h(b)q(e)g(displa)o(y)o(ed)h(b)o(y)e(running)i(the)f
+(command)f(`)p Fl(amd)f(-v)p Fo('.)20 b(See)d(Section)f(2.2)240
+923 y([Supp)q(orted)g(Mac)o(hine)g(Arc)o(hitectures],)f(page)30
+b(SMM:13-7.)0 985 y(`)p Fl(autodir)p Fo(')46 b(the)16 b(default)h(directory)g
+(under)g(whic)o(h)g(to)f(moun)o(t)g(\014lesystems.)24 b(This)17
+b(ma)o(y)f(b)q(e)h(c)o(hanged)g(b)o(y)f(the)240 1035 y(\\-a")e(command)i
+(line)g(option.)21 b(See)15 b(the)h Fp(fs)g Fo(option.)0 1098
+y(`)p Fl(byte)p Fo(')118 b(the)16 b(mac)o(hine's)g(b)o(yte)f(ordering.)21
+b(This)c(is)f(either)g(`)p Fl(little)p Fo(',)e(indicating)j(little-endian,)h
+(or)e(`)p Fl(big)p Fo(',)240 1148 y(indicating)k(big-endian.)31
+b(One)18 b(p)q(ossible)i(use)f(is)f(to)g(share)g(`)p Fl(rwho)p
+Fo(')e(databases)i(\(see)g(Section)h(8.5)240 1197 y([rwho)c(serv)o(ers],)h
+(page)32 b(SMM:13-49\).)21 b(Another)16 b(is)g(to)g(share)g(ndbm)h
+(databases,)e(ho)o(w)o(ev)o(er)h(this)240 1247 y(use)g(can)f(b)q(e)h
+(considered)g(a)f(courageous)g(juggling)h(act.)0 1310 y(`)p
+Fl(cluster)p Fo(')46 b(is)19 b(pro)o(vided)h(as)e(a)h(ho)q(ok)g(for)f(the)h
+(name)g(of)f(the)h(lo)q(cal)h(cluster.)32 b(This)19 b(can)g(b)q(e)h(used)f
+(to)f(decide)240 1360 y(whic)o(h)h(serv)o(ers)f(to)g(use)g(for)g(copies)h(of)
+f(replicated)i(\014lesystems.)30 b Fl(${cluster})16 b Fo(defaults)j(to)f(the)
+240 1410 y(v)m(alue)e(of)f Fl(${domain})f Fo(unless)i(a)f(di\013eren)o(t)h(v)
+m(alue)g(is)g(set)f(with)g(the)h(\\-C")e(command)h(line)i(option.)0
+1472 y(`)p Fl(domain)p Fo(')70 b(the)15 b(lo)q(cal)i(domain)e(name)g(as)g(sp)
+q(eci\014ed)j(b)o(y)d(the)g(\\-d")g(command)g(line)i(option.)j(See)c(`)p
+Fl(host)p Fo('.)0 1535 y(`)p Fl(host)p Fo(')118 b(the)13 b(lo)q(cal)h
+(hostname)e(as)h(determined)h(b)o(y)f Fk(gethostname)p Fo(\(2\).)18
+b(If)13 b(no)g(domain)g(name)g(w)o(as)f(sp)q(eci\014ed)240
+1585 y(on)19 b(the)g(command)f(line)j(and)e(the)f(hostname)h(con)o(tains)g(a)
+f(p)q(erio)q(d)i(`)p Fl(.)p Fo(')e(then)h(the)g(string)g(b)q(efore)240
+1635 y(the)i(p)q(erio)q(d)g(is)g(used)g(as)f(the)h(host)f(name,)h(and)g(the)f
+(string)h(after)e(the)i(p)q(erio)q(d)h(is)f(assigned)g(to)240
+1684 y Fl(${domain})p Fo(.)d(F)l(or)13 b(example,)h(if)f(the)h(hostname)f(is)
+g(`)p Fl(styx.doc.ic.ac.uk)p Fo(')d(then)k Fl(host)f Fo(w)o(ould)g(b)q(e)240
+1734 y(`)p Fl(styx)p Fo(')h(and)h Fl(domain)g Fo(w)o(ould)g(b)q(e)h(`)p
+Fl(doc.ic.ac.uk)p Fo('.)h Fl(hostd)e Fo(w)o(ould)h(b)q(e)f(`)p
+Fl(styx.doc.ic.ac.uk)p Fo('.)0 1797 y(`)p Fl(hostd)p Fo(')94
+b(is)16 b Fl(${host})e Fo(and)i Fl(${domain})e Fo(concatenated)h(with)h(a)f
+(`)p Fl(.)p Fo(')f(inserted)i(b)q(et)o(w)o(een)g(them)f(if)h(required.)240
+1847 y(If)f Fl(${domain})f Fo(is)i(an)f(empt)o(y)g(string)g(then)h
+Fl(${host})e Fo(and)h Fl(${hostd})f Fo(will)j(b)q(e)f(iden)o(tical.)0
+1909 y(`)p Fl(karch)p Fo(')94 b(is)13 b(pro)o(vided)g(as)f(a)g(ho)q(ok)h(for)
+e(the)i(k)o(ernel)g(arc)o(hitecture.)19 b(This)13 b(is)g(used)g(on)g(SunOS)g
+(4,)g(for)e(example,)240 1959 y(to)i(distinguish)i(b)q(et)o(w)o(een)f
+(di\013eren)o(t)f(`)p Fl(/usr/kvm)p Fo(')f(v)o(olumes.)20 b
+Fl(${karch})12 b Fo(defaults)i(to)e(the)i(v)m(alue)g(of)240
+2009 y Fl(${arch})g Fo(unless)j(a)d(di\013eren)o(t)i(v)m(alue)g(is)g(set)f
+(with)g(the)h(\\-k")e(command)i(line)g(option.)0 2072 y(`)p
+Fl(os)p Fo(')166 b(the)15 b(op)q(erating)g(system.)k(Lik)o(e)d(the)f(mac)o
+(hine)h(arc)o(hitecture,)f(this)g(is)g(automatically)h(determined)240
+2122 y(at)11 b(compile)h(time.)19 b(The)12 b(op)q(erating)f(system)g(name)g
+(can)h(b)q(e)g(displa)o(y)o(ed)g(b)o(y)f(running)i(the)e(command)240
+2171 y(`)p Fl(amd)j(-v)p Fo('.)20 b(See)15 b(Section)h(2.1)f([Supp)q(orted)g
+(Op)q(erating)h(Systems],)f(page)30 b(SMM:13-6.)62 2263 y(The)15
+b(follo)o(wing)g(selectors)g(are)f(also)h(pro)o(vided.)20 b(Unlik)o(e)c(the)f
+(other)f(selectors,)h(they)f(v)m(ary)h(for)f(eac)o(h)h(lo)q(okup.)0
+2313 y(Note)h(that)h(when)g(the)g(name)g(from)f(the)h(k)o(ernel)g(is)g
+(expanded)h(prior)f(to)f(a)h(map)g(lo)q(okup,)g(these)g(selectors)g(are)0
+2362 y(all)f(de\014ned)h(as)e(empt)o(y)f(strings.)0 2433 y(`)p
+Fl(key)p Fo(')142 b(the)13 b(name)f(b)q(eing)i(resolv)o(ed.)19
+b(F)l(or)12 b(example,)i(if)e(`)p Fl(/home)p Fo(')f(is)i(an)g(automoun)o(t)e
+(p)q(oin)o(t,)i(then)g(accessing)240 2483 y(`)p Fl(/home/foo)p
+Fo(')c(w)o(ould)i(set)g Fl(${key})f Fo(to)g(the)h(string)f(`)p
+Fl(foo)p Fo('.)18 b(The)11 b(k)o(ey)f(is)i(pre\014xed)f(b)o(y)g(the)g
+Fp(pref)20 b Fo(option)240 2533 y(set)15 b(in)g(the)g(paren)o(t)f(moun)o(t)h
+(p)q(oin)o(t.)20 b(The)15 b(default)g(pre\014x)g(is)h(an)e(empt)o(y)h
+(string.)20 b(If)15 b(the)g(pre\014x)g(w)o(as)240 2582 y(`)p
+Fl(blah/)p Fo(')f(then)h Fl(${key})g Fo(w)o(ould)g(b)q(e)h(set)f(to)g(`)p
+Fl(blah/foo)p Fo('.)0 2645 y(`)p Fl(map)p Fo(')142 b(the)15
+b(name)g(of)g(the)h(moun)o(t)e(map)h(b)q(eing)i(used.)p eop
+%%Page: 14 16
+14 15 bop 15 -83 a Fo(SMM:13-14)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y(`)p Fl(path)p Fo(')118 b(the)12
+b(full)i(pathname)e(of)g(the)h(name)f(b)q(eing)i(resolv)o(ed.)19
+b(F)l(or)12 b(example)h(`)p Fl(/home/foo)p Fo(')d(in)k(the)e(example)240
+208 y(ab)q(o)o(v)o(e.)0 272 y(`)p Fl(wire)p Fo(')118 b(the)21
+b(name)g(of)g(the)g(net)o(w)o(ork)f(to)h(whic)o(h)h(the)f(primary)g(net)o(w)o
+(ork)g(in)o(terface)g(is)h(attac)o(hed.)37 b(If)21 b(a)240
+322 y(sym)o(b)q(olic)i(name)e(cannot)h(b)q(e)g(found)g(in)g(the)g(net)o(w)o
+(orks)e(or)h(hosts)g(database)g(then)h(dotted)g(IP)240 372
+y(address)15 b(format)f(is)i(used.)k(This)c(v)m(alue)g(is)g(also)f(output)g
+(b)o(y)g(the)h(\\-v")f(option.)62 463 y(Selectors)j(can)f(b)q(e)h(negated)f
+(b)o(y)h(using)f(`)p Fl(!=)p Fo(')g(instead)g(of)g(`)p Fl(==)p
+Fo('.)25 b(F)l(or)16 b(example)j(to)d(select)i(a)f(lo)q(cation)h(on)f(all)0
+513 y(non-V)l(ax)f(mac)o(hines)g(the)f(selector)g(`)p Fl(arch!=vax)p
+Fo(')e(w)o(ould)j(b)q(e)g(used.)0 669 y Fi(3.3.4)30 b(Map)15
+b(Options)62 760 y Fo(Options)e(are)f(parsed)g(concurren)o(tly)h(with)g
+(selectors.)19 b(The)12 b(di\013erence)i(is)f(that)e(when)i(an)f(option)g(is)
+h(seen)g(the)0 810 y(string)g(follo)o(wing)i(the)e(`)p Fl(:=)p
+Fo(')g(is)h(recorded)g(for)e(later)i(use.)20 b(As)13 b(a)g(minim)o(um)i(the)e
+Fp(t)o(yp)q(e)j Fo(option)e(m)o(ust)f(b)q(e)h(sp)q(eci\014ed.)0
+860 y(Eac)o(h)k(\014lesystem)h(t)o(yp)q(e)g(has)f(other)g(options)g(whic)o(h)
+i(m)o(ust)e(also)g(b)q(e)h(sp)q(eci\014ed.)31 b(See)19 b(Chapter)g(5)f
+([Filesystem)0 910 y(T)o(yp)q(es],)d(page)30 b(SMM:13-20,)13
+b(for)h(details)j(on)e(the)g(\014lesystem)h(sp)q(eci\014c)h(options.)62
+980 y(Sup)q(er\015uous)g(option)e(sp)q(eci\014cations)i(are)e(ignored)h(and)f
+(are)g(not)g(rep)q(orted)g(as)g(errors.)62 1051 y(The)h(follo)o(wing)g
+(options)f(apply)h(to)f(more)f(than)h(one)h(\014lesystem)g(t)o(yp)q(e.)0
+1207 y Fi(3.3.4.1)30 b(dela)n(y)15 b(Option)62 1298 y Fo(The)21
+b(dela)o(y)l(,)h(in)f(seconds,)h(b)q(efore)f(an)f(attempt)g(will)i(b)q(e)f
+(made)f(to)g(moun)o(t)g(from)g(the)g(curren)o(t)h(lo)q(cation.)0
+1348 y(Auxilliary)g(data,)d(suc)o(h)g(as)g(net)o(w)o(ork)f(address,)i(\014le)
+g(handles)h(and)e(so)g(on)h(are)f(computed)g(regardless)h(of)f(this)0
+1398 y(v)m(alue.)62 1468 y(A)23 b(dela)o(y)g(can)g(b)q(e)h(used)f(to)f
+(implemen)o(t)i(the)f(notion)g(of)f(primary)h(and)g(secondary)g(\014le)h
+(serv)o(ers.)42 b(The)0 1518 y(secondary)14 b(serv)o(ers)g(w)o(ould)h(ha)o(v)
+o(e)e(a)h(dela)o(y)h(of)f(a)g(few)g(seconds,)g(th)o(us)g(giving)i(the)e
+(primary)g(serv)o(ers)g(a)g(c)o(hance)h(to)0 1568 y(resp)q(ond)h(\014rst.)0
+1724 y Fi(3.3.4.2)30 b(fs)15 b(Option)62 1815 y Fo(The)h(lo)q(cal)g(moun)o(t)
+f(p)q(oin)o(t.)20 b(The)15 b(seman)o(tics)h(of)f(this)g(option)h(v)m(ary)f(b)
+q(et)o(w)o(een)g(\014lesystems.)62 1885 y(F)l(or)i(NFS)h(and)g(UFS)f
+(\014lesystems)h(the)g(v)m(alue)h(of)e Fl(${fs})g Fo(is)h(used)g(as)f(the)h
+(lo)q(cal)h(moun)o(t)e(p)q(oin)o(t.)27 b(F)l(or)17 b(other)0
+1935 y(\014lesystem)f(t)o(yp)q(es)f(it)g(has)g(other)f(meanings)i(whic)o(h)f
+(are)g(describ)q(ed)i(in)f(the)f(section)g(describing)i(the)e(resp)q(ectiv)o
+(e)0 1985 y(\014lesystem)d(t)o(yp)q(e.)19 b(It)11 b(is)h(imp)q(ortan)o(t)f
+(that)g(this)h(string)f(uniquely)j(iden)o(ti\014es)f(the)f(\014lesystem)g(b)q
+(eing)h(moun)o(ted.)18 b(T)l(o)0 2035 y(satisfy)d(this)g(requiremen)o(t,)g
+(it)g(should)h(con)o(tain)f(the)g(name)g(of)f(the)h(host)f(on)h(whic)o(h)h
+(the)f(\014lesystem)g(is)g(residen)o(t)0 2085 y(and)g(the)h(pathname)f(of)g
+(the)g(\014lesystem)h(on)f(the)g(lo)q(cal)h(or)f(remote)g(host.)62
+2155 y(The)21 b(reason)g(for)f(requiring)i(the)f(hostname)f(is)h(clear)h(if)f
+(replicated)h(\014lesystems)g(are)e(considered.)38 b(If)21
+b(a)0 2205 y(\014leserv)o(er)g(go)q(es)f(do)o(wn)f(and)i(a)e(replacemen)o(t)i
+(\014lesystem)g(is)f(moun)o(ted)g(then)g(the)h Fp(lo)q(cal)i
+Fo(moun)o(t)c(p)q(oin)o(t)i Fp(m)o(ust)0 2255 y Fo(b)q(e)e(di\013eren)o(t)f
+(from)g(that)g(of)f(the)i(\014lesystem)g(whic)o(h)g(is)g(h)o(ung.)29
+b(Some)18 b(enco)q(ding)i(of)e(the)g(\014lesystem)h(name)f(is)0
+2305 y(required)e(if)g(more)f(than)g(one)g(\014lesystem)h(is)g(to)e(b)q(e)i
+(moun)o(ted)f(from)g(an)o(y)g(giv)o(en)g(host.)62 2375 y(If)21
+b(the)f(hostname)f(is)i(\014rst)e(in)i(the)f(path)g(then)g(all)h(moun)o(ts)f
+(from)f(a)h(particular)g(host)g(will)h(b)q(e)g(gathered)0 2425
+y(b)q(elo)o(w)16 b(a)e(single)j(directory)l(.)j(If)c(that)e(serv)o(er)h(go)q
+(es)g(do)o(wn)f(then)i(the)f(h)o(ung)g(moun)o(t)g(p)q(oin)o(ts)g(are)g(less)h
+(lik)o(ely)h(to)d(b)q(e)0 2475 y(acciden)o(tally)j(referenced,)e(for)g
+(example)g(when)h Fk(get)o(wd)p Fo(\(3\))d(tra)o(v)o(erses)h(the)h(namespace)
+g(to)f(\014nd)i(the)f(pathname)0 2525 y(of)g(the)g(curren)o(t)g(directory)l
+(.)62 2595 y(The)i(`)p Fl(fs)p Fo(')e(option)h(defaults)g(to)g
+Fl(${autodir}/${rhost}${rfs)o(})p Fo(.)k(In)c(addition,)h(`)p
+Fl(rhost)p Fo(')e(defaults)h(to)g(the)0 2645 y(lo)q(cal)k(host)e(name)h(\()p
+Fl(${host})p Fo(\))e(and)i(`)p Fl(rfs)p Fo(')e(defaults)i(to)f(the)h(v)m
+(alue)h(of)e Fl(${path})p Fo(,)g(whic)o(h)i(is)f(the)g(full)h(path)e(of)p
+eop
+%%Page: 15 17
+15 16 bop 0 -83 a Fo(Chapter)15 b(3:)k(Moun)o(t)c(Maps)1236
+b(SMM:13-15)0 158 y(the)15 b(requested)h(\014le;)g(`)p Fl(/home/foo)p
+Fo(')d(in)j(the)f(example)h(ab)q(o)o(v)o(e)f(\(see)g(Section)h(3.3.3)d
+([Selectors],)i(page)30 b(SMM:13-)0 208 y(13\).)23 b Fl(${autodir})16
+b Fo(defaults)h(to)f(`)p Fl(/a)p Fo(')f(but)i(ma)o(y)f(b)q(e)i(c)o(hanged)f
+(with)g(the)f(\\-a")g(command)h(line)h(option.)25 b(Sun's)0
+258 y(automoun)o(ter)15 b(defaults)i(to)e(`)p Fl(/tmp_mnt)p
+Fo('.)22 b(Note)15 b(that)h(there)g(is)h(no)f(`)p Fl(/)p Fo(')f(b)q(et)o(w)o
+(een)i(the)f Fl(${rhost})f Fo(and)i Fl(${rfs})0 308 y Fo(since)f
+Fl(${rfs})f Fo(b)q(egins)h(with)g(a)f(`)p Fl(/)p Fo('.)0 437
+y Fi(3.3.4.3)30 b(opts)15 b(Option)62 528 y Fo(The)20 b(options)f(to)f(pass)h
+(to)g(the)g(moun)o(t)g(system)g(call.)32 b(A)20 b(leading)g(`)p
+Fl(-)p Fo(')e(is)i(silen)o(tly)h(ignored.)32 b(The)19 b(moun)o(t)0
+578 y(options)h(supp)q(orted)h(generally)g(corresp)q(ond)f(to)f(those)h(used)
+h(b)o(y)f Fk(moun)o(t)p Fo(\(8\))e(and)i(are)g(listed)h(b)q(elo)o(w.)35
+b(Some)0 628 y(additional)17 b(pseudo-options)f(are)f(in)o(terpreted)g(b)o(y)
+h Fp(Amd)h Fo(and)e(are)g(also)g(listed.)62 698 y(Unless)k(sp)q(eci\014cally)
+h(o)o(v)o(erridden,)e(eac)o(h)f(of)g(the)g(system)g(default)h(moun)o(t)e
+(options)i(applies.)28 b(An)o(y)17 b(options)0 748 y(not)12
+b(recognised)h(are)f(ignored.)19 b(If)12 b(no)g(options)h(list)g(is)f
+(supplied)j(the)d(string)g(`)p Fl(rw,defaults)p Fo(')e(is)j(used)f(and)h(all)
+g(the)0 798 y(system)k(default)g(moun)o(t)g(options)g(apply)l(.)26
+b(Options)18 b(whic)o(h)f(are)g(not)g(applicable)i(for)d(a)h(particular)h(op)
+q(erating)0 848 y(system)d(are)h(silen)o(tly)h(ignored.)22
+b(F)l(or)15 b(example,)h(only)g(4.4)f(BSD)h(is)g(kno)o(wn)f(to)g(implemen)o
+(t)i(the)f Fl(compress)f Fo(and)0 898 y Fl(spongy)f Fo(options.)0
+968 y Fl(compress)48 b Fo(Use)15 b(NFS)h(compression)f(proto)q(col.)0
+1027 y Fl(grpid)120 b Fo(Use)15 b(BSD)h(directory)f(group-id)h(seman)o(tics.)
+0 1087 y Fl(intr)144 b Fo(Allo)o(w)16 b(k)o(eyb)q(oard)f(in)o(terrupts)g(on)g
+(hard)h(moun)o(ts.)0 1146 y Fl(noconn)96 b Fo(Don't)14 b(mak)o(e)h(a)g
+(connection)h(on)f(datagram)f(transp)q(orts.)0 1205 y Fl(nocto)120
+b Fo(No)15 b(close-to-op)q(en)h(consistency)l(.)0 1265 y Fl(nodevs)96
+b Fo(Don't)14 b(allo)o(w)i(lo)q(cal)g(sp)q(ecial)h(devices)f(on)g(this)f
+(\014lesystem.)0 1324 y Fl(nosuid)96 b Fo(Don't)14 b(allo)o(w)i(set-uid)g(or)
+f(set-gid)g(executables)i(on)e(this)g(\014lesystem.)0 1383
+y Fl(quota)120 b Fo(Enable)16 b(quota)f(c)o(hec)o(king)h(on)f(this)h(moun)o
+(t.)0 1442 y Fl(retrans=)p Fp(n)240 1502 y Fo(The)21 b(n)o(um)o(b)q(er)g(of)f
+(NFS)h(retransmits)f(made)h(b)q(efore)f(a)h(user)g(error)f(is)h(generated)f
+(b)o(y)h(a)f(`)p Fl(soft)p Fo(')240 1551 y(moun)o(ted)15 b(\014lesystem,)h
+(and)g(b)q(efore)f(a)g(`)p Fl(hard)p Fo(')f(moun)o(ted)i(\014lesystem)g(rep)q
+(orts)f(`)p Fl(NFS)f(server)g Fp(y)o(o)o(y)o(o)240 1601 y Fl(not)h
+(responding)f(still)g(trying)p Fo('.)0 1660 y Fl(ro)192 b Fo(Moun)o(t)14
+b(this)i(\014lesystem)g(readonly)l(.)0 1720 y Fl(rsize=)p Fp(n)71
+b Fo(The)12 b(NFS)g(read)f(pac)o(k)o(et)g(size.)20 b(Y)l(ou)12
+b(ma)o(y)f(need)h(to)f(set)h(this)g(if)g(y)o(ou)f(are)h(using)g(NFS/UDP)f
+(through)240 1770 y(a)k(gatew)o(a)o(y)l(.)0 1829 y Fl(soft)144
+b Fo(Giv)o(e)15 b(up)h(after)e Fp(retrans)j Fo(retransmissions.)0
+1888 y Fl(spongy)96 b Fo(Lik)o(e)16 b(`)p Fl(soft)p Fo(')e(for)h(status)f
+(requests,)h(and)g(`)p Fl(hard)p Fo(')f(for)g(data)h(transfers.)0
+1947 y Fl(tcp)168 b Fo(Use)15 b(TCP/IP)f(instead)h(of)f(UDP/IP)l(,)g(ignored)
+h(if)g(the)g(NFS)f(implemen)o(tation)i(do)q(es)f(not)f(supp)q(ort)240
+1997 y(TCP/IP)h(moun)o(ts.)0 2056 y Fl(timeo=)p Fp(n)71 b Fo(The)15
+b(NFS)h(timeout,)e(in)i(ten)o(th-seconds,)g(b)q(efore)f(a)g(request)g(is)h
+(retransmitted.)0 2116 y Fl(wsize=)p Fp(n)71 b Fo(The)21 b(NFS)h(write)f(pac)
+o(k)o(et)g(size.)39 b(Y)l(ou)21 b(ma)o(y)g(need)h(to)e(set)h(this)h(if)g(y)o
+(ou)f(are)g(using)h(NFS/UDP)240 2165 y(through)15 b(a)g(gatew)o(a)o(y)l(.)62
+2257 y(The)h(follo)o(wing)g(options)f(are)g(implemen)o(ted)i(b)o(y)e
+Fp(Amd)p Fo(,)g(rather)g(than)g(b)q(eing)h(passed)g(to)e(the)h(k)o(ernel.)0
+2327 y Fl(nounmount)240 2387 y Fo(Con\014gures)f(the)g(moun)o(t)g(so)g(that)g
+(its)g(time-to-liv)o(e)h(will)h(nev)o(er)f(expire.)20 b(This)15
+b(is)g(also)f(the)g(default)240 2436 y(for)h(some)f(\014lesystem)i(t)o(yp)q
+(es.)0 2496 y Fl(ping=)p Fp(n)95 b Fo(The)16 b(in)o(terv)m(al,)h(in)g
+(seconds,)f(b)q(et)o(w)o(een)h(k)o(eep-aliv)o(e)g(pings.)23
+b(When)17 b(four)f(consecutiv)o(e)h(pings)f(ha)o(v)o(e)240
+2545 y(failed)h(the)f(moun)o(t)f(p)q(oin)o(t)h(is)g(mark)o(ed)f(as)h(h)o
+(ung.)21 b(This)16 b(in)o(terv)m(al)h(defaults)f(to)f(30)g(seconds.)22
+b(If)16 b(the)240 2595 y(ping)g(in)o(terv)m(al)h(is)f(less)g(than)g(zero,)f
+(no)g(pings)i(are)e(sen)o(t)g(and)h(the)g(host)f(is)h(assumed)g(to)e(b)q(e)j
+(alw)o(a)o(ys)240 2645 y(up.)j(By)c(default,)f(pings)h(are)f(not)g(sen)o(t)g
+(for)f(an)h(NFS/TCP)g(moun)o(t.)p eop
+%%Page: 16 18
+16 17 bop 15 -83 a Fo(SMM:13-16)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fl(retry=)p Fp(n)71 b Fo(The)15
+b(n)o(um)o(b)q(er)h(of)f(times)g(to)g(retry)f(the)i(moun)o(t)e(system)h
+(call.)0 220 y Fl(utimeout=)p Fp(n)240 282 y Fo(The)k(in)o(terv)m(al,)h(in)g
+(seconds,)f(b)o(y)g(whic)o(h)h(the)e(moun)o(t's)g(time-to-liv)o(e)i(is)f
+(extended)h(after)e(an)g(un-)240 332 y(moun)o(t)k(attempt)f(has)h(failed.)42
+b(In)23 b(fact)f(the)g(in)o(terv)m(al)h(is)g(extended)g(b)q(efore)g(the)f
+(unmoun)o(t)g(is)240 382 y(attempted)13 b(to)g(a)o(v)o(oid)g(thrashing.)20
+b(The)14 b(default)g(v)m(alue)h(is)f(120)e(seconds)i(\(t)o(w)o(o)e(min)o
+(utes\))i(or)f(as)g(set)240 432 y(b)o(y)i(the)g(\\-w")g(command)g(line)i
+(option.)0 572 y Fi(3.3.4.4)30 b(remopts)15 b(Option)62 663
+y Fo(This)j(option)f(has)g(the)h(same)f(use)g(as)g Fl(${opts})f
+Fo(but)h(applies)i(only)f(when)f(the)h(remote)e(host)h(is)h(on)f(a)g(non-)0
+713 y(lo)q(cal)g(net)o(w)o(ork.)j(F)l(or)15 b(example,)h(when)g(using)g(NFS)g
+(across)e(a)i(gatew)o(a)o(y)d(it)j(is)g(often)g(necessary)f(to)g(use)h
+(smaller)0 763 y(v)m(alues)g(for)e(the)g(data)g(read)g(and)h(write)g(sizes.)
+20 b(This)15 b(can)g(simply)h(b)q(e)f(done)g(b)o(y)f(sp)q(ecifying)j(the)d
+(small)h(v)m(alues)h(in)0 812 y Fp(remopts)p Fo(.)j(When)d(a)f(non-lo)q(cal)h
+(host)f(is)h(accessed,)f(the)h(smaller)g(sizes)g(will)g(automatically)g(b)q
+(e)g(used.)62 883 y Fp(Amd)21 b Fo(determines)f(whether)f(a)f(host)g(is)i(lo)
+q(cal)f(b)o(y)g(examining)h(the)f(net)o(w)o(ork)f(in)o(terface)h
+(con\014guration)g(at)0 933 y(startup.)24 b(An)o(y)17 b(in)o(terface)h(c)o
+(hanges)f(made)g(after)f Fp(Amd)j Fo(has)e(b)q(een)h(started)e(will)j(not)d
+(b)q(e)i(noticed.)26 b(The)17 b(lik)o(ely)0 983 y(e\013ect)e(will)i(b)q(e)f
+(that)e(a)h(host)g(ma)o(y)f(incorrectly)j(b)q(e)e(declared)i(non-lo)q(cal.)62
+1053 y(Unless)f(otherwise)g(set,)e(the)i(v)m(alue)g(of)f Fl(${rem})f
+Fo(is)i(the)f(same)g(as)g(the)g(v)m(alue)i(of)d Fl(${opts})p
+Fo(.)0 1193 y Fi(3.3.4.5)30 b(sublink)16 b(Option)62 1284 y
+Fo(The)22 b(sub)q(directory)h(within)g(the)e(moun)o(ted)h(\014lesystem)g(to)f
+(whic)o(h)i(the)f(reference)g(should)h(p)q(oin)o(t.)39 b(This)0
+1334 y(can)16 b(b)q(e)h(used)f(to)f(prev)o(en)o(t)h(duplicate)h(moun)o(ts)f
+(in)g(cases)g(where)g(m)o(ultiple)i(directories)f(in)g(the)e(same)h(moun)o
+(ted)0 1384 y(\014lesystem)g(are)f(used.)0 1524 y Fi(3.3.4.6)30
+b(t)n(yp)r(e)15 b(Option)62 1615 y Fo(The)h(\014lesystem)g(t)o(yp)q(e)f(to)g
+(b)q(e)h(used.)k(See)c(Chapter)f(5)g([Filesystem)h(T)o(yp)q(es],)e(page)31
+b(SMM:13-20,)13 b(for)i(a)g(full)0 1665 y(description)i(of)d(eac)o(h)i(t)o
+(yp)q(e.)0 1853 y Fm(4)41 b Fh(Amd)16 b Fm(Command)g(Line)f(Options)62
+1973 y Fo(Man)o(y)g(of)g Fp(Amd)r Fo('s)g(parameters)g(can)g(b)q(e)h(set)f
+(from)g(the)h(command)f(line.)22 b(The)16 b(command)f(line)i(is)f(also)f
+(used)0 2022 y(to)g(sp)q(ecify)h(automoun)o(t)e(p)q(oin)o(ts)i(and)f(maps.)62
+2093 y(The)h(general)f(format)f(of)h(a)g(command)g(line)i(is)120
+2164 y Fl(amd)23 b([)p Fp(options)r Fl(])h({)g Fp(directory)k(map-name)e
+Fl([-)p Fp(map-options)r Fl(])e(})g(...)62 2255 y Fo(F)l(or)11
+b(eac)o(h)h(directory)g(and)f(map-name)h(giv)o(en,)g Fp(Amd)i
+Fo(establishes)f(an)e(automoun)o(t)g(p)q(oin)o(t.)19 b(The)12
+b Fp(map-options)0 2305 y Fo(ma)o(y)h(b)q(e)i(an)o(y)e(sequence)j(of)d
+(options)h(or)f(selectors|see)i(Section)g(3.3)e([Lo)q(cation)h(F)l(ormat],)e
+(page)28 b(SMM:13-11.)0 2355 y(The)15 b Fp(map-options)j Fo(apply)e(only)f
+(to)g Fp(Amd)r Fo('s)g(moun)o(t)f(p)q(oin)o(t.)62 2425 y(`)p
+Fl(type:=toplvl;cache:=mapde)o(fault;fs)o(:=${map)o(})p Fo(')c(is)j(the)f
+(default)i(v)m(alue)g(for)e(the)g(map)h(options.)19 b(De-)0
+2475 y(fault)12 b(options)f(for)g(a)h(map)f(are)g(read)h(from)f(a)g(sp)q
+(ecial)i(en)o(try)f(in)g(the)g(map)f(whose)h(k)o(ey)f(is)h(the)g(string)f(`)p
+Fl(/defaults)p Fo('.)0 2525 y(When)16 b(default)g(options)f(are)g(giv)o(en)h
+(they)f(are)g(prep)q(ended)j(to)c(an)o(y)h(options)h(sp)q(eci\014ed)h(in)f
+(the)g(moun)o(t-map)e(lo-)0 2575 y(cations)h(as)g(explained)i(in.)k(See)16
+b(Section)g(3.3.1)e([Map)g(Defaults],)g(page)31 b(SMM:13-12,)13
+b(for)h(more)h(details.)62 2645 y(The)h Fp(options)h Fo(are)e(an)o(y)g(com)o
+(bination)g(of)g(those)g(listed)i(b)q(elo)o(w.)p eop
+%%Page: 17 19
+17 18 bop 0 -83 a Fo(Chapter)15 b(4:)k Fp(Amd)f Fo(Command)c(Line)j(Options)
+899 b(SMM:13-17)62 158 y(Once)14 b(the)f(command)g(line)h(has)f(b)q(een)h
+(parsed,)f(the)g(automoun)o(t)f(p)q(oin)o(ts)h(are)g(moun)o(ted.)19
+b(The)13 b(moun)o(t)g(p)q(oin)o(ts)0 208 y(are)21 b(created)g(if)g(they)g(do)
+g(not)f(already)h(exist,)i(in)e(whic)o(h)h(case)f(they)g(will)i(b)q(e)e(remo)
+o(v)o(ed)g(when)g Fp(Amd)i Fo(exits.)0 258 y(Finally)l(,)17
+b Fp(Amd)g Fo(disasso)q(ciates)f(itself)g(from)e(its)i(con)o(trolling)g
+(terminal)g(and)f(forks)f(in)o(to)i(the)f(bac)o(kground.)62
+329 y(Note:)k(Ev)o(en)c(if)f Fp(Amd)j Fo(has)d(b)q(een)h(built)h(with)f(`)p
+Fl(-DDEBUG)p Fo(')d(it)j(will)h(still)f(bac)o(kground)g(itself)g(and)f
+(disasso)q(ciate)0 378 y(itself)j(from)e(the)h(con)o(trolling)g(terminal.)23
+b(T)l(o)15 b(use)h(a)g(debugger)g(it)g(is)g(necessary)g(to)f(sp)q(ecify)i(`)p
+Fl(-D)e(nodaemon)p Fo(')f(on)0 428 y(the)h(command)g(line.)0
+648 y Fq(4.1)33 b Fg(-a)14 b Ff(directory)62 739 y Fo(Sp)q(eci\014es)25
+b(the)d(default)h(moun)o(t)f(directory)l(.)41 b(This)23 b(option)g(c)o
+(hanges)f(the)h(v)m(ariable)g Fl(${autodir})e Fo(whic)o(h)0
+789 y(otherwise)15 b(defaults)h(to)f(`)p Fl(/a)p Fo('.)j(F)l(or)d(example,)h
+(some)f(sites)g(prefer)g(`)p Fl(/amd)p Fo('.)120 860 y Fl(amd)23
+b(-a)h(/amd)f(...)0 1080 y Fq(4.2)33 b Fg(-c)14 b Ff(cac)n(he-in)n(terv)m(al)
+62 1171 y Fo(Selects)k(the)e(p)q(erio)q(d,)i(in)f(seconds,)g(for)e(whic)o(h)j
+(a)e(name)g(is)h(cac)o(hed)g(b)o(y)f Fp(Amd)p Fo(.)23 b(If)17
+b(no)f(reference)h(is)g(made)g(to)0 1221 y(the)e(v)o(olume)h(in)g(this)g(p)q
+(erio)q(d,)g Fp(Amd)h Fo(discards)f(the)f(v)o(olume)h(name)f(to)f
+(\014lesystem)i(mapping.)62 1291 y(Once)e(the)f(last)g(reference)h(to)e(a)g
+(\014lesystem)i(has)f(b)q(een)h(remo)o(v)o(ed,)e Fp(Amd)j Fo(attempts)d(to)g
+(unmoun)o(t)h(the)g(\014lesys-)0 1341 y(tem.)35 b(If)21 b(the)f(unmoun)o(t)h
+(fails)g(the)f(in)o(terv)m(al)i(is)f(extended)g(b)o(y)g(a)f(further)g(p)q
+(erio)q(d)i(as)e(sp)q(eci\014ed)i(b)o(y)f(the)f(`)p Fl(-w)p
+Fo(')0 1391 y(command)15 b(line)i(option)e(or)g(b)o(y)g(the)g(`)p
+Fl(utimeout)p Fo(')f(moun)o(t)g(option.)62 1461 y(The)i(default)f
+Fp(cac)o(he-in)o(terv)m(al)k Fo(is)d(300)e(seconds)i(\(\014v)o(e)f(min)o
+(utes\).)0 1691 y Fq(4.3)33 b Fg(-d)14 b Ff(domain)62 1782
+y Fo(Sp)q(eci\014es)i(the)e(host's)e(domain.)20 b(This)14 b(sets)g(the)f(in)o
+(ternal)i(v)m(ariable)g Fl(${domain})d Fo(and)i(a\013ects)e(the)i
+Fl(${hostd})0 1832 y Fo(v)m(ariable.)62 1902 y(If)i(this)h(option)f(is)h(not)
+e(sp)q(eci\014ed)j(and)e(the)g(hostname)g(already)g(con)o(tains)g(the)g(lo)q
+(cal)h(domain)g(then)f(that)f(is)0 1952 y(used,)g(otherwise)h(the)f(default)h
+(v)m(alue)g(of)f Fl(${domain})f Fo(is)i(`)p Fl(unknown.domain)p
+Fo('.)62 2023 y(F)l(or)f(example,)g(if)h(the)f(lo)q(cal)i(domain)e(w)o(as)g
+(`)p Fl(doc.ic.ac.uk)p Fo(',)d Fp(Amd)17 b Fo(could)g(b)q(e)e(started)g(as)g
+(follo)o(ws:)120 2093 y Fl(amd)23 b(-d)h(doc.ic.ac.uk)e(...)0
+2313 y Fq(4.4)33 b Fg(-k)14 b Ff(k)n(ernel-arc)n(hitecture)62
+2404 y Fo(Sp)q(eci\014es)19 b(the)e(k)o(ernel)g(arc)o(hitecture)g(of)f(the)g
+(system.)24 b(This)17 b(is)g(usually)h(the)f(output)f(of)g(`)p
+Fl(arch)e(-k)p Fo(')i(and)h(its)0 2454 y(only)d(e\013ect)f(is)h(to)f(set)g
+(the)h(v)m(ariable)h Fl(${karch})p Fo(.)j(If)c(this)g(option)f(is)h(not)f
+(giv)o(en,)h Fl(${karch})f Fo(has)g(the)h(same)f(v)m(alue)0
+2504 y(as)i Fl(${arch})p Fo(.)62 2575 y(This)h(w)o(ould)g(b)q(e)f(used)h(as)f
+(follo)o(ws:)120 2645 y Fl(amd)23 b(-k)h(`arch)f(-k`)h(...)p
+eop
+%%Page: 18 20
+18 19 bop 15 -83 a Fo(SMM:13-18)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fq(4.5)33 b Fg(-l)14 b Ff(log-option)62
+250 y Fo(Selects)j(the)e(form)f(of)h(logging)h(to)e(b)q(e)i(made.)k(Tw)o(o)14
+b(sp)q(ecial)j Fp(log-options)h Fo(are)c(recognised.)25 320
+y(1.)29 b(If)15 b Fp(log-option)h Fo(is)g(the)f(string)g(`)p
+Fl(syslog)p Fo(',)e Fp(Amd)18 b Fo(will)e(use)g(the)f Fk(syslog)p
+Fo(\(3\))f(mec)o(hanism.)25 384 y(2.)29 b(If)12 b Fp(log-option)h
+Fo(is)g(the)f(string)g(`)p Fl(/dev/stderr)p Fo(',)e Fp(Amd)k
+Fo(will)g(use)f(standard)f(error,)f(whic)o(h)i(is)g(also)f(the)g(default)90
+434 y(target)i(for)h(log)g(messages.)k(T)l(o)c(implemen)o(t)i(this,)e
+Fp(Amd)i Fo(sim)o(ulates)f(the)f(e\013ect)g(of)g(the)g(`)p
+Fl(/dev/fd)p Fo(')e(driv)o(er.)62 525 y(An)o(y)18 b(other)f(string)g(is)h
+(tak)o(en)e(as)h(a)g(\014lename)i(to)d(use)i(for)f(logging.)26
+b(Log)17 b(messages)g(are)g(app)q(ended)i(to)e(the)0 575 y(\014le)f(if)f(it)g
+(already)g(exists,)g(otherwise)g(a)f(new)h(\014le)h(is)g(created.)j(The)c
+(\014le)h(is)f(op)q(ened)h(once)g(and)e(then)i(held)g(op)q(en,)0
+625 y(rather)f(than)g(b)q(eing)h(re-op)q(ened)h(for)d(eac)o(h)h(message.)62
+695 y(If)j(the)f(`)p Fl(syslog)p Fo(')e(option)j(is)f(sp)q(eci\014ed)j(but)d
+(the)g(system)g(do)q(es)g(not)g(supp)q(ort)g(syslog)g(or)g(if)g(the)h(named)f
+(\014le)0 745 y(cannot)e(b)q(e)h(op)q(ened)h(or)e(created,)g
+Fp(Amd)i Fo(will)g(use)f(standard)f(error.)k(Error)c(messages)g(generated)g
+(b)q(efore)h Fp(Amd)0 795 y Fo(has)f(\014nished)i(parsing)e(the)h(command)f
+(line)i(are)e(prin)o(ted)h(on)f(standard)f(error.)62 866 y(Using)i(`)p
+Fl(syslog)p Fo(')e(is)h(usually)i(b)q(est,)e(in)h(whic)o(h)g(case)f
+Fp(Amd)i Fo(w)o(ould)f(b)q(e)g(started)e(as)h(follo)o(ws:)120
+936 y Fl(amd)23 b(-l)h(syslog)f(...)0 1107 y Fq(4.6)33 b Fg(-n)62
+1199 y Fo(Normalises)17 b(the)f(remote)g(hostname)g(b)q(efore)g(using)h(it.)
+24 b(Normalisation)16 b(is)h(done)g(b)o(y)f(replacing)h(the)g(v)m(alue)0
+1248 y(of)e Fl(${rhost})f Fo(with)h(the)h(primary)f(name)g(returned)h(b)o(y)f
+(a)g(hostname)f(lo)q(okup.)62 1319 y(This)i(option)f(should)i(b)q(e)f(used)f
+(if)h(sev)o(eral)f(names)g(are)g(used)h(to)f(refer)g(to)f(a)h(single)i(host)d
+(in)i(a)f(moun)o(t)g(map.)0 1490 y Fq(4.7)33 b Fg(-p)62 1581
+y Fo(Causes)14 b Fp(Amd)r Fo('s)f(pro)q(cess)h(id)g(to)f(b)q(e)h(prin)o(ted)h
+(on)e(standard)g(output.)20 b(This)14 b(can)f(b)q(e)i(redirected)f(to)f(a)h
+(suitable)0 1631 y(\014le)i(for)f(use)g(with)h(kill:)120 1702
+y Fl(amd)23 b(-p)h(>)g(/var/run/amd.pid)d(...)62 1793 y Fo(This)c(option)f
+(only)h(has)f(an)g(a\013ect)f(if)h Fp(Amd)i Fo(is)f(running)g(in)g(daemon)f
+(mo)q(de.)22 b(If)17 b Fp(Amd)h Fo(is)e(started)g(with)g(the)0
+1843 y Fl(-D)f(nodaemon)f Fo(debug)i(\015ag,)e(this)i(option)f(is)h(ignored.)
+0 2014 y Fq(4.8)33 b Fg(-r)62 2105 y Fo(T)l(ells)16 b Fp(Amd)f
+Fo(to)f(restart)e(existing)j(moun)o(ts)e(\(see)h(Section)h(5.14)e
+([Inheritance)i(Filesystem],)f(page)27 b(SMM:13-)0 2155 y(26\).)0
+2334 y Fq(4.9)33 b Fg(-t)14 b Ff(timeout.retransmit)62 2425
+y Fo(Sp)q(eci\014es)i(the)d(RPC)g Fp(timeout)i Fo(and)e Fp(retransmit)h
+Fo(in)o(terv)m(als)g(used)g(b)o(y)f(the)g(k)o(ernel)h(to)f(comm)o(unicate)h
+(to)e Fp(Amd)p Fo(.)0 2475 y(These)k(are)e(used)i(to)f(set)g(the)g(`)p
+Fl(timeo)p Fo(')f(and)h(`)p Fl(retrans)p Fo(')f(moun)o(t)g(options.)62
+2545 y Fp(Amd)21 b Fo(relies)g(on)e(the)g(k)o(ernel)h(RPC)f(retransmit)g(mec)
+o(hanism)h(to)e(trigger)h(moun)o(t)g(retries.)32 b(The)19 b(v)m(alue)h(of)0
+2595 y(this)14 b(parameter)g(c)o(hanges)g(the)g(retry)f(in)o(terv)m(al.)21
+b(T)l(o)q(o)13 b(long)i(an)f(in)o(terv)m(al)h(giv)o(es)f(p)q(o)q(or)g(in)o
+(teractiv)o(e)g(resp)q(onse,)h(to)q(o)0 2645 y(short)g(an)g(in)o(terv)m(al)h
+(causes)f(excessiv)o(e)h(retries.)p eop
+%%Page: 19 21
+19 20 bop 0 -83 a Fo(Chapter)15 b(4:)k Fp(Amd)f Fo(Command)c(Line)j(Options)
+899 b(SMM:13-19)0 158 y Fq(4.10)32 b Fg(-v)62 250 y Fo(Prin)o(t)15
+b(v)o(ersion)h(information)f(on)g(standard)g(error)g(and)g(then)h(exit.)k
+(The)15 b(output)g(is)h(of)f(the)g(form:)120 320 y Fl(amd)23
+b(5.2.1.11)g(of)h(91/03/17)f(18:04:05)f(5.3Alpha11)h(#0:)g(Sun)h(Mar)f(17)h
+(18:07:28)f(GMT)g(1991)120 370 y(Built)g(by)h(pendry@vangogh.Berkeley.)o(EDU)
+d(for)i(a)h(hp300)f(running)g(bsd44)g(\(big-endian\).)120 420
+y(Map)g(support)g(for:)h(root,)f(passwd,)g(union,)g(file,)g(error.)120
+470 y(FS:)g(ufs,)h(nfs,)f(nfsx,)g(host,)g(link,)h(program,)e(union,)h(auto,)h
+(direct,)f(toplvl,)f(error.)120 519 y(Primary)h(network)g(is)g(128.32.130.0.)
+62 611 y Fo(The)12 b(information)f(includes)i(the)f(v)o(ersion)f(n)o(um)o(b)q
+(er,)h(release)g(date)f(and)g(name)g(of)g(the)g(release.)19
+b(The)11 b(arc)o(hitec-)0 661 y(ture)16 b(\(see)f(Section)i(2.2)e([Supp)q
+(orted)h(Mac)o(hine)h(Arc)o(hitectures],)e(page)32 b(SMM:13-7\),)14
+b(op)q(erating)i(system)f(\(see)0 710 y(Section)j(2.1)f([Supp)q(orted)h(Op)q
+(erating)g(Systems],)f(page)35 b(SMM:13-6\))15 b(and)j(b)o(yte)f(ordering)h
+(are)f(also)g(prin)o(ted)0 760 y(as)e(they)g(app)q(ear)g(in)h(the)g
+Fl(${os})p Fo(,)e Fl(${arch})g Fo(and)h Fl(${byte})g Fo(v)m(ariables.)0
+918 y Fq(4.11)32 b Fg(-w)15 b Ff(w)n(ait-timeout)62 1009 y
+Fo(Selects)j(the)e(in)o(terv)m(al)i(in)f(seconds)g(b)q(et)o(w)o(een)g(unmoun)
+o(t)g(attempts)e(after)h(the)h(initial)h(time-to-liv)o(e)g(has)f(ex-)0
+1059 y(pired.)62 1129 y(This)f(defaults)g(to)e(120)h(seconds)g(\(t)o(w)o(o)f
+(min)o(utes\).)0 1293 y Fq(4.12)32 b Fg(-x)15 b Ff(opts)62
+1384 y Fo(Sp)q(eci\014es)k(the)d(t)o(yp)q(e)h(and)f(v)o(erb)q(osit)o(y)h(of)f
+(log)g(messages.)23 b Fp(opts)18 b Fo(is)f(a)f(comma)g(separated)g(list)h
+(selected)h(from)0 1434 y(the)d(follo)o(wing)h(options:)0 1505
+y Fl(fatal)120 b Fo(F)l(atal)15 b(errors)0 1567 y Fl(error)120
+b Fo(Non-fatal)15 b(errors)0 1629 y Fl(user)144 b Fo(Non-fatal)15
+b(user)g(errors)0 1691 y Fl(warn)144 b Fo(Reco)o(v)o(erable)16
+b(errors)0 1753 y Fl(warning)72 b Fo(Alias)16 b(for)f Fl(warn)0
+1815 y(info)144 b Fo(Information)15 b(messages)0 1877 y Fl(map)168
+b Fo(Moun)o(t)14 b(map)h(usage)0 1940 y Fl(stats)120 b Fo(Additional)17
+b(statistics)0 2002 y Fl(all)168 b Fo(All)16 b(of)f(the)h(ab)q(o)o(v)o(e)62
+2093 y(Initially)g(a)d(set)h(of)f(default)h(logging)g(\015ags)f(is)h
+(enabled.)21 b(This)14 b(is)g(as)f(if)h(`)p Fl(-x)g(all,nomap,nostats)p
+Fo(')d(had)j(b)q(een)0 2143 y(selected.)23 b(The)16 b(command)g(line)h(is)g
+(parsed)f(and)g(logging)g(is)g(con)o(trolled)h(b)o(y)e(the)h(\\-x")g(option.)
+22 b(The)16 b(v)o(ery)f(\014rst)0 2193 y(set)h(of)g(logging)h(\015ags)g(is)g
+(sa)o(v)o(ed)f(and)g(can)h(not)f(b)q(e)h(subsequen)o(tly)h(disabled)h(using)e
+Fp(Amq)p Fo(.)24 b(This)17 b(default)g(set)f(of)0 2243 y(options)f(is)h
+(useful)g(for)f(general)h(pro)q(duction)g(use.)62 2313 y(The)h(`)p
+Fl(info)p Fo(')f(messages)g(include)j(details)f(of)e(what)g(is)h(moun)o(ted)g
+(and)g(unmoun)o(ted)g(and)g(when)g(\014lesystems)0 2363 y(ha)o(v)o(e)e(timed)
+h(out.)k(If)c(y)o(ou)f(w)o(an)o(t)f(to)h(ha)o(v)o(e)g(the)h(default)g(set)f
+(of)g(messages)g(without)g(the)h(`)p Fl(info)p Fo(')e(messages)h(then)0
+2413 y(y)o(ou)f(simply)i(need)f(`)p Fl(-x)f(noinfo)p Fo('.)19
+b(The)14 b(messages)g(giv)o(en)h(b)o(y)f(`)p Fl(user)p Fo(')f(relate)i(to)e
+(errors)h(in)h(the)g(moun)o(t)e(maps,)h(so)0 2463 y(these)g(are)f(useful)i
+(when)g(new)f(maps)f(are)h(installed.)21 b(The)14 b(follo)o(wing)h(table)f
+(lists)g(the)g(syslog)g(priorites)g(used)h(for)0 2512 y(eac)o(h)g(of)g(the)g
+(message)g(t)o(yp)q(es.)0 2583 y Fl(fatal)120 b Fo(LOG)p 342
+2583 14 2 v 17 w(CRIT)0 2645 y Fl(error)g Fo(LOG)p 342 2645
+V 17 w(ERR)p eop
+%%Page: 20 22
+20 21 bop 15 -83 a Fo(SMM:13-20)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fl(user)144 b Fo(LOG)p 342 158
+14 2 v 17 w(W)-5 b(ARNING)0 220 y Fl(warning)72 b Fo(LOG)p
+342 220 V 17 w(W)-5 b(ARNING)0 281 y Fl(info)144 b Fo(LOG)p
+342 281 V 17 w(INF)o(O)0 343 y Fl(debug)120 b Fo(LOG)p 342
+343 V 17 w(DEBUG)0 404 y Fl(map)168 b Fo(LOG)p 342 404 V 17
+w(DEBUG)0 466 y Fl(stats)120 b Fo(LOG)p 342 466 V 17 w(INF)o(O)62
+557 y(The)15 b(options)g(can)f(b)q(e)h(pre\014xed)h(b)o(y)e(the)h(string)f(`)
+p Fl(no)p Fo(')g(to)f(indicate)j(that)e(this)h(option)g(should)g(b)q(e)g
+(turned)g(o\013.)0 607 y(F)l(or)g(example,)g(to)g(obtain)g(all)h(but)g(`)p
+Fl(info)p Fo(')e(messages)g(the)h(option)h(`)p Fl(-x)e(all,noinfo)p
+Fo(')g(w)o(ould)h(b)q(e)h(used.)62 678 y(If)f Fp(Amd)i Fo(w)o(as)d(built)j
+(with)e(debugging)h(enabled)g(the)f Fl(debug)f Fo(option)i(is)f
+(automatically)g(enabled)i(regardless)0 728 y(of)e(the)g(command)g(line)i
+(options.)0 889 y Fq(4.13)32 b Fg(-y)15 b Ff(NIS-domain)62
+980 y Fo(Selects)d(an)e(alternate)g(NIS)h(domain.)19 b(This)11
+b(is)f(useful)i(for)e(debugging)h(and)f(cross-domain)h(shared)f(moun)o(ting.)
+0 1030 y(If)15 b(this)h(\015ag)f(is)h(sp)q(eci\014ed,)h Fp(Amd)g
+Fo(immediately)g(attempts)d(to)g(bind)j(to)d(a)h(serv)o(er)g(for)g(this)g
+(domain.)0 1192 y Fq(4.14)32 b Fg(-C)15 b Ff(cluster-name)62
+1283 y Fo(Sp)q(eci\014es)f(the)e(name)g(of)f(the)h(cluster)g(of)g(whic)o(h)g
+(the)g(lo)q(cal)h(mac)o(hine)f(is)h(a)e(mem)o(b)q(er.)19 b(The)12
+b(only)g(e\013ect)g(is)g(to)f(set)0 1333 y(the)k(v)m(ariable)i
+Fl(${cluster})p Fo(.)h(The)e Fp(cluster-name)j Fo(is)c(will)i(usually)g
+(obtained)f(b)o(y)f(running)h(another)f(command)0 1383 y(whic)o(h)k(uses)f(a)
+f(database)g(to)g(map)h(the)g(lo)q(cal)h(hostname)e(in)o(to)h(a)f(cluster)h
+(name.)28 b Fl(${cluster})16 b Fo(can)i(then)g(b)q(e)0 1433
+y(used)f(as)f(a)f(selector)i(to)e(restrict)h(moun)o(ting)h(of)e(replicated)j
+(data.)k(If)16 b(this)h(option)f(is)h(not)f(giv)o(en,)g Fl(${cluster})0
+1482 y Fo(has)f(the)g(same)g(v)m(alue)i(as)d Fl(${domain})p
+Fo(.)19 b(This)d(w)o(ould)f(b)q(e)h(used)g(as)f(follo)o(ws:)120
+1553 y Fl(amd)23 b(-C)h(`clustername`)e(...)0 1708 y Fq(4.15)32
+b Fg(-D)15 b Ff(opts)62 1799 y Fo(Con)o(trols)20 b(the)h(v)o(erb)q(osit)o(y)f
+(and)h(co)o(v)o(erage)f(of)g(the)g(debugging)i(trace;)h Fp(opts)f
+Fo(is)f(a)f(comma)g(separated)g(list)0 1849 y(of)g(debugging)h(options.)36
+b(The)20 b(\\-D")g(option)h(is)g(only)f(a)o(v)m(ailable)j(if)d
+Fp(Amd)j Fo(w)o(as)c(compiled)j(with)f(`)p Fl(-DDEBUG)p Fo('.)0
+1899 y(The)c(memory)g(debugging)h(facilities)h(are)e(only)h(a)o(v)m(ailable)h
+(if)f Fp(Amd)h Fo(w)o(as)d(compiled)j(with)f(`)p Fl(-DDEBUG_MEM)p
+Fo(')c(\(in)0 1948 y(addition)i(to)f(`)p Fl(-DDEBUG)p Fo('\).)62
+2019 y(The)j(most)f(common)g(options)h(to)f(use)h(are)f(`)p
+Fl(-D)d(trace)p Fo(')j(and)h(`)p Fl(-D)c(test)p Fo(')j(\(whic)o(h)h(turns)f
+(on)h(all)g(the)g(useful)0 2069 y(debug)e(options\).)k(See)15
+b(the)h(program)e(source)h(for)g(a)f(more)h(detailed)i(explanation)f(of)f
+(the)g(a)o(v)m(ailable)i(options.)0 2258 y Fm(5)41 b(Filesystem)13
+b(T)n(yp)r(es)62 2375 y Fo(T)l(o)i(moun)o(t)g(a)g(v)o(olume,)g
+Fp(Amd)i Fo(m)o(ust)e(b)q(e)h(told)f(the)g(t)o(yp)q(e)h(of)e(\014lesystem)i
+(to)f(b)q(e)h(used.)k(Eac)o(h)15 b(\014lesystem)h(t)o(yp)q(e)0
+2425 y(t)o(ypically)h(requires)f(additional)g(information)g(suc)o(h)f(as)g
+(the)g(\014leserv)o(er)h(name)f(for)g(NFS.)62 2496 y(F)l(rom)j(the)i(p)q(oin)
+o(t)f(of)g(view)g(of)g Fp(Amd)p Fo(,)g(a)g Fp(\014lesystem)h
+Fo(is)f(an)o(ything)g(that)g(can)g(resolv)o(e)g(an)g(incoming)h(name)0
+2545 y(lo)q(okup.)g(An)12 b(imp)q(ortan)o(t)f(feature)g(is)h(supp)q(ort)g
+(for)f(m)o(ultiple)j(\014lesystem)e(t)o(yp)q(es.)19 b(Some)12
+b(of)f(these)h(\014lesystems)g(are)0 2595 y(implemen)o(ted)k(in)g(the)f(lo)q
+(cal)g(k)o(ernel)h(and)f(some)f(on)g(remote)g(\014leserv)o(ers,)h(whilst)h
+(the)f(others)f(are)g(implemen)o(ted)0 2645 y(in)o(ternally)j(b)o(y)e
+Fp(Amd)p Fo(.)p eop
+%%Page: 21 23
+21 22 bop 0 -83 a Fo(Chapter)15 b(5:)k(Filesystem)d(T)o(yp)q(es)1145
+b(SMM:13-21)62 158 y(The)21 b(t)o(w)o(o)f(common)g(\014lesystem)i(t)o(yp)q
+(es)f(are)f(UFS)h(and)g(NFS.)g(F)l(our)f(other)h(user)g(accessible)h
+(\014lesystems)0 208 y(\(`)p Fl(link)p Fo(',)c(`)p Fl(program)p
+Fo(',)g(`)p Fl(auto)p Fo(')g(and)i(`)p Fl(direct)p Fo('\))d(are)i(also)g
+(implemen)o(ted)i(in)o(ternally)g(b)o(y)e Fp(Amd)i Fo(and)f(these)f(are)0
+258 y(describ)q(ed)d(b)q(elo)o(w.)21 b(There)14 b(are)h(t)o(w)o(o)e
+(additional)j(\014lesystem)f(t)o(yp)q(es)f(in)o(ternal)i(to)e
+Fp(Amd)i Fo(whic)o(h)f(are)g(not)f(directly)0 308 y(accessible)j(to)e(the)g
+(user)h(\(`)p Fl(inherit)p Fo(')d(and)j(`)p Fl(error)p Fo('\).)j(Their)d(use)
+f(is)h(describ)q(ed)i(since)e(they)g(ma)o(y)e(still)j(ha)o(v)o(e)e(an)0
+358 y(e\013ect)g(visible)i(to)e(the)g(user.)0 508 y Fq(5.1)33
+b(Net)n(w)n(ork)15 b(Filesystem)g(\(`)p Fg(type:=nfs)p Fq('\))62
+599 y Fo(The)h Fp(nfs)h Fo(\014lesystem)f(t)o(yp)q(e)f(pro)o(vides)h(access)f
+(to)f(Sun's)i(NFS.)0 670 y(The)f(follo)o(wing)h(options)g(m)o(ust)e(b)q(e)i
+(sp)q(eci\014ed:)0 751 y Fl(rhost)120 b Fo(the)17 b(remote)g(\014leserv)o
+(er.)26 b(This)17 b(m)o(ust)g(b)q(e)h(an)f(en)o(try)f(in)i(the)f(hosts)g
+(database.)25 b(IP)17 b(addresses)g(are)240 801 y(not)i(accepted.)34
+b(The)20 b(default)g(v)m(alue)h(is)f(tak)o(en)g(from)e(the)i(lo)q(cal)h(host)
+e(name)h(\()p Fl(${host})p Fo(\))e(if)i(no)240 851 y(other)15
+b(v)m(alue)h(is)g(sp)q(eci\014ed.)0 911 y Fl(rfs)168 b Fo(the)19
+b(remote)g(\014lesystem.)33 b(If)19 b(no)g(v)m(alue)i(is)f(sp)q(eci\014ed)h
+(for)e(this)g(option,)h(an)f(in)o(ternal)i(default)e(of)240
+961 y Fl(${path})14 b Fo(is)i(used.)62 1052 y(NFS)d(moun)o(ts)g(require)g(a)g
+(t)o(w)o(o)f(stage)g(pro)q(cess.)19 b(First,)13 b(the)g Fp(\014le)h(handle)j
+Fo(of)c(the)g(remote)f(\014le)i(system)f(m)o(ust)f(b)q(e)0
+1102 y(obtained)i(from)f(the)h(serv)o(er.)19 b(Then)14 b(a)f(moun)o(t)g
+(system)g(call)i(m)o(ust)d(b)q(e)j(done)f(on)f(the)h(lo)q(cal)g(system.)19
+b Fp(Amd)d Fo(k)o(eeps)0 1152 y(a)f(cac)o(he)g(of)g(\014le)h(handles)h(for)d
+(remote)h(\014le)h(systems.)k(The)15 b(cac)o(he)g(en)o(tries)h(ha)o(v)o(e)f
+(a)g(lifetime)i(of)d(a)h(few)g(min)o(utes.)62 1223 y(If)g(a)f(required)h
+(\014le)g(handle)h(is)f(not)f(in)h(the)f(cac)o(he,)g Fp(Amd)j
+Fo(sends)d(a)g(request)h(to)e(the)i(remote)e(serv)o(er)h(to)g(obtain)0
+1272 y(it.)19 b Fp(Amd)14 b(do)q(es)d(not)i Fo(w)o(ait)e(for)g(a)g(resp)q
+(onse;)i(it)f(notes)f(that)g(one)h(of)f(the)h(lo)q(cations)g(needs)h
+(retrying,)f(but)f(con)o(tin)o(ues)0 1322 y(with)17 b(an)o(y)f(remaining)h
+(lo)q(cations.)24 b(When)17 b(the)g(\014le)g(handle)h(b)q(ecomes)f(a)o(v)m
+(ailable,)h(and)e(assuming)h(none)g(of)f(the)0 1372 y(other)11
+b(lo)q(cations)h(w)o(as)e(successfully)j(moun)o(ted,)e Fp(Amd)j
+Fo(will)e(retry)f(the)g(moun)o(t.)18 b(This)12 b(mec)o(hanism)g(allo)o(ws)f
+(sev)o(eral)0 1422 y(NFS)17 b(\014lesystems)h(to)e(b)q(e)i(moun)o(ted)f(in)h
+(parallel.)28 b(The)17 b(\014rst)g(one)g(whic)o(h)h(resp)q(onds)g(with)g(a)f
+(v)m(alid)h(\014le)h(handle)0 1472 y(will)e(b)q(e)f(used.)0
+1542 y(An)f(NFS)h(en)o(try)e(migh)o(t)i(b)q(e:)120 1613 y Fl(jsp)47
+b(host!=charm;type:=nfs;rhost:)o(=charm;r)o(fs:=/ho)o(me/char)o(m;sublin)o
+(k:=jsp)62 1704 y Fo(The)16 b(moun)o(t)f(system)g(call)i(and)f(an)o(y)f
+(unmoun)o(t)h(attempts)f(are)g(alw)o(a)o(ys)g(done)h(in)g(a)g(new)g(task)e
+(to)h(a)o(v)o(oid)h(the)0 1754 y(p)q(ossibilt)o(y)h(of)e(blo)q(c)o(king)h
+Fp(Amd)p Fo(.)0 1914 y Fq(5.2)33 b(Net)n(w)n(ork)15 b(Host)f(Filesystem)h
+(\(`)p Fg(type:=host)p Fq('\))62 2006 y Fo(The)d Fp(host)g
+Fo(\014lesystem)g(allo)o(ws)g(access)g(to)f(the)g(en)o(tire)h(exp)q(ort)g
+(tree)f(of)g(an)h(NFS)g(serv)o(er.)18 b(The)12 b(implemen)o(tation)0
+2056 y(is)18 b(la)o(y)o(ered)g(ab)q(o)o(v)o(e)f(the)h(`)p Fl(nfs)p
+Fo(')e(implemen)o(tation)j(so)e(k)o(eep-aliv)o(es)i(w)o(ork)d(in)j(the)e
+(same)h(w)o(a)o(y)l(.)26 b(The)18 b(only)g(option)0 2105 y(whic)o(h)e(needs)g
+(to)f(sp)q(eci\014ed)i(is)f(`)p Fl(rhost)p Fo(')d(whic)o(h)j(is)g(the)f(name)
+h(of)e(the)i(\014leserv)o(er)g(to)e(moun)o(t.)62 2176 y(The)e(`)p
+Fl(host)p Fo(')e(\014lesystem)j(t)o(yp)q(e)e(w)o(orks)g(b)o(y)g(querying)i
+(the)e(moun)o(t)h(daemon)f(on)h(the)f(giv)o(en)h(\014leserv)o(er)h(to)e
+(obtain)0 2226 y(its)i(exp)q(ort)f(list.)19 b Fp(Amd)c Fo(then)d(obtains)h
+(\014lehandles)h(for)e(eac)o(h)h(of)e(the)i(exp)q(orted)f(\014lesystems.)20
+b(An)o(y)12 b(errors)g(at)g(this)0 2276 y(stage)17 b(cause)i(that)e
+(particular)i(\014lesystem)g(to)f(b)q(e)g(ignored.)30 b(Finally)19
+b(eac)o(h)g(\014lesystem)f(is)h(moun)o(ted.)29 b(Again,)0 2325
+y(errors)14 b(are)g(logged)g(but)h(ignored.)20 b(One)15 b(common)f(reason)g
+(for)g(moun)o(ts)g(to)g(fail)h(is)g(that)e(the)i(moun)o(t)f(p)q(oin)o(t)h(do)
+q(es)0 2375 y(not)e(exist.)19 b(Although)13 b Fp(Amd)i Fo(attempts)d(to)g
+(automatically)i(create)e(the)h(moun)o(t)g(p)q(oin)o(t,)g(it)g(ma)o(y)g(b)q
+(e)g(on)g(a)g(remote)0 2425 y(\014lesystem)j(to)e(whic)o(h)i
+Fp(Amd)i Fo(do)q(es)d(not)g(ha)o(v)o(e)g(write)g(p)q(ermission.)62
+2496 y(When)j(an)f(attempt)f(to)h(unmoun)o(t)g(a)g(`)p Fl(host)p
+Fo(')e(\014lesystem)j(moun)o(t)f(fails,)h Fp(Amd)h Fo(remoun)o(ts)e(an)o(y)f
+(\014lesystems)0 2545 y(whic)o(h)21 b(had)e(succesfully)j(b)q(een)f(unmoun)o
+(ted.)34 b(T)l(o)19 b(do)h(this)g Fp(Amd)i Fo(queries)e(the)g(moun)o(t)f
+(daemon)h(again)g(and)0 2595 y(obtains)d(a)g(fresh)g(cop)o(y)g(of)g(the)g
+(exp)q(ort)g(list.)26 b Fp(Amd)19 b Fo(then)f(tries)f(to)g(moun)o(t)f(an)o(y)
+h(exp)q(orted)g(\014lesystems)h(whic)o(h)0 2645 y(are)d(not)g(curren)o(tly)g
+(moun)o(ted.)p eop
+%%Page: 22 24
+22 23 bop 15 -83 a Fo(SMM:13-22)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)62 158 y(Sun's)22 b(automoun)o(ter)e(pro)o(vides)i(a)f
+(sp)q(ecial)i(`)p Fl(-hosts)p Fo(')d(map.)38 b(T)l(o)21 b(ac)o(hiev)o(e)h
+(the)f(same)g(e\013ect)g(with)h Fp(Amd)0 208 y Fo(requires)16
+b(t)o(w)o(o)e(steps.)20 b(First)14 b(a)h(moun)o(t)g(map)g(m)o(ust)g(b)q(e)h
+(created)f(as)g(follo)o(ws:)120 279 y Fl(/defaults)46 b
+(type:=host;fs:=${autodir}/${rh)o(ost}/ro)o(ot;rhos)o(t:=${key)o(})120
+329 y(*)238 b(opts:=rw,nosuid,grpid)0 420 y Fo(and)15 b(then)h(start)e
+Fp(Amd)j Fo(with)f(the)f(follo)o(wing)h(command)120 490 y Fl(amd)23
+b(/n)h(net.map)0 582 y Fo(where)17 b(`)p Fl(net.map)p Fo(')d(is)j(the)g(name)
+f(of)g(map)g(describ)q(ed)i(ab)q(o)o(v)o(e.)23 b(Note)16 b(that)g(the)g(v)m
+(alue)i(of)e Fl(${fs})g Fo(is)g(o)o(v)o(erridden)0 632 y(in)f(the)f(map.)19
+b(This)c(is)f(done)h(to)e(a)o(v)o(oid)h(a)g(clash)h(b)q(et)o(w)o(een)f(the)g
+(moun)o(t)g(tree)f(and)i(an)o(y)e(other)h(\014lesystem)h(already)0
+681 y(moun)o(ted)g(from)g(the)g(same)g(\014leserv)o(er.)62
+752 y(If)g(di\013eren)o(t)f(moun)o(t)g(options)g(are)g(needed)h(for)f
+(di\013eren)o(t)g(hosts)g(then)g(additional)i(en)o(tries)f(can)f(b)q(e)h
+(added)g(to)0 802 y(the)g(map,)g(for)f(example)120 872 y Fl(host2)166
+b(opts:=ro,nosuid,soft)0 964 y Fo(w)o(ould)16 b(soft)e(moun)o(t)h(`)p
+Fl(host2)p Fo(')e(read-only)l(.)0 1130 y Fq(5.3)33 b(Net)n(w)n(ork)15
+b(Filesystem)g(Group)h(\(`)p Fg(type:=nfsx)p Fq('\))62 1221
+y Fo(The)f Fp(nfsx)k Fo(\014lesystem)c(allo)o(ws)g(a)g(group)g(of)f
+(\014lesystems)i(to)e(b)q(e)h(moun)o(ted)g(from)g(a)f(single)i(NFS)f(serv)o
+(er.)20 b(The)0 1271 y(implemen)o(tation)c(is)g(la)o(y)o(ered)g(ab)q(o)o(v)o
+(e)e(the)i(`)p Fl(nfs)p Fo(')e(implemen)o(tation)i(so)f(k)o(eep-aliv)o(es)i
+(w)o(ork)d(in)i(the)f(same)g(w)o(a)o(y)l(.)62 1342 y(The)h(options)f(are)g
+(the)g(same)g(as)g(for)f(the)i(`)p Fl(nfs)p Fo(')e(\014lesystem)i(with)f(one)
+g(di\013erence.)0 1412 y(The)g(follo)o(wing)h(options)g(m)o(ust)e(b)q(e)i(sp)
+q(eci\014ed:)0 1483 y Fl(rhost)120 b Fo(the)17 b(remote)g(\014leserv)o(er.)26
+b(This)17 b(m)o(ust)g(b)q(e)h(an)f(en)o(try)f(in)i(the)f(hosts)g(database.)25
+b(IP)17 b(addresses)g(are)240 1533 y(not)i(accepted.)34 b(The)20
+b(default)g(v)m(alue)h(is)f(tak)o(en)g(from)e(the)i(lo)q(cal)h(host)e(name)h
+(\()p Fl(${host})p Fo(\))e(if)i(no)240 1582 y(other)15 b(v)m(alue)h(is)g(sp)q
+(eci\014ed.)0 1644 y Fl(rfs)168 b Fo(as)15 b(a)f(list)i(of)f(\014lesystems)g
+(to)f(moun)o(t.)20 b(The)15 b(list)h(is)f(in)h(the)f(form)f(of)h(a)f(comma)h
+(separated)f(strings.)0 1736 y(F)l(or)h(example:)120 1806 y
+Fl(pub)143 b(type:=nfsx;rhost:=gould;)o(\\)120 1856 y
+(rfs:=/public,/,graphics,us)o(enet;fs)o(:=${auto)o(dir}/${)o(rhost}/)o(root)
+62 1947 y Fo(The)14 b(\014rst)g(string)f(de\014nes)i(the)f(ro)q(ot)f(of)g
+(the)h(tree,)g(and)g(is)g(applied)i(as)d(a)h(pre\014x)g(to)f(the)h(remaining)
+h(mem)o(b)q(ers)0 1997 y(of)e(the)h(list)h(whic)o(h)g(de\014ne)g(the)e
+(individual)k(\014lesystems.)j(The)15 b(\014rst)e(string)h(is)g
+Fp(not)g Fo(used)h(as)e(a)h(\014lesystem)g(name.)0 2047 y(A)h(parallel)h(op)q
+(eration)f(is)h(used)f(to)g(determine)h(the)e(lo)q(cal)i(moun)o(t)f(p)q(oin)o
+(ts)g(to)f(ensure)i(a)e(consisten)o(t)i(la)o(y)o(out)e(of)g(a)0
+2097 y(tree)h(of)g(moun)o(ts.)62 2167 y(Here,)20 b(the)e Fp(three)k
+Fo(\014lesystems,)d(`)p Fl(/public)p Fo(',)f(`)p Fl(/public/graphics)p
+Fo(')d(and)k(`)p Fl(/public/usenet)p Fo(',)d(w)o(ould)j(b)q(e)0
+2217 y(moun)o(ted.)62 2288 y(A)g(lo)q(cal)g(moun)o(t)f(p)q(oin)o(t,)h
+Fl(${fs})p Fo(,)f Fp(m)o(ust)h Fo(b)q(e)g(sp)q(eci\014ed.)32
+b(The)19 b(default)g(lo)q(cal)g(moun)o(t)f(p)q(oin)o(t)h(will)h(not)e(w)o
+(ork)0 2338 y(correctly)d(in)h(the)g(general)f(case.)20 b(A)c(suggestion)f
+(is)g(to)g(use)h(`)p Fl(fs:=${autodir}/${rho)o(st}/roo)o(t)p
+Fo('.)0 2504 y Fq(5.4)33 b(Unix)16 b(Filesystem)g(\(`)p Fg(type:=ufs)p
+Fq('\))62 2595 y Fo(The)22 b Fp(ufs)i Fo(\014lesystem)e(t)o(yp)q(e)g(pro)o
+(vides)g(access)g(to)f(the)h(system's)e(standard)i(disk)g
+(\014lesystem|usually)i(a)0 2645 y(deriv)m(ativ)o(e)16 b(of)f(the)h(Berk)o
+(eley)g(F)l(ast)e(Filesystem.)p eop
+%%Page: 23 25
+23 24 bop 0 -83 a Fo(Chapter)15 b(5:)k(Filesystem)d(T)o(yp)q(es)1145
+b(SMM:13-23)0 158 y(The)15 b(follo)o(wing)h(option)g(m)o(ust)e(b)q(e)i(sp)q
+(eci\014ed:)0 246 y Fl(dev)168 b Fo(the)15 b(blo)q(c)o(k)h(sp)q(ecial)h
+(device)g(to)d(b)q(e)i(moun)o(ted.)62 338 y(A)g(UFS)f(en)o(try)f(migh)o(t)i
+(b)q(e:)120 408 y Fl(jsp)71 b(host==charm;type:=ufs;dev:=)o(/dev/xd0)o
+(g;subli)o(nk:=jsp)0 617 y Fq(5.5)33 b(Program)15 b(Filesystem)g(\(`)p
+Fg(type:=program)p Fq('\))62 709 y Fo(The)21 b Fp(program)f
+Fo(\014lesystem)i(t)o(yp)q(e)f(allo)o(ws)g(a)f(program)g(to)g(b)q(e)i(run)f
+(whenev)o(er)g(a)g(moun)o(t)f(or)h(unmoun)o(t)f(is)0 758 y(required.)43
+b(This)24 b(allo)o(ws)f(easy)f(addition)i(of)e(supp)q(ort)h(for)f(other)g
+(\014lesystem)i(t)o(yp)q(es,)g(suc)o(h)f(as)f(MIT's)g(Re-)0
+808 y(mote)16 b(Virtual)h(Disk)g(\(R)-5 b(VD\))16 b(whic)o(h)h(has)g(a)f
+(programmatic)g(in)o(terface)g(via)h(the)g(commands)f(`)p Fl(rvdmount)p
+Fo(')f(and)0 858 y(`)p Fl(rvdunmount)p Fo('.)0 929 y(The)g(follo)o(wing)h
+(options)g(m)o(ust)e(b)q(e)i(sp)q(eci\014ed:)0 1017 y Fl(mount)120
+b Fo(the)15 b(program)f(whic)o(h)i(will)h(p)q(erform)e(the)h(moun)o(t.)0
+1084 y Fl(unmount)72 b Fo(the)15 b(program)f(whic)o(h)i(will)h(p)q(erform)e
+(the)h(unmoun)o(t.)62 1175 y(The)f(exit)h(co)q(de)f(from)f(these)h(t)o(w)o(o)
+f(programs)f(is)i(in)o(terpreted)h(as)e(a)h(Unix)h(error)e(co)q(de.)20
+b(As)15 b(usual,)g(exit)g(co)q(de)0 1225 y(zero)i(indicates)h(success.)26
+b(T)l(o)17 b(execute)g(the)g(program)f Fp(Amd)j Fo(splits)f(the)f(string)g
+(on)g(whitespace)h(to)e(create)h(an)0 1275 y(arra)o(y)h(of)h(substrings.)33
+b(Single)21 b(quotes)e(`)p Fl(')p Fo(')g(can)g(b)q(e)h(used)g(to)f(quote)g
+(whitespace)i(if)f(that)e(is)i(required)h(in)f(an)0 1325 y(argumen)o(t.)f
+(There)d(is)f(no)g(w)o(a)o(y)g(to)f(escap)q(e)i(or)f(c)o(hange)g(the)g(quote)
+g(c)o(haracter.)62 1395 y(T)l(o)d(run)g(the)f(program)g(`)p
+Fl(rvdmount)p Fo(')f(with)i(a)f(host)g(name)h(and)g(\014lesystem)g(as)g
+(argumen)o(ts)e(w)o(ould)i(b)q(e)h(sp)q(eci\014ed)0 1445 y(b)o(y)i(`)p
+Fl(mount:="/etc/rvdmount)d(rvdmount)i(fserver)g(${path}")p
+Fo('.)62 1516 y(The)j(\014rst)f(elemen)o(t)h(in)g(the)f(arra)o(y)f(is)i(tak)o
+(en)f(as)g(the)g(pathname)h(of)f(the)g(program)f(to)h(execute.)24
+b(The)16 b(other)0 1566 y(mem)o(b)q(ers)g(of)f(the)h(arra)o(y)e(form)h(the)h
+(argumen)o(t)f(v)o(ector)g(to)g(b)q(e)h(passed)g(to)f(the)h(program,)e
+Fp(including)19 b(argumen)o(t)0 1615 y(zero)p Fo(.)27 b(This)18
+b(means)f(that)g(the)h(split)g(string)g(m)o(ust)e(ha)o(v)o(e)i(at)e(least)i
+(t)o(w)o(o)e(elemen)o(ts.)28 b(The)17 b(program)g(is)h(directly)0
+1665 y(executed)23 b(b)o(y)f Fp(Amd)p Fo(,)h(not)f(via)g(a)f(shell.)42
+b(This)22 b(means)g(that)g(scripts)g(m)o(ust)f(b)q(egin)i(with)g(a)e
+Fl(#!)h Fo(in)o(terpreter)0 1715 y(sp)q(eci\014cation.)62 1786
+y(If)c(a)g(\014lesystem)g(t)o(yp)q(e)g(is)g(to)f(b)q(e)i(hea)o(vily)g(used,)f
+(it)g(ma)o(y)f(b)q(e)i(w)o(orth)o(while)f(adding)g(a)g(new)f(\014lesystem)i
+(t)o(yp)q(e)0 1835 y(in)o(to)c Fp(Amd)p Fo(,)g(but)h(for)e(most)g(uses)i(the)
+f(program)f(\014lesystem)i(should)g(su\016ce.)62 1906 y(When)k(the)f(program)
+f(is)i(run,)g(standard)e(input)i(and)g(standard)e(error)h(are)g(inherited)i
+(from)d(the)h(curren)o(t)0 1956 y(v)m(alues)f(used)g(b)o(y)f
+Fp(Amd)p Fo(.)26 b(Standard)17 b(output)g(is)h(a)f(duplicate)i(of)e(standard)
+f(error.)25 b(The)18 b(v)m(alue)g(sp)q(eci\014ed)i(with)0 2006
+y(the)15 b(\\-l")h(command)f(line)i(option)e(has)g(no)g(e\013ect)g(on)g
+(standard)g(error.)0 2213 y Fq(5.6)33 b(Sym)n(b)r(olic)17 b(Link)g
+(Filesystem)f(\(`)p Fg(type:=link)p Fq('\))62 2305 y Fo(Eac)o(h)k
+(\014lesystem)g(t)o(yp)q(e)f(creates)h(a)f(sym)o(b)q(olic)h(link)h(to)e(p)q
+(oin)o(t)h(from)f(the)h(v)o(olume)g(name)f(to)g(the)h(ph)o(ysical)0
+2355 y(moun)o(t)15 b(p)q(oin)o(t.)22 b(The)16 b(`)p Fl(link)p
+Fo(')e(\014lesystem)i(do)q(es)g(the)g(same)f(without)h(an)o(y)f(other)g(side)
+i(e\013ects.)j(This)d(allo)o(ws)e(an)o(y)0 2404 y(part)g(of)f(the)i(mac)o
+(hines)g(name)f(space)g(to)g(b)q(e)h(accessed)g(via)f Fp(Amd)p
+Fo(.)62 2475 y(One)h(common)f(use)g(for)f(the)h(symlink)i(\014lesystem)e(is)h
+(`)p Fl(/homes)p Fo(')d(whic)o(h)j(can)f(b)q(e)h(made)f(to)f(con)o(tain)h(an)
+g(en)o(try)0 2525 y(for)e(eac)o(h)g(user)g(whic)o(h)i(p)q(oin)o(ts)e(to)g
+(their)h(\(auto-moun)o(ted\))e(home)h(directory)l(.)20 b(Although)14
+b(this)f(ma)o(y)g(seem)h(rather)0 2575 y(exp)q(ensiv)o(e,)i(it)g(pro)o(vides)
+g(a)e(great)h(deal)h(of)e(administrativ)o(e)i(\015exibili)q(t)o(y)l(.)0
+2645 y(The)f(follo)o(wing)h(option)g(m)o(ust)e(b)q(e)i(de\014ned:)p
+eop
+%%Page: 24 26
+24 25 bop 15 -83 a Fo(SMM:13-24)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fl(fs)192 b Fo(The)16 b(v)m(alue)h(of)f
+Fp(fs)h Fo(option)f(sp)q(eci\014es)i(the)e(destination)g(of)g(the)g(link,)h
+(as)e(mo)q(di\014ed)i(b)o(y)f(the)g Fp(sublink)240 208 y Fo(option.)k(If)14
+b Fp(sublink)k Fo(is)c(non-n)o(ull,)i(it)e(is)g(app)q(ended)i(to)d
+Fl(${fs}/)g Fo(and)h(the)f(resulting)i(string)f(is)g(used)240
+258 y(as)h(the)g(target.)62 349 y(The)g(`)p Fl(link)p Fo(')f(\014lesystem)h
+(can)g(b)q(e)h(though)f(of)f(as)g(iden)o(tical)j(to)d(the)h(`)p
+Fl(ufs)p Fo(')f(\014lesystem)h(but)g(without)g(actually)0 399
+y(moun)o(ting)g(an)o(ything.)62 470 y(An)h(example)g(en)o(try)f(migh)o(t)g(b)
+q(e:)120 540 y Fl(jsp)71 b(host==charm;type:=link;fs:=)o(/home/ch)o(arm;sub)o
+(link:=j)o(sp)62 632 y Fo(whic)o(h)16 b(w)o(ould)g(return)f(a)g(sym)o(b)q
+(olic)h(link)h(p)q(oin)o(ting)f(to)f(`)p Fl(/home/charm/jsp)p
+Fo('.)0 792 y Fq(5.7)33 b(Sym)n(b)r(olic)17 b(Link)g(Filesystem)f(I)r(I)f
+(\(`)p Fg(type:=link)p Fq('\))62 884 y Fo(The)h(`)p Fl(linkx)p
+Fo(')e(\014lesystem)i(t)o(yp)q(e)f(is)h(iden)o(tical)h(to)e(`)p
+Fl(link)p Fo(')f(with)i(the)f(exception)i(that)d(the)i(target)e(of)h(the)h
+(link)0 933 y(m)o(ust)f(exist.)20 b(Existence)c(is)g(c)o(hec)o(k)o(ed)f(with)
+h(the)f(`)p Fl(lstat)p Fo(')f(system)h(call.)62 1004 y(The)f(`)p
+Fl(linkx)p Fo(')e(\014lesystem)j(t)o(yp)q(e)f(is)g(particularly)h(useful)g
+(for)e(wildcard)i(map)e(en)o(tries.)20 b(In)15 b(this)f(case,)f(a)h(list)g
+(of)0 1054 y(p)q(ossible)j(targets)d(can)h(b)q(e)h(giv)o(e)f(and)h
+Fp(Amd)h Fo(will)g(c)o(ho)q(ose)e(the)g(\014rst)g(one)h(whic)o(h)g(exists)f
+(on)g(the)g(lo)q(cal)i(mac)o(hine.)0 1213 y Fq(5.8)33 b(Automoun)n(t)15
+b(Filesystem)h(\(`)p Fg(type:=auto)p Fq('\))62 1305 y Fo(The)j
+Fp(auto)g Fo(\014lesystem)g(t)o(yp)q(e)f(creates)g(a)g(new)g(automoun)o(t)f
+(p)q(oin)o(t)h(b)q(elo)o(w)h(an)f(existing)h(automoun)o(t)e(p)q(oin)o(t.)0
+1354 y(T)l(op-lev)o(el)g(automoun)o(t)e(p)q(oin)o(ts)h(app)q(ear)f(as)h
+(system)f(moun)o(t)g(p)q(oin)o(ts.)22 b(An)16 b(automoun)o(t)e(moun)o(t)h(p)q
+(oin)o(t)h(can)g(also)0 1404 y(app)q(ear)h(as)g(a)g(sub-directory)h(of)f(an)g
+(existing)i(automoun)o(t)d(p)q(oin)o(t.)26 b(This)18 b(allo)o(ws)g(some)e
+(additional)j(structure)0 1454 y(to)c(b)q(e)g(added,)h(for)e(example)i(to)f
+(mimic)h(the)g(moun)o(t)e(tree)h(of)g(another)g(mac)o(hine.)62
+1525 y(The)h(follo)o(wing)g(options)f(ma)o(y)f(b)q(e)i(sp)q(eci\014ed:)0
+1605 y Fl(cache)120 b Fo(sp)q(eci\014es)19 b(whether)e(the)g(data)f(in)i
+(this)g(moun)o(t-map)e(should)i(b)q(e)g(cac)o(hed.)25 b(The)18
+b(default)f(v)m(alue)h(is)240 1655 y(`)p Fl(none)p Fo(',)13
+b(in)i(whic)o(h)g(case)f(no)g(cac)o(hing)h(is)g(done)f(in)h(order)f(to)g
+(conserv)o(e)g(memory)l(.)19 b(Ho)o(w)o(ev)o(er,)13 b(b)q(etter)240
+1705 y(p)q(erformance)i(and)h(reliabilit)o(y)h(can)f(b)q(e)g(obtained)f(b)o
+(y)h(cac)o(hing)f(some)g(or)g(all)h(of)f(a)g(moun)o(t-map.)240
+1765 y(If)f(the)g(cac)o(he)g(option)g(sp)q(eci\014es)h(`)p
+Fl(all)p Fo(',)e(the)g(en)o(tire)i(map)e(is)h(en)o(umerated)g(when)g(the)g
+(moun)o(t)f(p)q(oin)o(t)240 1815 y(is)j(created.)240 1875 y(If)h(the)g(cac)o
+(he)g(option)h(sp)q(eci\014es)g(`)p Fl(inc)p Fo(',)e(cac)o(hing)i(is)f(done)g
+(incremen)o(tally)i(as)e(and)g(when)g(data)f(is)240 1925 y(required.)k(Some)
+13 b(map)f(t)o(yp)q(es)h(do)g(not)f(supp)q(ort)h(cac)o(he)g(mo)q(de)f(`)p
+Fl(all)p Fo(',)g(in)i(whic)o(h)f(case)g(`)p Fl(inc)p Fo(')e(is)i(used)240
+1975 y(whenev)o(er)j(`)p Fl(all)p Fo(')e(is)h(requested.)240
+2035 y(Cac)o(hing)h(can)f(b)q(e)h(en)o(tirely)g(disabled)h(b)o(y)e(using)h
+(cac)o(he)g(mo)q(de)f(`)p Fl(none)p Fo('.)240 2095 y(If)f(the)g(cac)o(he)h
+(option)f(sp)q(eci\014es)h(`)p Fl(regexp)p Fo(')e(then)h(the)g(en)o(tire)h
+(map)e(will)j(b)q(e)f(en)o(umerated)f(and)g(eac)o(h)240 2145
+y(k)o(ey)i(will)i(b)q(e)g(treated)d(as)i(an)f(egrep-st)o(yle)h(regular)f
+(expression.)25 b(The)17 b(order)f(in)h(whic)o(h)g(a)f(cac)o(hed)240
+2195 y(map)f(is)i(searc)o(hed)f(do)q(es)f(not)h(corresp)q(ond)g(to)f(the)g
+(ordering)h(in)h(the)f(source)f(map)h(so)f(the)h(regular)240
+2245 y(expressions)g(should)g(b)q(e)g(m)o(utually)g(exclusiv)o(e)h(to)d(a)o
+(v)o(oid)h(confusion.)240 2305 y(Eac)o(h)i(moun)o(t)g(map)g(t)o(yp)q(e)h(has)
+f(a)g(default)h(cac)o(he)g(t)o(yp)q(e,)g(usually)g(`)p Fl(inc)p
+Fo(',)f(whic)o(h)h(can)g(b)q(e)g(selected)240 2355 y(b)o(y)d(sp)q(ecifying)i
+(`)p Fl(mapdefault)p Fo('.)240 2415 y(The)e(cac)o(he)g(mo)q(de)g(for)f(a)g
+(moun)o(t)g(map)h(can)g(only)g(b)q(e)g(selected)h(on)f(the)f(command)h(line.)
+21 b(Starting)240 2465 y Fp(Amd)c Fo(with)f(the)f(command:)360
+2525 y Fl(amd)23 b(/homes)g(hesiod.homes)g(-cache:=inc)240
+2595 y Fo(will)17 b(cause)f(`)p Fl(/homes)p Fo(')d(to)i(b)q(e)h(automoun)o
+(ted)f(using)h(the)f Fp(Hesio)q(d)j Fo(name)e(serv)o(er)f(with)g(lo)q(cal)i
+(incre-)240 2645 y(men)o(tal)e(cac)o(hing)h(of)f(all)h(succesfully)h(resolv)o
+(ed)f(names.)p eop
+%%Page: 25 27
+25 26 bop 0 -83 a Fo(Chapter)15 b(5:)k(Filesystem)d(T)o(yp)q(es)1145
+b(SMM:13-25)240 158 y(All)21 b(cac)o(hed)f(data)g(is)g(forgotten)e(whenev)o
+(er)j Fp(Amd)h Fo(receiv)o(es)e(a)g(`)p Fl(SIGHUP)p Fo(')e(signal)j(and,)f
+(if)h(cac)o(he)240 208 y(`)p Fl(all)p Fo(')14 b(mo)q(de)i(w)o(as)f(selected,)
+i(the)e(cac)o(he)h(will)i(b)q(e)e(reloaded.)22 b(This)16 b(can)g(b)q(e)g
+(used)g(to)f(inform)h Fp(Amd)240 258 y Fo(that)i(a)g(map)g(has)g(b)q(een)h
+(up)q(dated.)30 b(In)19 b(addition,)h(whenev)o(er)f(a)f(cac)o(he)g(lo)q(okup)
+h(fails)g(and)g Fp(Amd)240 308 y Fo(needs)g(to)f(examine)h(a)f(map,)h(the)f
+(map's)g(mo)q(dify)h(time)g(is)g(examined.)31 b(If)18 b(the)h(cac)o(he)f(is)h
+(out)f(of)240 358 y(date)d(with)h(resp)q(ect)f(to)g(the)g(map)g(then)h(it)f
+(is)h(\015ushed)g(as)f(if)h(a)e(`)p Fl(SIGHUP)p Fo(')g(had)h(b)q(een)i
+(receiv)o(ed.)240 422 y(An)c(additional)g(option)g(\(`)p Fl(sync)p
+Fo('\))d(ma)o(y)i(b)q(e)h(sp)q(eci\014ed)h(to)e(force)g Fp(Amd)i
+Fo(to)e(c)o(hec)o(k)g(the)h(map's)e(mo)q(dify)240 472 y(time)h(whenev)o(er)h
+(a)f(cac)o(hed)g(en)o(try)g(is)g(b)q(eing)i(used.)19 b(F)l(or)11
+b(example,)i(an)f(incremen)o(tal,)i(sync)o(hronised)240 522
+y(cac)o(he)h(w)o(ould)h(b)q(e)g(created)f(b)o(y)g(the)h(follo)o(wing)f
+(command:)360 587 y Fl(amd)23 b(/homes)g(hesiod.homes)g(-cache:=inc,sync)0
+652 y(fs)192 b Fo(sp)q(eci\014es)17 b(the)e(name)h(of)e(the)i(moun)o(t)e(map)
+h(to)g(use)g(for)g(the)g(new)h(moun)o(t)e(p)q(oin)o(t.)240
+716 y(Arguably)g(this)g(should)g(ha)o(v)o(e)f(b)q(een)i(sp)q(eci\014ed)h
+(with)d(the)h Fl(${rfs})f Fo(option)g(but)h(w)o(e)f(are)g(no)o(w)g(stuc)o(k)
+240 766 y(with)j(it)f(due)h(to)e(historical)j(acciden)o(t.)0
+831 y Fl(pref)144 b Fo(alters)13 b(the)h(name)f(that)g(is)h(lo)q(ok)o(ed)g
+(up)g(in)g(the)g(moun)o(t)f(map.)19 b(If)13 b Fl(${pref})p
+Fo(,)g(the)g Fp(pre\014x)p Fo(,)h(is)g(non-n)o(ull)240 881
+y(then)i(it)f(is)h(prep)q(ended)h(to)d(the)i(name)f(requested)g(b)o(y)h(the)f
+(k)o(ernel)h Fp(b)q(efore)i Fo(the)d(map)g(is)h(searc)o(hed.)62
+972 y(The)22 b(serv)o(er)e(`)p Fl(dylan.doc.ic.ac.uk)p Fo(')e(has)j(t)o(w)o
+(o)f(user)h(disks:)33 b(`)p Fl(/dev/dsk/2s0)p Fo(')18 b(and)k(`)p
+Fl(/dev/dsk/5s0)p Fo('.)0 1022 y(These)e(are)f(accessed)h(as)f(`)p
+Fl(/home/dylan/dk2)p Fo(')e(and)i(`)p Fl(/home/dylan/dk5)p
+Fo(')e(resp)q(ectiv)o(ely)l(.)35 b(Since)20 b(`)p Fl(/home)p
+Fo(')e(is)0 1072 y(already)d(an)h(automoun)o(t)e(p)q(oin)o(t,)h(this)h
+(naming)f(is)h(ac)o(hiev)o(ed)g(with)g(the)f(follo)o(wing)h(map)f(en)o
+(tries:)120 1142 y Fl(dylan)190 b(type:=auto;fs:=${map};pref:=)o(${key}/)120
+1192 y(dylan/dk2)94 b(type:=ufs;dev:=/dev/dsk/2s0)120 1242
+y(dylan/dk5)g(type:=ufs;dev:=/dev/dsk/5s0)0 1432 y Fq(5.9)33
+b(Direct)15 b(Automoun)n(t)h(Filesystem)g(\(`)p Fg(type:=direct)p
+Fq(')o(\))62 1523 y Fo(The)h Fp(direct)i Fo(\014lesystem)e(is)h(almost)e
+(iden)o(tical)j(to)d(the)h(automoun)o(t)f(\014lesystem.)25
+b(Instead)18 b(of)e(app)q(earing)i(to)0 1573 y(b)q(e)e(a)f(directory)g(of)g
+(moun)o(t)f(p)q(oin)o(ts,)h(it)h(app)q(ears)f(as)g(a)f(sym)o(b)q(olic)j(link)
+f(to)f(a)g(moun)o(ted)g(\014lesystem.)20 b(The)15 b(moun)o(t)0
+1622 y(is)f(done)h(at)e(the)h(time)g(the)g(link)h(is)f(accessed.)20
+b(See)15 b(Section)g(5.8)d([Automoun)o(t)h(Filesystem],)h(page)28
+b(SMM:13-24)0 1672 y(for)15 b(a)f(list)i(of)f(required)i(options.)62
+1743 y(Direct)c(automoun)o(t)e(p)q(oin)o(ts)i(are)g(created)f(b)o(y)h(sp)q
+(ecifying)h(the)f(`)p Fl(direct)p Fo(')e(\014lesystem)i(t)o(yp)q(e)g(on)f
+(the)h(command)0 1793 y(line:)120 1863 y Fl(amd)23 b(...)h(/usr/man)f
+(auto.direct)f(-type:=direct)62 1955 y Fo(where)16 b(`)p Fl(auto.direct)p
+Fo(')d(w)o(ould)i(con)o(tain)h(an)f(en)o(try)f(suc)o(h)i(as:)120
+2025 y Fl(usr/man)94 b(-type:=nfs;rfs:=/usr/man)21 b(\\)382
+2075 y(rhost:=man-server1)46 b(rhost:=man-server2)62 2166 y
+Fo(In)19 b(this)f(example,)h(`)p Fl(man-server1)p Fo(')d(and)i(`)p
+Fl(man-server2)p Fo(')d(are)j(\014le)h(serv)o(ers)e(whic)o(h)i(exp)q(ort)f
+(copies)g(of)g(the)0 2216 y(man)o(ual)e(pages.)22 b(Note)16
+b(that)f(the)i(k)o(ey)f(whic)o(h)g(is)h(lo)q(ok)o(ed)f(up)h(is)g(the)f(name)g
+(of)f(the)i(automoun)o(t)d(p)q(oin)o(t)j(without)0 2266 y(the)e(leading)i(`)p
+Fl(/)p Fo('.)0 2454 y Fq(5.10)32 b(Union)16 b(Filesystem)g(\(`)p
+Fg(type:=union)p Fq('\))62 2545 y Fo(The)21 b Fp(union)g Fo(\014lesystem)g(t)
+o(yp)q(e)f(allo)o(ws)h(the)f(con)o(ten)o(ts)g(of)g(sev)o(eral)g(directories)i
+(to)d(b)q(e)i(merged)f(and)h(made)0 2595 y(visible)16 b(in)f(a)f(single)h
+(directory)l(.)20 b(This)14 b(can)g(b)q(e)h(used)g(to)e(o)o(v)o(ercome)g(one)
+h(of)g(the)g(ma)s(jor)e(limitations)j(of)f(the)g(Unix)0 2645
+y(moun)o(t)h(mec)o(hanism)h(whic)o(h)g(only)f(allo)o(ws)h(complete)g
+(directories)g(to)e(b)q(e)i(moun)o(ted.)p eop
+%%Page: 26 28
+26 27 bop 15 -83 a Fo(SMM:13-26)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)62 158 y(F)l(or)g(example,)i(supp)q(osing)g(`)p
+Fl(/tmp)p Fo(')e(and)h(`)p Fl(/var/tmp)p Fo(')d(w)o(ere)j(to)f(b)q(e)h
+(merged)g(in)o(to)g(a)f(new)h(directory)g(called)0 208 y(`)p
+Fl(/mtmp)p Fo(',)j(with)g(\014les)h(in)g(`)p Fl(/var/tmp)p
+Fo(')e(taking)h(precedence.)39 b(The)22 b(follo)o(wing)g(command)f(could)h(b)
+q(e)g(used)g(to)0 258 y(ac)o(hiev)o(e)16 b(this)f(e\013ect:)120
+329 y Fl(amd)23 b(...)h(/mtmp)f(union:/tmp:/var/tmp)e(-type:=union)62
+420 y Fo(Curren)o(tly)l(,)12 b(the)f(unioned)h(directories)g(m)o(ust)f
+Fp(not)g Fo(b)q(e)h(automoun)o(ted.)18 b(That)10 b(w)o(ould)h(cause)g(a)g
+(deadlo)q(c)o(k.)19 b(This)0 470 y(seriously)d(limits)h(the)e(curren)o(t)g
+(usefulness)i(of)e(this)h(\014lesystem)f(t)o(yp)q(e)h(and)f(the)h(problem)g
+(will)g(b)q(e)g(addressed)g(in)0 519 y(a)f(future)g(release)h(of)f
+Fp(Amd)p Fo(.)62 590 y(Files)20 b(created)e(in)i(the)e(union)i(directory)e
+(are)h(actually)g(created)f(in)i(the)e(last)g(named)h(directory)l(.)30
+b(This)19 b(is)0 640 y(done)h(b)o(y)g(creating)f(a)h(wildcard)h(en)o(try)e
+(whic)o(h)i(p)q(oin)o(ts)f(to)f(the)g(correct)h(directory)l(.)33
+b(The)20 b(wildcard)h(en)o(try)e(is)0 690 y(visible)e(if)f(the)f(union)i
+(directory)e(is)h(listed,)g(so)f(allo)o(wing)h(y)o(ou)f(to)f(see)i(whic)o(h)g
+(directory)f(has)g(priorit)o(y)l(.)62 760 y(The)j(\014les)g(visible)h(in)f
+(the)f(union)h(directory)f(are)g(computed)g(at)g(the)g(time)g
+Fp(Amd)i Fo(is)f(started,)e(and)i(are)e(not)0 810 y(k)o(ept)c(upto)q(date)g
+(with)g(resp)q(ect)h(to)e(the)h(underlying)i(directories.)20
+b(Similarly)l(,)15 b(if)d(a)g(link)h(is)g(remo)o(v)o(ed,)f(for)f(example)0
+860 y(with)16 b(the)f(`)p Fl(rm)p Fo(')f(command,)h(it)g(will)i(b)q(e)f(lost)
+f(forev)o(er.)0 1019 y Fq(5.11)32 b(Error)16 b(Filesystem)g(\(`)p
+Fg(type:=error)p Fq('\))62 1111 y Fo(The)i Fp(error)i Fo(\014lesystem)e(t)o
+(yp)q(e)f(is)h(used)g(in)o(ternally)h(as)e(a)g(catc)o(h-all)h(in)g(the)f
+(case)h(where)f(none)h(of)f(the)g(other)0 1160 y(\014lesystems)g(w)o(as)e
+(selected,)i(or)e(some)h(other)g(error)f(o)q(ccurred.)23 b(Lo)q(okups)16
+b(and)h(moun)o(ts)e(alw)o(a)o(ys)g(fail)i(with)f(\\No)0 1210
+y(suc)o(h)g(\014le)g(or)e(directory".)20 b(All)d(other)e(op)q(erations)g
+(trivially)i(succeed.)62 1281 y(The)f(error)e(\014lesystem)i(is)g(not)f
+(directly)h(accessible.)0 1440 y Fq(5.12)32 b(T)-6 b(op-lev)n(el)17
+b(Filesystem)f(\(`)p Fg(type:=toplvl)p Fq('\))62 1532 y Fo(The)23
+b Fp(toplvl)i Fo(\014lesystems)d(is)h(deriv)o(ed)g(from)f(the)g(`)p
+Fl(auto)p Fo(')f(\014lesystem)i(and)f(is)h(used)g(to)e(moun)o(t)h(the)g(top-)
+0 1581 y(lev)o(el)17 b(automoun)o(t)d(no)q(des.)21 b(Requests)16
+b(of)f(this)g(t)o(yp)q(e)h(are)f(automatically)h(generated)f(from)g(the)g
+(command)g(line)0 1631 y(argumen)o(ts)f(and)i(can)f(also)g(b)q(e)h(passed)g
+(in)g(b)o(y)f(using)h(the)f(\\-M")f(option)i(of)f(the)g Fp(Amq)h
+Fo(command.)0 1787 y Fq(5.13)32 b(Ro)r(ot)15 b(Filesystem)62
+1879 y Fo(The)j Fp(ro)q(ot)g Fo(\(`)p Fl(type:=root)p Fo('\))e(\014lesystem)i
+(t)o(yp)q(e)g(acts)f(as)h(an)g(in)o(ternal)h(placeholder)g(on)o(to)e(whic)o
+(h)i Fp(Amd)h Fo(can)0 1929 y(pin)c(`)p Fl(toplvl)p Fo(')e(moun)o(ts.)20
+b(Only)d(one)e(no)q(de)h(of)f(this)h(t)o(yp)q(e)g(need)g(ev)o(er)f(exist)h
+(and)g(one)f(is)h(created)g(automatically)0 1978 y(during)g(startup.)j(The)d
+(e\013ect)f(of)f(creating)i(a)f(second)g(ro)q(ot)g(no)q(de)h(is)f
+(unde\014ned.)0 2135 y Fq(5.14)32 b(Inheritance)17 b(Filesystem)62
+2226 y Fo(The)c Fp(inheritance)k Fo(\(`)p Fl(type:=inherit)p
+Fo('\))10 b(\014lesystem)k(is)f(not)f(directly)j(accessible.)20
+b(Instead,)14 b(in)o(ternal)f(moun)o(t)0 2276 y(no)q(des)j(of)f(this)h(t)o
+(yp)q(e)f(are)g(automatically)h(generated)f(when)h Fp(Amd)i
+Fo(is)e(started)e(with)i(the)f(\\-r")g(option.)21 b(A)o(t)15
+b(this)0 2325 y(time)j(the)g(system)f(moun)o(t)g(table)h(is)g(scanned)g(to)f
+(lo)q(cate)h(an)o(y)f(\014lesystems)h(whic)o(h)h(are)e(already)h(moun)o(ted.)
+27 b(If)0 2375 y(an)o(y)17 b(reference)h(to)f(these)h(\014lesystems)g(is)g
+(made)f(through)g Fp(Amd)i Fo(then)f(instead)g(of)f(attempting)g(to)g(moun)o
+(t)g(it,)0 2425 y Fp(Amd)k Fo(sim)o(ulates)e(the)g(moun)o(t)f(and)h
+Fp(inherits)j Fo(the)d(\014lesystem.)31 b(This)19 b(allo)o(ws)g(a)f(new)h(v)o
+(ersion)g(of)g Fp(Amd)h Fo(to)e(b)q(e)0 2475 y(installed)d(on)e(a)g(liv)o(e)i
+(system)e(simply)h(b)o(y)f(killing)j(the)d(old)h(daemon)f(with)h
+Fl(SIGTERM)e Fo(and)i(starting)e(the)i(new)f(one.)62 2545 y(This)18
+b(\014lesystem)g(t)o(yp)q(e)f(is)g(not)g(generally)h(visible)h(externally)l
+(,)g(but)e(it)g(is)h(p)q(ossible)g(that)f(the)g(output)g(from)0
+2595 y(`)p Fl(amq)d(-m)p Fo(')g(ma)o(y)f(list)h(`)p Fl(inherit)p
+Fo(')f(as)g(the)h(\014lesystem)h(t)o(yp)q(e.)k(This)c(happ)q(ens)g(when)f(an)
+g(inherit)h(op)q(eration)f(cannot)0 2645 y(b)q(e)i(completed)g(for)f(some)g
+(reason,)f(usually)i(b)q(ecause)h(a)e(\014leserv)o(er)g(is)h(do)o(wn.)p
+eop
+%%Page: 27 29
+27 28 bop 0 -83 a Fo(Chapter)15 b(6:)k(Run-time)e(Administration)987
+b(SMM:13-27)0 158 y Fm(6)41 b(Run-time)14 b(Administration)0
+379 y Fq(6.1)33 b(Starting)16 b Ff(Amd)62 470 y Fp(Amd)h Fo(is)f(b)q(est)g
+(started)e(from)g(`)p Fl(/etc/rc.local)p Fo(':)120 540 y Fl(if)24
+b([)f(-f)h(/etc/amd.start)e(];)h(then)311 590 y(sh)g(/etc/amd.start;)f
+(\(echo)h(-n)h(')g(amd'\))142 b(>/dev/console)120 640 y(fi)0
+731 y Fo(The)15 b(shell)i(script,)e(`)p Fl(amd.start)p Fo(',)e(con)o(tains:)
+120 802 y Fl(#!/bin/sh)23 b(-)120 852 y(PATH=/etc:/bin:/usr/bin:/u)o(sr/ucb:)
+o($PATH)e(export)i(PATH)120 951 y(#)120 1001 y(#)h(Either)f(name)g(of)h
+(logfile)f(or)g("syslog")120 1051 y(#)120 1101 y(LOGFILE=syslog)120
+1151 y(#LOGFILE=/var/log/amd)120 1250 y(#)120 1300 y(#)h(Figure)f(out)g
+(whether)g(domain)g(name)g(is)h(in)g(host)f(name)120 1350 y(#)h(If)f(the)h
+(hostname)f(is)g(just)g(the)h(machine)f(name)g(then)120 1400
+y(#)h(pass)f(in)h(the)f(name)g(of)h(the)f(local)h(domain)f(so)g(that)h(the)
+120 1450 y(#)g(hostnames)e(in)i(the)f(map)h(are)f(domain)g(stripped)g
+(correctly.)120 1499 y(#)120 1549 y(case)g(`hostname`)g(in)120
+1599 y(*.*\))g(dmn=)h(;;)120 1649 y(*\))g(dmn='-d)e(doc.ic.ac.uk')120
+1699 y(esac)120 1798 y(#)120 1848 y(#)i(Zap)f(earlier)g(log)h(file)120
+1898 y(#)120 1948 y(case)f("$LOGFILE")g(in)120 1998 y(*/*\))311
+2047 y(mv)g("$LOGFILE")g("$LOGFILE"-)311 2097 y(>)h("$LOGFILE")311
+2147 y(;;)120 2197 y(syslog\))311 2247 y(:)g(nothing)311 2296
+y(;;)120 2346 y(esac)120 2446 y(cd)g(/usr/sbin)120 2496 y(#)120
+2545 y(#)g(-r)286 b(restart)120 2595 y(#)24 b(-d)f(dmn)191
+b(local)23 b(domain)120 2645 y(#)h(-w)f(wait)167 b(wait)23
+b(between)g(unmount)g(attempts)p eop
+%%Page: 28 30
+28 29 bop 15 -83 a Fo(SMM:13-28)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)120 158 y Fl(#)24 b(-l)f(log)191 b(logfile)23
+b(or)g("syslog")120 208 y(#)120 258 y(eval)g(./amd)g(-r)h($dmn)f(-w)h(240)f
+(-l)h("$LOGFILE")f(\\)311 308 y(/homes)g(amd.homes)g(-cache:=inc)f(\\)311
+358 y(/home)h(amd.home)g(-cache:=inc)f(\\)311 407 y(/vol)h(amd.vol)g
+(-cache:=inc)f(\\)311 457 y(/n)h(amd.net)g(-cache:=inc)62 549
+y Fo(If)12 b(the)g(list)g(of)f(automoun)o(t)f(p)q(oin)o(ts)i(and)g(maps)f(is)
+h(con)o(tained)g(in)h(a)e(\014le)i(or)e(NIS)h(map)f(it)h(is)g(easily)g
+(incorp)q(orated)0 598 y(on)o(to)i(the)i(command)f(line:)120
+669 y Fl(...)120 719 y(eval)23 b(./amd)g(-r)h($dmn)f(-w)h(240)f(-l)h
+("$LOGFILE")f(`ypcat)g(-k)g(auto.master`)0 904 y Fq(6.2)33
+b(Stopping)16 b Ff(Amd)62 995 y Fp(Amd)h Fo(stops)e(in)h(resp)q(onse)g(to)e
+(t)o(w)o(o)g(signals.)0 1066 y(`)p Fl(SIGTERM)p Fo(')46 b(causes)18
+b(the)f(top-lev)o(el)i(automoun)o(t)d(p)q(oin)o(ts)i(to)f(b)q(e)h(unmoun)o
+(ted)f(and)h(then)g Fp(Amd)h Fo(to)e(exit.)27 b(An)o(y)240
+1116 y(automoun)o(ted)16 b(\014lesystems)g(are)g(left)h(moun)o(ted.)23
+b(They)17 b(can)f(b)q(e)h(reco)o(v)o(ered)f(b)o(y)g(restarting)g
+Fp(Amd)240 1166 y Fo(with)g(the)f(\\-r")f(command)h(line)i(option.)0
+1230 y(`)p Fl(SIGINT)p Fo(')70 b(causes)22 b Fp(Amd)i Fo(to)d(attempt)g(to)g
+(unmoun)o(t)h(an)o(y)g(\014lesystems)g(whic)o(h)h(it)f(has)g(automoun)o(ted,)
+g(in)240 1280 y(addition)16 b(to)f(the)g(actions)g(of)g(`)p
+Fl(SIGTERM)p Fo('.)j(This)e(signal)g(is)g(primarly)g(used)g(for)e(debugging.)
+62 1371 y(Actions)i(tak)o(en)f(for)f(other)h(signals)h(are)f(unde\014ned.)0
+1556 y Fq(6.3)33 b(Con)n(trolling)17 b Ff(Amd)62 1647 y Fo(It)f(is)h
+(sometimes)f(desirable)i(or)d(necessary)i(to)e(exercise)i(external)g(con)o
+(trol)f(o)o(v)o(er)f(some)h(of)f Fp(Amd)r Fo('s)h(in)o(ternal)0
+1697 y(state.)j(T)l(o)c(supp)q(ort)g(this)h(requiremen)o(t,)f
+Fp(Amd)i Fo(implemen)o(ts)g(an)e(RPC)g(in)o(terface)g(whic)o(h)h(is)g(used)g
+(b)o(y)f(the)g Fp(Amq)0 1746 y Fo(program.)k(A)c(v)m(ariet)o(y)g(of)g
+(information)g(is)h(a)o(v)m(ailable.)62 1817 y Fp(Amq)e Fo(generally)h
+(applies)f(an)f(op)q(eration,)h(sp)q(eci\014ed)h(b)o(y)e(a)g(single)h(letter)
+f(option,)h(to)e(a)h(list)h(of)e(moun)o(t)h(p)q(oin)o(ts.)0
+1867 y(The)i(default)g(op)q(eration)g(is)g(to)f(obtain)g(statistics)h(ab)q
+(out)f(eac)o(h)h(moun)o(t)f(p)q(oin)o(t.)20 b(This)15 b(is)g(similar)h(to)e
+(the)g(output)0 1917 y(sho)o(wn)f(ab)q(o)o(v)o(e)g(but)h(includes)h
+(information)f(ab)q(out)f(the)h(n)o(um)o(b)q(er)g(and)f(t)o(yp)q(e)h(of)f
+(accesses)h(to)e(eac)o(h)i(moun)o(t)f(p)q(oin)o(t.)0 2077 y
+Fi(6.3.1)30 b Fe(Amq)16 b Fi(default)f(information)62 2169
+y Fo(With)k(no)f(argumen)o(ts,)f Fp(Amq)i Fo(obtains)f(a)g(brief)h(list)g(of)
+e(all)i(existing)h(moun)o(ts)d(created)h(b)o(y)g Fp(Amd)p Fo(.)29
+b(This)18 b(is)0 2218 y(di\013eren)o(t)d(from)g(the)g(list)h(displa)o(y)o(ed)
+h(b)o(y)e Fk(df)p Fo(\(1\))f(since)j(the)e(latter)g(only)g(includes)j(system)
+d(moun)o(t)f(p)q(oin)o(ts.)0 2289 y(The)h(output)g(from)g(this)h(option)f
+(includes)i(the)f(follo)o(wing)g(information:)37 2360 y Fn(\017)30
+b Fo(the)15 b(automoun)o(t)f(p)q(oin)o(t,)37 2424 y Fn(\017)30
+b Fo(the)15 b(\014lesystem)h(t)o(yp)q(e,)37 2489 y Fn(\017)30
+b Fo(the)15 b(moun)o(t)g(map)g(or)g(moun)o(t)f(information,)37
+2554 y Fn(\017)30 b Fo(the)15 b(in)o(ternal,)h(or)f(system)f(moun)o(t)h(p)q
+(oin)o(t.)0 2645 y(F)l(or)g(example:)p eop
+%%Page: 29 31
+29 30 bop 0 -83 a Fo(Chapter)15 b(6:)k(Run-time)e(Administration)987
+b(SMM:13-29)120 158 y Fl(/)286 b(root)71 b("root")477 b(sky:\(pid75\))120
+208 y(/homes)166 b(toplvl)23 b(/usr/local/etc/amd.homes)45
+b(/homes)120 258 y(/home)190 b(toplvl)23 b(/usr/local/etc/amd.home)69
+b(/home)120 308 y(/homes/jsp)h(nfs)95 b(charm:/home/charm)213
+b(/a/charm/home/charm/jsp)120 358 y(/homes/phjk)46 b(nfs)95
+b(toytown:/home/toytown)117 b(/a/toytown/home/toytown/)o(ai/phjk)0
+449 y Fo(If)15 b(an)h(argumen)o(t)e(is)i(giv)o(en)f(then)h(statistics)f(for)g
+(that)f(v)o(olume)i(name)f(will)i(b)q(e)f(output.)j(F)l(or)c(example:)120
+519 y Fl(What)286 b(Uid)71 b(Getattr)23 b(Lookup)g(RdDir)71
+b(RdLnk)g(Statfs)23 b(Mounted@)120 569 y(/homes)238 b(0)119
+b(1196)95 b(512)g(22)143 b(0)167 b(30)119 b(90/09/14)23 b(12:32:55)120
+619 y(/homes/jsp)142 b(0)119 b(0)167 b(0)143 b(0)167 b(1180)95
+b(0)143 b(90/10/13)23 b(12:56:58)0 690 y(What)144 b Fo(the)15
+b(v)o(olume)h(name.)0 752 y Fl(Uid)168 b Fo(ignored.)0 815
+y Fl(Getattr)72 b Fo(the)21 b(coun)o(t)g(of)f(NFS)h Fp(getattr)i
+Fo(requests)e(on)g(this)g(no)q(de.)38 b(This)21 b(should)h(only)g(b)q(e)f
+(non-zero)h(for)240 865 y(directory)15 b(no)q(des.)0 928 y
+Fl(Lookup)96 b Fo(the)21 b(coun)o(t)g(of)g(NFS)g Fp(lo)q(okup)j
+Fo(requests)d(on)g(this)h(no)q(de.)38 b(This)22 b(should)g(only)g(b)q(e)g
+(non-zero)g(for)240 978 y(directory)15 b(no)q(des.)0 1040 y
+Fl(RdDir)120 b Fo(the)21 b(coun)o(t)f(of)g(NFS)h Fp(readdir)j
+Fo(requests)d(on)g(this)g(no)q(de.)36 b(This)22 b(should)f(only)g(b)q(e)h
+(non-zero)f(for)240 1090 y(directory)15 b(no)q(des.)0 1153
+y Fl(RdLnk)120 b Fo(the)19 b(coun)o(t)g(of)g(NFS)g Fp(readlink)k
+Fo(requests)c(on)h(this)f(no)q(de.)32 b(This)20 b(should)g(b)q(e)g(zero)f
+(for)g(directory)240 1203 y(no)q(des.)0 1266 y Fl(Statfs)96
+b Fo(the)11 b(could)h(of)f(NFS)g Fp(statfs)h Fo(requests)f(on)g(this)h(no)q
+(de.)19 b(This)11 b(should)h(only)g(b)q(e)g(non-zero)f(for)g(top-lev)o(el)240
+1315 y(automoun)o(t)j(p)q(oin)o(ts.)0 1378 y Fl(Mounted@)48
+b Fo(the)15 b(date)g(and)h(time)f(the)g(v)o(olume)h(name)f(w)o(as)g(\014rst)f
+(referenced.)0 1523 y Fi(6.3.2)30 b Fe(Amq)16 b Fi(-f)f(option)62
+1615 y Fo(The)i(\\-f)t(")f(option)h(causes)g Fp(Amd)i Fo(to)d(\015ush)h(the)g
+(in)o(ternal)h(moun)o(t)e(map)g(cac)o(he.)25 b(This)18 b(is)f(useful)h(for)e
+(Hesio)q(d)0 1664 y(maps)f(since)i Fp(Amd)g Fo(will)g(not)e(automatically)h
+(notice)g(when)g(they)g(ha)o(v)o(e)f(b)q(een)i(up)q(dated.)k(The)16
+b(map)f(cac)o(he)h(can)0 1714 y(also)g(b)q(e)g(sync)o(hronised)g(with)g(the)g
+(map)f(source)h(b)o(y)g(using)g(the)f(`)p Fl(sync)p Fo(')g(option)h(\(see)f
+(Section)h(5.8)f([Automoun)o(t)0 1764 y(Filesystem],)g(page)30
+b(SMM:13-24\).)0 1909 y Fi(6.3.3)g Fe(Amq)16 b Fi(-h)g(option)62
+2000 y Fo(By)g(default)g(the)g(lo)q(cal)g(host)f(is)h(used.)22
+b(In)16 b(an)f(HP-UX)h(cluster)g(the)g(ro)q(ot)e(serv)o(er)h(is)h(used)g
+(since)h(that)e(is)h(the)0 2050 y(only)k(place)g(in)g(the)f(cluster)h(where)f
+Fp(Amd)i Fo(will)g(b)q(e)f(running.)33 b(T)l(o)19 b(query)g
+Fp(Amd)i Fo(on)e(another)g(host)g(the)g(\\-h")0 2100 y(option)c(should)i(b)q
+(e)e(used.)0 2245 y Fi(6.3.4)30 b Fe(Amq)16 b Fi(-m)g(option)62
+2336 y Fo(The)c(\\-m")e(option)h(displa)o(ys)h(similar)h(information)e(ab)q
+(out)g(moun)o(ted)g(\014lesystems,)h(rather)e(than)h(automoun)o(t)0
+2386 y(p)q(oin)o(ts.)20 b(The)c(output)f(includes)i(the)e(follo)o(wing)h
+(information:)37 2457 y Fn(\017)30 b Fo(the)15 b(moun)o(t)g(information,)37
+2520 y Fn(\017)30 b Fo(the)15 b(moun)o(t)g(p)q(oin)o(t,)37
+2582 y Fn(\017)30 b Fo(the)15 b(\014lesystem)h(t)o(yp)q(e,)37
+2645 y Fn(\017)30 b Fo(the)15 b(n)o(um)o(b)q(er)h(of)f(references)g(to)g
+(this)h(\014lesystem,)p eop
+%%Page: 30 32
+30 31 bop 15 -83 a Fo(SMM:13-30)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)37 158 y Fn(\017)30 b Fo(the)15 b(serv)o(er)g
+(hostname,)37 221 y Fn(\017)30 b Fo(the)15 b(state)g(of)f(the)i(\014le)g
+(serv)o(er,)37 284 y Fn(\017)30 b Fo(an)o(y)15 b(error)f(whic)o(h)i(has)f(o)q
+(ccured.)62 375 y(F)l(or)g(example:)120 446 y Fl("root")262
+b(truth:\(pid602\))117 b(root)71 b(1)24 b(localhost)e(is)i(up)120
+496 y(hesiod.home)142 b(/home)333 b(toplvl)23 b(1)h(localhost)e(is)i(up)120
+546 y(hesiod.vol)166 b(/vol)357 b(toplvl)23 b(1)h(localhost)e(is)i(up)120
+595 y(hesiod.homes)118 b(/homes)309 b(toplvl)23 b(1)h(localhost)e(is)i(up)120
+645 y(amy:/home/amy)94 b(/a/amy/home/amy)f(nfs)i(5)24 b(amy)f(is)h(up)120
+695 y(swan:/home/swan)46 b(/a/swan/home/swan)f(nfs)95 b(0)24
+b(swan)f(is)h(up)f(\(Permission)g(denied\))120 745 y(ex:/home/ex)142
+b(/a/ex/home/ex)f(nfs)95 b(0)24 b(ex)f(is)h(down)62 836 y Fo(When)15
+b(the)g(reference)g(coun)o(t)f(is)h(zero)g(the)f(\014lesystem)i(is)f(not)f
+(moun)o(ted)g(but)h(the)g(moun)o(t)f(p)q(oin)o(t)h(and)f(serv)o(er)0
+886 y(information)h(is)h(still)h(b)q(eing)f(main)o(tained)g(b)o(y)f
+Fp(Amd)p Fo(.)0 1032 y Fi(6.3.5)30 b Fe(Amq)16 b Fi(-M)g(option)62
+1123 y Fo(The)j(\\-M")f(option)i(passes)e(a)h(new)g(map)g(en)o(try)f(to)g
+Fp(Amd)j Fo(and)e(w)o(aits)g(for)f(it)h(to)f(b)q(e)i(ev)m(aluated,)g(p)q
+(ossibly)0 1173 y(causing)i(a)f(moun)o(t.)38 b(F)l(or)21 b(example,)j(the)d
+(follo)o(wing)h(command)g(w)o(ould)f(cause)h(`)p Fl(/home/toytown)p
+Fo(')d(on)i(host)0 1223 y(`)p Fl(toytown)p Fo(')13 b(to)i(b)q(e)h(moun)o(ted)
+f(lo)q(cally)i(on)e(`)p Fl(/mnt/toytown)p Fo('.)120 1293 y
+Fl(amq)23 b(-M)h('/mnt/toytown)e(type:=nfs;rfs:=/home/toytow)o(n;rhost)o
+(:=toytow)o(n;fs:=$)o({key}')62 1385 y Fp(Amd)13 b Fo(applies)g(some)e
+(simple)i(securit)o(y)e(c)o(hec)o(ks)h(b)q(efore)f(allo)o(wing)h(this)g(op)q
+(eration.)18 b(The)12 b(c)o(hec)o(k)f(tests)g(whether)0 1434
+y(the)16 b(incoming)h(request)f(is)g(from)f(a)h(privileged)i(UDP)d(p)q(ort)h
+(on)g(the)f(lo)q(cal)i(mac)o(hine.)23 b(\\P)o(ermission)16
+b(denied")h(is)0 1484 y(returned)f(if)f(the)h(c)o(hec)o(k)f(fails.)62
+1555 y(A)f(future)f(release)h(of)e Fp(Amd)j Fo(will)g(include)h(co)q(de)e(to)
+e(allo)o(w)i(the)f Fk(moun)o(t)p Fo(\(8\))f(command)h(to)f(moun)o(t)h
+(automoun)o(t)0 1605 y(p)q(oin)o(ts:)120 1675 y Fl(mount)23
+b(-t)h(amd)f(/vol)h(hesiod.vol)62 1766 y Fo(This)16 b(will)h(then)e(allo)o(w)
+h Fp(Amd)h Fo(to)e(b)q(e)g(con)o(trolled)h(from)f(the)g(standard)g(system)g
+(\014lesystem)h(moun)o(t)e(list.)0 1912 y Fi(6.3.6)30 b Fe(Amq)16
+b Fi(-s)g(option)62 2004 y Fo(The)h(\\-s")f(option)h(displa)o(ys)h(global)f
+(statistics.)24 b(If)17 b(an)o(y)g(other)f(options)h(are)f(sp)q(eci\014ed)j
+(or)d(an)o(y)g(\014lesystems)0 2053 y(named)f(then)h(this)g(option)f(is)h
+(ignored.)k(F)l(or)15 b(example:)120 2124 y Fl(requests)47
+b(stale)118 b(mount)h(mount)g(unmount)120 2174 y(deferred)47
+b(fhandles)f(ok)191 b(failed)95 b(failed)120 2224 y(1054)143
+b(1)214 b(487)167 b(290)g(7017)0 2294 y Fo(`)p Fl(Deferred)14
+b(requests)p Fo(')240 2357 y(are)k(those)f(for)h(whic)o(h)h(an)f(immediate)h
+(reply)f(could)h(not)f(b)q(e)h(constructed.)28 b(F)l(or)17
+b(example,)j(this)240 2407 y(w)o(ould)c(happ)q(en)g(if)g(a)e(bac)o(kground)i
+(moun)o(t)e(w)o(as)h(required.)0 2470 y(`)p Fl(Stale)f(filehandles)p
+Fo(')240 2532 y(coun)o(ts)f(the)g(n)o(um)o(b)q(er)g(of)g(times)g(the)g(k)o
+(ernel)h(passes)f(a)g(stale)g(\014lehandle)i(to)e Fp(Amd)p
+Fo(.)19 b(Large)13 b(n)o(um)o(b)q(ers)240 2582 y(indicate)k(problems.)0
+2645 y(`)p Fl(Mount)d(ok)p Fo(')32 b(coun)o(ts)15 b(the)g(n)o(um)o(b)q(er)h
+(of)f(automoun)o(ts)f(whic)o(h)i(w)o(ere)e(successful.)p eop
+%%Page: 31 33
+31 32 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-31)0
+158 y(`)p Fl(Mount)14 b(failed)p Fo(')240 222 y(coun)o(ts)h(the)g(n)o(um)o(b)
+q(er)h(of)f(automoun)o(ts)f(whic)o(h)i(failed.)0 286 y(`)p
+Fl(Unmount)e(failed)p Fo(')240 350 y(coun)o(ts)h(the)g(n)o(um)o(b)q(er)g(of)f
+(times)h(a)g(\014lesystem)g(could)h(not)f(b)q(e)g(unmoun)o(ted.)21
+b(V)l(ery)15 b(large)g(n)o(um)o(b)q(ers)240 400 y(here)h(indicate)g(that)f
+(the)g(time)h(b)q(et)o(w)o(een)f(unmoun)o(t)g(attempts)f(should)j(b)q(e)f
+(increased.)0 554 y Fi(6.3.7)30 b Fe(Amq)16 b Fi(-u)g(option)62
+645 y Fo(The)f(\\-u")g(option)g(causes)h(the)f(time-to-liv)o(e)h(in)o(terv)m
+(al)g(of)e(the)h(named)h(moun)o(t)e(p)q(oin)o(ts)h(to)g(b)q(e)g(expired,)h
+(th)o(us)0 695 y(causing)f(an)e(unmoun)o(t)h(attempt.)19 b(This)14
+b(is)g(the)g(only)h(safe)e(w)o(a)o(y)g(to)g(unmoun)o(t)h(an)g(automoun)o(ted)
+f(\014lesystem.)20 b(It)0 745 y(is)c(not)f(p)q(ossible)h(to)f(unmoun)o(t)g(a)
+g(\014lesystem)h(whic)o(h)g(has)f(b)q(een)h(moun)o(ted)f(with)h(the)f(`)p
+Fl(nounmount)p Fo(')e(\015ag.)0 899 y Fi(6.3.8)30 b Fe(Amq)16
+b Fi(-v)g(option)62 990 y Fo(The)g(\\-v")e(option)i(displa)o(ys)g(the)f(v)o
+(ersion)h(of)f Fp(Amd)i Fo(in)f(a)f(similar)h(w)o(a)o(y)e(to)h
+Fp(Amd)r Fo('s)f(\\-v")h(option.)0 1145 y Fi(6.3.9)30 b(Other)15
+b Fe(Amq)h Fi(options)62 1236 y Fo(Three)j(other)g(op)q(erations)f(are)h
+(implemen)o(ted.)32 b(These)19 b(mo)q(dify)g(the)g(state)f(of)g
+Fp(Amd)j Fo(as)d(a)h(whole,)h(rather)0 1286 y(than)e(an)o(y)g(particular)h
+(\014lesystem.)30 b(The)19 b(\\-l",)g(\\-x")f(and)h(\\-D")e(options)i(ha)o(v)
+o(e)f(exactly)h(the)f(same)g(e\013ect)g(as)0 1336 y Fp(Amd)r
+Fo('s)g(corresp)q(onding)h(command)g(line)h(options.)30 b(The)18
+b(\\-l")h(option)g(is)g(rejected)f(b)o(y)h Fp(Amd)h Fo(in)g(the)e(curren)o(t)
+0 1385 y(v)o(ersion)e(for)e(ob)o(vious)i(securit)o(y)g(reasons.)j(When)d
+Fp(Amd)h Fo(receiv)o(es)g(a)e(\\-x"\015ag)f(it)i(limits)g(the)g(log)f
+(options)h(b)q(eing)0 1435 y(mo)q(di\014ed)g(to)e(those)h(whic)o(h)g(w)o(ere)
+g(not)f(enabled)j(at)d(startup.)19 b(This)c(prev)o(en)o(ts)g(a)f(user)h
+(turning)g Fp(o\013)23 b Fo(an)o(y)15 b(logging)0 1485 y(option)h(whic)o(h)h
+(w)o(as)f(sp)q(eci\014ed)i(at)d(startup,)h(though)g(an)o(y)g(whic)o(h)h(ha)o
+(v)o(e)e(b)q(een)j(turned)e(o\013)f(since)j(then)e(can)h(still)0
+1535 y(b)q(e)f(turned)f(o\013.)20 b(The)15 b(\\-D")f(option)i(has)f(a)g
+(similar)h(b)q(eha)o(viour.)0 1737 y Fm(7)41 b(FSinfo)0 1964
+y Fq(7.1)33 b Ff(FSinfo)16 b Fq(o)n(v)n(erview)62 2056 y Fp(FSinfo)h
+Fo(is)d(a)f(\014lesystem)h(managemen)o(t)f(to)q(ol.)19 b(It)14
+b(has)g(b)q(een)g(designed)h(to)e(w)o(ork)g(with)h Fp(Amd)i
+Fo(to)c(help)j(system)0 2105 y(administrators)g(k)o(eep)g(trac)o(k)g(of)f
+(the)i(ev)o(er)f(increasing)h(\014lesystem)g(namespace)g(under)g(their)f(con)
+o(trol.)62 2176 y(The)20 b(purp)q(ose)g(of)f Fp(FSinfo)j Fo(is)e(to)e
+(generate)h(all)i(the)e(imp)q(ortan)o(t)g(standard)g(\014lesystem)h(data)e
+(\014les)j(from)d(a)0 2226 y(single)g(set)e(of)g(input)h(data.)23
+b(Starting)16 b(with)h(a)f(single)h(data)f(source)h(guaran)o(tees)e(that)h
+(all)h(the)g(generated)f(\014les)0 2276 y(are)i(self-consisten)o(t.)28
+b(One)19 b(of)e(the)h(p)q(ossible)i(output)e(data)f(formats)f(is)j(a)e(set)h
+(of)f Fp(Amd)j Fo(maps)e(whic)o(h)g(can)g(b)q(e)0 2325 y(used)e(amongst)e
+(the)h(set)g(of)g(hosts)g(describ)q(ed)i(in)f(the)f(input)h(data.)62
+2396 y Fp(FSinfo)i Fo(implemen)o(ts)f(a)e(declarativ)o(e)h(language.)k(This)c
+(language)g(is)g(sp)q(eci\014cally)i(designed)e(for)f(describing)0
+2446 y(\014lesystem)21 b(namespace)g(and)f(ph)o(ysical)i(la)o(y)o(outs.)34
+b(The)21 b(basic)g(declaration)g(de\014nes)g(a)f(moun)o(ted)g(\014lesystem)0
+2496 y(including)e(its)e(device)h(name,)e(moun)o(t)g(p)q(oin)o(t,)g(and)h
+(all)g(the)g(v)o(olumes)g(and)f(access)h(p)q(ermissions.)22
+b Fp(FSinfo)c Fo(reads)0 2545 y(this)e(information)g(and)f(builds)j(an)d(in)o
+(ternal)h(map)f(of)h(the)f(en)o(tire)h(net)o(w)o(ork)e(of)h(hosts.)21
+b(Using)16 b(this)f(map,)g(man)o(y)0 2595 y(di\013eren)o(t)d(data)g(formats)f
+(can)h(b)q(e)h(pro)q(duced)h(including)h(`)p Fl(/etc/fstab)p
+Fo(',)10 b(`)p Fl(/etc/exports)p Fo(',)g Fp(Amd)k Fo(moun)o(t)e(maps)0
+2645 y(and)j(`)p Fl(/etc/bootparams)p Fo('.)p eop
+%%Page: 32 34
+32 33 bop 15 -83 a Fo(SMM:13-32)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fq(7.2)33 b(Using)15 b Ff(FSinfo)62
+250 y Fo(The)20 b(basic)h(strategy)d(when)i(using)h Fp(FSinfo)h
+Fo(is)e(to)f(gather)g(all)i(the)f(information)g(ab)q(out)f(all)i(disks)f(on)g
+(all)0 299 y(mac)o(hines)i(in)o(to)e(one)h(set)g(of)g(declarations.)37
+b(F)l(or)20 b(eac)o(h)h(mac)o(hine)h(b)q(eing)g(managed,)g(the)f(follo)o
+(wing)g(data)f(is)0 349 y(required:)37 420 y Fn(\017)30 b Fo(Hostname)37
+482 y Fn(\017)g Fo(List)16 b(of)f(all)h(\014lesystems)f(and,)g(optionally)l
+(,)i(their)e(moun)o(t)g(p)q(oin)o(ts.)37 544 y Fn(\017)30 b
+Fo(Names)15 b(of)g(v)o(olumes)g(stored)g(on)g(eac)o(h)g(\014lesystem.)37
+606 y Fn(\017)30 b Fo(NFS)15 b(exp)q(ort)g(information)h(for)e(eac)o(h)h(v)o
+(olume.)37 668 y Fn(\017)30 b Fo(The)15 b(list)h(of)f(static)g(\014lesystem)h
+(moun)o(ts.)62 759 y(The)g(follo)o(wing)g(information)f(can)h(also)f(b)q(e)h
+(en)o(tered)g(in)o(to)f(the)h(same)f(con\014guration)g(\014les)i(so)e(that)f
+(all)j(data)0 809 y(can)e(b)q(e)h(k)o(ept)f(in)h(one)g(place.)37
+879 y Fn(\017)30 b Fo(List)16 b(of)f(net)o(w)o(ork)f(in)o(terfaces)37
+941 y Fn(\017)30 b Fo(IP)16 b(address)f(of)g(eac)o(h)g(in)o(terface)37
+1003 y Fn(\017)30 b Fo(Hardw)o(are)14 b(address)i(of)e(eac)o(h)i(in)o
+(terface)37 1065 y Fn(\017)30 b Fo(Dumpset)15 b(to)g(whic)o(h)h(eac)o(h)f
+(\014lesystem)h(b)q(elongs)37 1127 y Fn(\017)30 b Fo(and)15
+b(more)g Fj(:)8 b(:)g(:)62 1218 y Fo(T)l(o)13 b(generate)f
+Fp(Amd)j Fo(moun)o(t)d(maps,)g(the)h(automoun)o(t)f(tree)g(m)o(ust)g(also)h
+(b)q(e)g(de\014ned)h(\(see)f(Section)g(7.8)f([FSinfo)0 1268
+y(automoun)o(t)k(de\014nitions],)j(page)34 b(SMM:13-39\).)23
+b(This)18 b(will)h(ha)o(v)o(e)d(b)q(een)j(designed)f(at)f(the)g(time)g(the)h
+(v)o(olume)0 1318 y(names)f(w)o(ere)f(allo)q(cated.)26 b(Some)17
+b(v)o(olume)g(names)f(will)j(not)d(b)q(e)i(automoun)o(ted,)e(so)g
+Fp(FSinfo)k Fo(needs)d(an)g(explicit)0 1368 y(list)f(of)f(whic)o(h)h(v)o
+(olumes)f(should)i(b)q(e)e(automoun)o(ted.)62 1438 y(Hostnames)k(are)f
+(required)j(at)d(sev)o(eral)h(places)h(in)g(the)f Fp(FSinfo)j
+Fo(language.)32 b(It)19 b(is)g(imp)q(ortan)o(t)g(to)f(stic)o(k)i(to)0
+1488 y(either)15 b(fully)h(quali\014ed)g(names)e(or)g(unquali\014ed)j(names.)
+i(Using)c(a)f(mixture)h(of)f(the)g(t)o(w)o(o)f(will)j(inevitably)h(result)0
+1538 y(in)f(confusion.)62 1609 y(Sometimes)c(v)o(olumes)f(need)h(to)e(b)q(e)i
+(referenced)g(whic)o(h)g(are)e(not)h(de\014ned)h(in)g(the)f(set)g(of)f(hosts)
+h(b)q(eing)h(managed)0 1658 y(with)19 b Fp(FSinfo)p Fo(.)31
+b(The)18 b(required)i(action)f(is)g(to)f(add)h(a)f(dumm)o(y)h(set)f(of)g
+(de\014nitions)j(for)d(the)h(host)f(and)h(v)o(olume)0 1708
+y(names)d(required.)24 b(Since)17 b(the)g(\014les)g(generated)f(for)f(those)h
+(particular)h(hosts)f(will)i(not)d(b)q(e)i(used)g(on)f(them,)g(the)0
+1758 y(exact)f(v)m(alues)h(used)g(is)g(not)f(critical.)0 1914
+y Fq(7.3)33 b Ff(FSinfo)16 b Fq(grammar)62 2006 y Fp(FSinfo)24
+b Fo(has)d(a)g(relativ)o(ely)i(simple)g(grammar.)36 b(Distinct)22
+b(syn)o(tactic)f(constructs)g(exist)h(for)f(eac)o(h)g(of)g(the)0
+2056 y(di\013eren)o(t)c(t)o(yp)q(es)f(of)g(data,)g(though)g(they)h(share)f(a)
+g(common)g(\015a)o(v)o(our.)23 b(Sev)o(eral)17 b(con)o(v)o(en)o(tions)f(are)h
+(used)g(in)g(the)0 2105 y(grammar)d(fragmen)o(ts)g(b)q(elo)o(w.)62
+2176 y(The)g(notation,)f Fp(list\()t Fl(xxx)p Fp(\))p Fo(,)g(indicates)i(a)e
+(list)h(of)f(zero)h(or)e(more)h Fl(xxx)p Fo('s.)19 b(The)13
+b(notation,)g Fp(opt\()t Fl(xxx)p Fp(\))p Fo(,)g(indicates)0
+2226 y(zero)22 b(or)g(one)g Fl(xxx)p Fo(.)41 b(Items)23 b(in)g(double)g
+(quotes,)h Fp(eg)i Fl("host")p Fo(,)d(represen)o(t)f(input)h(tok)o(ens.)41
+b(Items)22 b(in)h(angle)0 2276 y(brac)o(k)o(ets,)d Fp(eg)j
+Fl(<)p Fp(hostname)p Fl(>)p Fo(,)d(represen)o(t)g(strings)g(in)g(the)g
+(input.)35 b(Strings)20 b(need)g(not)g(b)q(e)g(in)h(double)g(quotes,)0
+2325 y(except)d(to)e(di\013eren)o(tiate)i(them)f(from)f(reserv)o(ed)i(w)o
+(ords.)25 b(Quoted)17 b(strings)g(ma)o(y)g(include)i(the)f(usual)f(set)g(of)g
+(C)0 2375 y(\\)p Fl(\\)p Fo(")12 b(escap)q(e)h(sequences)g(with)f(one)h
+(exception:)19 b(a)12 b(bac)o(kslash-newline-whi)q(tespace)j(sequence)e(is)g
+(squashed)g(in)o(to)0 2425 y(a)i(single)i(space)g(c)o(haracter.)j(T)l(o)c
+(defeat)f(this)i(feature,)e(put)h(a)f(further)h(bac)o(kslash)g(at)f(the)h
+(start)e(of)i(the)f(second)0 2475 y(line.)62 2545 y(A)o(t)f(the)h(outermost)e
+(lev)o(el)j(of)e(the)g(grammar,)f(the)i(input)g(consists)g(of)f(a)g(sequence)
+h(of)f(host)g(and)h(automoun)o(t)0 2595 y(declarations.)34
+b(These)20 b(declarations)h(are)e(all)i(parsed)f(b)q(efore)g(they)g(are)f
+(analyzed.)35 b(This)20 b(means)g(they)g(can)0 2645 y(app)q(ear)15
+b(in)h(an)o(y)f(order)g(and)h(cyclic)h(host)d(references)i(are)f(p)q
+(ossible.)p eop
+%%Page: 33 35
+33 34 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-33)120
+158 y Fl(fsinfo)142 b(:)24 b Fp(list\()t Fl(fsinfo_attr)p Fp(\))g
+Fl(;)120 258 y(fsinfo_attr)e(:)i(host)f(|)h(automount)f(;)0
+460 y Fq(7.4)33 b Ff(FSinfo)16 b Fq(host)f(de\014nitions)62
+552 y Fo(A)h(host)g(declaration)g(consists)g(of)g(three)g(parts:)k(a)c(set)f
+(of)h(mac)o(hine)g(attribute)g(data,)f(a)g(list)i(of)e(\014lesystems)0
+601 y(ph)o(ysically)i(attac)o(hed)e(to)f(the)i(mac)o(hine,)f(and)h(a)e(list)i
+(of)f(additional)i(statically)f(moun)o(ted)f(\014lesystems.)120
+672 y Fl(host)190 b(:)24 b("host")f(host_data)g Fp(list\()t
+Fl(filesystem)p Fp(\))h(list\()t Fl(mount)p Fp(\))g Fl(;)62
+763 y Fo(Eac)o(h)15 b(host)f(m)o(ust)g(b)q(e)i(declared)g(in)f(this)h(w)o(a)o
+(y)d(exactly)i(once.)20 b(Suc)o(h)c(things)f(as)f(the)h(hardw)o(are)f
+(address,)h(the)0 813 y(arc)o(hitecture)e(and)f(op)q(erating)h(system)f(t)o
+(yp)q(es)h(and)f(the)h(cluster)g(name)g(are)f(all)h(sp)q(eci\014ed)i(within)e
+(the)g Fp(host)f(data)p Fo(.)62 884 y(All)h(the)e(disks)h(the)f(mac)o(hine)h
+(has)f(should)h(then)g(b)q(e)f(describ)q(ed)j(in)e(the)f Fp(list)h(of)e
+(\014lesystems)p Fo(.)20 b(When)11 b(describing)0 933 y(disks,)17
+b(y)o(ou)f(can)h(sp)q(ecify)h(what)e Fp(v)o(olname)j Fo(the)e(disk/partition)
+g(should)h(ha)o(v)o(e)e(and)h(all)g(suc)o(h)g(en)o(tries)g(are)g(built)0
+983 y(up)f(in)o(to)f(a)g(dictionary)h(whic)o(h)g(can)f(then)h(b)q(e)g(used)f
+(for)g(building)j(the)d(automoun)o(ter)f(maps.)62 1054 y(The)f
+Fp(list)g(of)e(moun)o(ts)j Fo(sp)q(eci\014es)g(all)f(the)f(\014lesystems)h
+(that)e(should)i(b)q(e)g(statically)g(moun)o(ted)f(on)g(the)g(mac)o(hine.)0
+1263 y Fq(7.5)33 b Ff(FSinfo)16 b Fq(host)f(attributes)62 1354
+y Fo(The)20 b(host)g(data,)f Fp(host)p 472 1354 14 2 v 16 w(data)p
+Fo(,)h(alw)o(a)o(ys)f(includes)j(the)e Fp(hostname)p Fo(.)33
+b(In)20 b(addition,)i(sev)o(eral)e(other)f(host)g(at-)0 1404
+y(tributes)d(can)f(b)q(e)h(giv)o(en.)120 1474 y Fl(host_data)70
+b(:)24 b(<)p Fp(hostname)p Fl(>)406 1524 y(|)g("{")g Fp(list\()t
+Fl(host_attrs)p Fp(\))f Fl("}")h(<)p Fp(hostname)p Fl(>)406
+1574 y(;)120 1674 y(host_attrs)46 b(:)24 b(host_attr)f("=")g(<)p
+Fp(string)p Fl(>)406 1724 y(|)h(netif)406 1773 y(;)120 1873
+y(host_attr)70 b(:)24 b("config")406 1923 y(|)g("arch")406
+1973 y(|)g("os")406 2022 y(|)g("cluster")406 2072 y(;)62 2164
+y Fo(The)16 b Fp(hostname)h Fo(is,)e(t)o(ypically)l(,)i(the)e(fully)i
+(quali\014ed)g(hostname)e(of)f(the)i(mac)o(hine.)62 2234 y(Examples:)120
+2305 y Fl(host)23 b(dylan.doc.ic.ac.uk)120 2404 y(host)g({)215
+2454 y(os)h(=)g(hpux)215 2504 y(arch)g(=)f(hp300)120 2554 y(})h
+(dougal.doc.ic.ac.uk)62 2645 y Fo(The)16 b(options)f(that)g(can)g(b)q(e)h
+(giv)o(en)f(as)g(host)g(attributes)g(are)g(sho)o(wn)g(b)q(elo)o(w.)p
+eop
+%%Page: 34 36
+34 35 bop 15 -83 a Fo(SMM:13-34)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fi(7.5.1)30 b(netif)15 b(Option)62
+250 y Fo(This)j(de\014nes)g(the)f(set)g(of)g(net)o(w)o(ork)f(in)o(terfaces)h
+(con\014gured)h(on)f(the)g(mac)o(hine.)26 b(The)18 b(in)o(terface)f
+(attributes)0 299 y(collected)k(b)o(y)e Fp(FSinfo)j Fo(are)d(the)g(IP)g
+(address,)h(subnet)g(mask)e(and)i(hardw)o(are)e(address.)32
+b(Multiple)21 b(in)o(terfaces)0 349 y(ma)o(y)c(b)q(e)h(de\014ned)h(for)d
+(hosts)h(with)h(sev)o(eral)g(in)o(terfaces)f(b)o(y)h(an)f(en)o(try)g(for)g
+(eac)o(h)g(in)o(terface.)27 b(The)18 b(v)m(alues)g(giv)o(en)0
+399 y(are)d(sanit)o(y)g(c)o(hec)o(k)o(ed,)g(but)h(are)e(curren)o(tly)i(un)o
+(used)g(for)f(an)o(ything)g(else.)120 470 y Fl(netif)166 b(:)24
+b("netif")f(<)p Fp(string)p Fl(>)h("{")f Fp(list\()t Fl(netif_attrs)p
+Fp(\))h Fl("}")f(;)120 569 y(netif_attrs)f(:)i(netif_attr)f("=")g(<)p
+Fp(string)p Fl(>)h(;)120 669 y(netif_attr)46 b(:)24 b("inaddr")f(|)h
+("netmask")e(|)i("hwaddr")f(;)62 760 y Fo(Examples:)120 831
+y Fl(netif)g(ie0)h({)215 881 y(inaddr)47 b(=)24 b(129.31.81.37)215
+930 y(netmask)f(=)h(0xfffffe00)215 980 y(hwaddr)47 b(=)24 b
+("08:00:20:01:a6:a5")120 1030 y(})120 1130 y(netif)f(ec0)h({)f(})0
+1292 y Fi(7.5.2)30 b(con\014g)15 b(Option)62 1383 y Fo(This)g(option)e(allo)o
+(ws)h(y)o(ou)g(to)f(sp)q(ecify)i(con\014guration)e(v)m(ariables)i(for)e(the)h
+(startup)f(scripts)h(\(`)p Fl(rc)p Fo(')e(scripts\).)20 b(A)0
+1433 y(simple)d(string)e(should)h(immediately)h(follo)o(w)e(the)g(k)o(eyw)o
+(ord.)62 1503 y(Example:)120 1574 y Fl(config)23 b("NFS_SERVER=true")120
+1624 y(config)g("ZEPHYR=true")62 1715 y Fo(This)16 b(option)f(is)h(curren)o
+(tly)g(unsupp)q(orted.)0 1877 y Fi(7.5.3)30 b(arc)n(h)16 b(Option)62
+1968 y Fo(This)g(de\014nes)g(the)g(arc)o(hitecture)f(of)g(the)g(mac)o(hine.)
+21 b(F)l(or)14 b(example:)120 2039 y Fl(arch)23 b(=)h(hp300)62
+2130 y Fo(This)12 b(is)g(in)o(tended)h(to)e(b)q(e)h(of)f(use)h(when)g
+(building)i(arc)o(hitecture)e(sp)q(eci\014c)h(moun)o(tmaps,)e(ho)o(w)o(ev)o
+(er,)g(the)h(option)0 2180 y(is)k(curren)o(tly)f(unsupp)q(orted.)0
+2342 y Fi(7.5.4)30 b(os)15 b(Option)62 2433 y Fo(This)h(de\014nes)g(the)g(op)
+q(erating)f(system)g(t)o(yp)q(e)g(of)g(the)g(host.)k(F)l(or)c(example:)120
+2504 y Fl(os)24 b(=)f(hpux)62 2595 y Fo(This)16 b(information)g(is)g(used)g
+(when)g(creating)g(the)g(`)p Fl(fstab)p Fo(')e(\014les,)i(for)f(example)i(in)
+f(c)o(ho)q(osing)g(whic)o(h)g(format)0 2645 y(to)f(use)g(for)g(the)g(`)p
+Fl(fstab)p Fo(')f(en)o(tries)h(within)i(the)e(\014le.)p eop
+%%Page: 35 37
+35 36 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-35)0
+158 y Fi(7.5.5)30 b(cluster)16 b(Option)62 250 y Fo(This)g(is)g(used)g(for)e
+(sp)q(ecifying)j(in)f(whic)o(h)g(cluster)g(the)f(mac)o(hine)h(b)q(elongs.)21
+b(F)l(or)15 b(example:)120 320 y Fl(cluster)23 b(=)h("theory")62
+412 y Fo(The)13 b(cluster)f(is)h(in)o(tended)g(to)e(b)q(e)i(used)g(when)f
+(generating)g(the)h(automoun)o(t)d(maps,)i(although)h(it)f(is)g(curren)o(tly)
+0 461 y(unsupp)q(orted.)0 657 y Fq(7.6)33 b Ff(FSinfo)16 b
+Fq(\014lesystems)62 748 y Fo(The)h(list)g(of)f(ph)o(ysically)j(attac)o(hed)d
+(\014lesystems)h(follo)o(ws)f(the)h(mac)o(hine)g(attributes.)24
+b(These)16 b(should)i(de\014ne)0 798 y(all)e(the)f(\014lesystems)h(a)o(v)m
+(ailable)g(from)f(this)g(mac)o(hine,)h(whether)f(exp)q(orted)g(or)g(not.)k
+(In)d(addition)g(to)e(the)i(device)0 848 y(name,)g(\014lesystems)g(ha)o(v)o
+(e)f(sev)o(eral)h(attributes,)f(suc)o(h)i(as)e(\014lesystem)h(t)o(yp)q(e,)g
+(moun)o(t)f(options,)h(and)g(`)p Fl(fsck)p Fo(')e(pass)0 897
+y(n)o(um)o(b)q(er)i(whic)o(h)g(are)e(needed)j(to)e(generate)f(`)p
+Fl(fstab)p Fo(')g(en)o(tries.)120 968 y Fl(filesystem)46 b(:)24
+b("fs")f(<)p Fp(device)p Fl(>)i("{")f Fp(list\()t Fl(fs_data)p
+Fp(\))g Fl("}")g(;)120 1068 y(fs_data)118 b(:)24 b(fs_data_attr)e("=")i(<)p
+Fp(string)p Fl(>)406 1117 y(|)g(mount)406 1167 y(;)120 1267
+y(fs_data_attr)406 1317 y(:)g("fstype")f(|)h("opts")f(|)g("passno")406
+1367 y(|)h("freq")f(|)h("dumpset")e(|)i("log")406 1416 y(;)62
+1508 y Fo(Here,)15 b Fl(<)p Fp(device)p Fl(>)h Fo(is)g(the)f(device)h(name)f
+(of)g(the)g(disk)h(\(for)e(example,)h(`)p Fl(/dev/dsk/2s0)p
+Fo('\).)i(The)f(device)g(name)0 1558 y(is)g(used)h(for)e(building)j(the)e
+(moun)o(t)g(maps)f(and)h(for)f(the)h(`)p Fl(fstab)p Fo(')f(\014le.)23
+b(The)16 b(attributes)f(that)g(can)h(b)q(e)h(sp)q(eci\014ed)0
+1607 y(are)e(sho)o(wn)g(in)h(the)f(follo)o(wing)h(section.)62
+1678 y(The)g Fp(FSinfo)i Fo(con\014guration)d(\014le)h(for)f
+Fl(dylan.doc.ic.ac.uk)d Fo(is)k(listed)h(b)q(elo)o(w.)120 1748
+y Fl(host)23 b(dylan.doc.ic.ac.uk)120 1848 y(fs)h(/dev/dsk/0s0)e({)120
+1898 y(fstype)h(=)h(swap)120 1948 y(})120 2047 y(fs)g(/dev/dsk/0s0)e({)120
+2097 y(fstype)h(=)h(hfs)120 2147 y(opts)f(=)h(rw,noquota,grpid)120
+2197 y(passno)f(=)h(0;)120 2247 y(freq)f(=)h(1;)120 2296 y(mount)f(/)h({)g(})
+120 2346 y(})120 2446 y(fs)g(/dev/dsk/1s0)e({)120 2496 y(fstype)h(=)h(hfs)120
+2545 y(opts)f(=)h(defaults)120 2595 y(passno)f(=)h(1;)120 2645
+y(freq)f(=)h(1;)p eop
+%%Page: 36 38
+36 37 bop 15 -83 a Fo(SMM:13-36)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)120 158 y Fl(mount)23 b(/usr)g({)120
+208 y(local)g({)120 258 y(exportfs)g("dougal)g(eden)g(dylan)g(zebedee)g
+(brian")120 308 y(volname)g(/nfs/hp300/local)120 358 y(})120
+407 y(})120 457 y(})120 557 y(fs)h(/dev/dsk/2s0)e({)120 607
+y(fstype)h(=)h(hfs)120 656 y(opts)f(=)h(defaults)120 706 y(passno)f(=)h(1;)
+120 756 y(freq)f(=)h(1;)120 806 y(mount)f(default)g({)120 856
+y(exportfs)g("toytown_clients)e(hangers_on")120 906 y(volname)i
+(/home/dylan/dk2)120 955 y(})120 1005 y(})120 1105 y(fs)h(/dev/dsk/3s0)e({)
+120 1155 y(fstype)h(=)h(hfs)120 1204 y(opts)f(=)h(defaults)120
+1254 y(passno)f(=)h(1;)120 1304 y(freq)f(=)h(1;)120 1354 y(mount)f(default)g
+({)120 1404 y(exportfs)g("toytown_clients)e(hangers_on")120
+1453 y(volname)i(/home/dylan/dk3)120 1503 y(})120 1553 y(})120
+1653 y(fs)h(/dev/dsk/5s0)e({)120 1703 y(fstype)h(=)h(hfs)120
+1752 y(opts)f(=)h(defaults)120 1802 y(passno)f(=)h(1;)120 1852
+y(freq)f(=)h(1;)120 1902 y(mount)f(default)g({)120 1952 y(exportfs)g
+("toytown_clients)e(hangers_on")120 2001 y(volname)i(/home/dylan/dk5)120
+2051 y(})120 2101 y(})0 2234 y Fi(7.6.1)30 b(fst)n(yp)r(e)15
+b(Option)62 2325 y Fo(This)g(sp)q(eci\014es)h(the)f(t)o(yp)q(e)f(of)g
+(\014lesystem)h(b)q(eing)h(declared)f(and)g(will)h(b)q(e)e(placed)i(in)o(to)e
+(the)h(`)p Fl(fstab)p Fo(')e(\014le)i(as)f(is.)0 2375 y(The)g(v)m(alue)g(of)f
+(this)h(option)f(will)i(b)q(e)f(handed)g(to)f Fl(mount)g Fo(as)f(the)i
+(\014lesystem)g(t)o(yp)q(e|it)g(should)g(ha)o(v)o(e)f(suc)o(h)h(v)m(alues)0
+2425 y(as)h Fl(4.2)p Fo(,)f Fl(nfs)h Fo(or)g Fl(swap)p Fo(.)k(The)c(v)m(alue)
+i(is)e(not)g(examined)i(for)d(correctness.)62 2496 y(There)21
+b(is)g(one)f(sp)q(ecial)i(case.)35 b(If)21 b(the)f(\014lesystem)h(t)o(yp)q(e)
+f(is)h(sp)q(eci\014ed)i(as)d(`)p Fl(export)p Fo(')e(then)j(the)f
+(\014lesystem)0 2545 y(information)d(will)h(not)f(b)q(e)g(added)h(to)e(the)h
+(host's)f(`)p Fl(fstab)p Fo(')f(information,)i(but)g(it)g(will)h(still)h(b)q
+(e)e(visible)i(on)e(the)0 2595 y(net)o(w)o(ork.)h(This)13 b(is)f(useful)h
+(for)f(de\014ning)i(hosts)d(whic)o(h)i(con)o(tain)g(referenced)g(v)o(olumes)f
+(but)h(whic)o(h)g(are)e(not)h(under)0 2645 y(full)17 b(con)o(trol)d(of)h
+Fp(FSinfo)p Fo(.)p eop
+%%Page: 37 39
+37 38 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-37)62
+158 y(Example:)120 229 y Fl(fstype)23 b(=)h(swap)0 378 y Fi(7.6.2)30
+b(opts)15 b(Option)62 470 y Fo(This)h(de\014nes)g(an)o(y)f(options)g(that)g
+(should)h(b)q(e)g(giv)o(en)g(to)e Fk(moun)o(t)p Fo(\(8\))g(in)i(the)f(`)p
+Fl(fstab)p Fo(')f(\014le.)21 b(F)l(or)15 b(example:)120 540
+y Fl(opts)23 b(=)h(rw,nosuid,grpid)0 690 y Fi(7.6.3)30 b(passno)15
+b(Option)62 781 y Fo(This)g(de\014nes)g(the)f Fk(fsc)o(k)p
+Fo(\(8\))f(pass)h(n)o(um)o(b)q(er)g(in)h(whic)o(h)g(to)f(c)o(hec)o(k)g(the)g
+(\014lesystem.)20 b(This)15 b(v)m(alue)g(will)h(b)q(e)f(placed)0
+831 y(in)o(to)g(the)g(`)p Fl(fstab)p Fo(')f(\014le.)62 902
+y(Example:)120 972 y Fl(passno)23 b(=)h(1)0 1122 y Fi(7.6.4)30
+b(freq)15 b(Option)62 1213 y Fo(This)k(de\014nes)f(the)g(in)o(terv)m(al)h
+(\(in)f(da)o(ys\))f(b)q(et)o(w)o(een)h(dumps.)28 b(The)18 b(v)m(alue)h(is)f
+(placed)h(as)f(is)g(in)o(to)g(the)f(`)p Fl(fstab)p Fo(')0 1263
+y(\014le.)62 1333 y(Example:)120 1404 y Fl(freq)23 b(=)h(3)0
+1553 y Fi(7.6.5)30 b(moun)n(t)15 b(Option)62 1645 y Fo(This)e(de\014nes)g
+(the)f(moun)o(tp)q(oin)o(t)g(at)f(whic)o(h)i(to)f(place)h(the)f
+(\014lesystem.)19 b(If)12 b(the)h(moun)o(tp)q(oin)o(t)f(of)f(the)h
+(\014lesystem)0 1694 y(is)19 b(sp)q(eci\014ed)h(as)e Fl(default)p
+Fo(,)f(then)i(the)f(\014lesystem)h(will)g(b)q(e)g(moun)o(ted)f(in)h(the)f
+(automoun)o(ter's)f(tree)h(under)h(its)0 1744 y(v)o(olume)d(name)f(and)g(the)
+g(moun)o(t)g(will)i(automatically)f(b)q(e)f(inherited)j(b)o(y)d(the)g
+(automoun)o(ter.)62 1815 y(F)l(ollo)o(wing)21 b(the)e(moun)o(tp)q(oin)o(t,)i
+(namespace)f(information)f(for)g(the)h(\014lesystem)g(ma)o(y)f(b)q(e)i
+(describ)q(ed.)35 b(The)0 1865 y(options)15 b(that)g(can)g(b)q(e)h(giv)o(en)g
+(here)f(are)g Fl(exportfs)p Fo(,)f Fl(volname)g Fo(and)h Fl(sel)p
+Fo(.)62 1935 y(The)h(format)e(is:)120 2006 y Fl(mount)166 b(:)24
+b("mount")f(vol_tree)g(;)120 2105 y(vol_tree)94 b(:)24 b Fp(list\()t
+Fl(vol_tree_attr)p Fp(\))f Fl(;)120 2205 y(vol_tree_attr)406
+2255 y(:)48 b(<)p Fp(string)p Fl(>)24 b("{")f Fp(list\()t Fl(vol_tree_info)p
+Fp(\))g Fl(vol_tree)g("}")h(;)120 2355 y(vol_tree_info)406
+2404 y(:)g("exportfs")f(<)p Fp(exp)q(ort-data)p Fl(>)406 2454
+y(|)h("volname")f(<)p Fp(v)o(olname)p Fl(>)406 2504 y(|)h("sel")f(<)p
+Fp(selector-list)p Fl(>)406 2554 y(;)62 2645 y Fo(Example:)p
+eop
+%%Page: 38 40
+38 39 bop 15 -83 a Fo(SMM:13-38)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)120 158 y Fl(mount)23 b(default)g({)215
+208 y(exportfs)g("dylan)g(dougal)g(florence)g(zebedee")215
+258 y(volname)g(/vol/andrew)120 308 y(})62 399 y Fo(In)15 b(the)f(ab)q(o)o(v)
+o(e)f(example,)i(the)f(\014lesystem)g(curren)o(tly)h(b)q(eing)g(declared)g
+(will)g(ha)o(v)o(e)f(an)f(en)o(try)h(placed)h(in)o(to)f(the)0
+449 y(`)p Fl(exports)p Fo(')d(\014le)j(allo)o(wing)g(the)f(\014lesystem)h(to)
+e(b)q(e)i(exp)q(orted)f(to)g(the)g(mac)o(hines)g Fl(dylan)p
+Fo(,)g Fl(dougal)p Fo(,)f Fl(florence)g Fo(and)0 499 y Fl(zebedee)p
+Fo(.)18 b(The)d(v)o(olume)f(name)g(b)o(y)g(whic)o(h)h(the)f(\014lesystem)g
+(will)i(b)q(e)f(referred)f(to)f(remotely)l(,)h(is)h(`)p Fl(/vol/andrew)p
+Fo('.)0 549 y(By)h(declaring)i(the)e(moun)o(tp)q(oin)o(t)g(to)f(b)q(e)i
+Fl(default)p Fo(,)e(the)h(\014lesystem)h(will)g(b)q(e)g(moun)o(ted)f(on)g
+(the)g(lo)q(cal)h(mac)o(hine)0 598 y(in)f(the)f(automoun)o(ter)f(tree,)h
+(where)g Fp(Amd)j Fo(will)f(automatically)e(inherit)i(the)e(moun)o(t)g(as)f
+(`)p Fl(/vol/andrew)p Fo('.)0 669 y(`)p Fl(exportfs)p Fo(')240
+732 y(a)g(string)h(de\014ning)h(whic)o(h)f(mac)o(hines)g(the)g(\014lesystem)g
+(ma)o(y)f(b)q(e)h(exp)q(orted)g(to.)k(This)c(is)g(copied,)g(as)240
+781 y(is,)g(in)o(to)h(the)f(`)p Fl(exports)p Fo(')e(\014le|no)k(sanit)o(y)e
+(c)o(hec)o(king)h(is)g(p)q(erformed)f(on)g(this)h(string.)0
+844 y(`)p Fl(volname)p Fo(')46 b(a)19 b(string)h(whic)o(h)g(declares)h(the)f
+(remote)f(name)h(b)o(y)f(whic)o(h)i(to)e(reference)h(the)g(\014lesystem.)34
+b(The)240 894 y(string)18 b(is)h(en)o(tered)g(in)o(to)f(a)h(dictionary)g(and)
+g(allo)o(ws)f(y)o(ou)g(to)g(refer)g(to)g(this)h(\014lesystem)g(in)g(other)240
+944 y(places)d(b)o(y)f(this)h(v)o(olume)f(name.)0 1006 y(`)p
+Fl(sel)p Fo(')142 b(a)15 b(string)g(whic)o(h)h(is)g(placed)g(in)o(to)f(the)h
+(automoun)o(ter)e(maps)h(as)f(a)h(selector)h(for)e(the)i(\014lesystem.)0
+1150 y Fi(7.6.6)30 b(dumpset)15 b(Option)62 1242 y Fo(This)d(pro)o(vides)f
+(supp)q(ort)g(for)f(Imp)q(erial)j(College's)e(lo)q(cal)h(\014le)g(bac)o(kup)g
+(to)q(ols)e(and)h(is)h(not)e(do)q(cumen)o(ted)i(further)0 1292
+y(here.)0 1436 y Fi(7.6.7)30 b(log)14 b(Option)62 1527 y Fo(Sp)q(eci\014es)f
+(the)e(log)g(device)i(for)d(the)h(curren)o(t)g(\014lesystem.)19
+b(This)11 b(is)h(ignored)f(if)h(not)e(required)i(b)o(y)f(the)g(particular)0
+1577 y(\014lesystem)16 b(t)o(yp)q(e.)0 1744 y Fq(7.7)33 b Ff(FSinfo)16
+b Fq(static)g(moun)n(ts)62 1836 y Fo(Eac)o(h)j(host)g(ma)o(y)f(also)h(ha)o(v)
+o(e)g(a)g(n)o(um)o(b)q(er)g(of)g(statically)h(moun)o(ted)f(\014lesystems.)32
+b(F)l(or)19 b(example,)h(the)f(host)0 1885 y(ma)o(y)14 b(b)q(e)h(a)f
+(diskless)i(w)o(orkstation)e(in)h(whic)o(h)g(case)g(it)g(will)h(ha)o(v)o(e)e
+(no)h Fl(fs)f Fo(declarations.)20 b(In)15 b(this)g(case)g(the)g
+Fl(mount)0 1935 y Fo(declaration)i(is)g(used)f(to)g(determine)h(from)e(where)
+i(its)f(\014lesystems)h(will)h(b)q(e)e(moun)o(ted.)23 b(In)17
+b(addition)g(to)f(b)q(eing)0 1985 y(added)e(to)e(the)h(`)p
+Fl(fstab)p Fo(')f(\014le,)i(this)g(information)f(can)g(also)g(b)q(e)h(used)g
+(to)e(generate)h(a)g(suitable)h(`)p Fl(bootparams)p Fo(')d(\014le.)120
+2056 y Fl(mount)166 b(:)24 b("mount")f(<)p Fp(v)o(olname)p
+Fl(>)h Fp(list\()t Fl(localinfo)p Fp(\))g Fl(;)120 2155 y(localinfo)70
+b(:)24 b(localinfo_attr)e(<)p Fp(string)p Fl(>)i(;)120 2255
+y(localinfo_attr)406 2305 y(:)g("as")406 2355 y(|)g("from")406
+2404 y(|)g("fstype")406 2454 y(|)g("opts")406 2504 y(;)62 2595
+y Fo(The)17 b(\014lesystem)g(sp)q(eci\014ed)h(to)e(b)q(e)h(moun)o(ted)f(will)
+i(b)q(e)f(searc)o(hed)f(for)g(in)h(the)f(dictionary)i(of)d(v)o(olume)i(names)
+0 2645 y(built)g(when)e(scanning)h(the)g(list)g(of)e(hosts')h(de\014nitions.)
+p eop
+%%Page: 39 41
+39 40 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-39)62
+158 y(The)16 b(attributes)f(ha)o(v)o(e)f(the)i(follo)o(wing)g(seman)o(tics:)0
+229 y(`)p Fl(from)e Fp(mac)o(hine)s Fo(')240 293 y(moun)o(t)h(the)g
+(\014lesystem)h(from)e(the)i(mac)o(hine)g(with)f(the)g(hostname)g(of)g
+Fp(mac)o(hine)p Fo(.)0 356 y(`)p Fl(as)g Fp(moun)o(tp)q(oin)o(t)q
+Fo(')240 420 y(moun)o(t)e(the)h(\014lesystem)g(lo)q(cally)i(as)d(the)h(name)f
+(giv)o(en,)h(in)h(case)e(this)h(is)h(di\013eren)o(t)f(from)e(the)i(adv)o(er-)
+240 470 y(tised)i(v)o(olume)f(name)h(of)e(the)i(\014lesystem.)0
+534 y(`)p Fl(opts)e Fp(options)r Fo(')240 598 y(nativ)o(e)h
+Fk(moun)o(t)p Fo(\(8\))f(options.)0 661 y(`)p Fl(fstype)g Fp(t)o(yp)q(e)s
+Fo(')240 725 y(t)o(yp)q(e)h(of)g(\014lesystem)h(to)e(b)q(e)i(moun)o(ted.)62
+816 y(An)g(example:)120 887 y Fl(mount)23 b(/export/exec/hp300/local)e(as)i
+(/usr/local)62 978 y Fo(If)15 b(the)g(moun)o(tp)q(oin)o(t)g(sp)q(eci\014ed)i
+(is)f(either)g(`)p Fl(/)p Fo(')e(or)g(`)p Fl(swap)p Fo(',)f(the)i(mac)o(hine)
+h(will)h(b)q(e)e(considered)i(to)d(b)q(e)h(b)q(o)q(oting)0
+1028 y(o\013)f(the)h(net)f(and)h(this)g(will)i(b)q(e)e(noted)g(for)f(use)h
+(in)g(generating)g(a)g(`)p Fl(bootparams)p Fo(')d(\014le)k(for)e(the)h(host)f
+(whic)o(h)i(o)o(wns)0 1078 y(the)f(\014lesystems.)0 1254 y
+Fq(7.8)33 b(De\014ning)15 b(an)h Ff(Amd)g Fq(Moun)n(t)g(Map)f(in)h
+Ff(FSinfo)62 1346 y Fo(The)i(maps)f(used)i(b)o(y)e Fp(Amd)j
+Fo(can)d(b)q(e)i(constructed)e(from)g Fp(FSinfo)j Fo(b)o(y)e(de\014ning)h
+(all)f(the)g(automoun)o(t)f(trees.)0 1396 y Fp(FSinfo)h Fo(tak)o(es)c(all)i
+(the)g(de\014nitions)h(found)e(and)h(builds)h(one)e(map)g(for)g(eac)o(h)g
+(top)g(lev)o(el)h(tree.)62 1466 y(The)23 b(automoun)o(t)e(tree)i(is)g
+(usually)h(de\014ned)f(last.)42 b(A)23 b(single)g(automoun)o(t)f
+(con\014guration)g(will)j(usually)0 1516 y(apply)e(to)f(an)g(en)o(tire)h
+(managemen)o(t)e(domain.)41 b(One)23 b Fl(automount)e Fo(declaration)i(is)g
+(needed)h(for)d(eac)o(h)i Fp(Amd)0 1566 y Fo(automoun)o(t)11
+b(p)q(oin)o(t.)20 b Fp(FSinfo)15 b Fo(determines)f(whether)f(the)f(automoun)o
+(t)g(p)q(oin)o(t)h(is)g Fp(direct)h Fo(\(see)f(Section)g(5.9)f([Direct)0
+1616 y(Automoun)o(t)20 b(Filesystem],)i(page)41 b(SMM:13-25\))18
+b(or)j Fp(indirect)i Fo(\(see)d(Section)i(5.12)d([T)l(op-lev)o(el)j
+(Filesystem],)0 1665 y(page)e(SMM:13-26\).)c(Direct)11 b(automoun)o(t)e(p)q
+(oin)o(ts)h(are)g(distinguished)j(b)o(y)d(the)g(fact)g(that)f(there)h(is)h
+(no)f(underlying)0 1715 y Fp(automoun)o(t)p 220 1715 14 2 v
+15 w(tree)p Fo(.)120 1786 y Fl(automount)70 b(:)24 b("automount")e
+(opt\(auto_opts)p Fp(\))h Fl(automount_tree)f(;)120 1885 y(auto_opts)70
+b(:)24 b("opts")f(<)p Fp(moun)o(t-options)p Fl(>)h(;)120 1985
+y(automount_tree)406 2035 y(:)g Fp(list\()t Fl(automount_attr)p
+Fp(\))406 2085 y Fl(;)120 2184 y(automount_attr)406 2234 y(:)g(<)p
+Fp(string)p Fl(>)g("=")f(<)p Fp(v)o(olname)p Fl(>)406 2284
+y(|)h(<)p Fp(string)p Fl(>)g("->")f(<)p Fp(symlink)p Fl(>)406
+2334 y(|)h(<)p Fp(string)p Fl(>)g("{")f(automount_tree)f("}")406
+2384 y(;)62 2475 y Fo(If)15 b Fl(<)p Fp(moun)o(t-options)p
+Fl(>)e Fo(is)i(giv)o(en,)f(then)g(it)g(is)h(the)f(string)g(to)f(b)q(e)i
+(placed)g(in)g(the)f(maps)g(for)f Fp(Amd)j Fo(for)d(the)i Fl(opts)0
+2525 y Fo(option.)62 2595 y(A)d Fp(map)g Fo(is)g(t)o(ypically)h(a)e(tree)g
+(of)g(\014lesystems,)i(for)d(example)j(`)p Fl(home)p Fo(')d(normally)i(con)o
+(tains)f(a)g(tree)g(of)g(\014lesystems)0 2645 y(represen)o(ting)16
+b(other)f(mac)o(hines)h(in)g(the)f(net)o(w)o(ork.)p eop
+%%Page: 40 42
+40 41 bop 15 -83 a Fo(SMM:13-40)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)62 158 y(A)g(map)g(can)h(either)f(b)q(e)h(giv)o(en)g
+(as)f(a)f(name)h(represen)o(ting)h(an)f(already)h(de\014ned)g(v)o(olume)g
+(name,)f(or)f(it)i(can)0 208 y(b)q(e)g(a)g(tree.)27 b(A)18
+b(tree)g(is)g(represen)o(ted)g(b)o(y)g(placing)h(braces)f(after)f(the)h
+(name.)28 b(F)l(or)17 b(example,)i(to)e(de\014ne)i(a)e(tree)0
+258 y(`)p Fl(/vol)p Fo(',)c(the)j(follo)o(wing)g(map)f(w)o(ould)g(b)q(e)h
+(de\014ned:)120 329 y Fl(automount)23 b(/vol)g({)h(})62 420
+y Fo(Within)17 b(a)d(tree,)h(the)g(only)h(items)g(that)e(can)h(app)q(ear)h
+(are)f(more)f(maps.)20 b(F)l(or)15 b(example:)120 490 y Fl(automount)23
+b(/vol)g({)215 540 y(andrew)g({)h(})215 590 y(X11)g({)g(})120
+640 y(})62 731 y Fo(In)13 b(this)g(case,)g Fp(FSinfo)i Fo(will)f(lo)q(ok)e
+(for)g(v)o(olumes)h(named)f(`)p Fl(/vol/andrew)p Fo(')e(and)j(`)p
+Fl(/vol/X11)p Fo(')e(and)h(a)g(map)g(en)o(try)0 781 y(will)17
+b(b)q(e)e(generated)h(for)e(eac)o(h.)20 b(If)15 b(the)g(v)o(olumes)h(are)f
+(de\014ned)h(more)f(than)g(once,)g(then)g Fp(FSinfo)j Fo(will)e(generate)f(a)
+0 831 y(series)h(of)f(alternate)g(en)o(tries)g(for)g(them)g(in)h(the)f(maps.)
+62 901 y(Instead)j(of)g(a)f(tree,)h(either)g(a)f(link)i(\()p
+Fp(name)h Fl(->)d Fp(destination)p Fo(\))i(or)e(a)g(reference)h(can)g(b)q(e)g
+(sp)q(eci\014ed)i(\()p Fp(name)g Fl(=)0 951 y Fp(destination)p
+Fo(\).)i(A)16 b(link)h(creates)f(a)f(sym)o(b)q(olic)i(link)g(to)f(the)f
+(string)h(sp)q(eci\014ed,)i(without)e(further)f(pro)q(cessing)i(the)0
+1001 y(en)o(try)l(.)i(A)13 b(reference)h(will)h(examine)f(the)f(destination)h
+(\014lesystem)g(and)g(optimise)g(the)f(reference.)20 b(F)l(or)12
+b(example,)0 1051 y(to)j(create)g(an)g(en)o(try)f(for)h Fl(njw)g
+Fo(in)h(the)f(`)p Fl(/homes)p Fo(')f(map,)g(either)i(of)f(the)g(t)o(w)o(o)f
+(forms)h(can)g(b)q(e)h(used:)120 1121 y Fl(automount)23 b(/homes)g({)215
+1171 y(njw)h(->)f(/home/dylan/njw)120 1221 y(})62 1312 y Fo(or)120
+1383 y Fl(automount)g(/homes)g({)215 1433 y(njw)h(=)g(/home/dylan/njw)120
+1483 y(})62 1574 y Fo(In)13 b(the)e(\014rst)h(example,)g(when)h(`)p
+Fl(/homes/njw)p Fo(')c(is)j(referenced)h(from)e Fp(Amd)p Fo(,)h(a)f(link)i
+(will)h(b)q(e)e(created)g(leading)h(to)0 1624 y(`)p Fl(/home/dylan/njw)p
+Fo(')f(and)j(the)g(automoun)o(ter)e(will)j(b)q(e)g(referenced)g(a)e(second)h
+(time)g(to)f(resolv)o(e)h(this)g(\014lename.)0 1673 y(The)g(map)g(en)o(try)g
+(w)o(ould)h(b)q(e:)120 1744 y Fl(njw)23 b(type:=link;fs:=/home/dylan/nj)o(w)
+62 1835 y Fo(In)17 b(the)g(second)g(example,)g(the)f(destination)i(directory)
+e(is)h(analysed)g(and)g(found)g(to)e(b)q(e)j(in)f(the)f(\014lesystem)0
+1885 y(`)p Fl(/home/dylan)p Fo(')c(whic)o(h)j(has)g(previously)g(b)q(een)h
+(de\014ned)g(in)f(the)f(maps.)20 b(Hence)15 b(the)f(map)g(en)o(try)g(will)j
+(lo)q(ok)d(lik)o(e:)120 1956 y Fl(njw)23 b(rhost:=dylan;rfs:=/home/dylan)o
+(;sublink)o(:=njw)62 2047 y Fo(Creating)15 b(only)h(one)f(sym)o(b)q(olic)i
+(link,)f(and)f(one)h(access)f(to)g Fp(Amd)p Fo(.)0 2292 y Fq(7.9)33
+b Ff(FSinfo)16 b Fq(Command)f(Line)h(Options)62 2384 y Fp(FSinfo)i
+Fo(is)e(started)e(from)h(the)g(command)g(line)i(b)o(y)e(using)h(the)f
+(command:)120 2454 y Fl(fsinfo)23 b([)p Fp(options)r Fl(])h(files)f(...)62
+2545 y Fo(The)16 b(input)h(to)d Fp(FSinfo)19 b Fo(is)d(a)f(single)i(set)e(of)
+g(de\014nitions)i(of)e(mac)o(hines)i(and)e(automoun)o(t)g(maps.)20
+b(If)c(m)o(ultiple)0 2595 y(\014les)21 b(are)e(giv)o(en)h(on)f(the)h
+(command-line,)i(then)e(the)f(\014les)i(are)e(concatenated)h(together)f(to)f
+(form)h(the)h(input)0 2645 y(source.)g(The)15 b(\014les)i(are)d(passed)i
+(individuall)q(y)i(through)d(the)g(C)g(pre-pro)q(cessor)g(b)q(efore)h(b)q
+(eing)g(parsed.)p eop
+%%Page: 41 43
+41 42 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-41)62
+158 y(Sev)o(eral)18 b(options)f(de\014ne)i(a)e(pre\014x)h(for)e(the)i(name)f
+(of)g(an)g(output)g(\014le.)27 b(If)18 b(the)f(pre\014x)h(is)g(not)f(sp)q
+(eci\014ed)i(no)0 208 y(output)14 b(of)f(that)g(t)o(yp)q(e)h(is)g(pro)q
+(duced.)20 b(The)14 b(su\016x)g(used)g(will)i(corresp)q(ond)e(either)g(to)f
+(the)h(hostname)g(to)f(whic)o(h)h(a)0 258 y(\014le)j(b)q(elongs,)f(or)f(to)g
+(the)g(t)o(yp)q(e)h(of)f(output)g(if)h(only)g(one)g(\014le)g(is)g(pro)q
+(duced.)22 b(Dumpsets)16 b(and)g(the)f(`)p Fl(bootparams)p
+Fo(')0 308 y(\014le)h(are)e(in)h(the)g(latter)f(class.)20 b(T)l(o)14
+b(put)g(the)h(output)f(in)o(to)h(a)f(sub)q(directory)h(simply)h(put)f(a)f(`)p
+Fl(/)p Fo(')f(at)h(the)h(end)g(of)f(the)0 358 y(pre\014x,)h(making)h(sure)f
+(that)f(the)i(directory)f(has)g(already)h(b)q(een)g(made)f(b)q(efore)h
+(running)g(`)p Fl(fsinfo)p Fo('.)0 550 y Fi(7.9.1)30 b Fd(-a)15
+b Fe(auto)q(dir)62 642 y Fo(Sp)q(eci\014es)h(the)e(directory)g(name)g(in)g
+(whic)o(h)h(to)e(place)i(the)f(automoun)o(ter's)e(moun)o(tp)q(oin)o(ts.)19
+b(This)14 b(defaults)h(to)0 691 y(`)p Fl(/a)p Fo('.)k(Some)c(sites)h(ha)o(v)o
+(e)e(the)i(auto)q(dir)f(set)g(to)g(b)q(e)g(`)p Fl(/amd)p Fo(',)f(and)h(this)h
+(w)o(ould)g(b)q(e)f(ac)o(hiev)o(ed)i(b)o(y:)120 762 y Fl(fsinfo)23
+b(-a)h(/amd)f(...)0 955 y Fi(7.9.2)30 b Fd(-b)15 b Fe(b)q(o)q(otparams)62
+1046 y Fo(This)i(sp)q(eci\014es)h(the)f(pre\014x)g(for)f(the)g(`)p
+Fl(bootparams)p Fo(')e(\014lename.)25 b(If)16 b(it)h(is)g(not)f(giv)o(en,)h
+(then)f(the)h(\014le)g(will)h(not)0 1096 y(b)q(e)h(generated.)27
+b(The)18 b(`)p Fl(bootparams)p Fo(')e(\014le)j(will)h(b)q(e)e(constructed)g
+(for)f(the)h(destination)h(mac)o(hine)g(and)f(will)h(b)q(e)0
+1146 y(placed)g(in)o(to)f(a)f(\014le)i(named)f(`)p Fl(bootparams)p
+Fo(')e(and)i(pre\014xed)h(b)o(y)f(this)g(string.)28 b(The)18
+b(\014le)h(generated)e(con)o(tains)h(a)0 1195 y(list)e(of)f(en)o(tries)g
+(describing)i(eac)o(h)f(diskless)g(clien)o(t)h(that)d(can)i(b)q(o)q(ot)f
+(from)f(the)h(destination)h(mac)o(hine.)62 1266 y(As)f(an)g(example,)g(to)f
+(create)g(a)h(`)p Fl(bootparams)p Fo(')d(\014le)k(in)g(the)e(directory)h(`)p
+Fl(generic)p Fo(',)e(the)i(follo)o(wing)g(w)o(ould)g(b)q(e)0
+1316 y(used:)120 1386 y Fl(fsinfo)23 b(-b)h(generic/)e(...)0
+1579 y Fi(7.9.3)30 b Fd(-d)15 b Fe(dumpsets)62 1670 y Fo(This)k(sp)q
+(eci\014es)g(the)f(pre\014x)g(for)f(the)h(`)p Fl(dumpsets)p
+Fo(')d(\014le.)29 b(If)18 b(it)g(is)g(not)f(sp)q(eci\014ed,)j(then)e(the)g
+(\014le)h(will)g(not)e(b)q(e)0 1720 y(generated.)h(The)12 b(\014le)g(will)g
+(b)q(e)g(for)e(the)h(destination)h(mac)o(hine)f(and)h(will)g(b)q(e)g(placed)g
+(in)o(to)f(a)f(\014lename)i(`)p Fl(dumpsets)p Fo(',)0 1770
+y(pre\014xed)k(b)o(y)f(this)h(string.)k(The)15 b(`)p Fl(dumpsets)p
+Fo(')e(\014le)k(is)e(for)g(use)h(b)o(y)f(Imp)q(erial)i(College's)e(lo)q(cal)i
+(bac)o(kup)e(system.)62 1840 y(F)l(or)22 b(example,)i(to)d(create)g(a)h
+(dumpsets)g(\014le)h(in)g(the)f(directory)g(`)p Fl(generic)p
+Fo(',)g(then)g(y)o(ou)f(w)o(ould)i(use)f(the)0 1890 y(follo)o(wing:)120
+1961 y Fl(fsinfo)h(-d)h(generic/)e(...)0 2153 y Fi(7.9.4)30
+b Fd(-e)15 b Fe(exp)q(ortfs)62 2245 y Fo(De\014nes)d(the)g(pre\014x)g(for)f
+(the)g(`)p Fl(exports)p Fo(')f(\014les.)20 b(If)11 b(it)h(is)g(not)f(giv)o
+(en,)i(then)e(the)h(\014le)h(will)g(not)e(b)q(e)h(generated.)19
+b(F)l(or)0 2295 y(eac)o(h)14 b(mac)o(hine)h(de\014ned)g(in)f(the)g
+(con\014guration)g(\014les)h(as)e(ha)o(ving)h(disks,)h(an)f(`)p
+Fl(exports)p Fo(')e(\014le)j(is)f(constructed)g(and)0 2344
+y(giv)o(en)k(a)e(\014lename)j(determined)f(b)o(y)f(the)g(name)g(of)g(the)g
+(mac)o(hine,)h(pre\014xed)g(with)g(this)f(string.)26 b(If)17
+b(a)g(mac)o(hine)0 2394 y(is)j(de\014ned)h(as)e(diskless,)j(then)e(no)f(`)p
+Fl(exports)p Fo(')f(\014le)j(will)g(b)q(e)f(created)g(for)e(it.)34
+b(The)19 b(\014les)i(con)o(tain)f(en)o(tries)g(for)0 2444 y(directories)c(on)
+f(the)h(mac)o(hine)g(that)e(ma)o(y)h(b)q(e)g(exp)q(orted)h(to)f(clien)o(ts.)
+62 2515 y(Example:)k(T)l(o)10 b(create)h(the)g(`)p Fl(exports)p
+Fo(')e(\014les)j(for)e(eac)o(h)h(diskful)h(mac)o(hine)g(and)f(place)h(them)f
+(in)o(to)g(the)g(directory)0 2564 y(`)p Fl(exports)p Fo(':)120
+2635 y Fl(fsinfo)23 b(-e)h(exports/)e(...)p eop
+%%Page: 42 44
+42 43 bop 15 -83 a Fo(SMM:13-42)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fi(7.9.5)30 b Fd(-f)15 b Fe(fstab)62
+250 y Fo(This)f(de\014nes)g(the)f(pre\014x)h(for)e(the)h(`)p
+Fl(fstab)p Fo(')f(\014les.)20 b(The)13 b(\014les)i(will)f(only)g(b)q(e)g
+(created)f(if)g(this)h(pre\014x)f(is)h(de\014ned.)0 299 y(F)l(or)21
+b(eac)o(h)h(mac)o(hine)g(de\014ned)h(in)g(the)f(con\014guration)g(\014les,)i
+(a)d(`)p Fl(fstab)p Fo(')f(\014le)j(is)f(created)g(with)g(the)g(\014lename)0
+349 y(determined)c(b)o(y)f(pre\014xing)h(this)g(string)f(with)g(the)g(name)h
+(of)e(the)h(mac)o(hine.)27 b(These)17 b(\014les)h(con)o(tain)f(en)o(tries)h
+(for)0 399 y(\014lesystems)e(and)f(partitions)h(to)e(moun)o(t)h(at)f(b)q(o)q
+(ot)h(time.)62 470 y(Example,)h(to)e(create)h(the)g(\014les)i(in)f(the)f
+(directory)g(`)p Fl(fstabs)p Fo(':)120 540 y Fl(fsinfo)23 b(-f)h(fstabs/)f
+(...)0 686 y Fi(7.9.6)30 b Fd(-h)15 b Fe(hostname)62 778 y
+Fo(De\014nes)d(the)g(hostname)f(of)g(the)h(destination)g(mac)o(hine)g(to)f
+(pro)q(cess)h(for.)18 b(If)12 b(this)g(is)g(not)f(sp)q(eci\014ed,)j(it)d
+(defaults)0 827 y(to)k(the)g(lo)q(cal)h(mac)o(hine)g(name,)f(as)g(returned)g
+(b)o(y)h Fk(gethostname)p Fo(\(2\).)62 898 y(Example:)120 969
+y Fl(fsinfo)23 b(-h)h(dylan.doc.ic.ac.uk)d(...)0 1115 y Fi(7.9.7)30
+b Fd(-m)15 b Fe(moun)o(t-maps)62 1206 y Fo(De\014nes)k(the)f(pre\014x)g(for)g
+(the)g(automoun)o(ter)f(\014les.)29 b(The)18 b(maps)g(will)i(only)e(b)q(e)h
+(pro)q(duced)g(if)g(this)f(pre\014x)g(is)0 1256 y(de\014ned.)j(The)15
+b(moun)o(t)f(maps)g(suitable)i(for)e(the)h(net)o(w)o(ork)e(de\014ned)j(b)o(y)
+f(the)g(con\014guration)g(\014les)g(will)h(b)q(e)g(placed)0
+1306 y(in)o(to)f(\014les)h(with)g(names)f(calculated)i(b)o(y)e(pre\014xing)h
+(this)g(string)f(to)f(the)i(name)f(of)g(eac)o(h)g(map.)62 1376
+y(F)l(or)g(example,)g(to)g(create)g(the)g(automoun)o(ter)f(maps)h(and)h
+(place)g(them)f(in)h(the)f(directory)h(`)p Fl(automaps)p Fo(':)120
+1447 y Fl(fsinfo)23 b(-m)h(automaps/)e(...)0 1593 y Fi(7.9.8)30
+b Fd(-q)62 1684 y Fo(Selects)21 b(quiet)f(mo)q(de.)34 b Fp(FSinfo)23
+b Fo(suppress)d(the)g(\\running)g(commen)o(tary")f(and)h(only)g(outputs)f(an)
+o(y)h(error)0 1734 y(messages)15 b(whic)o(h)h(are)f(generated.)0
+1880 y Fi(7.9.9)30 b Fd(-v)62 1971 y Fo(Selects)21 b(v)o(erb)q(ose)e(mo)q
+(de.)34 b(When)19 b(this)h(is)g(activ)m(ated,)h(the)f(program)e(will)j
+(displa)o(y)g(more)e(messages,)h(and)0 2021 y(displa)o(y)c(all)g(the)e
+(information)h(disco)o(v)o(ered)h(when)f(p)q(erforming)g(the)g(seman)o(tic)g
+(analysis)g(phase.)20 b(Eac)o(h)15 b(v)o(erb)q(ose)0 2071 y(message)g(is)g
+(output)g(to)g(`)p Fl(stdout)p Fo(')f(on)h(a)g(line)h(starting)f(with)h(a)e
+(`)p Fl(#)p Fo(')h(c)o(haracter.)0 2217 y Fi(7.9.10)29 b Fd(-D)16
+b Fe(name[=defn])62 2308 y Fo(De\014nes)f(a)g(sym)o(b)q(ol)f
+Fp(name)j Fo(for)d(the)h(prepro)q(cessor)g(when)g(reading)g(the)f
+(con\014guration)h(\014les.)21 b(Equiv)m(alen)o(t)16 b(to)0
+2358 y Fl(#define)e Fo(directiv)o(e.)0 2504 y Fi(7.9.11)29
+b Fd(-I)16 b Fe(directory)62 2595 y Fo(This)g(option)g(is)g(passed)g(in)o(to)
+f(the)h(prepro)q(cessor)f(for)g(the)h(con\014guration)f(\014les.)22
+b(It)15 b(sp)q(eci\014es)j(directories)e(in)0 2645 y(whic)o(h)g(to)f(\014nd)h
+(include)h(\014les)p eop
+%%Page: 43 45
+43 44 bop 0 -83 a Fo(Chapter)15 b(7:)k(FSinfo)1362 b(SMM:13-43)0
+158 y Fi(7.9.12)29 b Fd(-U)16 b Fe(name)62 250 y Fo(Remo)o(v)o(es)f(an)o(y)g
+(initial)i(de\014nition)g(of)e(the)h(sym)o(b)q(ol)f Fp(name)p
+Fo(.)20 b(In)o(v)o(erse)15 b(of)g(the)g Fl(-D)g Fo(option.)0
+423 y Fq(7.10)32 b(Errors)16 b(pro)r(duced)g(b)n(y)g Ff(FSinfo)62
+514 y Fo(The)g(follo)o(wing)g(table)f(do)q(cumen)o(ts)h(the)f(errors)f(and)i
+(w)o(arnings)f(whic)o(h)h Fp(FSinfo)i Fo(ma)o(y)c(pro)q(duce.)0
+585 y Fl(can't)23 b(open)g Fp(\014lename)28 b Fl(for)c(writing)240
+648 y Fo(Occurs)16 b(if)g(an)o(y)e(errors)h(are)g(encoun)o(tered)h(when)f(op)
+q(ening)i(an)e(output)g(\014le.)0 712 y Fl(unknown)23 b(host)g(attribute)240
+775 y Fo(Occurs)16 b(if)g(an)f(unrecognised)h(k)o(eyw)o(ord)f(is)g(used)h
+(when)g(de\014ning)h(a)d(host.)0 839 y Fl(unknown)23 b(filesystem)f
+(attribute)240 902 y Fo(Occurs)16 b(if)g(an)f(unrecognised)h(k)o(eyw)o(ord)f
+(is)g(used)h(when)g(de\014ning)h(a)d(host's)h(\014lesystems.)0
+965 y Fl(not)23 b(allowed)g('/')h(in)f(a)h(directory)f(name)240
+1029 y Fo(When)14 b(reading)g(the)g(con\014guration)g(input,)h(if)f(there)g
+(is)g(a)f(\014lesystem)i(de\014nition)g(whic)o(h)g(con)o(tains)240
+1079 y(a)f(pathname)g(with)g(m)o(ultiple)i(directories)f(for)e(an)o(y)h(part)
+f(of)g(the)i(moun)o(tp)q(oin)o(t)f(elemen)o(t,)g(and)g(it)g(is)240
+1128 y(not)h(a)g(single)h(absolute)g(path,)e(then)i(this)g(message)e(will)j
+(b)q(e)f(pro)q(duced)g(b)o(y)g(the)f(parser.)0 1192 y Fl(unknown)23
+b(directory)g(attribute)240 1255 y Fo(If)d(an)g(unkno)o(wn)h(k)o(eyw)o(ord)e
+(is)h(found)h(while)g(reading)g(the)f(de\014nition)i(of)e(a)f(hosts's)g
+(\014lesystem)240 1305 y(moun)o(t)c(option.)0 1368 y Fl(unknown)23
+b(mount)g(attribute)240 1432 y Fo(Occurs)16 b(if)g(an)f(unrecognised)h(k)o
+(eyw)o(ord)f(is)g(found)h(while)h(parsing)e(the)g(list)h(of)f(static)g(moun)o
+(ts.)0 1495 y Fl(")24 b(expected)240 1558 y Fo(Occurs)16 b(if)g(an)f(unescap)
+q(ed)h(newline)i(is)d(found)h(in)g(a)f(quoted)g(string.)0 1622
+y Fl(unknown)23 b(\\)h(sequence)240 1685 y Fo(Occurs)12 b(if)h(an)e(unkno)o
+(wn)h(escap)q(e)h(sequence)g(is)f(found)g(inside)i(a)d(string.)19
+b(Within)13 b(a)e(string,)h(y)o(ou)g(can)240 1735 y(giv)o(e)j(the)g(standard)
+g(C)g(escap)q(e)h(sequences)g(for)e(strings,)h(suc)o(h)h(as)e(newlines)j(and)
+e(tab)g(c)o(haracters.)0 1798 y Fp(\014lename)s Fl(:)24 b(cannot)f(open)h
+(for)f(reading)240 1862 y Fo(If)18 b(a)f(\014le)h(sp)q(eci\014ed)i(on)d(the)h
+(command)f(line)i(as)e(con)o(taining)h(con\014guration)g(data)f(could)h(not)f
+(b)q(e)240 1912 y(op)q(ened.)0 1975 y Fl(end)23 b(of)h(file)f(within)g
+(comment)240 2038 y Fo(A)15 b(commen)o(t)g(w)o(as)f(un)o(terminated)i(b)q
+(efore)g(the)f(end)h(of)e(one)i(of)f(the)g(con\014guration)g(\014les.)0
+2102 y Fl(host)23 b(field)g(")p Fp(\014eld-name)s Fl(")i(already)e(set)240
+2165 y Fo(If)15 b(duplicate)i(de\014nitions)g(are)e(giv)o(en)h(for)f(an)o(y)f
+(of)h(the)g(\014elds)i(with)e(a)g(host)g(de\014nition.)0 2229
+y Fl(duplicate)23 b(host)g Fp(hostname)s Fl(!)240 2292 y Fo(If)15
+b(a)g(host)g(has)g(more)g(than)g(one)g(de\014nition.)0 2355
+y Fl(netif)23 b(field)g Fp(\014eld-name)28 b Fl(already)23
+b(set)240 2419 y Fo(Occurs)16 b(if)g(y)o(ou)e(attempt)h(to)f(de\014ne)j(an)e
+(attribute)g(of)f(an)i(in)o(terface)f(more)g(than)g(once.)0
+2482 y Fl(malformed)23 b(IP)g(dotted)g(quad:)g Fp(address)240
+2545 y Fo(If)e(the)g(In)o(ternet)h(address)f(of)f(an)h(in)o(terface)g(is)h
+(incorrectly)g(sp)q(eci\014ed.)39 b(An)22 b(In)o(ternet)f(address)240
+2595 y(de\014nition)e(is)e(handled)i(to)d Fk(inet)p 801 2595
+14 3 v 17 w(addr)p Fo(\(3N\))h(to)f(see)i(if)f(it)g(can)g(cop)q(e.)26
+b(If)17 b(not,)g(then)g(this)g(message)240 2645 y(will)g(b)q(e)f(displa)o(y)o
+(ed.)p eop
+%%Page: 44 46
+44 45 bop 15 -83 a Fo(SMM:13-44)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fl(malformed)23 b(netmask:)f
+Fp(netmask)240 223 y Fo(If)16 b(the)g(netmask)f(cannot)g(b)q(e)i(deco)q(ded)g
+(as)e(though)h(it)g(w)o(ere)f(a)g(hexadecimal)j(n)o(um)o(b)q(er,)d(then)i
+(this)240 273 y(message)i(will)h(b)q(e)g(displa)o(y)o(ed.)32
+b(It)19 b(will)i(t)o(ypically)f(b)q(e)g(caused)g(b)o(y)e(incorrect)i(c)o
+(haracters)e(in)i(the)240 322 y Fp(netmask)e Fo(v)m(alue.)0
+387 y Fl(fs)24 b(field)f(")p Fp(\014eld-name)s Fl(")h(already)f(set)240
+451 y Fo(Occurs)16 b(when)g(m)o(ultiple)h(de\014nitions)g(are)e(giv)o(en)h
+(for)f(one)g(of)g(the)g(attributes)h(of)e(a)h(host's)g(\014lesys-)240
+501 y(tem.)0 565 y Fl(mount)23 b(tree)g(field)h(")p Fp(\014eld-name)s
+Fl(")g(already)f(set)240 630 y Fo(Occurs)13 b(when)h(the)f
+Fp(\014eld-name)j Fo(is)e(de\014ned)g(more)e(than)h(once)g(during)h(the)f
+(de\014nition)h(of)e(a)h(\014lesys-)240 680 y(tems)i(moun)o(tp)q(oin)o(t.)0
+744 y Fl(mount)23 b(field)g(")p Fp(\014eld-name)s Fl(")i(already)e(set)240
+809 y Fo(Occurs)16 b(when)g(a)e(static)h(moun)o(t)g(has)g(m)o(ultiple)i
+(de\014nitions)g(of)e(the)g(same)g(\014eld.)0 873 y Fl(no)24
+b(disk)f(mounts)g(on)h Fp(hostname)240 937 y Fo(If)11 b(there)g(are)g(no)g
+(static)g(moun)o(ts,)g(nor)f(lo)q(cal)i(disk)g(moun)o(ts)f(sp)q(eci\014ed)i
+(for)d(a)h(mac)o(hine,)h(this)f(message)240 987 y(will)17 b(b)q(e)f(displa)o
+(y)o(ed.)0 1052 y Fp(host)q Fl(:)p Fp(device)27 b Fl(needs)d(field)f(")p
+Fp(\014eld-name)s Fl(")240 1116 y Fo(Occurs)13 b(when)f(a)g(\014lesystem)g
+(is)h(missing)f(a)g(required)h(\014eld.)20 b Fp(\014eld-name)c
+Fo(could)d(b)q(e)g(one)f(of)f Fl(fstype)p Fo(,)240 1166 y Fl(opts)p
+Fo(,)j Fl(passno)h Fo(or)f Fl(mount)p Fo(.)0 1230 y Fp(\014lesystem)25
+b Fl(has)e(a)h(volname)f(but)g(no)h(exportfs)e(data)240 1295
+y Fo(Occurs)13 b(when)f(a)g(v)o(olume)h(name)f(is)g(declared)i(for)d(a)h
+(\014le)h(system,)f(but)g(the)g(string)g(sp)q(ecifying)j(what)240
+1345 y(mac)o(hines)h(the)f(\014lesystem)h(can)f(b)q(e)h(exp)q(orted)g(to)e
+(is)i(missing.)0 1409 y Fl(sub-directory)22 b Fp(directory)28
+b Fl(of)c Fp(directory-tree)i Fl(starts)d(with)h('/')240 1473
+y Fo(Within)13 b(the)f(\014lesystem)h(sp)q(eci\014cation)h(for)d(a)h(host,)f
+(if)i(an)f(elemen)o(t)g Fp(directory)k Fo(of)c(the)g(moun)o(tp)q(oin)o(t)240
+1523 y(b)q(egins)k(with)g(a)f(`)p Fl(/)p Fo(')f(and)h(it)h(is)g(not)e(the)i
+(start)e(of)g(the)i(tree.)0 1588 y Fp(host)q Fl(:)p Fp(device)27
+b Fl(has)d(no)f(mount)h(point)240 1652 y Fo(Occurs)16 b(if)g(the)f(`)p
+Fl(mount)p Fo(')f(option)h(is)h(not)e(sp)q(eci\014ed)k(for)c(a)h(host's)g
+(\014lesystem.)0 1717 y Fp(host)q Fl(:)p Fp(device)27 b Fl(has)d(more)f(than)
+g(one)h(mount)f(point)240 1781 y Fo(Occurs)17 b(if)g(the)g(moun)o(t)f(option)
+h(for)f(a)g(host's)g(\014lesystem)h(sp)q(eci\014es)h(m)o(ultiple)h(trees)d
+(at)g(whic)o(h)i(to)240 1831 y(place)e(the)f(moun)o(tp)q(oin)o(t.)0
+1895 y Fl(no)24 b(volname)e(given)i(for)f Fp(host)q Fl(:)p
+Fp(device)240 1960 y Fo(Occurs)15 b(when)h(a)e(\014lesystem)h(is)g(de\014ned)
+h(to)e(b)q(e)i(moun)o(ted)e(on)h(`)p Fl(default)p Fo(',)e(but)h(no)h(v)o
+(olume)g(name)240 2009 y(is)h(giv)o(en)f(for)g(the)g(\014le)h(system,)f(then)
+g(the)h(moun)o(tp)q(oin)o(t)f(cannot)g(b)q(e)h(determined.)0
+2074 y Fp(host)q Fl(:mount)23 b(field)g(specified)f(for)i(swap)f(partition)
+240 2138 y Fo(Occurs)16 b(if)g(a)e(moun)o(tp)q(oin)o(t)i(is)f(giv)o(en)h(for)
+f(a)f(\014lesystem)i(whose)f(t)o(yp)q(e)h(is)f(declared)i(to)d(b)q(e)i
+Fl(swap)p Fo(.)0 2203 y Fl(ambiguous)23 b(mount:)g Fp(v)o(olume)k
+Fl(is)c(a)h(replicated)e(filesystem)240 2267 y Fo(If)17 b(sev)o(eral)f
+(\014lesystems)h(are)f(declared)h(as)f(ha)o(ving)g(the)h(same)f(v)o(olume)g
+(name,)h(they)f(will)i(b)q(e)f(con-)240 2317 y(sidered)j(replicated)h
+(\014lesystems.)33 b(T)l(o)19 b(moun)o(t)g(a)g(replicated)h(\014lesystem)g
+(statically)l(,)h(a)e(sp)q(eci\014c)240 2367 y(host)e(will)h(need)g(to)e(b)q
+(e)i(named,)f(to)g(sa)o(y)f(whic)o(h)i(particular)f(cop)o(y)g(to)g(try)f(and)
+h(moun)o(t,)g(else)h(this)240 2417 y(error)c(will)j(result.)0
+2481 y Fl(cannot)23 b(determine)g(localname)f(since)h(volname)g
+Fp(v)o(olume)k Fl(is)d(not)f(uniquely)g(defined)240 2545 y
+Fo(If)c(a)g(v)o(olume)h(is)g(replicated)g(and)g(an)f(attempt)f(is)i(made)f
+(to)f(moun)o(t)h(the)g(\014lesystem)h(statically)240 2595 y(without)d(sp)q
+(ecifying)j(a)d(lo)q(cal)h(moun)o(tp)q(oin)o(t,)g Fp(FSinfo)i
+Fo(cannot)d(calculate)h(a)f(moun)o(tp)q(oin)o(t,)h(as)f(the)240
+2645 y(desired)f(pathname)g(w)o(ould)f(b)q(e)h(am)o(biguous.)p
+eop
+%%Page: 45 47
+45 46 bop 0 -83 a Fo(Chapter)15 b(8:)k(Examples)1300 b(SMM:13-45)0
+158 y Fl(volname)23 b Fp(v)o(olume)k Fl(is)c(unknown)240 223
+y Fo(Occurs)14 b(if)g(an)f(attempt)f(is)i(made)f(to)f(moun)o(t)h(or)g
+(reference)g(a)g(v)o(olume)h(name)f(whic)o(h)h(has)f(not)g(b)q(een)240
+273 y(declared)j(during)g(the)g(host)f(\014lesystem)g(de\014nitions.)0
+338 y Fl(volname)23 b Fp(v)o(olume)k Fl(not)c(exported)g(from)g
+Fp(mac)o(hine)240 402 y Fo(Occurs)d(if)h(y)o(ou)e(attempt)g(to)g(moun)o(t)g
+(the)h(v)o(olume)g Fp(v)o(olume)j Fo(from)c(a)g(mac)o(hine)i(whic)o(h)g(has)e
+(not)240 452 y(declared)d(itself)h(to)d(ha)o(v)o(e)h(suc)o(h)g(a)g
+(\014lesystem)h(a)o(v)m(ailable.)0 517 y Fl(network)23 b(booting)g(requires)g
+(both)g(root)g(and)h(swap)f(areas)240 581 y Fo(Occurs)18 b(if)g(a)f(mac)o
+(hine)h(has)f(moun)o(t)g(declarations)h(for)e(either)i(the)f(ro)q(ot)g
+(partition)g(or)g(the)h(sw)o(ap)240 631 y(area,)12 b(but)f(not)h(b)q(oth.)19
+b(Y)l(ou)12 b(cannot)f(de\014ne)i(a)f(mac)o(hine)g(to)g(only)g(partially)h(b)
+q(o)q(ot)e(via)i(the)e(net)o(w)o(ork.)0 696 y Fl(unknown)23
+b(volname)g Fp(v)o(olume)k Fl(automounted)22 b Fp([)29 b Fl(on)24
+b(<name>)f Fp(])240 761 y Fo(Occurs)c(if)f Fp(v)o(olume)j Fo(is)e(used)g(in)g
+(a)e(de\014nition)j(of)e(an)g(automoun)o(t)f(map)h(but)g(the)g(v)o(olume)h
+(name)240 810 y(has)c(not)g(b)q(een)h(declared)h(during)f(the)f(host)g
+(\014lesystem)h(de\014nitions.)0 875 y Fl(not)23 b(allowed)g('/')h(in)f(a)h
+(directory)f(name)240 940 y Fo(Occurs)15 b(when)g(a)f(pathname)g(with)h(m)o
+(ultiple)h(directory)f(elemen)o(ts)g(is)g(sp)q(eci\014ed)i(as)d(the)g(name)h
+(for)240 990 y(an)g(automoun)o(ter)f(tree.)20 b(A)15 b(tree)g(should)h(only)g
+(ha)o(v)o(e)f(one)g(name)g(at)g(eac)o(h)g(lev)o(el.)0 1054
+y Fp(device)28 b Fl(has)23 b(duplicate)g(exportfs)g(data)240
+1119 y Fo(Pro)q(duced)16 b(if)h(the)e(`)p Fl(exportfs)p Fo(')f(option)i(is)g
+(used)g(m)o(ultiple)i(times)d(within)i(the)f(same)f(branc)o(h)h(of)f(a)240
+1169 y(\014lesytem)e(de\014nition.)21 b(F)l(or)12 b(example,)h(if)g(y)o(ou)f
+(attempt)f(to)h(set)g(the)h(`)p Fl(exportfs)p Fo(')d(data)i(at)g(di\013eren)o
+(t)240 1219 y(lev)o(els)k(of)f(the)h(moun)o(tp)q(oin)o(t)f(directory)g(tree.)
+0 1283 y Fl(sub-directory)22 b(of)i Fp(directory-tree)i Fl(is)e(named)f
+("default")240 1348 y Fo(`)p Fl(default)p Fo(')17 b(is)h(a)g(k)o(eyw)o(ord)g
+(used)h(to)f(sp)q(ecify)h(if)g(a)f(moun)o(tp)q(oin)o(t)g(should)i(b)q(e)f
+(automatically)f(cal-)240 1398 y(culated)g(b)o(y)f Fp(FSinfo)p
+Fo(.)25 b(If)17 b(y)o(ou)g(attempt)f(to)g(sp)q(ecify)i(a)f(directory)g(name)g
+(as)f(this,)i(it)f(will)i(use)e(the)240 1448 y(\014lename)f(of)f(`)p
+Fl(default)p Fo(')f(but)h(will)i(pro)q(duce)f(this)f(w)o(arning.)0
+1512 y Fl(pass)23 b(number)g(for)h Fp(host)q Fl(:)p Fp(device)j
+Fl(is)d(non-zero)240 1577 y Fo(Occurs)14 b(if)h Fp(device)i
+Fo(has)d(its)g(`)p Fl(fstype)p Fo(')e(declared)j(to)e(b)q(e)h(`)p
+Fl(swap)p Fo(')f(or)g(`)p Fl(export)p Fo(')f(and)i(the)g Fk(fsc)o(k)p
+Fo(\(8\))e(pass)240 1627 y(n)o(um)o(b)q(er)i(is)h(set.)k(Sw)o(ap)14
+b(devices)h(should)g(not)e(b)q(e)i(fsc)o(k'd.)k(See)14 b(Section)h(7.6.1)d
+([FSinfo)i(\014lesystems)240 1677 y(fst)o(yp)q(e],)g(page)31
+b(SMM:13-36)0 1741 y Fl(dump)23 b(frequency)g(for)g Fp(host)q
+Fl(:)p Fp(device)28 b Fl(is)23 b(non-zero)240 1806 y Fo(Occurs)12
+b(if)h Fp(device)i Fo(has)d(its)g(`)p Fl(fstype)p Fo(')e(declared)j(to)e(b)q
+(e)h(`)p Fl(swap)p Fo(')e(or)i(`)p Fl(export)p Fo(')e(and)i(the)f(`)p
+Fl(dump)p Fo(')g(option)240 1856 y(is)16 b(set)f(to)f(a)h(v)m(alue)i(greater)
+d(than)h(zero.)20 b(Sw)o(ap)15 b(devices)h(should)g(not)f(b)q(e)h(dump)q(ed.)
+0 2065 y Fm(8)41 b(Examples)0 2313 y Fq(8.1)33 b(User)14 b(Filesystems)62
+2404 y Fo(With)g(more)g(than)g(one)g(\014leserv)o(er,)g(the)g(directories)h
+(most)e(frequen)o(tly)i(cross-moun)o(ted)e(are)h(those)g(con)o(tain-)0
+2454 y(ing)19 b(user)g(home)f(directories.)31 b(A)19 b(common)f(con)o(v)o(en)
+o(tion)h(used)g(at)f(Imp)q(erial)i(College)f(is)g(to)f(moun)o(t)g(the)h(user)
+0 2504 y(disks)d(under)g Fl(/home/)p Fp(mac)o(hine)p Fo(.)62
+2575 y(T)o(ypically)l(,)h(the)e(`)p Fl(/etc/fstab)p Fo(')e(\014le)j(con)o
+(tained)g(a)f(long)h(list)g(of)e(en)o(tries)i(suc)o(h)f(as:)120
+2645 y Fp(mac)o(hine)s Fl(:/home/)p Fp(mac)o(hine)27 b Fl(/home/)p
+Fp(mac)o(hine)f Fl(nfs)e(...)p eop
+%%Page: 46 48
+46 47 bop 15 -83 a Fo(SMM:13-46)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)62 158 y(for)e(eac)o(h)g(\014leserv)o(er)h(on)f(the)g
+(net)o(w)o(ork.)62 229 y(There)20 b(are)e(n)o(umerous)h(problems)h(with)f
+(this)h(system.)31 b(The)19 b(moun)o(t)f(list)i(can)f(b)q(ecome)h(quite)g
+(large)f(and)0 279 y(some)d(of)h(the)f(mac)o(hines)i(ma)o(y)e(b)q(e)h(do)o
+(wn)g(when)g(a)f(system)h(is)g(b)q(o)q(oted.)24 b(When)18 b(a)e(new)h
+(\014leserv)o(er)g(is)g(installed,)0 329 y(`)p Fl(/etc/fstab)p
+Fo(')d(m)o(ust)h(b)q(e)i(up)q(dated)g(on)f(ev)o(ery)g(mac)o(hine,)g(the)g
+(moun)o(t)g(directory)g(created)g(and)g(the)g(\014lesystem)0
+378 y(moun)o(ted.)62 449 y(In)f(man)o(y)f(en)o(vironmen)o(ts)h(most)e(p)q
+(eople)j(use)f(the)f(same)g(few)g(w)o(orkstations,)f(but)i(it)f(is)h(con)o(v)
+o(enien)o(t)g(to)f(go)g(to)0 499 y(a)i(colleague's)g(mac)o(hine)h(and)f
+(access)g(y)o(our)f(o)o(wn)h(\014les.)23 b(When)16 b(a)f(serv)o(er)h(go)q(es)
+f(do)o(wn,)h(it)g(can)g(cause)g(a)g(pro)q(cess)0 549 y(on)e(a)g(clien)o(t)h
+(mac)o(hine)g(to)e(hang.)20 b(By)14 b(minimising)i(the)e(moun)o(ted)g
+(\014lesystems)h(to)e(only)i(include)h(those)e(activ)o(ely)0
+598 y(b)q(eing)i(used,)g(there)f(is)h(less)g(c)o(hance)f(that)g(a)g
+(\014lesystem)h(will)h(b)q(e)e(moun)o(ted)h(when)f(a)g(serv)o(er)g(go)q(es)g
+(do)o(wn.)62 669 y(The)f(follo)o(wing)g(is)g(a)f(short)g(extract)f(from)h(a)g
+(map)g(tak)o(en)g(from)g(a)g(researc)o(h)g(\014leserv)o(er)i(at)d(Imp)q
+(erial)j(College.)62 739 y(Note)g(the)h(en)o(try)f(for)f(`)p
+Fl(localhost)p Fo(')g(whic)o(h)i(is)f(used)h(for)f(users)g(suc)o(h)h(as)f
+(the)g(op)q(erator)g(\(`)p Fl(opr)p Fo('\))e(who)i(ha)o(v)o(e)g(a)0
+789 y(home)g(directory)h(on)f(most)f(mac)o(hine)i(as)f(`)p
+Fl(/home/localhost/opr)p Fo('.)120 860 y Fl(/defaults)166 b
+(opts:=rw,intr,grpid,nosui)o(d)120 910 y(charm)262 b
+(host!=${key};type:=nfs;rh)o(ost:=${)o(key};rf)o(s:=/home)o(/${key})20
+b(\\)502 959 y(host==${key};type:=ufs;de)o(v:=/dev)o(/xd0g)120
+1009 y(#)120 1059 y(...)120 1159 y(#)120 1209 y(localhost)166
+b(type:=link;fs:=${host})120 1258 y(...)120 1308 y(#)120 1358
+y(#)24 b(dylan)f(has)g(two)h(user)f(disks)g(so)h(have)f(a)120
+1408 y(#)h(top)f(directory)g(in)g(which)h(to)f(mount)g(them.)120
+1458 y(#)120 1507 y(dylan)262 b(type:=auto;fs:=${map};pre)o(f:=${ke)o(y}/)120
+1557 y(#)120 1607 y(dylan/dk2)166 b(host!=dylan;type:=nfs;rho)o(st:=dyl)o
+(an;rfs:)o(=/home/$)o({key})21 b(\\)502 1657 y(host==dylan;type:=ufs;dev)o
+(:=/dev/)o(dsk/2s0)120 1707 y(#)120 1757 y(dylan/dk5)166 b
+(host!=dylan;type:=nfs;rho)o(st:=dyl)o(an;rfs:)o(=/home/$)o({key})21
+b(\\)502 1806 y(host==dylan;type:=ufs;dev)o(:=/dev/)o(dsk/5s0)120
+1856 y(...)120 1906 y(#)120 1956 y(toytown)214 b(host!=${key};type:=nfs;rh)o
+(ost:=${)o(key};rf)o(s:=/home)o(/${key})20 b(\\)502 2006 y
+(host==${key};type:=ufs;de)o(v:=/dev)o(/xy1g)120 2055 y(...)120
+2105 y(#)120 2155 y(zebedee)214 b(host!=${key};type:=nfs;rh)o(ost:=${)o
+(key};rf)o(s:=/home)o(/${key})20 b(\\)502 2205 y(host==${key};type:=ufs;de)o
+(v:=/dev)o(/dsk/1s)o(0)120 2255 y(#)120 2304 y(#)k(Just)f(for)g(access...)120
+2354 y(#)120 2404 y(gould)262 b(type:=auto;fs:=${map};pre)o(f:=${ke)o(y}/)120
+2454 y(gould/staff)118 b(host!=gould;type:=nfs;rho)o(st:=gou)o(ld;rfs:)o
+(=/home/$)o({key})120 2504 y(#)120 2554 y(gummo)262 b
+(host!=${key};type:=nfs;rh)o(ost:=${)o(key};rf)o(s:=/home)o(/${key})120
+2603 y(...)p eop
+%%Page: 47 49
+47 48 bop 0 -83 a Fo(Chapter)15 b(8:)k(Examples)1300 b(SMM:13-47)62
+158 y(This)17 b(map)e(is)h(shared)g(b)o(y)g(most)e(of)i(the)f(mac)o(hines)i
+(listed)g(so)e(on)g(those)h(systems)f(an)o(y)g(of)h(the)f(user)h(disks)g(is)0
+208 y(accessible)h(via)f(a)e(consisten)o(t)i(name.)k Fp(Amd)d
+Fo(is)f(started)e(with)i(the)f(follo)o(wing)h(command)120 279
+y Fl(amd)23 b(/home)h(amd.home)62 370 y Fo(Note)16 b(that)g(when)g(moun)o
+(ting)h(a)e(remote)h(\014lesystem,)h(the)f Fp(automoun)o(ted)h
+Fo(moun)o(t)f(p)q(oin)o(t)h(is)f(referenced,)h(so)0 420 y(that)c(the)h
+(\014lesystem)h(will)g(b)q(e)g(moun)o(ted)f(if)g(it)g(is)g(not)g(y)o(et)f
+(\(at)g(the)h(time)g(the)g(remote)g(`)p Fl(mountd)p Fo(')e(obtains)i(the)g
+(\014le)0 470 y(handle\).)0 628 y Fq(8.2)33 b(Home)14 b(Directories)62
+719 y Fo(One)e(con)o(v)o(en)o(tion)e(for)g(home)h(directories)h(is)f(to)f(lo)
+q(cate)h(them)f(in)i(`)p Fl(/homes)p Fo(')d(so)h(user)h(`)p
+Fl(jsp)p Fo(''s)e(home)i(directory)f(is)0 769 y(`)p Fl(/homes/jsp)p
+Fo('.)17 b(With)e(more)f(than)h(a)f(single)i(\014leserv)o(er)f(it)f(is)h(con)
+o(v)o(enien)o(t)h(to)d(spread)i(user)g(\014les)g(across)f(sev)o(eral)0
+819 y(mac)o(hines.)34 b(All)21 b(that)f(is)g(required)h(is)f(a)f(moun)o
+(t-map)h(whic)o(h)g(con)o(v)o(erts)f(login)i(names)f(to)f(an)h(automoun)o
+(ted)0 868 y(directory)l(.)62 939 y(Suc)o(h)c(a)f(map)g(migh)o(t)g(b)q(e)h
+(started)e(b)o(y)h(the)h(command:)120 1010 y Fl(amd)23 b(/homes)g(amd.homes)
+62 1101 y Fo(where)16 b(the)f(map)g(`)p Fl(amd.homes)p Fo(')e(con)o(tained)j
+(the)f(en)o(tries:)120 1171 y Fl(/defaults)70 b(type:=link)h(#)23
+b(All)h(the)f(entries)g(are)h(of)f(type:=link)120 1221 y(jsp)214
+b(fs:=/home/charm/jsp)120 1271 y(njw)g(fs:=/home/dylan/dk5/njw)120
+1321 y(...)120 1371 y(phjk)190 b(fs:=/home/toytown/ai/phjk)120
+1421 y(sjv)214 b(fs:=/home/ganymede/sjv)62 1512 y Fo(Whenev)o(er)21
+b(a)e(login)i(name)f(is)g(accessed)h(in)g(`)p Fl(/homes)p Fo(')d(a)i(sym)o(b)
+q(olic)h(link)g(app)q(ears)f(p)q(oin)o(ting)h(to)f(the)g(real)0
+1562 y(lo)q(cation)12 b(of)f(that)f(user's)h(home)h(directory)l(.)19
+b(In)12 b(this)f(example,)i(`)p Fl(/homes/jsp)p Fo(')c(w)o(ould)j(app)q(ear)f
+(to)g(b)q(e)h(a)f(sym)o(b)q(olic)0 1611 y(link)17 b(p)q(oin)o(ting)f(to)e(`)p
+Fl(/home/charm/jsp)p Fo('.)k(Of)d(course,)g(`)p Fl(/home)p
+Fo(')f(w)o(ould)h(also)g(b)q(e)h(an)f(automoun)o(t)f(p)q(oin)o(t.)62
+1682 y(This)j(system)f(causes)h(an)f(extra)g(lev)o(el)h(of)f(sym)o(b)q(olic)i
+(links)f(to)f(b)q(e)h(used.)24 b(Although)17 b(that)e(turns)i(out)f(to)f(b)q
+(e)0 1732 y(relativ)o(ely)i(inexp)q(ensiv)o(e,)i(an)d(alternativ)o(e)g(is)h
+(to)f(directly)h(moun)o(t)f(the)g(required)h(\014lesystems)g(in)g(the)g(`)p
+Fl(/homes)p Fo(')0 1782 y(map.)i(The)14 b(required)g(map)f(is)h(simple,)h
+(but)e(long,)h(and)f(its)h(creation)f(is)h(b)q(est)g(automated.)k(The)c(en)o
+(try)e(for)h(`)p Fl(jsp)p Fo(')0 1831 y(could)j(b)q(e:)120
+1902 y Fl(jsp)71 b(-sublink:=${key};rfs:=/home)o(/charm)21
+b(\\)478 1952 y(host==charm;type:=ufs;dev:)o(=/dev/x)o(d0g)g(\\)478
+2002 y(host!=charm;type:=nfs;rhos)o(t:=char)o(m)62 2093 y Fo(This)14
+b(map)g(can)f(b)q(ecome)h(quite)h(big)f(if)f(it)h(con)o(tains)g(a)f(large)g
+(n)o(um)o(b)q(er)h(of)f(en)o(tries.)20 b(By)14 b(com)o(bining)g(t)o(w)o(o)e
+(other)0 2143 y(features)j(of)g Fp(Amd)i Fo(it)e(can)h(b)q(e)f(greatly)g
+(simpli\014ed.)62 2213 y(First)e(the)g(UFS)g(partitions)g(should)h(b)q(e)g
+(moun)o(ted)f(under)h(the)f(con)o(trol)f(of)h(`)p Fl(/etc/fstab)p
+Fo(',)e(taking)i(care)g(that)0 2263 y(they)j(are)f(moun)o(ted)g(in)i(the)e
+(same)h(place)g(that)f Fp(Amd)i Fo(w)o(ould)f(ha)o(v)o(e)f(automoun)o(ted)g
+(them.)21 b(In)16 b(most)f(cases)h(this)0 2313 y(w)o(ould)e(b)q(e)h
+(something)f(lik)o(e)h(`)p Fl(/a/)p Fp(host)q Fl(/home/)p Fp(host)q
+Fo(')c(and)j(`)p Fl(/etc/fstab)p Fo(')e(on)i(host)f(`)p Fl(charm)p
+Fo(')f(w)o(ould)j(ha)o(v)o(e)e(a)h(line:)120 2384 y Fl(/dev/xy0g)23
+b(/a/charm/home/charm)e(4.2)i(rw,nosuid,grpid)f(1)i(5)62 2475
+y Fo(The)16 b(map)f(can)g(then)h(b)q(e)f(c)o(hanged)h(to:)120
+2545 y Fl(/defaults)94 b(type:=nfs;sublink:=${key};op)o(ts:=rw,)o(intr,no)o
+(suid,grp)o(id)120 2595 y(jsp)238 b(rhost:=charm;rfs:=/home/char)o(m)120
+2645 y(njw)g(rhost:=dylan;rfs:=/home/dyla)o(n/dk5)p eop
+%%Page: 48 50
+48 49 bop 15 -83 a Fo(SMM:13-48)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)120 158 y Fl(...)120 208 y(phjk)214
+b(rhost:=toytown;rfs:=/home/to)o(ytown;s)o(ublink:)o(=ai/${ke)o(y})120
+258 y(sjv)238 b(rhost:=ganymede;rfs:=/home/g)o(anymede)62 349
+y Fo(This)17 b(map)e(op)q(erates)h(as)f(usual)h(on)g(a)f(remote)h(mac)o(hine)
+g(\()p Fp(ie)j Fl(${host})c Fo(not)g(equal)h(to)g Fl(${rhost})p
+Fo(\).)k(On)c(the)0 399 y(mac)o(hine)f(where)f(the)f(\014lesystem)i(is)f
+(stored)f(\()p Fp(ie)k Fl(${host})c Fo(equal)h(to)g Fl(${rhost})p
+Fo(\),)e Fp(Amd)k Fo(will)f(construct)e(a)h(lo)q(cal)0 449
+y(\014lesystem)k(moun)o(t)g(p)q(oin)o(t)g(whic)o(h)h(corresp)q(onds)f(to)f
+(the)h(name)g(of)f(the)h(lo)q(cally)h(moun)o(ted)f(UFS)g(partition.)28
+b(If)0 499 y Fp(Amd)18 b Fo(is)f(started)f(with)h(the)f(\\-r")g(option)g
+(then)h(instead)g(of)f(attempting)g(an)g(NFS)h(moun)o(t,)e
+Fp(Amd)k Fo(will)f(simply)0 549 y(inherit)d(the)f(UFS)g(moun)o(t)f(\(see)h
+(Section)h(5.14)d([Inheritance)j(Filesystem],)f(page)28 b(SMM:13-26\).)17
+b(If)d(\\-r")f(is)h(not)0 598 y(used)i(then)g(a)f(lo)q(opbac)o(k)g(NFS)h
+(moun)o(t)e(will)j(b)q(e)f(made.)21 b(This)16 b(t)o(yp)q(e)f(of)g(moun)o(t)g
+(is)h(kno)o(wn)f(to)f(cause)i(a)f(deadlo)q(c)o(k)0 648 y(on)g(man)o(y)g
+(systems.)0 810 y Fq(8.3)33 b(Arc)n(hitecture)16 b(Sharing)62
+902 y Fo(Often)h(a)f(\014lesystem)h(will)h(b)q(e)f(shared)f(b)o(y)h(mac)o
+(hines)g(of)f(di\013eren)o(t)g(arc)o(hitectures.)24 b(Separate)16
+b(trees)g(can)g(b)q(e)0 951 y(main)o(tained)f(for)f(the)g(executable)h
+(images)f(for)g(eac)o(h)g(arc)o(hitecture,)g(but)h(it)f(ma)o(y)g(b)q(e)g
+(more)g(con)o(v)o(enien)o(t)h(to)e(ha)o(v)o(e)0 1001 y(a)i(shared)g(tree,)g
+(with)g(distinct)i(sub)q(directories.)62 1072 y(A)23 b(shared)f(tree)h(migh)o
+(t)f(ha)o(v)o(e)g(the)h(follo)o(wing)g(structure)f(on)g(the)h(\014leserv)o
+(er)g(\(called)h(`)p Fl(fserver)p Fo(')d(in)i(the)0 1122 y(example\):)120
+1192 y Fl(local/tex)120 1242 y(local/tex/fonts)120 1292 y(local/tex/lib)120
+1342 y(local/tex/bin)120 1391 y(local/tex/bin/sun3)120 1441
+y(local/tex/bin/sun4)120 1491 y(local/tex/bin/hp9000)120 1541
+y(...)62 1632 y Fo(In)15 b(this)g(example,)g(the)g(sub)q(directories)h(of)e
+(`)p Fl(local/tex/bin)p Fo(')e(should)j(b)q(e)g(hidden)h(when)f(accessed)g
+(via)g(the)0 1682 y(automoun)o(t)f(p)q(oin)o(t)i(\(con)o(v)o(en)o(tionally)g
+(`)p Fl(/vol)p Fo('\).)i(A)d(moun)o(t-map)g(for)f(`)p Fl(/vol)p
+Fo(')g(to)h(ac)o(hiev)o(e)h(this)f(w)o(ould)h(lo)q(ok)f(lik)o(e:)120
+1752 y Fl(/defaults)70 b(sublink:=${/key};rhost:=fserv)o(er;type)o(:=link)120
+1802 y(tex)214 b(type:=auto;fs:=${map};pref:=$)o({key}/)120
+1852 y(tex/fonts)70 b(host!=fserver;type:=nfs;rfs:=)o(/vol/te)o(x)21
+b(\\)406 1902 y(host==fserver;fs:=/usr/local/)o(tex)120 1952
+y(tex/lib)118 b(host!=fserver;type:=nfs;rfs:=)o(/vol/te)o(x)21
+b(\\)406 2002 y(host==fserver;fs:=/usr/local/)o(tex)120 2051
+y(tex/bin)118 b(-sublink:=${/key}/${arch})21 b(host!=fserver;type:=nfs;r)o
+(fs:=/vo)o(l/tex)120 2101 y(\\)406 2151 y(host:=fserver;fs:=/usr/local/)o
+(tex)62 2242 y Fo(When)12 b(`)p Fl(/vol/tex/bin)p Fo(')d(is)k(referenced,)g
+(the)e(curren)o(t)h(mac)o(hine)g(arc)o(hitecture)g(is)g(automatically)g(app)q
+(ended)0 2292 y(to)j(the)h(path)g(b)o(y)f(the)h Fl(${sublink})e
+Fo(v)m(ariable.)23 b(This)17 b(means)e(that)g(users)h(can)g(ha)o(v)o(e)g(`)p
+Fl(/vol/tex/bin)p Fo(')d(in)j(their)0 2342 y(`)p Fl(PATH)p
+Fo(')e(without)h(concern)h(for)e(arc)o(hitecture)i(dep)q(endencies.)0
+2504 y Fq(8.4)33 b(Wildcard)17 b(names)e(&)g(Replicated)i(Serv)n(ers)62
+2595 y Fo(By)h(using)g(the)g(wildcard)h(facilit)o(y)l(,)g Fp(Amd)h
+Fo(can)e Fp(o)o(v)o(erla)o(y)j Fo(an)c(existing)i(directory)f(with)g
+(additional)h(en)o(tries.)0 2645 y(The)12 b(system)f(\014les)i(are)e(usually)
+j(moun)o(ted)d(under)i(`)p Fl(/usr)p Fo('.)k(If)12 b(instead)g
+Fp(Amd)i Fo(is)e(moun)o(ted)g(on)g(`)p Fl(/usr)p Fo(',)f(additional)p
+eop
+%%Page: 49 51
+49 50 bop 0 -83 a Fo(Chapter)15 b(8:)k(Examples)1300 b(SMM:13-49)0
+158 y(names)18 b(can)g(b)q(e)h(o)o(v)o(erla)o(y)o(ed)e(to)h(augmen)o(t)f(or)h
+(replace)h(names)f(in)g(the)h(\\master")d(`)p Fl(/usr)p Fo('.)27
+b(A)18 b(map)g(to)g(do)g(this)0 208 y(w)o(ould)e(ha)o(v)o(e)e(the)i(form:)120
+279 y Fl(local)47 b(type:=auto;fs:=local-map)120 329 y(share)g
+(type:=auto;fs:=share-map)120 378 y(*)143 b(-type:=nfs;rfs:=/export/ex)o
+(ec/${arc)o(h};subl)o(ink:="$)o({key}")21 b(\\)311 428 y(rhost:=fserv1)46
+b(rhost:=fserv2)g(rhost:=fserv3)62 519 y Fo(Note)11 b(that)g(the)g(assignmen)
+o(t)g(to)g Fl(${sublink})f Fo(is)i(surrounded)g(b)o(y)f(double)i(quotes)e(to)
+f(prev)o(en)o(t)h(the)h(incoming)0 569 y(k)o(ey)j(from)f(causing)i(the)f(map)
+f(to)h(b)q(e)g(misin)o(terpreted.)21 b(This)16 b(map)f(has)f(the)h(e\013ect)g
+(of)g(directing)h(an)o(y)f(access)g(to)0 619 y(`)p Fl(/usr/local)p
+Fo(')e(or)i(`)p Fl(/usr/share)p Fo(')e(to)h(another)h(automoun)o(t)f(p)q(oin)
+o(t.)62 690 y(In)i(this)g(example,)g(it)g(is)f(assumed)h(that)f(the)g(`)p
+Fl(/usr)p Fo(')f(\014les)i(are)f(replicated)i(on)f(three)f(\014leserv)o(ers:)
+21 b(`)p Fl(fserv1)p Fo(',)0 739 y(`)p Fl(fserv2)p Fo(')15
+b(and)h(`)p Fl(fserv3)p Fo('.)21 b(F)l(or)16 b(an)o(y)g(references)h(other)f
+(than)g(to)f(`)p Fl(local)p Fo(')g(and)h(`)p Fl(share)p Fo(')f(one)i(of)e
+(the)i(serv)o(ers)e(is)0 789 y(used)j(and)g(a)f(sym)o(b)q(olic)i(link)g(to)e
+Fl(${autodir}/${rhost}/expo)o(rt/exec/)o(${arch})o(/)p Fp(whatev)o(er)g
+Fo(is)i(returned)0 839 y(once)d(an)f(appropriate)g(\014lesystem)h(has)f(b)q
+(een)h(moun)o(ted.)0 1011 y Fq(8.5)33 b(`)p Fg(rwho)p Fq(')13
+b(serv)n(ers)62 1102 y Fo(The)j(`)p Fl(/usr/spool/rwho)p Fo(')c(directory)j
+(is)h(a)f(go)q(o)q(d)g(candidate)h(for)f(automoun)o(ting.)k(F)l(or)c
+(e\016ciency)h(reasons)0 1152 y(it)d(is)f(b)q(est)h(to)f(capture)g(the)h
+(rwho)e(data)h(on)g(a)g(small)i(n)o(um)o(b)q(er)e(of)g(mac)o(hines)h(and)g
+(then)f(moun)o(t)g(that)g(information)0 1202 y(on)o(to)g(a)h(large)g(n)o(um)o
+(b)q(er)h(of)f(clien)o(ts.)20 b(The)14 b(data)e(written)i(in)o(to)f(the)g
+(rwho)g(\014les)h(is)g(b)o(yte)f(order)g(dep)q(enden)o(t)i(so)d(only)0
+1252 y(serv)o(ers)j(with)g(the)h(correct)e(b)o(yte)h(ordering)h(can)f(b)q(e)h
+(used)g(b)o(y)f(a)g(clien)o(t:)120 1322 y Fl(/defaults)214
+b(type:=nfs)120 1372 y(usr/spool/rwho)94 b(-byte==little;rfs:=/usr)o(/spool/)
+o(rwho)21 b(\\)645 1422 y(rhost:=vaxA)46 b(rhost:=vaxB)23 b(\\)550
+1472 y(||)g(-rfs:=/usr/spool/rwho)e(\\)645 1521 y(rhost:=sun4)46
+b(rhost:=hp300)0 1694 y Fq(8.6)33 b(`)p Fg(/vol)p Fq(')62 1786
+y Fo(`)p Fl(/vol)p Fo(')14 b(is)i(used)g(as)e(a)h(catc)o(h-all)h(for)f(v)o
+(olumes)g(whic)o(h)i(do)e(not)f(ha)o(v)o(e)h(other)g(con)o(v)o(en)o(tional)h
+(names.)62 1856 y(Belo)o(w)21 b(is)f(part)g(of)f(the)h(`)p
+Fl(/vol)p Fo(')f(map)h(for)g(the)g(domain)g(`)p Fl(doc.ic.ac.uk)p
+Fo('.)32 b(The)21 b(`)p Fl(r+d)p Fo(')d(tree)i(is)h(used)g(for)0
+1906 y(new)15 b(or)e(exp)q(erimen)o(tal)j(soft)o(w)o(are)d(that)g(needs)i(to)
+f(b)q(e)h(a)o(v)m(ailable)h(ev)o(erywhere)e(without)h(installing)h(it)e(on)h
+(all)g(the)0 1956 y(\014leserv)o(ers.)24 b(Users)16 b(wishing)i(to)d(try)h
+(out)g(the)g(new)h(soft)o(w)o(are)d(then)j(simply)h(include)g(`)p
+Fl(/vol/r+d/{bin,ucb})p Fo(')0 2006 y(in)e(their)g(path.)62
+2076 y(The)e(main)g(tree)f(resides)h(on)g(one)f(host)g(`)p
+Fl(gould.doc.ic.ac.uk)p Fo(',)d(whic)o(h)15 b(has)e(di\013eren)o(t)h(`)p
+Fl(bin)p Fo(',)e(`)p Fl(etc)p Fo(',)g(`)p Fl(lib)p Fo(')0 2126
+y(and)k(`)p Fl(ucb)p Fo(')e(sub-directories)k(for)d(eac)o(h)g(mac)o(hine)i
+(arc)o(hitecture.)k(F)l(or)15 b(example,)i(`)p Fl(/vol/r+d/bin)p
+Fo(')c(for)i(a)g(Sun-4)0 2176 y(w)o(ould)e(b)q(e)g(stored)e(in)j(the)e
+(sub-directory)h(`)p Fl(bin/sun4)p Fo(')d(of)i(the)h(\014lesystem)g(`)p
+Fl(/usr/r+d)p Fo('.)k(When)12 b(it)h(w)o(as)e(accessed)0 2226
+y(a)k(sym)o(b)q(olic)h(link)h(p)q(oin)o(ting)f(to)f(`)p Fl
+(/a/gould/usr/r+d/bin/s)o(un4)p Fo(')d(w)o(ould)j(b)q(e)h(returned.)120
+2296 y Fl(/defaults)94 b(type:=nfs;opts:=rw,grpid,nos)o(uid,int)o(r,soft)120
+2346 y(wp)262 b(-opts:=rw,grpid,nosuid;rhost)o(:=charm)20 b(\\)430
+2396 y(host==charm;type:=link;fs:=/)o(usr/loc)o(al/wp)h(\\)430
+2446 y(host!=charm;type:=nfs;rfs:=/)o(vol/wp)120 2496 y(...)120
+2545 y(#)120 2595 y(src)238 b(-opts:=rw,grpid,nosuid;rhost)o(:=charm)20
+b(\\)430 2645 y(host==charm;type:=link;fs:=/)o(usr/src)g(\\)p
+eop
+%%Page: 50 52
+50 51 bop 15 -83 a Fo(SMM:13-50)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)430 158 y Fl(host!=charm;type:=nfs;rfs:=/)o(vol/src)
+120 208 y(#)120 258 y(r+d)238 b(type:=auto;fs:=${map};pref:=)o(r+d/)120
+308 y(#)24 b(per)f(architecture)f(bin,etc,lib&ucb...)120 358
+y(r+d/bin)142 b(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)o(blink:=$)o
+({/key}/)o(${arch})120 407 y(r+d/etc)g(rhost:=gould.doc.ic.ac.uk;rf)o
+(s:=/usr)o(/r+d;su)o(blink:=$)o({/key}/)o(${arch})120 457 y(r+d/include)46
+b(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)o(blink:=$)o({/key})120
+507 y(r+d/lib)142 b(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)o
+(blink:=$)o({/key}/)o(${arch})120 557 y(r+d/man)g
+(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)o(blink:=$)o({/key})120
+607 y(r+d/src)g(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)o(blink:=$)o
+({/key})120 656 y(r+d/ucb)g(rhost:=gould.doc.ic.ac.uk;rf)o(s:=/usr)o(/r+d;su)
+o(blink:=$)o({/key}/)o(${arch})120 706 y(#)24 b(hades)f(pictures)120
+756 y(pictures)118 b(-opts:=rw,grpid,nosuid;rhost)o(:=thpfs)20
+b(\\)430 806 y(host==thpfs;type:=link;fs:=/)o(nbsd/pi)o(ctures)g(\\)430
+856 y(host!=thpfs;type:=nfs;rfs:=/)o(nbsd;su)o(blink:=)o(pictures)120
+906 y(#)k(hades)f(tools)120 955 y(hades)190 b(-opts:=rw,grpid,nosuid;rhost)o
+(:=thpfs)20 b(\\)430 1005 y(host==thpfs;type:=link;fs:=/)o(nbsd/ha)o(des)h
+(\\)430 1055 y(host!=thpfs;type:=nfs;rfs:=/)o(nbsd;su)o(blink:=)o(hades)120
+1105 y(#)j(bsd)f(tools)g(for)h(hp.)120 1155 y(bsd)238 b
+(-opts:=rw,grpid,nosuid;arch=)o(=hp9000)o(;rhost:)o(=thpfs)21
+b(\\)430 1204 y(host==thpfs;type:=link;fs:=/)o(nbsd/bs)o(d)g(\\)430
+1254 y(host!=thpfs;type:=nfs;rfs:=/)o(nbsd;su)o(blink:=)o(bsd)0
+1468 y Fm(9)41 b(In)n(ternals)0 1709 y Fq(9.1)33 b(Log)14 b(Messages)62
+1800 y Fo(In)h(the)f(follo)o(wing)h(sections)g(a)f(brief)g(explanation)i(is)e
+(giv)o(en)h(of)e(some)h(of)g(the)g(log)g(messages)g(made)g(b)o(y)g
+Fp(Amd)p Fo(.)0 1850 y(Where)20 b(the)f(message)g(is)h(in)h(`)p
+Fl(typewriter)p Fo(')c(fon)o(t,)i(it)h(corresp)q(onds)g(exactly)g(to)f(the)g
+(message)g(pro)q(duced)i(b)o(y)0 1900 y Fp(Amd)p Fo(.)i(W)l(ords)16
+b(in)i Fp(italic)i Fo(are)c(replaced)i(b)o(y)e(an)g(appropriate)g(string.)24
+b(V)l(ariables,)17 b Fl(${var})p Fo(,)e(indicate)j(that)e(the)0
+1950 y(v)m(alue)g(of)f(the)g(appropriate)h(v)m(ariable)g(is)g(output.)62
+2020 y(Log)h(messages)f(are)g(either)h(sen)o(t)g(direct)g(to)f(a)g(\014le,)i
+(or)e(logged)h(via)g(the)f Fk(syslog)p Fo(\(3\))g(mec)o(hanism.)25
+b(Messages)0 2070 y(are)15 b(logged)g(with)g(facilit)o(y)h(`)p
+Fl(LOG_DAEMON)p Fo(')d(when)i(using)h Fk(syslog)p Fo(\(3\).)j(In)c(either)h
+(case,)f(en)o(tries)g(in)h(the)f(\014le)h(are)e(of)0 2120 y(the)h(form:)120
+2191 y Fp(date-string)52 b(hostname)26 b Fl(amd[)p Fp(pid)r
+Fl(])48 b Fp(message)0 2355 y Fi(9.1.1)30 b(F)-5 b(atal)14
+b(errors)62 2446 y Fp(Amd)20 b Fo(attempts)c(to)h(deal)h(with)g(un)o(usual)g
+(ev)o(en)o(ts.)27 b(Whenev)o(er)17 b(it)h(is)g(not)f(p)q(ossible)i(to)e(deal)
+h(with)g(suc)o(h)g(an)0 2496 y(error,)d Fp(Amd)k Fo(will)f(log)e(an)g
+(appropriate)h(message)e(and,)i(if)f(it)h(cannot)f(p)q(ossibly)i(con)o(tin)o
+(ue,)f(will)h(either)f(exit)f(or)0 2545 y(ab)q(ort.)24 b(These)17
+b(messages)f(are)g(selected)i(b)o(y)e(`)p Fl(-x)f(fatal)p Fo(')g(on)i(the)g
+(command)f(line.)26 b(When)17 b Fk(syslog)p Fo(\(3\))f(is)h(b)q(eing)0
+2595 y(used,)22 b(they)e(are)g(logged)h(with)g(lev)o(el)g(`)p
+Fl(LOG_FATAL)p Fo('.)34 b(Ev)o(en)20 b(if)h Fp(Amd)h Fo(con)o(tin)o(ues)f(to)
+f(op)q(erate)g(it)h(is)f(lik)o(ely)j(to)0 2645 y(remain)16
+b(in)g(a)f(precarious)g(state)g(and)g(should)h(b)q(e)g(restarted)e(at)h(the)g
+(earliest)h(opp)q(ortunit)o(y)l(.)p eop
+%%Page: 51 53
+51 52 bop 0 -83 a Fo(Chapter)15 b(9:)k(In)o(ternals)1317 b(SMM:13-51)0
+158 y Fl(Attempting)22 b(to)i(inherit)f(not-a-filesystem)240
+219 y Fo(The)14 b(protot)o(yp)q(e)g(moun)o(t)g(p)q(oin)o(t)g(created)h
+(during)g(a)f(\014lesystem)h(restart)e(did)i(not)f(con)o(tain)g(a)g(refer-)
+240 269 y(ence)i(to)f(the)g(restarted)f(\014lesystem.)21 b(This)16
+b(erorr)e(\\should)i(nev)o(er)f(happ)q(en".)0 330 y Fl(Can't)23
+b(bind)g(to)h(domain)f(")p Fp(NIS-domain)p Fl(")240 391 y Fo(A)e(sp)q
+(eci\014c)i(NIS)e(domain)h(w)o(as)e(requested)h(on)g(the)g(command)f(line,)k
+(but)d(no)g(serv)o(er)f(for)h(that)240 441 y(domain)16 b(is)f(a)o(v)m
+(ailable)i(on)e(the)h(lo)q(cal)g(net.)0 502 y Fl(Can't)23 b(determine)g(IP)g
+(address)g(of)h(this)f(host)h(\()p Fp(hostname)s Fl(\))240
+563 y Fo(When)11 b Fp(Amd)h Fo(starts)d(it)i(determines)g(its)g(o)o(wn)e(IP)i
+(address.)18 b(If)11 b(this)g(lo)q(okup)g(fails)g(then)g Fp(Amd)h
+Fo(cannot)240 612 y(con)o(tin)o(ue.)19 b(The)11 b(hostname)e(it)i(lo)q(oks)g
+(up)g(is)f(that)g(obtained)h(returned)g(b)o(y)f Fk(gethostname)p
+Fo(\(2\))f(system)240 662 y(call.)0 723 y Fl(Can't)23 b(find)g(root)h(file)f
+(handle)g(for)h Fp(automoun)o(t)14 b(p)q(oin)o(t)240 784 y(Amd)19
+b Fo(creates)d(its)h(o)o(wn)g(\014le)g(handles)h(for)f(the)f(automoun)o(t)g
+(p)q(oin)o(ts.)25 b(When)17 b(it)g(moun)o(ts)g(itself)g(as)240
+834 y(a)i(serv)o(er,)i(it)f(m)o(ust)f(pass)h(these)g(\014le)g(handles)h(to)f
+(the)g(lo)q(cal)g(k)o(ernel.)35 b(If)20 b(the)g(\014lehandle)i(is)e(not)240
+884 y(obtainable)c(the)g(moun)o(t)e(p)q(oin)o(t)i(is)g(ignored.)k(This)c
+(error)e(\\should)i(nev)o(er)g(happ)q(en".)0 945 y Fl(Must)23
+b(be)h(root)f(to)h(mount)f(filesystems)f(\(euid)i(=)f Fp(euid)r
+Fl(\))240 1006 y Fo(T)l(o)13 b(prev)o(en)o(t)f(em)o(barrassmen)o(t,)g
+Fp(Amd)j Fo(mak)o(es)d(sure)h(it)g(has)g(appropriate)g(system)f(privileges.)
+21 b(This)240 1055 y(amoun)o(ts)12 b(to)g(ha)o(ving)h(an)f(euid)i(of)f(0.)18
+b(The)13 b(c)o(hec)o(k)g(is)g(made)g(after)f(argumen)o(t)g(pro)q(cessing)h
+(complete)240 1105 y(to)i(giv)o(e)g(non-ro)q(ot)g(users)g(a)g(c)o(hance)h(to)
+e(access)h(the)h(\\-v")f(option.)0 1166 y Fl(No)24 b(work)f(to)g(do)h(-)g
+(quitting)240 1227 y Fo(No)15 b(automoun)o(t)f(p)q(oin)o(ts)i(w)o(ere)f(giv)o
+(en)g(on)g(the)h(command)f(line)i(and)e(so)g(there)g(is)h(no)f(w)o(ork)f(to)h
+(do.)0 1288 y Fl(Out)23 b(of)h(memory)f(in)h(realloc)240 1349
+y Fo(While)c(attempting)e(to)g(reallo)q(c)h(some)f(memory)l(,)h(the)f(memory)
+g(space)h(a)o(v)m(ailable)h(to)d Fp(Amd)k Fo(w)o(as)240 1399
+y(exhausted.)f(This)c(is)g(an)f(unreco)o(v)o(erable)h(error.)0
+1460 y Fl(Out)23 b(of)h(memory)240 1521 y Fo(While)c(attempting)e(to)g(mallo)
+q(c)h(some)f(memory)l(,)h(the)f(memory)g(space)h(a)o(v)m(ailable)h(to)d
+Fp(Amd)k Fo(w)o(as)240 1570 y(exhausted.)f(This)c(is)g(an)f(unreco)o(v)o
+(erable)h(error.)0 1631 y Fl(cannot)23 b(create)g(rpc/udp)g(service)240
+1692 y Fo(Either)16 b(the)f(NFS)g(or)g(AMQ)g(endp)q(oin)o(t)h(could)h(not)d
+(b)q(e)i(created.)0 1753 y Fl(gethostname:)e Fp(description)240
+1814 y Fo(The)h Fk(gethostname)p Fo(\(2\))f(system)h(call)i(failed)f(during)g
+(startup.)0 1875 y Fl(host)23 b(name)h(is)f(not)h(set)240 1936
+y Fo(The)14 b Fk(gethostname)p Fo(\(2\))g(system)f(call)j(returned)e(a)g
+(zero)h(length)f(host)g(name.)20 b(This)15 b(can)f(happ)q(en)h(if)240
+1986 y Fp(Amd)i Fo(is)f(started)e(in)i(single)h(user)e(mo)q(de)h(just)f
+(after)f(b)q(o)q(oting)i(the)f(system.)0 2047 y Fl(ifs_match)23
+b(called!)240 2108 y Fo(An)i(in)o(ternal)g(error)f(o)q(ccurred)h(while)i
+(restarting)d(a)g(pre-moun)o(ted)h(\014lesystem.)48 b(This)26
+b(error)240 2158 y(\\should)16 b(nev)o(er)f(happ)q(en".)0 2219
+y Fl(mount_afs:)f Fp(description)240 2279 y Fo(An)h(error)g(o)q(ccured)h
+(while)h Fp(Amd)g Fo(w)o(as)d(moun)o(ting)i(itself.)0 2340
+y Fl(run_rpc)23 b(failed)240 2401 y Fo(Someho)o(w)15 b(the)g(main)h(NFS)f
+(serv)o(er)g(lo)q(op)g(failed.)22 b(This)15 b(error)g(\\should)h(nev)o(er)f
+(happ)q(en".)0 2462 y Fl(unable)23 b(to)h(free)f(rpc)g(arguments)g(in)h
+(amqprog_1)240 2523 y Fo(The)15 b(incoming)i(argumen)o(ts)d(to)h(the)g(AMQ)g
+(serv)o(er)g(could)h(not)f(b)q(e)h(free'ed.)0 2584 y Fl(unable)23
+b(to)h(free)f(rpc)g(arguments)g(in)h(nfs_program_1)240 2645
+y Fo(The)15 b(incoming)i(argumen)o(ts)d(to)h(the)g(NFS)g(serv)o(er)g(could)h
+(not)f(b)q(e)h(free'ed.)p eop
+%%Page: 52 54
+52 53 bop 15 -83 a Fo(SMM:13-52)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fl(unable)23 b(to)h(register)e(\(AMQ_PROGRAM,)
+g(AMQ_VERSION,)h(udp\))240 221 y Fo(The)d(AMQ)g(serv)o(er)g(could)g(not)g(b)q
+(e)g(registered)h(with)f(the)g(lo)q(cal)h(p)q(ortmapp)q(er)f(or)f(the)h(in)o
+(ternal)240 271 y(RPC)15 b(dispatc)o(her.)0 334 y Fl(unable)23
+b(to)h(register)e(\(NFS_PROGRAM,)g(NFS_VERSION,)h(0\))240 397
+y Fo(The)15 b(NFS)h(serv)o(er)e(could)j(not)d(b)q(e)i(registered)g(with)f
+(the)h(in)o(ternal)g(RPC)f(dispatc)o(her.)0 543 y Fi(9.1.2)30
+b(Info)14 b(messages)62 634 y Fp(Amd)f Fo(generates)e(information)g(messages)
+g(to)f(record)i(state)e(c)o(hanges.)18 b(These)12 b(messages)e(are)h
+(selected)i(b)o(y)e(`)p Fl(-x)0 684 y(info)p Fo(')j(on)h(the)h(command)f
+(line.)21 b(When)16 b Fk(syslog)p Fo(\(3\))e(is)i(b)q(eing)g(used,)g(they)f
+(are)g(logged)g(with)h(lev)o(el)g(`)p Fl(LOG_INFO)p Fo('.)62
+754 y(The)h(messages)f(listed)i(b)q(elo)o(w)g(can)f(b)q(e)g(generated)g(and)g
+(are)f(in)i(a)e(format)f(suitable)j(for)e(simple)j(statistical)0
+804 y(analysis.)24 b Fp(moun)o(t-info)18 b Fo(is)f(the)g(string)f(that)f(is)i
+(displa)o(y)o(ed)h(b)o(y)e Fp(Amq)h Fo(in)g(its)g(moun)o(t)e(information)i
+(column)g(and)0 854 y(placed)f(in)g(the)g(system)e(moun)o(t)h(table.)0
+924 y Fl(mount)23 b(of)h("${)p Fp(path)p Fl(}")f(on)g(${)p
+Fp(fs)r Fl(})h(timed)f(out)240 987 y Fo(A)o(ttempts)13 b(to)h(moun)o(t)f(a)h
+(\014lesystem)h(for)f(the)g(giv)o(en)h(automoun)o(t)e(p)q(oin)o(t)h(ha)o(v)o
+(e)g(failed)i(to)d(complete)240 1037 y(within)j(30)f(seconds.)0
+1100 y Fl("${)p Fp(path)p Fl(}")23 b(forcibly)g(timed)g(out)240
+1163 y Fo(An)15 b(automoun)o(t)g(p)q(oin)o(t)g(has)g(b)q(een)i(timed)e(out)g
+(b)o(y)g(the)h Fp(Amq)g Fo(command.)0 1226 y Fl(restarting)22
+b Fp(moun)o(t-info)27 b Fl(on)c(${)p Fp(fs)r Fl(})240 1288
+y Fo(A)15 b(pre-moun)o(ted)h(\014le)g(system)f(has)g(b)q(een)h(noted.)0
+1351 y Fl("${)p Fp(path)p Fl(}")23 b(has)h(timed)f(out)240
+1414 y Fo(No)15 b(access)g(to)g(the)g(automoun)o(t)f(p)q(oin)o(t)i(has)f(b)q
+(een)h(made)f(within)i(the)e(timeout)g(p)q(erio)q(d.)0 1477
+y Fl(file)23 b(server)g(${)p Fp(rhost)q Fl(})g(is)h(down)f(-)h(timeout)f(of)g
+("${)p Fp(path)p Fl(}")g(ignored)240 1540 y Fo(An)18 b(automoun)o(t)e(p)q
+(oin)o(t)i(has)f(timed)h(out,)f(but)h(the)g(corresp)q(onding)g(\014le)g(serv)
+o(er)f(is)h(kno)o(wn)g(to)e(b)q(e)240 1590 y(do)o(wn.)23 b(This)17
+b(message)f(is)h(only)g(pro)q(duced)g(once)g(for)f(eac)o(h)g(moun)o(t)g(p)q
+(oin)o(t)h(for)f(whic)o(h)h(the)f(serv)o(er)240 1639 y(is)g(do)o(wn.)0
+1702 y Fl(Re-synchronizing)22 b(cache)h(for)g(map)h(${)p Fp(map)q
+Fl(})240 1765 y Fo(The)15 b(named)h(map)f(has)g(b)q(een)h(mo)q(di\014ed)h
+(and)e(the)h(in)o(ternal)g(cac)o(he)f(is)h(b)q(eing)g(re-sync)o(hronized.)0
+1828 y Fl(Filehandle)22 b(denied)i(for)f("${)p Fp(rhost)q Fl(}:${)p
+Fp(rfs)r Fl(}")240 1891 y Fo(The)15 b(moun)o(t)g(daemon)g(refused)h(to)f
+(return)g(a)g(\014le)h(handle)g(for)f(the)g(requested)h(\014lesystem.)0
+1954 y Fl(Filehandle)22 b(error)i(for)f("${)p Fp(rhost)q Fl(}:${)p
+Fp(rfs)r Fl(}":)13 b Fp(description)240 2017 y Fo(The)i(moun)o(t)g(daemon)g
+(ga)o(v)o(e)g(some)f(other)h(error)g(for)f(the)i(requested)f(\014lesystem.)0
+2079 y Fl(file)23 b(server)g(${)p Fp(rhost)q Fl(})g(type)h(nfs)f(starts)g(up)
+240 2142 y Fo(A)15 b(new)h(NFS)f(\014le)h(serv)o(er)f(has)g(b)q(een)h
+(referenced)g(and)g(is)g(kno)o(wn)e(to)h(b)q(e)h(up.)0 2205
+y Fl(file)23 b(server)g(${)p Fp(rhost)q Fl(})g(type)h(nfs)f(starts)g(down)240
+2268 y Fo(A)15 b(new)h(NFS)f(\014le)h(serv)o(er)f(has)g(b)q(een)h(referenced)
+g(and)g(is)g(kno)o(wn)e(to)h(b)q(e)h(do)o(wn.)0 2331 y Fl(file)23
+b(server)g(${)p Fp(rhost)q Fl(})g(type)h(nfs)f(is)h(up)240
+2394 y Fo(An)15 b(NFS)h(\014le)g(serv)o(er)f(that)f(w)o(as)h(previously)h(do)
+o(wn)f(is)h(no)o(w)e(up.)0 2457 y Fl(file)23 b(server)g(${)p
+Fp(rhost)q Fl(})g(type)h(nfs)f(is)h(down)240 2519 y Fo(An)15
+b(NFS)h(\014le)g(serv)o(er)f(that)f(w)o(as)h(previously)h(up)g(is)f(no)o(w)g
+(do)o(wn.)0 2582 y Fl(Finishing)23 b(with)g(status)g Fp(exit-status)240
+2645 y(Amd)17 b Fo(is)f(ab)q(out)f(to)f(exit)i(with)g(the)f(giv)o(en)h(exit)f
+(status.)p eop
+%%Page: 53 55
+53 54 bop 0 -83 a Fo(Index)1613 b(SMM:13-53)0 158 y Fp(moun)o(t-info)26
+b Fl(mounted)d(fstype)g(${)p Fp(t)o(yp)q(e)s Fl(})g(on)h(${)p
+Fp(fs)r Fl(})240 221 y Fo(A)15 b(new)h(\014le)g(system)f(has)g(b)q(een)h
+(moun)o(ted.)0 283 y Fp(moun)o(t-info)26 b Fl(restarted)d(fstype)g(${)p
+Fp(t)o(yp)q(e)s Fl(})g(on)h(${)p Fp(fs)r Fl(})240 345 y Fp(Amd)17
+b Fo(is)f(using)g(a)f(pre-moun)o(ted)g(\014lesystem)h(to)f(satisfy)g(a)f
+(moun)o(t)h(request.)0 407 y Fp(moun)o(t-info)26 b Fl(unmounted)d(fstype)g
+(${)p Fp(t)o(yp)q(e)s Fl(})g(from)g(${)p Fp(fs)r Fl(})240 470
+y Fo(A)15 b(\014le)h(system)f(has)g(b)q(een)i(unmoun)o(ted.)0
+532 y Fp(moun)o(t-info)26 b Fl(unmounted)d(fstype)g(${)p Fp(t)o(yp)q(e)s
+Fl(})g(from)g(${)p Fp(fs)r Fl(})h(link)f(${)p Fp(fs)r Fl(}/${)p
+Fp(sublink)s Fl(})240 594 y Fo(A)15 b(\014le)h(system)f(of)g(whic)o(h)h(only)
+g(a)f(sub-directory)h(w)o(as)e(in)i(use)g(has)f(b)q(een)h(unmoun)o(ted.)0
+784 y Fm(Ac)n(kno)n(wledgemen)n(ts)e(&)h(T)-7 b(rademarks)62
+904 y Fo(Thanks)19 b(to)g(the)g(F)l(ormal)f(Metho)q(ds)h(Group)g(at)f(Imp)q
+(erial)j(College)f(for)e(su\013ering)i(patien)o(tly)f(while)i
+Fp(Amd)0 954 y Fo(w)o(as)14 b(b)q(eing)j(dev)o(elop)q(ed)g(on)e(their)h(mac)o
+(hines.)62 1024 y(Thanks)j(to)f(the)h(man)o(y)f(p)q(eople)i(who)e(ha)o(v)o(e)
+h(help)q(ed)h(with)f(the)g(dev)o(elopmen)o(t)h(of)e Fp(Amd)p
+Fo(,)h(esp)q(ecially)i(Piete)0 1074 y(Bro)q(oks)c(at)g(the)h(Cam)o(bridge)g
+(Univ)o(ersit)o(y)g(Computing)g(Lab)g(for)f(man)o(y)g(hours)h(of)f(testing,)h
+(exp)q(erimen)o(tation)0 1124 y(and)d(discussion.)37 1195 y
+Fn(\017)30 b Fk(DEC)p Fo(,)14 b Fk(V)-5 b(AX)16 b Fo(and)g
+Fk(Ultrix)g Fo(are)f(registered)h(trademarks)e(of)h(Digital)h(Equipmen)o(t)g
+(Corp)q(oration.)37 1257 y Fn(\017)30 b Fk(AIX)16 b Fo(and)f
+Fk(IBM)h Fo(are)f(registered)g(trademarks)g(of)f(In)o(ternational)i(Business)
+h(Mac)o(hines)e(Corp)q(oration.)37 1319 y Fn(\017)30 b Fk(Sun)p
+Fo(,)16 b Fk(NFS)e Fo(and)h Fk(SunOS)i Fo(are)e(registered)g(trademarks)f(of)
+h(Sun)h(Microsystems,)e(Inc.)37 1381 y Fn(\017)30 b Fk(Unix)20
+b Fo(is)f(a)g(registered)g(trademark)f(of)h(A)l(T&T)g(Unix)h(Systems)f(Lab)q
+(oratories)g(in)h(the)f(USA)g(and)g(other)90 1431 y(coun)o(tries.)0
+1606 y Fm(Index)0 1826 y Fc(/etc/amd.start)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(33)0 1871
+y(/etc/passwd)d(maps)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)22 b Fc(13)0 1917 y(/etc/rc.lo)q(cal)15 b(additions)e
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(33)0 1963
+y(/v)o(ol)11 b Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)22 b
+Fc(56)0 2008 y(Additions)15 b(to)e(/etc/rc.lo)q(cal)7 b Fb(:)h(:)f(:)f(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)20 b Fc(33)0 2054 y(Aliased)15 b(hostnames)8 b Fb(:)f(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fc(22)0 2100 y(Alternate)14
+b(lo)q(cations)t Fb(:)8 b(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)17 b Fc(6)0 2145 y(Amd)c(command)h(line)g(options)8 b Fb(:)g(:)e(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)21 b Fc(21)0 2191 y(Amq)13 b(command)d Fb(:)d(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)22 b Fc(33)0 2236 y(arc)o(h,)13
+b(FSinfo)h(host)g(attribute)6 b Fb(:)h(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)19
+b Fc(41)0 2282 y(arc)o(h,)13 b(moun)o(t)h(selector)c Fb(:)c(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(16)0 2328 y(Arc)o(hitecture)14
+b(dep)q(enden)o(t)h(v)o(olumes)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)24 b Fc(55)0 2373 y(Arc)o(hitecture)14
+b(sharing)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(55)0 2419 y(Arc)o(hitecture)14 b(sp)q(eci\014c)h(moun)o(ts)9
+b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)22 b Fc(56)0 2465 y(A)o(tomic)13 b(NFS)g(moun)o(ts)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 b Fc(27)0
+2510 y(auto,)13 b(\014lesystem)i(t)o(yp)q(e)6 b Fb(:)g(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)19 b Fc(29)0 2556 y(auto)q(dir,)14 b(moun)o(t)g(selector)c
+Fb(:)c(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(16)0 2602 y(Automatic)14
+b(generation)h(of)d(user)i(maps)t Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(13)1015 1826 y(Automoun)o(t)d(directory)f
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b Fc(21)1015
+1871 y(Automoun)o(t)14 b(\014lesystem)t Fb(:)8 b(:)f(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)18 b Fc(29)1015 1917 y(Automoun)o(ter)c(con\014guration)i(maps)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)17 b Fc(11)1015 1963 y(Automoun)o(ter)d(fundamen)o(tals)f
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)23 b Fc(5)1015 2008 y(Bac)o(kground)15
+b(moun)o(ts)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(6)1015 2054 y(Binding)e(names)e(to)f(\014lesystems)6 b
+Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)19 b Fc(6)1015 2100 y(b)q(o)q(otparams,)c(FSinfo)f
+(pre\014x)s Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)16 b Fc(47)1015
+2145 y(Bug)e(rep)q(orts)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(3)1015 2191
+y(b)o(yte,)c(moun)o(t)f(selector)c Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)22 b Fc(16)1015 2236 y(Cac)o(he)14 b(in)o(terv)n(al)9
+b Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22
+b Fc(21)1015 2282 y(cac)o(he,)14 b(moun)o(t)f(option)e Fb(:)6
+b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(29)1015
+2328 y(Catc)o(h-all)15 b(moun)o(t)e(p)q(oin)o(t)f Fb(:)6 b(:)g(:)h(:)f(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)24 b Fc(56)1015 2373 y(Changing)15 b(the)e(in)o(terv)n(al)i(b)
+q(efore)e(a)g(\014lesystem)i(times)f(out)1098 2419 y Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)18 b Fc(21)1015 2465 y(Cluster)c(names)9
+b Fb(:)e(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)22
+b Fc(24)1015 2510 y(cluster,)14 b(FSinfo)g(host)g(attribute)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)17 b Fc(41)1015 2556 y(cluster,)d(moun)o(t)g(selector)6
+b Fb(:)h(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(17)1015
+2602 y(Command)14 b(line)h(options,)f(Amd)6 b Fb(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(21)p eop
+%%Page: 54 56
+54 55 bop 15 -83 a Fo(SMM:13-54)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fc(Command)d(line)g(options,)g(FSinfo)9
+b Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)22 b Fc(47)0 204 y(con\014g,)14 b(FSinfo)g(host)f(attribute)f
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)23 b Fc(40)0 250 y(Con\014guration)15 b(map)f(t)o(yp)q(es)
+6 b Fb(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fc(11)0 295 y(Con)o(trolling)e(Amd)t
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(34)0 341 y(Creating)d(a)f(pid)h(\014le)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)23 b Fc(22)0 387 y(Debug)14 b(options)8
+b Fb(:)f(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20
+b Fc(24)0 432 y(De\014ning)15 b(a)e(host,)g(FSinfo)g Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b Fc(39)0 478 y(De\014ning)15
+b(an)e(Amd)g(moun)o(t)h(map,)f(FSinfo)s Fb(:)7 b(:)f(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(45)0 524 y(De\014ning)f(host)e
+(attributes,)i(FSinfo)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(39)0 569 y(dela)o(y)m(,)14
+b(moun)o(t)f(option)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+17 b Fc(18)0 615 y(Dela)o(ying)e(moun)o(ts)f(from)f(sp)q(eci\014c)h(lo)q
+(cations)8 b Fb(:)h(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(18)0 661 y(Determining)15 b(the)f(map)f(t)o(yp)q(e)8 b
+Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(11)0 706 y(dev,)13 b(moun)o(t)h(option)8
+b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)21
+b Fc(28)0 752 y(Direct)14 b(automoun)o(t)g(\014lesystem)e Fb(:)6
+b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)23 b Fc(30)0 798 y(direct,)14 b(\014lesystem)g(t)o(yp)q(e)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(30)0
+843 y(Disco)o(v)o(ering)f(v)o(ersion)e(information)8 b Fb(:)h(:)d(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(23)0 889 y(Disco)o(v)o(ering)16 b(what)d(is)g(going)i(on)e(at)g
+(run-time)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20
+b Fc(34)0 935 y(Disk)14 b(\014lesystems)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(28)0 980 y(Displa)o(yin)q(g)f(the)
+d(pro)q(cess)h(id)t Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)16 b
+Fc(22)0 1026 y(Domain)f(name)s Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(21)0 1072 y(Domain)f(stripping)7
+b Fb(:)i(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20
+b Fc(15)0 1117 y(domain,)14 b(moun)o(t)g(selector)9 b Fb(:)e(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)22 b Fc(17)0 1163 y(Domainname)15 b(op)q(erators)c
+Fb(:)6 b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(15)0 1209 y(dumpset,)14
+b(FSinfo)g(\014lesystems)g(option)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(44)0 1254 y(dumpset,)14
+b(FSinfo)g(pre\014x)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(48)0 1300 y(Duplicated)e(v)o(olumes)7 b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(5)0 1346 y(En)o(vironmen)o(t)15
+b(v)n(ariables)9 b Fb(:)f(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22
+b Fc(15)0 1391 y(Error)13 b(\014lesystem)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(31)0 1437 y(error,)c
+(\014lesystem)h(t)o(yp)q(e)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24
+b Fc(31)0 1483 y(Example)14 b(of)f(arc)o(hitecture)i(sp)q(eci\014c)f(moun)o
+(ts)6 b Fb(:)h(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(56)0 1528 y(Example)14 b(of)f(moun)o(ting)i(home)e(directories)8
+b Fb(:)h(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b
+Fc(54)0 1574 y(exp)q(ort,)13 b(FSinfo)h(sp)q(ecial)i(fst)o(yp)q(e)8
+b Fb(:)e(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)21 b Fc(43)0 1620 y(exp)q(ortfs,)13 b(FSinfo)h(moun)o(t)g
+(option)f Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)24 b Fc(44)0 1665 y(exp)q(orts,)14 b(FSinfo)g(pre\014x)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)0
+1711 y(File)14 b(map)g(syn)o(tactic)g(con)o(v)o(en)o(tions)6
+b Fb(:)j(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)19 b Fc(11)0 1757 y(File)14 b(maps)t Fb(:)7 b(:)f(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(11)0 1802 y(Fileserv)o(er)6 b Fb(:)i(:)e(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b
+Fc(5)0 1848 y(Filesystem)c(info)f(pac)o(k)n(age)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)20 b Fc(38)0 1893 y(Filesystem)15 b(t)o(yp)q(e;)e(auto)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)20 b Fc(29)0
+1939 y(Filesystem)15 b(t)o(yp)q(e;)e(direct)5 b Fb(:)i(:)f(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)18 b Fc(30)0 1985 y(Filesystem)d(t)o(yp)q(e;)e(error)t
+Fb(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(31)0
+2030 y(Filesystem)e(t)o(yp)q(e;)e(host)d Fb(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)22 b Fc(26)0 2076 y(Filesystem)15 b(t)o(yp)q(e;)e(inherit)6
+b Fb(:)i(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(32)0 2122 y(Filesystem)c(t)o
+(yp)q(e;)e(linkx)s Fb(:)8 b(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16
+b Fc(29)0 2167 y(Filesystem)f(t)o(yp)q(e;)e(link)5 b Fb(:)j(:)e(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)17 b Fc(29)0 2213 y(Filesystem)e(t)o(yp)q(e;)e
+(nfsx)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 b
+Fc(27)0 2259 y(Filesystem)15 b(t)o(yp)q(e;)e(nfs)t Fb(:)6 b(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)16 b Fc(26)0 2304 y(Filesystem)f(t)o(yp)q(e;)e
+(program)8 b Fb(:)f(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)21 b Fc(28)0 2350
+y(Filesystem)15 b(t)o(yp)q(e;)e(ro)q(ot)d Fb(:)c(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)23 b Fc(31)0 2396 y(Filesystem)15 b(t)o(yp)q(e;)e(toplvl)5
+b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)17 b Fc(31)0 2441
+y(Filesystem)e(t)o(yp)q(e;)e(ufs)t Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)16 b Fc(28)0 2487 y(Filesystem)f(t)o(yp)q(e;)e(union)6
+b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(31)0 2533
+y(Filesystem)c(t)o(yp)q(es)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)19 b Fc(26)0 2578 y(Filesystem)7 b Fb(:)h(:)e(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19
+b Fc(5)0 2624 y(Flat)14 b(\014le)g(maps)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(11)1015
+158 y(Flushing)f(the)d(map)h(cac)o(he)6 b Fb(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)19 b Fc(35)1015 204 y(F)m(orcing)c(\014lesystem)f(to)f(time)g(out)5
+b Fb(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)18 b Fc(37)1015 250 y(freq,)13 b(FSinfo)h(\014lesystems)h
+(option)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)25 b Fc(43)1015 295 y(fs,)13 b(moun)o(t)g(option)7
+b Fb(:)h(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(18)1015 341 y(FSinfo)15 b(arc)o(h)e(host)g(attribute)s
+Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)16 b Fc(41)1015 387 y(FSinfo)f(automoun)o(t)f
+(de\014nitions)s Fb(:)9 b(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)16 b Fc(45)1015 432 y(FSinfo)f(cluster)f
+(host)f(attribute)c Fb(:)e(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 b Fc(41)1015 478 y(FSinfo)15
+b(command)f(line)g(options)f Fb(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)24 b Fc(47)1015
+524 y(FSinfo)15 b(con\014g)f(host)f(attribute)7 b Fb(:)g(:)f(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20
+b Fc(40)1015 569 y(FSinfo)15 b(dumpset)f(\014lesystems)g(option)f
+Fb(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25
+b Fc(44)1015 615 y(FSinfo)15 b(error)e(messages)6 b Fb(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)19 b Fc(49)1015 661 y(FSinfo)c(\014lesystems)t
+Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)17
+b Fc(41)1015 706 y(FSinfo)e(freq)e(\014lesystems)h(option)8
+b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)22 b Fc(43)1015 752 y(FSinfo)15 b(fst)o(yp)q(e)e
+(\014lesystems)h(option)7 b Fb(:)h(:)e(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fc(43)1015 798 y(FSinfo)15
+b(grammar)9 b Fb(:)d(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)22 b Fc(39)1015 843 y(FSinfo)15 b(host)e(attributes)t Fb(:)7
+b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(39)1015 889
+y(FSinfo)e(host)e(de\014nitions)8 b Fb(:)h(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)
+21 b Fc(39)1015 935 y(FSinfo)15 b(log)e(\014lesystems)i(option)7
+b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)21 b Fc(45)1015 980 y(FSinfo)15 b(moun)o(t)e
+(\014lesystems)i(option)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(44)1015 1026 y(FSinfo)e(opts)e
+(\014lesystems)i(option)5 b Fb(:)i(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fc(43)1015 1072
+y(FSinfo)d(os)e(host)g(attribute)5 b Fb(:)i(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(41)1015 1117 y(FSinfo)d(o)o(v)o(erview)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(38)1015 1163
+y(FSinfo)e(passno)f(\014lesystems)g(option)e Fb(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(43)1015
+1209 y(FSinfo)15 b(static)e(moun)o(ts)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)19 b Fc(45)1015 1254 y(FSinfo)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)19 b Fc(38)1015 1300 y(fstab,)13 b(FSinfo)h(pre\014x)e Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)23 b Fc(48)1015
+1346 y(fst)o(yp)q(e,)13 b(FSinfo)i(\014lesystems)f(option)e
+Fb(:)6 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)24 b Fc(43)1015 1391 y(Generic)15 b(v)o(olume)f(name)7 b
+Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fc(56)1015
+1437 y(Global)15 b(statistics)d Fb(:)6 b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)23 b Fc(36)1015 1483 y(Grammar,)14 b(FSinfo)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)20
+b Fc(39)1015 1528 y(Hesio)q(d)15 b(maps)5 b Fb(:)h(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)18 b Fc(13)1015
+1574 y(Home)13 b(directories)t Fb(:)c(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)18 b Fc(54)1015 1620 y(host,)c(\014lesystem)g(t)o(yp)q(e)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)21 b Fc(26)1015
+1665 y(host,)14 b(moun)o(t)f(selector)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)23 b Fc(17)1015 1711 y(hostd,)14 b(moun)o(t)f(selector)8
+b Fb(:)f(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(17)1015
+1757 y(Hostname)14 b(normalisation)f Fb(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23
+b Fc(22)1015 1802 y(hostname,)14 b(FSinfo)g(command)g(line)h(option)t
+Fb(:)7 b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b
+Fc(48)1015 1848 y(Ho)o(w)c(k)o(eys)g(are)h(lo)q(ok)o(ed)g(up)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 b Fc(14)1015 1893
+y(Ho)o(w)13 b(lo)q(cations)i(are)e(parsed)s Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)17 b Fc(14)1015 1939 y(Ho)o(w)c(to)g(access)g(en)o(vironmen)o(t)i(v)n
+(ariables)h(in)d(maps)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)18 b
+Fc(15)1015 1985 y(Ho)o(w)13 b(to)g(disco)o(v)o(er)h(y)o(our)g(v)o(ersion)g
+(of)f(Amd)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(23)1015 2030 y(Ho)o(w)13 b(to)g(moun)o(t)g(a)g(lo)q(cal)i(disk)9
+b Fb(:)e(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)22 b Fc(28)1015 2076 y(Ho)o(w)13
+b(to)g(moun)o(t)g(a)g(UFS)g(\014lesystems)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(28)1015
+2122 y(Ho)o(w)13 b(to)g(moun)o(t)g(all)i(NFS)e(exp)q(orted)h(\014lesystems)9
+b Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(26)1015 2167 y(Ho)o(w)12
+b(to)g(moun)o(t)h(an)f(atomic)h(group)g(of)f(NFS)g(\014lesystems)5
+b Fb(:)j(:)17 b Fc(27)1015 2213 y(Ho)o(w)c(to)g(moun)o(t)g(and)h(NFS)f
+(\014lesystem)c Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)22 b Fc(26)1015 2259 y(Ho)o(w)13 b(to)g(reference)g(an)g(existing)j
+(part)d(of)g(the)g(lo)q(cal)h(name)1092 2304 y(space)f Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)25 b Fc(29)1015 2350 y(Ho)o(w)13 b(to)g(reference)g(part)g(of)g(the)g
+(lo)q(cal)i(name)e(space)8 b Fb(:)f(:)f(:)g(:)g(:)g(:)21 b
+Fc(29)1015 2396 y(Ho)o(w)13 b(to)g(select)h(log)g(messages)6
+b Fb(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(23)1015 2441 y(Ho)o(w)13
+b(to)g(set)g(default)h(map)f(parameters)f Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)
+h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(15)1015 2487 y(Ho)o(w)13
+b(to)g(set)g(map)g(cac)o(he)h(parameters)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(29)1015
+2533 y(Ho)o(w)13 b(to)g(start)g(a)g(direct)h(automoun)o(t)g(p)q(oin)o(t)9
+b Fb(:)e(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b
+Fc(30)1015 2578 y(Ho)o(w)13 b(to)g(start)g(an)g(indirect)i(automoun)o(t)f(p)q
+(oin)o(t)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b
+Fc(29)1015 2624 y(Ho)o(w)13 b(v)n(ariables)i(are)e(expanded)5
+b Fb(:)j(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)18 b Fc(15)p eop
+%%Page: 55 57
+55 56 bop 0 -83 a Fo(Index)1613 b(SMM:13-55)0 158 y Fc(inherit,)14
+b(\014lesystem)h(t)o(yp)q(e)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(32)0 204 y(Inheritance)d(\014lesystem)6 b Fb(:)h(:)f(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)19 b Fc(32)0 250 y(In)o(terv)n(al)14 b(b)q(efore)f(a)g
+(\014lesystem)i(times)e(out)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)18 b Fc(21)0 295 y(In)o(tro)q(duction)8 b Fb(:)g(:)e(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20
+b Fc(4)0 341 y(k)n(arc)o(h,)13 b(moun)o(t)h(selector)9 b Fb(:)e(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)21 b Fc(17)0 387 y(Keep-aliv)o(es)11
+b Fb(:)c(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)22 b Fc(7)0 432 y(Key)13 b(lo)q(okup)7 b Fb(:)h(:)e(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20
+b Fc(14)0 478 y(k)o(ey)m(,)13 b(moun)o(t)g(selector)e Fb(:)6
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(17)0
+524 y(License)14 b(Information)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)18 b Fc(2)0 569 y(link,)c(\014lesystem)h(t)o(yp)q(e)s
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)16 b
+Fc(29)0 615 y(linkx,)f(\014lesystem)f(t)o(yp)q(e)d Fb(:)6 b(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(29)0 661 y(Listing)15 b(curren)o(tly)f(moun)o
+(ted)g(\014lesystems)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)23 b Fc(34)0 706 y(Lo)q(cation)14 b(format)d Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23
+b Fc(14)0 752 y(Lo)q(cation)14 b(lists)8 b Fb(:)h(:)d(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(6)0
+798 y(Log)13 b(\014lename)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(22)0 843 y(Log)13
+b(message)h(selection)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)18
+b Fc(23)0 889 y(log,)c(FSinfo)g(\014lesystems)g(option)e Fb(:)6
+b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)23 b Fc(45)0 935 y(Lo)q(oking)15 b(up)e(k)o(eys)c Fb(:)e(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)21 b Fc(14)0
+980 y(Mac)o(hine)15 b(arc)o(hitecture)f(names)6 b Fb(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(9)0 1026 y(Mac)o(hine)d(arc)o(hitectures)f(supp)q(orted)h(b)o(y)e(Amd)s
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(9)0
+1072 y(Mailing)g(list)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)21 b Fc(3)0 1117 y(Map)14
+b(cac)o(he)f(options)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)19 b Fc(29)0 1163 y(Map)14 b(cac)o(he)f(sync)o(hronising)6
+b Fb(:)j(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(29)0 1209 y(Map)c(cac)o(he)f(t)o
+(yp)q(es)6 b Fb(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)18 b Fc(29)0 1254 y(Map)c(cac)o(he,)f(\015ushing)5 b Fb(:)j(:)e(:)g(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(35)0 1300 y(Map)c(defaults)d
+Fb(:)6 b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)23 b Fc(15)0 1346 y(Map)14 b(en)o(try)f(format)t Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b
+Fc(14)0 1391 y(Map)d(lo)q(okup)f Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(14)0 1437 y(Map)14
+b(options)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)19 b Fc(17)0 1483 y(Map)14 b(t)o(yp)q(es)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)19 b Fc(11)0 1528 y(map,)13 b(moun)o(t)h(selector)9
+b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(17)0
+1574 y(maps,)13 b(FSinfo)h(command)g(line)h(option)6 b Fb(:)h(:)f(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)0
+1620 y(Moun)o(t)14 b(a)f(\014lesystem)h(under)g(program)g(con)o(trol)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(28)0 1665
+y(Moun)o(t)d(home)f(directories)6 b Fb(:)i(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(54)0 1711 y(Moun)o(t)14 b(information)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)16 b Fc(11)0 1757 y(Moun)o(t)e(map)f(t)o(yp)q(es)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)18
+b Fc(11)0 1802 y(Moun)o(t)c(maps)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(11)0 1848
+y(Moun)o(t)14 b(option;)g(cac)o(he)8 b Fb(:)e(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)21 b Fc(29)0 1893 y(Moun)o(t)14 b(option;)g(dela)o(y)d
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)22 b Fc(18)0
+1939 y(Moun)o(t)14 b(option;)g(dev)7 b Fb(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)20 b Fc(28)0 1985 y(Moun)o(t)14 b(option;)g(fs)6
+b Fb(:)f(:)h(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)18
+b Fc(18)0 2030 y(Moun)o(t)c(option;)g(moun)o(t)8 b Fb(:)f(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)21 b Fc(28)0 2076 y(Moun)o(t)14 b(option;)g(opts)c
+Fb(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 b Fc(18)0
+2122 y(Moun)o(t)14 b(option;)g(remopts)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)24 b Fc(19)0 2167 y(Moun)o(t)14 b(option;)g(rfs)7 b Fb(:)e(:)i(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 b Fc(26)0 2213 y(Moun)o(t)14
+b(option;)g(rhost)d Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)23
+b Fc(26)0 2259 y(Moun)o(t)14 b(option;)g(sublink)e Fb(:)7 b(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)23 b Fc(20)0 2304 y(Moun)o(t)14 b(option;)g(t)o(yp)q(e)8
+b Fb(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b
+Fc(20)0 2350 y(Moun)o(t)14 b(option;)g(unmoun)o(t)t Fb(:)7
+b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)16 b Fc(28)0 2396 y(Moun)o(t)e(retries)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)20 b Fc(6)0 2441 y(Moun)o(t)14 b(selector;)f(arc)o(h)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)20 b Fc(16)0
+2487 y(Moun)o(t)14 b(selector;)f(auto)q(dir)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)20 b Fc(16)0 2533 y(Moun)o(t)14 b(selector;)f(b)o(yte)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(16)0
+2578 y(Moun)o(t)14 b(selector;)f(cluster)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)18 b Fc(17)0 2624 y(Moun)o(t)c(selector;)f(domain)7
+b Fb(:)h(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(17)1015 158
+y(Moun)o(t)14 b(selector;)g(hostd)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)19 b Fc(17)1015 204 y(Moun)o(t)14 b(selector;)g(host)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)21 b Fc(17)1015
+250 y(Moun)o(t)14 b(selector;)g(k)n(arc)o(h)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)20 b Fc(17)1015 295 y(Moun)o(t)14 b(selector;)g(k)o(ey)7
+b Fb(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b
+Fc(17)1015 341 y(Moun)o(t)14 b(selector;)g(map)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)20 b Fc(17)1015 387 y(Moun)o(t)14 b(selector;)g(os)9
+b Fb(:)d(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)22
+b Fc(17)1015 432 y(Moun)o(t)14 b(selector;)g(path)5 b Fb(:)i(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fc(17)1015 478 y(Moun)o(t)c(selector;)g(wire)
+8 b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 b Fc(17)1015
+524 y(moun)o(t)14 b(system)f(call)i(\015ags)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)22 b Fc(18)1015 569 y(moun)o(t)14 b(system)f(call)f
+Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24
+b Fc(18)1015 615 y(Moun)o(t)14 b(t)o(yp)q(es)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b
+Fc(26)1015 661 y(moun)o(t,)14 b(FSinfo)g(\014lesystems)g(option)7
+b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)20 b Fc(44)1015 706 y(moun)o(t,)14 b(moun)o(t)f(option)e
+Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(28)1015
+752 y(Moun)o(ting)15 b(a)e(lo)q(cal)i(disk)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)19 b Fc(28)1015 798 y(Moun)o(ting)c(a)e(UFS)g(\014lesystem)g
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(28)1015 843 y(Moun)o(ting)15
+b(a)e(v)o(olume)e Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+23 b Fc(6)1015 889 y(Moun)o(ting)15 b(an)f(atomic)g(group)f(of)g(NFS)g
+(\014lesystems)7 b Fb(:)h(:)e(:)g(:)g(:)g(:)20 b Fc(27)1015
+935 y(Moun)o(ting)15 b(an)e(existing)i(part)e(of)g(the)g(lo)q(cal)i(name)e
+(space)5 b Fb(:)i(:)18 b Fc(29)1015 980 y(Moun)o(ting)d(an)f(NFS)f
+(\014lesystem)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(26)1015 1026 y(Moun)o(ting)15
+b(en)o(tire)f(exp)q(ort)g(trees)7 b Fb(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(26)1015
+1072 y(Moun)o(ting)15 b(part)f(of)e(the)i(lo)q(cal)g(name)g(space)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b
+Fc(29)1015 1117 y(Moun)o(ting)15 b(user)f(\014lesystems)5 b
+Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(53)1015 1163 y(Multiple-thre)q(aded)d
+(serv)o(er)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(8)1015
+1209 y(Namespace)12 b Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(6)1015 1254 y(ndbm)14
+b(maps)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)18 b Fc(12)1015 1300 y(Net)o(w)o(ork)13
+b(\014lesystem)i(group)10 b Fb(:)c(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23
+b Fc(27)1015 1346 y(Net)o(w)o(ork)13 b(host)h(\014lesystem)5
+b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(26)1015 1391
+y(Net)o(w)o(ork-wide)14 b(naming)6 b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)19 b Fc(5)1015 1437 y(NFS)13 b(ping)7 b Fb(:)h(:)e(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)20
+b Fc(7)1015 1483 y(nfs,)13 b(\014lesystem)i(t)o(yp)q(e)c Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(26)1015
+1528 y(nfsx,)13 b(\014lesystem)i(t)o(yp)q(e)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)22 b Fc(27)1015 1574 y(NFS)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)19 b Fc(26)1015 1620 y(NIS)13 b(\(YP\))g(domain)h(name)5
+b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(24)1015 1665
+y(NIS)13 b(\(YP\))g(maps)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(12)1015 1711 y(No)q(des)14 b(generated)g(on)f
+(a)g(restart)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(32)1015 1757 y(Non-blo)q(c)o(king)
+e(op)q(eration)c Fb(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23
+b Fc(8)1015 1802 y(Normalising)16 b(hostnames)c Fb(:)6 b(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)24 b Fc(22)1015 1848 y(Obtaining)16 b(the)d(source)h(co)q(de)s
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(3)1015 1893 y(Op)q(erating)e
+(system)e(names)8 b Fb(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(9)1015 1939 y(Op)q(erating)15 b(systems)e(supp)q(orted)i(b)o(y)e(Amd)6
+b Fb(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(9)1015 1985 y(Op)q(erational)d(principles)t Fb(:)9 b(:)d(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)16 b Fc(6)1015 2030 y(opts,)e(FSinfo)g(\014lesystems)g
+(option)8 b Fb(:)g(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)22 b Fc(43)1015 2076 y(opts,)14 b(moun)o(t)f(option)g
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b
+Fc(18)1015 2122 y(os,)13 b(FSinfo)h(host)g(attribute)8 b Fb(:)f(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)21 b Fc(41)1015 2167 y(os,)13 b(moun)o(t)h(selector)e
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)24
+b Fc(17)1015 2213 y(Ov)o(erriding)16 b(defaults)e(on)f(the)g(command)h(line)6
+b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(21)1015
+2259 y(Ov)o(erriding)d(the)d(default)h(moun)o(t)f(p)q(oin)o(t)f
+Fb(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24
+b Fc(18)1015 2304 y(Ov)o(erriding)16 b(the)d(lo)q(cal)h(domain)h(name)t
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(21)1015 2350 y(Ov)o(erriding)f(the)d(NIS)g(\(YP\))f(domain)j(name)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b
+Fc(24)1015 2396 y(P)o(assing)d(parameters)f(to)f(the)g(moun)o(t)g(system)h
+(call)7 b Fb(:)g(:)g(:)f(:)g(:)g(:)g(:)20 b Fc(18)1015 2441
+y(passno,)14 b(FSinfo)g(\014lesystems)h(option)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)18 b Fc(43)1015
+2487 y(P)o(assw)o(ord)c(\014le)g(maps)t Fb(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(13)1015 2533 y(path,)d(moun)o(t)f(selector)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(17)1015
+2578 y(P)o(athname)14 b(op)q(erators)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)23 b Fc(15)1015 2624 y(Pic)o(king)16 b(up)d(existing)i(moun)o
+(ts)d Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)24 b Fc(23)p eop
+%%Page: 56 58
+56 57 bop 15 -83 a Fo(SMM:13-56)889 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 158 y Fc(pid)d(\014le,)g(creating)g(with)f(-p)g
+(option)g Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+h(:)f(:)g(:)g(:)23 b Fc(22)0 204 y(Primary)14 b(serv)o(er)t
+Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(18)0 250 y(pro)q(cess)d(id)g(of)e(Amd)h(daemon)8 b Fb(:)f(:)f(:)g(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)20 b Fc(22)0 295 y(Pro)q(cess)14 b(id)c Fb(:)c(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)22 b
+Fc(22)0 341 y(Program)14 b(\014lesystem)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)23 b Fc(28)0 387 y(program,)13 b(\014lesystem)i(t)o(yp)q
+(e)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(28)0 432 y(Querying)15
+b(an)e(alternate)h(host)t Fb(:)7 b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)17 b Fc(35)0
+478 y(quiet,)d(FSinfo)g(command)g(line)g(option)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fc(49)0 524
+y(Referencing)15 b(an)e(existing)i(part)e(of)g(the)g(lo)q(cal)i(name)e(space)
+82 569 y Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(29)0
+615 y(Referencing)d(part)e(of)g(the)g(lo)q(cal)h(name)g(space)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b Fc(29)0
+661 y(Regular)15 b(expressions)g(in)f(maps)d Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23
+b Fc(29)0 706 y(remopts,)13 b(moun)o(t)h(option)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)17 b Fc(19)0 752 y(Replacemen)o(t)e(v)o(olumes)9
+b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)21 b Fc(5)0
+798 y(Replicated)15 b(v)o(olumes)d Fb(:)6 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)23 b Fc(5)0 843 y(Resolving)16 b(aliased)f(hostnames)c
+Fb(:)6 b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)23 b Fc(22)0 889 y(Restarting)15 b(existing)g(moun)o(ts)5
+b Fb(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)17 b Fc(23)0 935 y(rfs,)12 b(moun)o(t)i(option)8
+b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(26)0 980 y(rhost,)13 b(moun)o(t)h(option)s Fb(:)8 b(:)e(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)16 b Fc(26)0 1026 y(Ro)q(ot)d(\014lesystem)8
+b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21
+b Fc(31)0 1072 y(ro)q(ot,)13 b(\014lesystem)h(t)o(yp)q(e)9
+b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)21 b Fc(31)0
+1117 y(RPC)13 b(retries)t Fb(:)7 b(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(8)0 1163 y(Run-time)d
+(administration)7 b Fb(:)i(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(33)0
+1209 y(rwho)13 b(serv)o(ers)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(56)0 1254 y(Secondary)15
+b(serv)o(er)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)17 b Fc(18)0 1300 y(sel,)c(FSinfo)h(moun)o(t)g(option)6
+b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)19 b Fc(44)0 1346 y(Selecting)c(sp)q
+(eci\014c)g(log)f(messages)s Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(23)0 1391
+y(Selector;)e(arc)o(h)7 b Fb(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)19 b Fc(16)0 1437 y(Selector;)14
+b(auto)q(dir)7 b Fb(:)g(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)19 b Fc(16)0 1483 y(Selector;)14 b(b)o(yte)6 b Fb(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b
+Fc(16)0 1528 y(Selector;)14 b(cluster)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(17)0 1574 y(Selector;)d(domain)6
+b Fb(:)i(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(17)0 1620 y(Selector;)14 b(hostd)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(17)0 1665 y(Selector;)c(host)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)20 b Fc(17)0 1711 y(Selector;)14 b(k)n(arc)o(h)6 b Fb(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(17)0
+1757 y(Selector;)14 b(k)o(ey)6 b Fb(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)18 b Fc(17)0 1802 y(Selector;)c(map)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)19 b Fc(17)0 1848 y(Selector;)14 b(os)8 b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b
+Fc(17)0 1893 y(Selector;)14 b(path)t Fb(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(17)0 1939 y(Selector;)d(wire)7
+b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)20 b Fc(17)0 1985 y(Selectors)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(16)0 2030 y(Serv)o(er)d(crashes)e Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(7)0 2076
+y(Setting)14 b(a)f(dela)o(y)i(on)e(a)g(moun)o(t)g(lo)q(cation)6
+b Fb(:)j(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(18)0 2122 y(Setting)14 b(Amd's)f(RPC)g(parameters)7 b
+Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)20 b Fc(23)0 2167 y(Setting)14 b(debug)g(\015ags)f Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b Fc(24)0
+2213 y(Setting)14 b(default)g(map)g(parameters)8 b Fb(:)e(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b
+Fc(15)0 2259 y(Setting)14 b(map)g(cac)o(he)f(parameters)s Fb(:)8
+b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)16 b Fc(29)0 2304 y(Setting)e(map)g(options)e Fb(:)6
+b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 b Fc(17)0 2350
+y(Setting)14 b(system)g(moun)o(t)f(options)i(for)e(non-lo)q(cal)i(net)o(w)o
+(orks)82 2396 y Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b
+Fc(19)0 2441 y(Setting)c(system)g(moun)o(t)f(options)6 b Fb(:)i(:)e(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(18)0 2487 y(Setting)14 b(the)f(cluster)h(name)8 b Fb(:)f(:)f(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)21 b Fc(24)0 2533 y(Setting)14 b(the)f(default)h(moun)o(t)g
+(directory)9 b Fb(:)e(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)22 b Fc(21)0 2578 y(Setting)14 b(the)f(\014lesystem)i(t)o(yp)q(e)e(option)
+7 b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+20 b Fc(20)0 2624 y(Setting)14 b(the)f(in)o(terv)n(al)i(b)q(efore)e(a)g
+(\014lesystem)i(times)f(out)c Fb(:)c(:)g(:)22 b Fc(21)1015
+158 y(Setting)15 b(the)e(in)o(terv)n(al)i(b)q(et)o(w)o(een)e(unmoun)o(t)h
+(attempts)e Fb(:)6 b(:)g(:)g(:)25 b Fc(23)1015 204 y(Setting)15
+b(the)e(Kernel)h(arc)o(hitecture)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(22)1015
+250 y(Setting)d(the)e(lo)q(cal)i(domain)f(name)8 b Fb(:)f(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)21
+b Fc(21)1015 295 y(Setting)15 b(the)e(lo)q(cal)i(moun)o(t)e(p)q(oin)o(t)8
+b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)22 b Fc(18)1015 341 y(Setting)15 b(the)e(log)h(\014le)8
+b Fb(:)f(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22
+b Fc(22)1015 387 y(Setting)15 b(the)e(NIS)g(\(YP\))f(domain)j(name)9
+b Fb(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22
+b Fc(24)1015 432 y(Setting)15 b(the)e(sublink)i(option)s Fb(:)9
+b(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(20)1015 478 y(Sharing)e(a)e(\014leserv)o(er)i
+(b)q(et)o(w)o(een)e(arc)o(hitectures)g Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)24 b Fc(55)1015 524 y(SIGHUP)13 b(signal)8 b Fb(:)h(:)d(:)g(:)g(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(29)1015
+569 y(SIGINT)13 b(signal)7 b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(34)1015 615 y(SIGTERM)14
+b(signal)9 b Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)22
+b Fc(34)1015 661 y(Source)14 b(co)q(de)g(distribution)g Fb(:)6
+b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(3)1015 706 y(Starting)15
+b(Amd)5 b Fb(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)18 b Fc(33)1015 752 y(Statically)e(moun)o(ts)e(\014lesystems,)g
+(FSinfo)7 b Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)20
+b Fc(45)1015 798 y(Statistics)12 b Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b
+Fc(36)1015 843 y(Stopping)16 b(Amd)7 b Fb(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(34)1015 889 y(Stripping)c(the)d
+(lo)q(cal)i(domain)f(name)7 b Fb(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(15)1015 935 y(sublink,)c(moun)o(t)d
+(option)g Fb(:)6 b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 b Fc(20)1015
+980 y(sublink)13 b Fb(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(5)1015
+1026 y(Supp)q(orted)15 b(mac)o(hine)g(arc)o(hitectures)8 b
+Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)21 b Fc(9)1015 1072 y(Supp)q(orted)15 b(op)q(erating)g(systems)5
+b Fb(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)18 b Fc(9)1015 1117 y(Sym)o(b)q(olic)e(link)f
+(\014lesystem)f(I)q(I)8 b Fb(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 b Fc(29)1015
+1163 y(Sym)o(b)q(olic)16 b(link)f(\014lesystem)s Fb(:)8 b(:)e(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)17 b Fc(29)1015 1209 y(symlink,)e(link)g(\014lesystem)f(t)o(yp)q
+(e)9 b Fb(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(29)1015 1254 y(symlink,)15 b(linkx)g
+(\014lesystem)g(t)o(yp)q(e)7 b Fb(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 b Fc(29)1015
+1300 y(Sync)o(hronisi)q(ng)c(the)d(map)h(cac)o(he)5 b Fb(:)h(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18
+b Fc(29)1015 1346 y(syslog)d(priorities)6 b Fb(:)j(:)d(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(23)1015 1391 y(syslog)13
+b Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)24 b Fc(22)1015 1437 y(The)13
+b(moun)o(t)h(system)f(call)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)18
+b Fc(18)1015 1483 y(T)m(op)13 b(lev)o(el)i(\014lesystem)7 b
+Fb(:)h(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fc(31)1015
+1528 y(toplvl,)15 b(\014lesystem)f(t)o(yp)q(e)s Fb(:)8 b(:)e(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)17 b Fc(31)1015 1574 y(t)o(yp)q(e,)d(moun)o(t)f(option)e
+Fb(:)6 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b
+Fc(20)1015 1620 y(T)o(yp)q(es)14 b(of)f(con\014guration)i(map)8
+b Fb(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(11)1015 1665 y(T)o(yp)q(es)14
+b(of)f(\014lesystem)f Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)
+24 b Fc(26)1015 1711 y(T)o(yp)q(es)14 b(of)f(moun)o(t)g(map)5
+b Fb(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(11)1015
+1757 y(ufs,)13 b(\014lesystem)i(t)o(yp)q(e)c Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(28)1015 1802 y(UFS)6 b Fb(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)19 b Fc(28)1015 1848 y(Union)c(\014le)e(maps)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19
+b Fc(13)1015 1893 y(Union)c(\014lesystem)7 b Fb(:)g(:)g(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fc(31)1015 1939 y(union,)15
+b(\014lesystem)f(t)o(yp)q(e)5 b Fb(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+18 b Fc(31)1015 1985 y(Unix)c(\014lesystem)9 b Fb(:)f(:)e(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(28)1015 2030
+y(Unix)14 b(namespace)e Fb(:)6 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)23 b Fc(6)1015 2076 y(unmoun)o(t)15 b(attempt)e(bac)o(k)o
+(o\013)h(in)o(terv)n(al)8 b Fb(:)g(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(23)1015 2122 y(unmoun)o(t,)14
+b(moun)o(t)g(option)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)18
+b Fc(28)1015 2167 y(Unmoun)o(ting)d(a)e(\014lesystem)6 b Fb(:)i(:)e(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)19 b Fc(37)1015 2213 y(User)13 b(\014lesystems)t
+Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17
+b Fc(53)1015 2259 y(User)c(maps,)g(automatic)i(generation)t
+Fb(:)8 b(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)18 b Fc(13)1015 2304 y(Using)c(FSinfo)s Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(38)1015
+2350 y(Using)d(syslog)h(to)e(log)h(errors)c Fb(:)c(:)g(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)23
+b Fc(22)1015 2396 y(Using)14 b(the)g(passw)o(ord)f(\014le)h(as)f(a)g(map)6
+b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)19 b Fc(13)1015 2441 y(V)m(ariable)c(expansion)5 b Fb(:)j(:)e(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(15)1015 2487 y(v)o(erb)q(ose,)c
+(FSinfo)g(command)g(line)h(option)t Fb(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(49)1015 2533 y(V)m(ersion)c(information)h(at)e
+(run-time)6 b Fb(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)19 b Fc(37)1015 2578 y(V)m(ersion)14 b(information)6
+b Fb(:)i(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b
+Fc(23)1015 2624 y(v)o(olname,)c(FSinfo)f(moun)o(t)f(option)f
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g
+(:)g(:)g(:)23 b Fc(44)p eop
+%%Page: 57 59
+57 58 bop 0 -83 a Fo(Index)1613 b(SMM:13-57)0 158 y Fc(V)m(olume)14
+b(binding)6 b Fb(:)j(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)19 b Fc(6)0 204 y(V)m(olume)14 b(names)8 b Fb(:)f(:)f(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b
+Fc(5)0 250 y(V)m(olume)7 b Fb(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b
+Fc(5)0 295 y(Wildcards)c(in)d(maps)5 b Fb(:)j(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)18 b Fc(14)1015 158 y(wire,)13 b(moun)o(t)h(selector)d
+Fb(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(17)1015
+204 y(YP)13 b(domain)i(name)8 b Fb(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g
+(:)g(:)g(:)g(:)21 b Fc(24)p eop
+%%Page: -1 60
+-1 59 bop 1756 -83 a Fo(SMM:13-i)0 158 y Fm(T)-7 b(able)15
+b(of)g(Con)n(ten)n(ts)0 308 y Fq(Preface)c Fa(:)e(:)i(:)f(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)34 b Fq(1)0 420 y(License)13 b Fa(:)e(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)35 b Fq(1)0 532 y(Source)23
+b(Distribution)15 b Fa(:)d(:)e(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)37 b Fq(1)149 594 y Fo(Bug)16 b(Rep)q(orts)e
+Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)28 b Fo(1)149 644 y(Mailing)17 b(List)8 b Fj(:)g(:)f(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)22
+b Fo(2)0 750 y Fq(In)n(tro)r(duction)14 b Fa(:)e(:)e(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)36
+b Fq(2)0 862 y(1)67 b(Ov)n(erview)11 b Fa(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)33
+b Fq(2)149 925 y Fo(1.1)45 b(F)l(undamen)o(tals)10 b Fj(:)d(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fo(2)149 975 y(1.2)45
+b(Filesystems)16 b(and)f(V)l(olumes)10 b Fj(:)e(:)f(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)24
+b Fo(3)149 1024 y(1.3)45 b(V)l(olume)16 b(Naming)9 b Fj(:)e(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)23 b Fo(3)149 1074 y(1.4)45
+b(V)l(olume)16 b(Binding)8 b Fj(:)i(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)22 b Fo(3)149 1124 y(1.5)45 b(Op)q(erational)16 b(Principles)6
+b Fj(:)k(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 b Fo(3)149 1174 y(1.6)45
+b(Moun)o(ting)15 b(a)g(V)l(olume)e Fj(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)26
+b Fo(4)149 1224 y(1.7)45 b(Automatic)15 b(Unmoun)o(ting)e Fj(:)7
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)27 b Fo(4)149 1273 y(1.8)45 b(Keep-aliv)o(es)5
+b Fj(:)10 b(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)20 b Fo(5)149 1323 y(1.9)45 b(Non-blo)q(c)o(king)17 b(Op)q(eration)10
+b Fj(:)e(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)24 b Fo(5)0 1430 y Fq(2)67 b(Supp)r(orted)24
+b(Platforms)11 b Fa(:)e(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)33
+b Fq(6)149 1492 y Fo(2.1)45 b(Supp)q(orted)16 b(Op)q(erating)g(Systems)11
+b Fj(:)c(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)25
+b Fo(6)149 1542 y(2.2)45 b(Supp)q(orted)16 b(Mac)o(hine)g(Arc)o(hitectures)6
+b Fj(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20
+b Fo(7)0 1648 y Fq(3)67 b(Moun)n(t)23 b(Maps)11 b Fa(:)f(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)34
+b Fq(7)149 1710 y Fo(3.1)45 b(Map)15 b(T)o(yp)q(es)5 b Fj(:)j(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 b Fo(7)299
+1760 y(3.1.1)44 b(File)16 b(maps)9 b Fj(:)e(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)23 b Fo(8)299 1810 y(3.1.2)44 b(ndbm)16 b(maps)10 b Fj(:)d(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)24 b Fo(8)299 1859 y(3.1.3)44 b(NIS)16 b(maps)9
+b Fj(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)23 b Fo(9)299 1909
+y(3.1.4)44 b(Hesio)q(d)16 b(maps)10 b Fj(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)24
+b Fo(9)299 1959 y(3.1.5)44 b(P)o(assw)o(ord)14 b(maps)f Fj(:)7
+b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)28 b Fo(10)299 2009 y(3.1.6)44 b(Union)16 b(maps)6 b
+Fj(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b Fo(10)149 2059 y(3.2)45 b(Ho)o(w)15
+b(k)o(eys)g(are)f(lo)q(ok)o(ed)i(up)c Fj(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 b
+Fo(10)149 2108 y(3.3)45 b(Lo)q(cation)16 b(F)l(ormat)11 b Fj(:)5
+b(:)i(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(11)299 2158
+y(3.3.1)44 b(Map)15 b(Defaults)c Fj(:)6 b(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)25 b
+Fo(12)299 2208 y(3.3.2)44 b(V)l(ariable)16 b(Expansion)e Fj(:)7
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)28
+b Fo(12)299 2258 y(3.3.3)44 b(Selectors)8 b Fj(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)
+h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)22 b Fo(13)299 2308 y(3.3.4)44 b(Map)15 b(Options)5
+b Fj(:)i(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)19 b Fo(14)448 2357 y(3.3.4.1)44
+b(dela)o(y)15 b(Option)5 b Fj(:)j(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)20 b Fo(14)448 2407 y(3.3.4.2)44 b(fs)15 b(Option)c
+Fj(:)c(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)
+25 b Fo(14)448 2457 y(3.3.4.3)44 b(opts)14 b(Option)5 b Fj(:)j(:)g(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 b Fo(15)448
+2507 y(3.3.4.4)44 b(remopts)14 b(Option)7 b Fj(:)i(:)e(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)22 b Fo(16)448 2557 y(3.3.4.5)44 b(sublink)17
+b(Option)6 b Fj(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)20
+b Fo(16)448 2607 y(3.3.4.6)44 b(t)o(yp)q(e)15 b(Option)f Fj(:)7
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)28
+b Fo(16)p eop
+%%Page: -2 61
+-2 60 bop 15 -83 a Fo(SMM:13-ii)911 b(4.4)15 b(BSD)g(Automoun)o(ter)f
+(Reference)j(Man)o(ual)0 17 y Fq(4)67 b Ff(Amd)24 b Fq(Command)e(Line)h
+(Options)6 b Fa(:)11 b(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)29 b Fq(16)149 79 y Fo(4.1)45
+b Fl(-a)15 b Fp(directory)8 b Fj(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)19 b Fo(17)149 129 y(4.2)45 b Fl(-c)15 b
+Fp(cac)o(he-in)o(terv)m(al)c Fj(:)e(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)24
+b Fo(17)149 178 y(4.3)45 b Fl(-d)15 b Fp(domain)d Fj(:)c(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)27 b Fo(17)149 228
+y(4.4)45 b Fl(-k)15 b Fp(k)o(ernel-arc)o(hitecture)f Fj(:)7
+b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)25 b Fo(17)149 278 y(4.5)45 b Fl(-l)15 b
+Fp(log-option)6 b Fj(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)20 b Fo(18)149 328 y(4.6)45 b Fl(-n)12 b Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)27
+b Fo(18)149 378 y(4.7)45 b Fl(-p)12 b Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)27
+b Fo(18)149 428 y(4.8)45 b Fl(-r)12 b Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)27
+b Fo(18)149 477 y(4.9)45 b Fl(-t)15 b Fp(timeout.retransmit)10
+b Fj(:)c(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fo(18)149 527 y(4.10)45 b Fl(-v)11
+b Fj(:)6 b(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)
+f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)26 b Fo(19)149 577 y(4.11)45 b Fl(-w)15
+b Fp(w)o(ait-timeout)8 b Fj(:)f(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)22
+b Fo(19)149 627 y(4.12)45 b Fl(-x)15 b Fp(opts)d Fj(:)7 b(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)26 b Fo(19)149
+677 y(4.13)45 b Fl(-y)15 b Fp(NIS-domain)6 b Fj(:)i(:)f(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)20 b Fo(20)149 726 y(4.14)45 b Fl(-C)15
+b Fp(cluster-name)9 b Fj(:)f(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)22
+b Fo(20)149 776 y(4.15)45 b Fl(-D)15 b Fp(opts)d Fj(:)7 b(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)26 b Fo(20)0
+883 y Fq(5)67 b(Filesystem)23 b(T)n(yp)r(es)7 b Fa(:)j(:)h(:)f(:)g(:)g(:)g(:)
+h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)30 b Fq(20)149 945 y
+Fo(5.1)45 b(Net)o(w)o(ork)14 b(Filesystem)i(\(`)p Fl(type:=nfs)p
+Fo('\))7 b Fj(:)e(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)22
+b Fo(21)149 995 y(5.2)45 b(Net)o(w)o(ork)14 b(Host)g(Filesystem)i(\(`)p
+Fl(type:=host)p Fo('\))10 b Fj(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fo(21)149
+1045 y(5.3)45 b(Net)o(w)o(ork)14 b(Filesystem)i(Group)f(\(`)p
+Fl(type:=nfsx)p Fo('\))5 b Fj(:)t(:)j(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)20 b Fo(22)149
+1094 y(5.4)45 b(Unix)16 b(Filesystem)g(\(`)p Fl(type:=ufs)p
+Fo('\))10 b Fj(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)
+27 b Fo(22)149 1144 y(5.5)45 b(Program)14 b(Filesystem)i(\(`)p
+Fl(type:=program)p Fo('\))6 b Fj(:)f(:)i(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)22
+b Fo(23)149 1194 y(5.6)45 b(Sym)o(b)q(olic)17 b(Link)f(Filesystem)g(\(`)p
+Fl(type:=link)p Fo('\))7 b Fj(:)t(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)21 b Fo(23)149
+1244 y(5.7)45 b(Sym)o(b)q(olic)17 b(Link)f(Filesystem)g(I)q(I)g(\(`)p
+Fl(type:=link)p Fo('\))10 b Fj(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 b Fo(24)149 1294
+y(5.8)45 b(Automoun)o(t)14 b(Filesystem)i(\(`)p Fl(type:=auto)p
+Fo('\))6 b Fj(:)t(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)20 b Fo(24)149
+1343 y(5.9)45 b(Direct)15 b(Automoun)o(t)g(Filesystem)h(\(`)p
+Fl(type:=direct)p Fo('\))10 b Fj(:)d(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)28 b Fo(25)149 1393 y(5.10)45 b(Union)16
+b(Filesystem)g(\(`)p Fl(type:=union)p Fo('\))5 b Fj(:)g(:)i(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)20 b Fo(25)149 1443 y(5.11)45 b(Error)14
+b(Filesystem)i(\(`)p Fl(type:=error)p Fo('\))9 b Fj(:)e(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)27 b Fo(26)149 1493 y(5.12)45 b(T)l(op-lev)o(el)16
+b(Filesystem)g(\(`)p Fl(type:=toplvl)p Fo('\))11 b Fj(:)c(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)29 b Fo(26)149 1543 y(5.13)45 b(Ro)q(ot)15 b(Filesystem)t
+Fj(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fo(26)149
+1592 y(5.14)45 b(Inheritance)16 b(Filesystem)d Fj(:)7 b(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)27
+b Fo(26)0 1699 y Fq(6)67 b(Run-time)24 b(Administration)6 b
+Fa(:)13 b(:)d(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)29 b Fq(27)149 1761 y Fo(6.1)45
+b(Starting)15 b Fp(Amd)c Fj(:)c(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)24 b Fo(27)149 1811 y(6.2)45 b(Stopping)16 b Fp(Amd)e
+Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 b
+Fo(28)149 1861 y(6.3)45 b(Con)o(trolling)16 b Fp(Amd)10 b Fj(:)d(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)23 b Fo(28)299 1911 y(6.3.1)44 b
+Fp(Amq)16 b Fo(default)g(information)9 b Fj(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)23 b Fo(28)299 1960 y(6.3.2)44 b Fp(Amq)16
+b Fo(-f)f(option)t Fj(:)8 b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)19 b Fo(29)299 2010
+y(6.3.3)44 b Fp(Amq)16 b Fo(-h)f(option)9 b Fj(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)23
+b Fo(29)299 2060 y(6.3.4)44 b Fp(Amq)16 b Fo(-m)f(option)e
+Fj(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)27 b Fo(29)299 2110 y(6.3.5)44 b Fp(Amq)16 b
+Fo(-M)f(option)10 b Fj(:)e(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)
+g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fo(30)299 2160 y(6.3.6)44
+b Fp(Amq)16 b Fo(-s)f(option)e Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 b Fo(30)299
+2209 y(6.3.7)44 b Fp(Amq)16 b Fo(-u)f(option)9 b Fj(:)f(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)23
+b Fo(31)299 2259 y(6.3.8)44 b Fp(Amq)16 b Fo(-v)f(option)9
+b Fj(:)f(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)24 b Fo(31)299 2309 y(6.3.9)44 b(Other)15
+b Fp(Amq)h Fo(options)d Fj(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)27 b Fo(31)p eop
+%%Page: -3 62
+-3 61 bop 1730 -83 a Fo(SMM:13-iii)0 17 y Fq(7)67 b(FSinfo)11
+b Fa(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)33 b Fq(31)149 79
+y Fo(7.1)45 b Fp(FSinfo)18 b Fo(o)o(v)o(erview)8 b Fj(:)f(:)g(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)23 b Fo(31)149 129 y(7.2)45 b(Using)16
+b Fp(FSinfo)9 b Fj(:)f(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)
+h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)22
+b Fo(32)149 178 y(7.3)45 b Fp(FSinfo)18 b Fo(grammar)12 b Fj(:)c(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)29 b Fo(32)149 228 y(7.4)45 b Fp(FSinfo)18
+b Fo(host)d(de\014nitions)f Fj(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 b Fo(33)149
+278 y(7.5)45 b Fp(FSinfo)18 b Fo(host)d(attributes)8 b Fj(:)e(:)h(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)22 b Fo(33)299 328 y(7.5.1)44 b(netif)16 b(Option)e Fj(:)7
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)28 b Fo(34)299 378 y(7.5.2)44 b(con\014g)15
+b(Option)10 b Fj(:)f(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fo(34)299 428 y(7.5.3)44
+b(arc)o(h)15 b(Option)6 b Fj(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)21 b
+Fo(34)299 477 y(7.5.4)44 b(os)15 b(Option)8 b Fj(:)f(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)23 b Fo(34)299 527 y(7.5.5)44 b(cluster)16 b(Option)d
+Fj(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)28 b Fo(35)149 577 y(7.6)45 b Fp(FSinfo)18
+b Fo(\014lesystems)8 b Fj(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)23
+b Fo(35)299 627 y(7.6.1)44 b(fst)o(yp)q(e)15 b(Option)9 b Fj(:)f(:)f(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)24 b Fo(36)299 677 y(7.6.2)44 b(opts)15 b(Option)6 b Fj(:)i(:)f(:)g(:)h(:)
+f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)21 b Fo(37)299 726 y(7.6.3)44 b(passno)15 b(Option)e
+Fj(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)27 b Fo(37)299 776 y(7.6.4)44 b(freq)15
+b(Option)10 b Fj(:)e(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fo(37)299 826
+y(7.6.5)44 b(moun)o(t)14 b(Option)5 b Fj(:)j(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)19
+b Fo(37)299 876 y(7.6.6)44 b(dumpset)15 b(Option)g Fj(:)7 b(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)29
+b Fo(38)299 926 y(7.6.7)44 b(log)15 b(Option)9 b Fj(:)f(:)f(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)24 b Fo(38)149 976 y(7.7)45 b Fp(FSinfo)18 b Fo(static)d(moun)o(ts)10
+b Fj(:)c(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)24 b Fo(38)149 1025 y(7.8)45
+b(De\014ning)16 b(an)f Fp(Amd)i Fo(Moun)o(t)e(Map)g(in)h Fp(FSinfo)f
+Fj(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fo(39)149 1075 y(7.9)45
+b Fp(FSinfo)18 b Fo(Command)d(Line)h(Options)6 b Fj(:)i(:)g(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)21 b Fo(40)299 1125
+y(7.9.1)44 b Fl(-a)15 b Fp(auto)q(dir)e Fj(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)24
+b Fo(41)299 1175 y(7.9.2)44 b Fl(-b)15 b Fp(b)q(o)q(otparams)7
+b Fj(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)20 b Fo(41)299 1225 y(7.9.3)44 b Fl(-d)15
+b Fp(dumpsets)c Fj(:)c(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)24 b Fo(41)299 1274
+y(7.9.4)44 b Fl(-e)15 b Fp(exp)q(ortfs)f Fj(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)27
+b Fo(41)299 1324 y(7.9.5)44 b Fl(-f)15 b Fp(fstab)5 b Fj(:)i(:)g(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)19 b Fo(42)299 1374 y(7.9.6)44 b Fl(-h)15
+b Fp(hostname)10 b Fj(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 b Fo(42)299 1424
+y(7.9.7)44 b Fl(-m)15 b Fp(moun)o(t-maps)c Fj(:)c(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)25 b
+Fo(42)299 1474 y(7.9.8)44 b Fl(-q)11 b Fj(:)6 b(:)h(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(42)299 1523 y(7.9.9)44
+b Fl(-v)11 b Fj(:)6 b(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)25 b Fo(42)299 1573 y(7.9.10)43 b Fl(-D)15 b Fp(name[=defn])8
+b Fj(:)g(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)21 b Fo(42)299 1623 y(7.9.11)43 b Fl(-I)15 b Fp(directory)h
+Fj(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)26 b Fo(42)299 1673 y(7.9.12)43 b Fl(-U)15
+b Fp(name)c Fj(:)c(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)
+g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)23 b Fo(43)149
+1723 y(7.10)45 b(Errors)14 b(pro)q(duced)i(b)o(y)f Fp(FSinfo)e
+Fj(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)25 b Fo(43)0 1829 y Fq(8)67 b(Examples)18 b Fa(:)10 b(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)40
+b Fq(45)149 1891 y Fo(8.1)45 b(User)15 b(Filesystems)10 b Fj(:)e(:)g(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fo(45)149 1941 y(8.2)45 b(Home)15
+b(Directories)5 b Fj(:)j(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20
+b Fo(47)149 1991 y(8.3)45 b(Arc)o(hitecture)16 b(Sharing)10
+b Fj(:)e(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fo(48)149 2041 y(8.4)45
+b(Wildcard)16 b(names)f(&)h(Replicated)h(Serv)o(ers)12 b Fj(:)7
+b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)27 b Fo(48)149 2091 y(8.5)45
+b(`)p Fl(rwho)p Fo(')14 b(serv)o(ers)d Fj(:)c(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)27 b Fo(49)149 2140 y(8.6)45 b(`)p Fl(/vol)p
+Fo(')6 b Fj(:)g(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)g(:)21 b Fo(49)0 2240 y Fq(9)67 b(In)n(ternals)15
+b Fa(:)c(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)38 b Fq(50)149 2302 y Fo(9.1)45
+b(Log)15 b(Messages)c Fj(:)c(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f
+(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h
+(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)27 b Fo(50)299 2352 y(9.1.1)44 b(F)l(atal)15 b(errors)10
+b Fj(:)c(:)h(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)25 b Fo(50)299 2402 y(9.1.2)44
+b(Info)15 b(messages)10 b Fj(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)25 b Fo(52)0
+2508 y Fq(Ac)n(kno)n(wledgemen)n(ts)d(&)h(T)-6 b(rademarks)9
+b Fa(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g
+(:)g(:)h(:)31 b Fq(53)0 2630 y(Index)7 b Fa(:)12 b(:)e(:)g(:)g(:)g(:)h(:)f(:)
+g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g
+(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g
+(:)h(:)f(:)g(:)g(:)h(:)f(:)30 b Fq(53)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/usr.sbin/amd/doc/amdref.texinfo b/usr.sbin/amd/doc/amdref.texinfo
new file mode 100644
index 00000000000..cfdebd1b436
--- /dev/null
+++ b/usr.sbin/amd/doc/amdref.texinfo
@@ -0,0 +1,4556 @@
+\input texinfo @c -*-texinfo-*-
+@c
+@c Copyright (c) 1989 Jan-Simon Pendry
+@c Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+@c Copyright (c) 1989 The Regents of the University of California.
+@c All rights reserved.
+@c
+@c This code is derived from software contributed to Berkeley by
+@c Jan-Simon Pendry at Imperial College, London.
+@c
+@c Redistribution and use in source and binary forms, with or without
+@c modification, are permitted provided that the following conditions
+@c are met:
+@c 1. Redistributions of source code must retain the above copyright
+@c notice, this list of conditions and the following disclaimer.
+@c 2. Redistributions in binary form must reproduce the above copyright
+@c notice, this list of conditions and the following disclaimer in the
+@c documentation and/or other materials provided with the distribution.
+@c 3. All advertising materials mentioning features or use of this software
+@c must display the following acknowledgement:
+@c This product includes software developed by the University of
+@c California, Berkeley and its contributors.
+@c 4. Neither the name of the University nor the names of its contributors
+@c may be used to endorse or promote products derived from this software
+@c without specific prior written permission.
+@c
+@c THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+@c ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+@c IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+@c ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+@c FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+@c DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+@c OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+@c HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+@c LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+@c OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+@c
+@c from: @(#)amdref.texinfo 8.1 (Berkeley) 6/6/93
+@c $Id: amdref.texinfo,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+@c
+@setfilename amdref.info
+@c @setfilename /usr/local/emacs/info/amd
+@tex
+\overfullrule=0pt
+@end tex
+
+@settitle 4.4 BSD Automounter Reference Manual
+@titlepage
+@sp 6
+@center @titlefont{Amd}
+@sp 2
+@center @titlefont{The 4.4 BSD Automounter}
+@sp 2
+@center @titlefont{Reference Manual}
+@sp 2
+@center @authorfont{Jan-Simon Pendry}
+@sp
+@center @i{and}
+@sp
+@center @authorfont{Nick Williams}
+@sp 4
+@center Last updated March 1991
+@center Documentation for software revision 5.3 Alpha
+@page
+Copyright @copyright{} 1989 Jan-Simon Pendry
+@sp -1
+Copyright @copyright{} 1989 Imperial College of Science, Technology & Medicine
+@sp -1
+Copyright @copyright{} 1989 The Regents of the University of California.
+@sp 0
+All Rights Reserved.
+@vskip 1ex
+Permission to copy this document, or any portion of it, as
+necessary for use of this software is granted provided this
+copyright notice and statement of permission are included.
+@end titlepage
+@page
+@ifinfo
+@node Top, License, , (DIR)
+
+Amd - The 4.4 BSD Automounter
+*****************************
+
+Amd is the 4.4 BSD Automounter. This Info file describes how
+to use and understand Amd.
+@end ifinfo
+
+@menu
+* License:: Explains the terms and conditions for using
+ and distributing Amd.
+* Distrib:: How to get the latest Amd distribution.
+* Intro:: An introduction to Automounting concepts.
+* Overview:: An overview of Amd.
+* Supported Platforms:: Machines and Systems supported by Amd.
+* Mount Maps:: Details of mount maps
+* Amd Command Line Options:: All the Amd command line options explained.
+* Filesystem Types:: The different mount types supported by Amd.
+* Run-time Administration:: How to start, stop and control Amd.
+* FSinfo:: The FSinfo filesystem management tool.
+* Internals:: Internals.
+* Acknowledgements & Trademarks:: Legal notes.
+* Examples:: Some examples showing how Amd might be used.
+* Internals:: Implementation details.
+* Acknowledgements & Trademarks::
+
+Indexes
+* Index:: An item for each concept.
+@end menu
+
+@iftex
+@unnumbered Preface
+
+This manual documents the use of the 4.4 BSD automounter---@i{Amd}.
+This is primarily a reference manual. Unfortunately, no tutorial
+exists.
+
+This manual comes in two forms: the published form and the Info form.
+The Info form is for on-line perusal with the INFO program which is
+distributed along with GNU Emacs. Both forms contain substantially the
+same text and are generated from a common source file, which is
+distributed with the @i{Amd} source.
+@end iftex
+
+@node License, Distrib, Top, Top
+@unnumbered License
+@cindex License Information
+
+@i{Amd} is not in the public domain; it is copyrighted and there are
+restrictions on its distribution.
+
+Redistribution and use in source and binary forms are permitted provided
+that: (1) source distributions retain this entire copyright notice and
+comment, and (2) distributions including binaries display the following
+acknowledgement: ``This product includes software developed by The
+University of California, Berkeley and its Contributors'' in the
+documentation or other materials provided with the distribution and in
+all advertising materials mentioning features or use of this software.
+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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+@node Distrib, Intro, License, Top
+@unnumbered Source Distribution
+@cindex Source code distribution
+@cindex Obtaining the source code
+
+If you have access to the Internet, you can get the latest distribution
+version of @i{Amd} from host @file{usc.edu} using anonymous FTP. Move to
+the directory @file{/pub/amd} on that host and fetch the file @file{amd.tar.Z}.
+
+If you are in the UK, you can get the latest distribution version of
+@i{Amd} from the UKnet info-server. Start by sending email to
+@file{info-server@@doc.ic.ac.uk}.
+
+Sites on the UK JANET network can get the latest distribution by using
+anonymous NIFTP to fetch the file @samp{<AMD>amd.tar.Z} from host
+@samp{uk.ac.imperial.doc.src}.
+
+Revision 5.2 was part of the 4.3 BSD Reno distribution.
+
+Revision 5.3bsdnet, a late alpha version of 5.3, was part
+of the BSD network version 2 distribution
+
+@unnumberedsec Bug Reports
+@cindex Bug reports
+
+Send all bug reports to @file{jsp@@doc.ic.ac.uk} quoting the details of
+the release and your configuration. These can be obtained by running
+the command @samp{amd -v}.
+
+@unnumberedsec Mailing List
+@cindex Mailing list
+
+There is a mailing list for people interested in keeping uptodate with
+developments. To subscribe, send a note to @file{amd-workers-request@@acl.lanl.gov}.
+
+@node Intro, Overview, Distrib, Top
+@unnumbered Introduction
+@cindex Introduction
+
+An @dfn{automounter} maintains a cache of mounted filesystems.
+Filesystems are mounted on demand when they are first referenced,
+and unmounted after a period of inactivity.
+
+@i{Amd} may be used as a replacement for Sun's automounter. The choice
+of which filesystem to mount can be controlled dynamically with
+@dfn{selectors}. Selectors allow decisions of the form ``hostname is
+@var{this},'' or ``architecture is not @var{that}.'' Selectors may be
+combined arbitrarily. @i{Amd} also supports a variety of filesystem
+types, including NFS, UFS and the novel @dfn{program} filesystem. The
+combination of selectors and multiple filesystem types allows identical
+configuration files to be used on all machines so reducing the
+administrative overhead.
+
+@i{Amd} ensures that it will not hang if a remote server goes down.
+Moreover, @i{Amd} can determine when a remote server has become
+inaccessible and then mount replacement filesystems as and when they
+become available.
+
+@i{Amd} contains no proprietary source code and has been ported to
+numerous flavours of Unix.
+
+@node Overview, Supported Platforms, Intro, Top
+@chapter Overview
+
+@i{Amd} maintains a cache of mounted filesystems. Filesystems are
+@dfn{demand-mounted} when they are first referenced, and unmounted after
+a period of inactivity. @i{Amd} may be used as a replacement for Sun's
+@b{automount}(8) program. It contains no proprietary source code and
+has been ported to numerous flavours of Unix. @xref{Supported Operating
+Systems}.@refill
+
+@i{Amd} was designed as the basis for experimenting with filesystem
+layout and management. Although @i{Amd} has many direct applications it
+is loaded with additional features which have little practical use. At
+some point the infrequently used components may be removed to streamline
+the production system.
+
+@c @i{Amd} supports the notion of @dfn{replicated} filesystems by evaluating
+@c each member of a list of possible filesystem locations in parallel.
+@c @i{Amd} checks that each cached mapping remains valid. Should a mapping be
+@c lost -- such as happens when a fileserver goes down -- @i{Amd} automatically
+@c selects a replacement should one be available.
+@c
+@menu
+* Fundamentals::
+* Filesystems and Volumes::
+* Volume Naming::
+* Volume Binding::
+* Operational Principles::
+* Mounting a Volume::
+* Automatic Unmounting::
+* Keep-alives::
+* Non-blocking Operation::
+@end menu
+
+@node Fundamentals, Filesystems and Volumes, Overview, Overview
+@comment node-name, next, previous, up
+@section Fundamentals
+@cindex Automounter fundamentals
+
+The fundamental concept behind @i{Amd} is the ability to separate the
+name used to refer to a file from the name used to refer to its physical
+storage location. This allows the same files to be accessed with the
+same name regardless of where in the network the name is used. This is
+very different from placing @file{/n/hostname} in front of the pathname
+since that includes location dependent information which may change if
+files are moved to another machine.
+
+By placing the required mappings in a centrally administered database,
+filesystems can be re-organised without requiring changes to
+configuration files, shell scripts and so on.
+
+@node Filesystems and Volumes, Volume Naming, Fundamentals, Overview
+@comment node-name, next, previous, up
+@section Filesystems and Volumes
+@cindex Filesystem
+@cindex Volume
+@cindex Fileserver
+@cindex sublink
+
+@i{Amd} views the world as a set of fileservers, each containg one or
+more filesystems where each filesystem contains one or more
+@dfn{volumes}. Here the term @dfn{volume} is used to refer to a
+coherent set of files such as a user's home directory or a @TeX{}
+distribution.@refill
+
+In order to access the contents of a volume, @i{Amd} must be told in
+which filesystem the volume resides and which host owns the filesystem.
+By default the host is assumed to be local and the volume is assumed to
+be the entire filesystem. If a filesystem contains more than one
+volume, then a @dfn{sublink} is used to refer to the sub-directory
+within the filesystem where the volume can be found.
+
+@node Volume Naming, Volume Binding, Filesystems and Volumes, Overview
+@comment node-name, next, previous, up
+@section Volume Naming
+@cindex Volume names
+@cindex Network-wide naming
+@cindex Replicated volumes
+@cindex Duplicated volumes
+@cindex Replacement volumes
+
+Volume names are defined to be unique across the entire network. A
+volume name is the pathname to the volume's root as known by the users
+of that volume. Since this name uniquely identifies the volume
+contents, all volumes can be named and accessed from each host, subject
+to administrative controls.
+
+Volumes may be replicated or duplicated. Replicated volumes contain
+identical copies of the same data and reside at two or more locations in
+the network. Each of the replicated volumes can be used
+interchangeably. Duplicated volumes each have the same name but contain
+different, though functionally identical, data. For example,
+@samp{/vol/tex} might be the name of a @TeX{} distribution which varied
+for each machine architecture.@refill
+
+@i{Amd} provides facilities to take advantage of both replicated and
+duplicated volumes. Configuration options allow a single set of
+configuration data to be shared across an entire network by taking
+advantage of replicated and duplicated volumes.
+
+@i{Amd} can take advantage of replacement volumes by mounting them as
+required should an active fileserver become unavailable.
+
+@node Volume Binding, Operational Principles, Volume Naming, Overview
+@comment node-name, next, previous, up
+@section Volume Binding
+@cindex Volume binding
+@cindex Unix namespace
+@cindex Namespace
+@cindex Binding names to filesystems
+
+Unix implements a namespace of hierarchically mounted filesystems. Two
+forms of binding between names and files are provided. A @dfn{hard
+link} completes the binding when the name is added to the filesystem. A
+@dfn{soft link} delays the binding until the name is accessed. An
+@dfn{automounter} adds a further form in which the binding of name to
+filesystem is delayed until the name is accessed.@refill
+
+The target volume, in its general form, is a tuple (host, filesystem,
+sublink) which can be used to name the physical location of any volume
+in the network.
+
+When a target is referenced, @i{Amd} ignores the sublink element and
+determines whether the required filesystem is already mounted. This is
+done by computing the local mount point for the filesystem and checking
+for an existing filesystem mounted at the same place. If such a
+filesystem already exists then it is assumed to be functionally
+identical to the target filesystem. By default there is a one-to-one
+mapping between the pair (host, filesystem) and the local mount point so
+this assumption is valid.
+
+@node Operational Principles, Mounting a Volume, Volume Binding, Overview
+@comment node-name, next, previous, up
+@section Operational Principles
+@cindex Operational principles
+
+@i{Amd} operates by introducing new mount points into the namespace.
+These are called @dfn{automount} points. The kernel sees these
+automount points as NFS filesystems being served by @i{Amd}. Having
+attached itself to the namespace, @i{Amd} is now able to control the
+view the rest of the system has of those mount points. RPC calls are
+received from the kernel one at a time.
+
+When a @dfn{lookup} call is received @i{Amd} checks whether the name is
+already known. If it is not, the required volume is mounted. A
+symbolic link pointing to the volume root is then returned. Once the
+symbolic link is returned, the kernel will send all other requests
+direct to the mounted filesystem.
+
+If a volume is not yet mounted, @i{Amd} consults a configuration
+@dfn{mount-map} corresponding to the automount point. @i{Amd} then
+makes a runtime decision on what and where to mount a filesystem based
+on the information obtained from the map.
+
+@i{Amd} does not implement all the NFS requests; only those relevant
+to name binding such as @dfn{lookup}, @dfn{readlink} and @dfn{readdir}.
+Some other calls are also implemented but most simply return an error
+code; for example @dfn{mkdir} always returns ``read-only filesystem''.
+
+@node Mounting a Volume, Automatic Unmounting, Operational Principles, Overview
+@comment node-name, next, previous, up
+@section Mounting a Volume
+@cindex Mounting a volume
+@cindex Location lists
+@cindex Alternate locations
+@cindex Mount retries
+@cindex Background mounts
+
+Each automount point has a corresponding mount map. The mount map
+contains a list of key--value pairs. The key is the name of the volume
+to be mounted. The value is a list of locations describing where the
+filesystem is stored in the network. In the source for the map the
+value would look like
+
+@display
+location1 location2 @dots{} locationN
+@end display
+
+@i{Amd} examines each location in turn. Each location may contain
+@dfn{selectors} which control whether @i{Amd} can use that location.
+For example, the location may be restricted to use by certain hosts.
+Those locations which cannot be used are ignored.
+
+@i{Amd} attempts to mount the filesystem described by each remaining
+location until a mount succeeds or @i{Amd} can no longer proceed. The
+latter can occur in three ways:
+
+@itemize @bullet
+@item
+If none of the locations could be used, or if all of the locations
+caused an error, then the last error is returned.
+
+@item
+If a location could be used but was being mounted in the background then
+@i{Amd} marks that mount as being ``in progress'' and continues with
+the next request; no reply is sent to the kernel.
+
+@item
+Lastly, one or more of the mounts may have been @dfn{deferred}. A mount
+is deferred if extra information is required before the mount can
+proceed. When the information becomes available the mount will take
+place, but in the mean time no reply is sent to the kernel. If the
+mount is deferred, @i{Amd} continues to try any remaining locations.
+@end itemize
+
+Once a volume has been mounted, @i{Amd} establishes a @dfn{volume
+mapping} which is used to satisfy subsequent requests.@refill
+
+@node Automatic Unmounting, Keep-alives, Mounting a Volume, Overview
+@comment node-name, next, previous, up
+@section Automatic Unmounting
+
+To avoid an ever increasing number of filesystem mounts, @i{Amd} removes
+volume mappings which have not been used recently. A time-to-live
+interval is associated with each mapping and when that expires the
+mapping is removed. When the last reference to a filesystem is removed,
+that filesystem is unmounted. If the unmount fails, for example the
+filesystem is still busy, the mapping is re-instated and its
+time-to-live interval is extended. The global default for this grace
+period is controlled by the ``-w'' command-line option (@pxref{-w
+Option, -w}). It is also possible to set this value on a per-mount
+basis (@pxref{opts Option, opts, opts}).@refill
+
+Filesystems can be forcefully timed out using the @i{Amq} command.
+@xref{Run-time Administration}.
+
+@node Keep-alives, Non-blocking Operation, Automatic Unmounting, Overview
+@comment node-name, next, previous, up
+@section Keep-alives
+@cindex Keep-alives
+@cindex Server crashes
+@cindex NFS ping
+
+Use of some filesystem types requires the presence of a server on
+another machine. If a machine crashes then it is of no concern to
+processes on that machine that the filesystem is unavailable. However,
+to processes on a remote host using that machine as a fileserver this
+event is important. This situation is most widely recognised when an
+NFS server crashes and the behaviour observed on client machines is that
+more and more processes hang. In order to provide the possibility of
+recovery, @i{Amd} implements a @dfn{keep-alive} interval timer for some
+filesystem types. Currently only NFS makes use of this service.
+
+The basis of the NFS keep-alive implementation is the observation that
+most sites maintain replicated copies of common system data such as
+manual pages, most or all programs, system source code and so on. If
+one of those servers goes down it would be reasonable to mount one of
+the others as a replacement.
+
+The first part of the process is to keep track of which fileservers are
+up and which are down. @i{Amd} does this by sending RPC requests to the
+servers' NFS @code{NullProc} and checking whether a reply is returned.
+While the server state is uncertain the requests are re-transmitted at
+three second intervals and if no reply is received after four attempts
+the server is marked down. If a reply is received the fileserver is
+marked up and stays in that state for 30 seconds at which time another
+NFS ping is sent.
+
+Once a fileserver is marked down, requests continue to be sent every 30
+seconds in order to determine when the fileserver comes back up. During
+this time any reference through @i{Amd} to the filesystems on that
+server fail with the error ``Operation would block''. If a replacement
+volume is available then it will be mounted, otherwise the error is
+returned to the user.
+
+@c @i{Amd} keeps track of which servers are up and which are down.
+@c It does this by sending RPC requests to the servers' NFS {\sc NullProc} and
+@c checking whether a reply is returned. If no replies are received after a
+@c short period, @i{Amd} marks the fileserver @dfn{down}.
+@c RPC requests continue to be sent so that it will notice when a fileserver
+@c comes back up.
+@c ICMP echo packets \cite{rfc:icmp} are not used because it is the availability
+@c of the NFS service that is important, not the existence of a base kernel.
+@c Whenever a reference to a fileserver which is down is made via @i{Amd}, an alternate
+@c filesystem is mounted if one is available.
+@c
+Although this action does not protect user files, which are unique on
+the network, or processes which do not access files via @i{Amd} or
+already have open files on the hung filesystem, it can prevent most new
+processes from hanging.
+
+By default, fileserver state is not maintained for NFS/TCP mounts. The
+remote fileserver is always assumed to be up.
+@c
+@c With a suitable combination of filesystem management and mount-maps,
+@c machines can be protected against most server downtime. This can be
+@c enhanced by allocating boot-servers dynamically which allows a diskless
+@c workstation to be quickly restarted if necessary. Once the root filesystem
+@c is mounted, @i{Amd} can be started and allowed to mount the remainder of
+@c the filesystem from whichever fileservers are available.
+
+@node Non-blocking Operation, , Keep-alives, Overview
+@comment node-name, next, previous, up
+@section Non-blocking Operation
+@cindex Non-blocking operation
+@cindex Multiple-threaded server
+@cindex RPC retries
+
+Since there is only one instance of @i{Amd} for each automount point,
+and usually only one instance on each machine, it is important that it
+is always available to service kernel calls. @i{Amd} goes to great
+lengths to ensure that it does not block in a system call. As a last
+resort @i{Amd} will fork before it attempts a system call that may block
+indefinitely, such as mounting an NFS filesystem. Other tasks such as
+obtaining filehandle information for an NFS filesystem, are done using a
+purpose built non-blocking RPC library which is integrated with
+@i{Amd}'s task scheduler. This library is also used to implement NFS
+keep-alives (@pxref{Keep-alives}).
+
+Whenever a mount is deferred or backgrounded, @i{Amd} must wait for it
+to complete before replying to the kernel. However, this would cause
+@i{Amd} to block waiting for a reply to be constructed. Rather than do
+this, @i{Amd} simply @dfn{drops} the call under the assumption that the
+kernel RPC mechanism will automatically retry the request.
+
+@node Supported Platforms, Mount Maps, Overview, Top
+@comment node-name, next, previous, up
+@chapter Supported Platforms
+
+@i{Amd} has been ported to a wide variety of machines and operating systems.
+The table below lists those platforms supported by the current release.
+
+@menu
+* Supported Operating Systems::
+* Supported Machine Architectures::
+@end menu
+
+@node Supported Operating Systems, Supported Machine Architectures, Supported Platforms, Supported Platforms
+@comment node-name, next, previous, up
+@section Supported Operating Systems
+@cindex Operating system names
+@cindex Operating systems supported by Amd
+@cindex Supported operating systems
+
+The following operating systems are currently supported by @i{Amd}.
+@i{Amd}'s conventional name for each system is given.
+
+@table @code
+@item acis43
+4.3 BSD for IBM RT. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item aix3
+AIX 3.1. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item aux
+System V for Mac-II. Contributed by Julian Onions @t{<jpo@@cs.nott.ac.uk>}
+@item bsd44
+4.4 BSD. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item concentrix
+Concentrix 5.0. Contributed by Sjoerd Mullender @t{<sjoerd@@cwi.nl>}
+@item convex
+Convex OS 7.1. Contributed by Eitan Mizrotsky @t{<eitan@@shumuji.ac.il>}
+@item dgux
+Data General DG/UX. Contributed by Mark Davies @t{<mark@@comp.vuw.ac.nz>}
+@item fpx4
+Celerity FPX 4.1/2. Contributed by Stephen Pope @t{<scp@@grizzly.acl.lanl.gov>}
+@item hcx
+Harris HCX/UX. Contributed by Chris Metcalf @t{<metcalf@@masala.lcs.mit.edu>}
+@item hlh42
+HLH OTS 1.@i{x} (4.2 BSD). Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item hpux
+HP-UX 6.@i{x} or 7.0. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item irix
+SGI Irix. Contributed by Scott R. Presnell @t{<srp@@cgl.ucsf.edu>}
+@item next
+Mach for NeXT. Contributed by Bill Trost @t{<trost%reed@@cse.ogi.edu>}
+@item pyrOSx
+Pyramid OSx. Contributed by Stefan Petri @t{<petri@@tubsibr.UUCP>}
+@item riscix
+Acorn RISC iX. Contributed by Piete Brooks @t{<pb@@cam.cl.ac.uk>}
+@item sos3
+SunOS 3.4 & 3.5. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item sos4
+SunOS 4.@i{x}. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@item u2_2
+Ultrix 2.2. Contributed by Piete Brooks @t{<pb@@cam.cl.ac.uk>}
+@item u3_0
+Ultrix 3. Contributed by Piete Brooks @t{<pb@@cam.cl.ac.uk>}
+@item u4_0
+Ultrix 4.0. Contributed by Chris Lindblad @t{<cjl@@ai.mit.edu>}
+@item umax43
+Umax 4.3 BSD. Contributed by Sjoerd Mullender @t{<sjoerd@@cwi.nl>}
+@item utek
+Utek 4.0. Contributed by Bill Trost @t{<trost%reed@@cse.ogi.edu>}
+@item xinu43
+mt Xinu MORE/bsd. Contributed by Jan-Simon Pendry @t{<jsp@@doc.ic.ac.uk>}
+@end table
+
+@node Supported Machine Architectures, , Supported Operating Systems, Supported Platforms
+@comment node-name, next, previous, up
+@section Supported Machine Architectures
+@cindex Supported machine architectures
+@cindex Machine architecture names
+@cindex Machine architectures supported by Amd
+
+@table @code
+@item alliant
+Alliant FX/4
+@item arm
+Acorn ARM
+@item aviion
+Data General AViiON
+@item encore
+Encore
+@item fps500
+FPS Model 500
+@item hp9000
+HP 9000/300 family
+@item hp9k8
+HP 9000/800 family
+@item ibm032
+IBM RT
+@item ibm6000
+IBM RISC System/6000
+@item iris4d
+SGI Iris 4D
+@item macII
+Apple Mac II
+@item mips
+MIPS RISC
+@item multimax
+Encore Multimax
+@item orion105
+HLH Orion 1/05
+@item sun3
+Sun-3 family
+@item sun4
+Sun-4 family
+@item tahoe
+Tahoe family
+@item vax
+DEC Vax
+@end table
+
+@node Mount Maps, Amd Command Line Options, Supported Platforms, Top
+@comment node-name, next, previous, up
+@chapter Mount Maps
+@cindex Mount maps
+@cindex Automounter configuration maps
+@cindex Mount information
+
+@i{Amd} has no built-in knowledge of machines or filesystems.
+External @dfn{mount-maps} are used to provide the required information.
+Specifically, @i{Amd} needs to know when and under what conditions it
+should mount filesystems.
+
+The map entry corresponding to the requested name contains a list of
+possible locations from which to resolve the request. Each location
+specifies filesystem type, information required by that filesystem (for
+example the block special device in the case of UFS), and some
+information describing where to mount the filesystem (@pxref{fs Option}). A
+location may also contain @dfn{selectors} (@pxref{Selectors}).@refill
+
+@menu
+* Map Types::
+* Key Lookup::
+* Location Format::
+@end menu
+
+@node Map Types, Key Lookup, Mount Maps, Mount Maps
+@comment node-name, next, previous, up
+@section Map Types
+@cindex Mount map types
+@cindex Map types
+@cindex Configuration map types
+@cindex Types of mount map
+@cindex Types of configuration map
+@cindex Determining the map type
+
+A mount-map provides the run-time configuration information to @i{Amd}.
+Maps can be implemented in many ways. Some of the forms supported by
+@i{Amd} are regular files, ndbm databases, NIS maps the @dfn{Hesiod}
+name server and even the password file.
+
+A mount-map @dfn{name} is a sequence of characters. When an automount
+point is created a handle on the mount-map is obtained. For each map
+type configured @i{Amd} attempts to reference the a map of the
+appropriate type. If a map is found, @i{Amd} notes the type for future
+use and deletes the reference, for example closing any open file
+descriptors. The available maps are configure when @i{Amd} is built and
+can be displayed by running the command @samp{amd -v}.
+
+By default, @i{Amd} caches data in a mode dependent on the type of map.
+This is the same as specifying @samp{cache:=mapdefault} and selects a
+suitable default cache mode depending on the map type. The individual
+defaults are described below. The @var{cache} option can be specified
+on automount points to alter the caching behaviour (@pxref{Automount
+Filesystem}).@refill
+
+The following map types have been implemented, though some are not
+available on all machines. Run the command @samp{amd -v} to obtain a
+list of map types configured on your machine.
+
+@menu
+* File maps::
+* ndbm maps::
+* NIS maps::
+* Hesiod maps::
+* Password maps::
+* Union maps::
+@end menu
+
+@node File maps, ndbm maps, Map Types, Map Types
+@comment node-name, next, previous, up
+@subsection File maps
+@cindex File maps
+@cindex Flat file maps
+@cindex File map syntactic conventions
+
+When @i{Amd} searches a file for a map entry it does a simple scan of
+the file and supports both comments and continuation lines.
+
+Continuation lines are indicated by a backslash character (@samp{\}) as
+the last character of a line in the file. The backslash, newline character
+@emph{and any leading white space on the following line} are discarded. A maximum
+line length of 2047 characters is enforced after continuation lines are read
+but before comments are stripped. Each line must end with
+a newline character; that is newlines are terminators, not separators.
+The following examples illustrate this:
+
+@example
+key valA valB; \
+ valC
+@end example
+
+specifies @emph{three} locations, and is identical to
+
+@example
+key valA valB; valC
+@end example
+
+However,
+
+@example
+key valA valB;\
+ valC
+@end example
+
+specifies only @emph{two} locations, and is identical to
+
+@example
+key valA valB;valC
+@end example
+
+After a complete line has been read from the file, including
+continuations, @i{Amd} determines whether there is a comment on the
+line. A comment begins with a hash (``@samp{#}'') character and
+continues to the end of the line. There is no way to escape or change
+the comment lead-in character.
+
+Note that continuation lines and comment support @dfn{only} apply to
+file maps, or ndbm maps built with the @code{mk-amd-map} program.
+
+When caching is enabled, file maps have a default cache mode of
+@code{all} (@pxref{Automount Filesystem}).
+
+@node ndbm maps, NIS maps, File maps, Map Types
+@comment node-name, next, previous, up
+@subsection ndbm maps
+@cindex ndbm maps
+
+An ndbm map may be used as a fast access form of a file map. The program,
+@code{mk-amd-map}, converts a normal map file into an ndbm database.
+This program supports the same continuation and comment conventions that
+are provided for file maps. Note that ndbm format files may @emph{not}
+be sharable across machine architectures. The notion of speed generally
+only applies to large maps; a small map, less than a single disk block,
+is almost certainly better implemented as a file map.
+
+ndbm maps do not support cache mode @samp{all} and, when caching is
+enabled, have a default cache mode of @samp{inc} (@pxref{Automount Filesystem}).
+
+@node NIS maps, Hesiod maps, ndbm maps, Map Types
+@comment node-name, next, previous, up
+@subsection NIS maps
+@cindex NIS (YP) maps
+
+When using NIS (formerly YP), an @i{Amd} map is implemented directly
+by the underlying NIS map. Comments and continuation lines are
+@emph{not} supported in the automounter and must be stripped when
+constructing the NIS server's database.
+
+NIS maps do not support cache mode @code{all} and, when caching is
+enabled, have a default cache mode of @code{inc} (@pxref{Automount Filesystem}).
+
+The following rule illustrates what could be added to your NIS @file{Makefile},
+in this case causing the @file{amd.home} map to be rebuilt:
+@example
+$(YPTSDIR)/amd.home.time: $(ETCDIR)/amd.home
+ -@@sed -e "s/#.*$$//" -e "/^$$/d" $(ETCDIR)/amd.home | \
+ awk '@{ \
+ for (i = 1; i <= NF; i++) \
+ if (i == NF) @{ \
+ if (substr($$i, length($$i), 1) == "\\") \
+ printf("%s", substr($$i, 1, length($$i) - 1)); \
+ else \
+ printf("%s\n", $$i); \
+ @} \
+ else \
+ printf("%s ", $$i); \
+ @}' | \
+ $(MAKEDBM) - $(YPDBDIR)/amd.home; \
+ touch $(YPTSDIR)/amd.home.time; \
+ echo "updated amd.home"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) amd.home; \
+ echo "pushed amd.home"; \
+ else \
+ : ; \
+ fi
+@end example
+
+Here @code{$(YPTSDIR)} contains the time stamp files, and @code{$(YPDBDIR)} contains
+the dbm format NIS files.
+
+@node Hesiod maps, Password maps, NIS maps, Map Types
+@comment node-name, next, previous, up
+@subsection Hesiod maps
+@cindex Hesiod maps
+
+When the map name begins with the string @samp{hesiod.} lookups are made
+using the @dfn{Hesiod} name server. The string following the dot is
+used as a name qualifier and is prepended with the key being located.
+The entire string is then resolved in the @code{automount} context. For
+example, if the the key is @samp{jsp} and map name is
+@samp{hesiod.homes} then @dfn{Hesiod} is asked to resolve
+@samp{jsp.homes.automount}.
+
+Hesiod maps do not support cache mode @samp{all} and, when caching is
+enabled, have a default cache mode of @samp{inc} (@pxref{Automount Filesystem}).
+
+The following is an example of a @dfn{Hesiod} map entry:
+
+@example
+jsp.homes.automount HS TXT "rfs:=/home/charm;rhost:=charm;sublink:=jsp"
+njw.homes.automount HS TXT "rfs:=/home/dylan/dk2;rhost:=dylan;sublink:=njw"
+@end example
+
+@node Password maps, Union maps, Hesiod maps, Map Types
+@comment node-name, next, previous, up
+@subsection Password maps
+@cindex Password file maps
+@cindex /etc/passwd maps
+@cindex User maps, automatic generation
+@cindex Automatic generation of user maps
+@cindex Using the password file as a map
+
+The password map support is unlike the four previous map types. When
+the map name is the string @file{/etc/passwd} @i{Amd} can lookup a user
+name in the password file and re-arrange the home directory field to
+produce a usable map entry.
+
+@i{Amd} assumes the home directory has the format
+`@t{/}@i{anydir}@t{/}@i{dom1}@t{/../}@i{domN}@t{/}@i{login}'.
+@c @footnote{This interpretation is not necessarily exactly what you want.}
+It breaks this string into a map entry where @code{$@{rfs@}} has the
+value `@t{/}@i{anydir}@t{/}@i{domN}', @code{$@{rhost@}} has the value
+`@i{domN}@t{.}@i{...}@t{.}@i{dom1}', and @code{$@{sublink@}} has the
+value @samp{login}.@refill
+
+Thus if the password file entry was
+
+@example
+/home/achilles/jsp
+@end example
+
+the map entry used by @i{Amd} would be
+
+@example
+rfs:=/home/achilles;rhost:=achilles;sublink:=jsp
+@end example
+
+Similarly, if the password file entry was
+
+@example
+/home/cc/sugar/mjh
+@end example
+
+the map entry used by @i{Amd} would be
+
+@example
+rfs:=/home/sugar;rhost:=sugar.cc;sublink:=jsp
+@end example
+
+@node Union maps, , Password maps, Map Types
+@comment node-name, next, previous, up
+@subsection Union maps
+@cindex Union file maps
+
+The union map support is provided specifically for use with the union
+filesystem, @pxref{Union Filesystem}.
+
+It is identified by the string @samp{union:} which is followed by a
+colon separated list of directories. The directories are read in order,
+and the names of all entries are recorded in the map cache. Later
+directories take precedence over earlier ones. The union filesystem
+type then uses the map cache to determine the union of the names in all
+the directories.
+
+@c subsection Gdbm
+
+@node Key Lookup, Location Format, Map Types, Mount Maps
+@comment node-name, next, previous, up
+@section How keys are looked up
+@cindex Key lookup
+@cindex Map lookup
+@cindex Looking up keys
+@cindex How keys are looked up
+@cindex Wildcards in maps
+
+The key is located in the map whose type was determined when the
+automount point was first created. In general the key is a pathname
+component. In some circumstances this may be modified by variable
+expansion (@pxref{Variable Expansion}) and prefixing. If the automount
+point has a prefix, specified by the @var{pref} option, then that is
+prepended to the search key before the map is searched.
+
+If the map cache is a @samp{regexp} cache then the key is treated as an
+egrep-style regular expression, otherwise a normal string comparison is
+made.
+
+If the key cannot be found then a @dfn{wildcard} match is attempted.
+@i{Amd} repeatedly strips the basename from the key, appends @samp{/*} and
+attempts a lookup. Finally, @i{Amd} attempts to locate the special key @samp{*}.
+
+@group
+For example, the following sequence would be checked if @file{home/dylan/dk2} was
+being located:
+
+@example
+ home/dylan/dk2
+ home/dylan/*
+ home/*
+ *
+@end example
+@end group
+
+At any point when a wildcard is found, @i{Amd} proceeds as if an exact
+match had been found and the value field is then used to resolve the
+mount request, otherwise an error code is propagated back to the kernel.
+(@pxref{Filesystem Types}).@refill
+
+@node Location Format, , Key Lookup, Mount Maps
+@comment node-name, next, previous, up
+@section Location Format
+@cindex Location format
+@cindex Map entry format
+@cindex How locations are parsed
+
+The value field from the lookup provides the information required to
+mount a filesystem. The information is parsed according to the syntax
+shown below.
+
+@display
+@i{location-list}:
+ @i{location-selection}
+ @i{location-list} @i{white-space} @t{||} @i{white-space} @i{location-selection}
+@i{location-selection}:
+ @i{location}
+ @i{location-selection} @i{white-space} @i{location}
+@i{location}:
+ @i{location-info}
+ @t{-}@i{location-info}
+ @t{-}
+@i{location-info}:
+ @i{sel-or-opt}
+ @i{location-info}@t{;}@i{sel-or-opt}
+ @t{;}
+@i{sel-or-opt}:
+ @i{selection}
+ @i{opt-ass}
+@i{selection}:
+ selector@t{==}@i{value}
+ selector@t{!=}@i{value}
+@i{opt-ass}:
+ option@t{:=}@i{value}
+@i{white-space}:
+ space
+ tab
+@end display
+
+Note that unquoted whitespace is not allowed in a location description.
+White space is only allowed, and is mandatory, where shown with non-terminal
+@samp{white-space}.
+
+A @dfn{location-selection} is a list of possible volumes with which to
+satisfy the request. @dfn{location-selection}s are separated by the
+@samp{||} operator. The effect of this operator is to prevent use of
+location-selections to its right if any of the location-selections on
+its left were selected whether or not any of them were successfully
+mounted (@pxref{Selectors}).@refill
+
+The location-selection, and singleton @dfn{location-list},
+@samp{type:=ufs;dev:=/dev/xd1g} would inform @i{Amd} to mount a UFS
+filesystem from the block special device @file{/dev/xd1g}.
+
+The @dfn{sel-or-opt} component is either the name of an option required
+by a specific filesystem, or it is the name of a built-in, predefined
+selector such as the architecture type. The value may be quoted with
+double quotes @samp{"}, for example
+@samp{type:="ufs";dev:="/dev/xd1g"}. These quotes are stripped when the
+value is parsed and there is no way to get a double quote into a value
+field. Double quotes are used to get white space into a value field,
+which is needed for the program filesystem (@pxref{Program Filesystem}).@refill
+
+@menu
+* Map Defaults::
+* Variable Expansion::
+* Selectors::
+* Map Options::
+@end menu
+
+@node Map Defaults, Variable Expansion, Location Format, Location Format
+@comment node-name, next, previous, up
+@subsection Map Defaults
+@cindex Map defaults
+@cindex How to set default map parameters
+@cindex Setting default map parameters
+
+A location beginning with a dash @samp{-} is used to specify default
+values for subsequent locations. Any previously specified defaults in
+the location-list are discarded. The default string can be empty in
+which case no defaults apply.
+
+The location @samp{-fs:=/mnt;opts:=ro} would set the local mount point
+to @file{/mnt} and cause mounts to be read-only by default. Defaults
+specified this way are appended to, and so override, any global map
+defaults given with @samp{/defaults}).
+@c
+@c A @samp{/defaults} value @dfn{gdef} and a location list
+@c \begin{quote}
+@c $@samp{-}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$
+@c \end{quote}
+@c is equivalent to
+@c \begin{quote}
+@c $@samp{-}@dfn{gdef}@samp{;}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{gdef}@samp{;}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$
+@c \end{quote}
+@c which is equivalent to
+@c \begin{quote}
+@c $@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_1} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_2} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_b@samp{;}@dfn{loc}_{b_1} \ldots$
+@c \end{quote}
+
+@node Variable Expansion, Selectors, Map Defaults, Location Format
+@comment node-name, next, previous, up
+@subsection Variable Expansion
+@cindex Variable expansion
+@cindex How variables are expanded
+@cindex Pathname operators
+@cindex Domain stripping
+@cindex Domainname operators
+@cindex Stripping the local domain name
+@cindex Environment variables
+@cindex How to access environment variables in maps
+
+To allow generic location specifications @i{Amd} does variable expansion
+on each location and also on some of the option strings. Any option or
+selector appearing in the form @code{$@dfn{var}} is replaced by the
+current value of that option or selector. For example, if the value of
+@code{$@{key@}} was @samp{bin}, @code{$@{autodir@}} was @samp{/a} and
+@code{$@{fs@}} was `@t{$@{autodir@}}@t{/local/}@t{$@{key@}}' then
+after expansion @code{$@{fs@}} would have the value @samp{/a/local/bin}.
+Any environment variable can be accessed in a similar way.@refill
+
+Two pathname operators are available when expanding a variable. If the
+variable name begins with @samp{/} then only the last component of
+then pathname is substituted. For example, if @code{$@{path@}} was
+@samp{/foo/bar} then @code{$@{/path@}} would be expanded to @samp{bar}.
+Similarly, if the variable name ends with @samp{/} then all but the
+last component of the pathname is substituted. In the previous example,
+@code{$@{path/@}} would be expanded to @samp{/foo}.@refill
+
+Two domain name operators are also provided. If the variable name
+begins with @samp{.} then only the domain part of the name is
+substituted. For example, if @code{$@{rhost@}} was
+@samp{swan.doc.ic.ac.uk} then @code{$@{.rhost@}} would be expanded to
+@samp{doc.ic.ac.uk}. Similarly, if the variable name ends with @samp{.}
+then only the host component is substituted. In the previous example,
+@code{$@{rhost.@}} would be expanded to @samp{swan}.@refill
+
+Variable expansion is a two phase process. Before a location is parsed,
+all references to selectors, @i{eg} @code{$@{path@}}, are expanded. The
+location is then parsed, selections are evaluated and option assignments
+recorded. If there were no selections or they all succeeded the
+location is used and the values of the following options are expanded in
+the order given: @var{sublink}, @var{rfs}, @var{fs}, @var{opts},
+@var{remopts}, @var{mount} and @var{unmount}.
+
+Note that expansion of option values is done after @dfn{all} assignments
+have been completed and not in a purely left to right order as is done
+by the shell. This generally has the desired effect but care must be
+taken if one of the options references another, in which case the
+ordering can become significant.
+
+There are two special cases concerning variable expansion:
+
+@enumerate
+@item
+before a map is consulted, any selectors in the name received
+from the kernel are expanded. For example, if the request from the
+kernel was for `@t{$@{arch@}}@t{.bin}' and the machine architecture
+was @samp{vax}, the value given to @code{$@{key@}} would be
+@samp{vax.bin}.@refill
+
+@item
+the value of @code{$@{rhost@}} is expanded and normalized before the
+other options are expanded. The normalization process strips any local
+sub-domain components. For example, if @code{$@{domain@}} was
+@samp{Berkeley.EDU} and @code{$@{rhost@}} was initially
+@samp{snow.Berkeley.EDU}, after the normalization it would simply be
+@samp{snow}. Hostname normalization is currently done in a
+@emph{case-dependent} manner.@refill
+@end enumerate
+
+@node Selectors, Map Options, Variable Expansion, Location Format
+@comment node-name, next, previous, up
+@subsection Selectors
+@cindex Selectors
+
+Selectors are used to control the use of a location. It is possible to
+share a mount map between many machines in such a way that filesystem
+location, architecture and operating system differences are hidden from
+the users. A selector of the form @samp{arch==sun3;os==sos4} would only
+apply on Sun-3s running SunOS 4.x.
+
+Selectors are evaluated left to right. If a selector fails then that
+location is ignored. Thus the selectors form a conjunction and the
+locations form a disjunction. If all the locations are ignored or
+otherwise fail then @i{Amd} uses the @dfn{error} filesystem
+(@pxref{Error Filesystem}). This is equivalent to having a location
+@samp{type:=error} at the end of each mount-map entry.@refill
+
+The selectors currently implemented are:
+
+@table @samp
+@cindex arch, mount selector
+@cindex Mount selector; arch
+@cindex Selector; arch
+@item arch
+the machine architecture which was automatically determined at compile
+time. The architecture type can be displayed by running the command
+@samp{amd -v}. @xref{Supported Machine Architectures}.@refill
+
+@item autodir
+@cindex autodir, mount selector
+@cindex Mount selector; autodir
+@cindex Selector; autodir
+the default directory under which to mount filesystems. This may be
+changed by the ``-a'' command line option. See the @var{fs} option.
+
+@item byte
+@cindex byte, mount selector
+@cindex Mount selector; byte
+@cindex Selector; byte
+the machine's byte ordering. This is either @samp{little}, indicating
+little-endian, or @samp{big}, indicating big-endian. One possible use
+is to share @samp{rwho} databases (@pxref{rwho servers}). Another is to
+share ndbm databases, however this use can be considered a courageous
+juggling act.
+
+@item cluster
+@cindex cluster, mount selector
+@cindex Mount selector; cluster
+@cindex Selector; cluster
+is provided as a hook for the name of the local cluster. This can be
+used to decide which servers to use for copies of replicated
+filesystems. @code{$@{cluster@}} defaults to the value of
+@code{$@{domain@}} unless a different value is set with the ``-C''
+command line option.
+
+@item domain
+@cindex domain, mount selector
+@cindex Mount selector; domain
+@cindex Selector; domain
+the local domain name as specified by the ``-d'' command line option.
+See @samp{host}.
+
+@item host
+@cindex host, mount selector
+@cindex Mount selector; host
+@cindex Selector; host
+the local hostname as determined by @b{gethostname}(2). If no domain
+name was specified on the command line and the hostname contains a
+period @samp{.} then the string before the period is used as the
+host name, and the string after the period is assigned to
+@code{$@{domain@}}. For example, if the hostname is
+@samp{styx.doc.ic.ac.uk} then @code{host} would be @samp{styx} and
+@code{domain} would be @samp{doc.ic.ac.uk}. @code{hostd} would be
+@samp{styx.doc.ic.ac.uk}.@refill
+
+@item hostd
+@cindex hostd, mount selector
+@cindex Mount selector; hostd
+@cindex Selector; hostd
+is @code{$@{host@}} and @code{$@{domain@}} concatenated with a
+@samp{.} inserted between them if required. If @code{$@{domain@}}
+is an empty string then @code{$@{host@}} and @code{$@{hostd@}} will be
+identical.
+
+@item karch
+@cindex karch, mount selector
+@cindex Mount selector; karch
+@cindex Selector; karch
+is provided as a hook for the kernel architecture. This is used on
+SunOS 4, for example, to distinguish between different @samp{/usr/kvm}
+volumes. @code{$@{karch@}} defaults to the value of @code{$@{arch@}}
+unless a different value is set with the ``-k'' command line option.
+
+@item os
+@cindex os, mount selector
+@cindex Mount selector; os
+@cindex Selector; os
+the operating system. Like the machine architecture, this is
+automatically determined at compile time. The operating system name can
+be displayed by running the command @samp{amd -v}. @xref{Supported
+Operating Systems}.@refill
+
+@end table
+
+The following selectors are also provided. Unlike the other selectors,
+they vary for each lookup. Note that when the name from the kernel is
+expanded prior to a map lookup, these selectors are all defined as empty
+strings.
+
+@table @samp
+@item key
+@cindex key, mount selector
+@cindex Mount selector; key
+@cindex Selector; key
+the name being resolved. For example, if @file{/home} is an automount
+point, then accessing @file{/home/foo} would set @code{$@{key@}} to the
+string @samp{foo}. The key is prefixed by the @var{pref} option set in
+the parent mount point. The default prefix is an empty string. If the
+prefix was @file{blah/} then @code{$@{key@}} would be set to
+@file{blah/foo}.@refill
+
+@item map
+@cindex map, mount selector
+@cindex Mount selector; map
+@cindex Selector; map
+the name of the mount map being used.
+
+@item path
+@cindex path, mount selector
+@cindex Mount selector; path
+@cindex Selector; path
+the full pathname of the name being resolved. For example
+@file{/home/foo} in the example above.
+
+@item wire
+@cindex wire, mount selector
+@cindex Mount selector; wire
+@cindex Selector; wire
+the name of the network to which the primary network interface is
+attached. If a symbolic name cannot be found in the networks or hosts
+database then dotted IP address format is used. This value is also
+output by the ``-v'' option.
+
+@end table
+
+Selectors can be negated by using @samp{!=} instead of @samp{==}. For
+example to select a location on all non-Vax machines the selector
+@samp{arch!=vax} would be used.
+
+@node Map Options, , Selectors, Location Format
+@comment node-name, next, previous, up
+@subsection Map Options
+@cindex Map options
+@cindex Setting map options
+
+Options are parsed concurrently with selectors. The difference is that
+when an option is seen the string following the @samp{:=} is
+recorded for later use. As a minimum the @var{type} option must be
+specified. Each filesystem type has other options which must also be
+specified. @xref{Filesystem Types}, for details on the filesystem
+specific options.@refill
+
+Superfluous option specifications are ignored and are not reported
+as errors.
+
+The following options apply to more than one filesystem type.
+
+@menu
+* delay Option::
+* fs Option::
+* opts Option::
+* remopts Option::
+* sublink Option::
+* type Option::
+@end menu
+
+@node delay Option, fs Option, Map Options, Map Options
+@comment node-name, next, previous, up
+@subsubsection delay Option
+@cindex Setting a delay on a mount location
+@cindex Delaying mounts from specific locations
+@cindex Primary server
+@cindex Secondary server
+@cindex delay, mount option
+@cindex Mount option; delay
+
+The delay, in seconds, before an attempt will be made to mount from the current location.
+Auxilliary data, such as network address, file handles and so on are computed
+regardless of this value.
+
+A delay can be used to implement the notion of primary and secondary file servers.
+The secondary servers would have a delay of a few seconds,
+thus giving the primary servers a chance to respond first.
+
+@node fs Option, opts Option, delay Option, Map Options
+@comment node-name, next, previous, up
+@subsubsection fs Option
+@cindex Setting the local mount point
+@cindex Overriding the default mount point
+@cindex fs, mount option
+@cindex Mount option; fs
+
+The local mount point. The semantics of this option vary between
+filesystems.
+
+For NFS and UFS filesystems the value of @code{$@{fs@}} is used as the
+local mount point. For other filesystem types it has other meanings
+which are described in the section describing the respective filesystem
+type. It is important that this string uniquely identifies the
+filesystem being mounted. To satisfy this requirement, it should
+contain the name of the host on which the filesystem is resident and the
+pathname of the filesystem on the local or remote host.
+
+The reason for requiring the hostname is clear if replicated filesystems
+are considered. If a fileserver goes down and a replacement filesystem
+is mounted then the @dfn{local} mount point @dfn{must} be different from
+that of the filesystem which is hung. Some encoding of the filesystem
+name is required if more than one filesystem is to be mounted from any
+given host.
+
+If the hostname is first in the path then all mounts from a particular
+host will be gathered below a single directory. If that server goes
+down then the hung mount points are less likely to be accidentally
+referenced, for example when @b{getwd}(3) traverses the namespace to
+find the pathname of the current directory.
+
+The @samp{fs} option defaults to
+@code{$@{autodir@}/$@{rhost@}$@{rfs@}}. In addition,
+@samp{rhost} defaults to the local host name (@code{$@{host@}}) and
+@samp{rfs} defaults to the value of @code{$@{path@}}, which is the full
+path of the requested file; @samp{/home/foo} in the example above
+(@pxref{Selectors}). @code{$@{autodir@}} defaults to @samp{/a} but may
+be changed with the ``-a'' command line option. Sun's automounter
+defaults to @samp{/tmp_mnt}. Note that there is no @samp{/} between
+the @code{$@{rhost@}} and @code{$@{rfs@}} since @code{$@{rfs@}} begins
+with a @samp{/}.@refill
+
+@node opts Option, remopts Option, fs Option, Map Options
+@comment node-name, next, previous, up
+@subsubsection opts Option
+@cindex Setting system mount options
+@cindex Passing parameters to the mount system call
+@cindex mount system call
+@cindex mount system call flags
+@cindex The mount system call
+@cindex opts, mount option
+@cindex Mount option; opts
+
+The options to pass to the mount system call. A leading @samp{-} is
+silently ignored. The mount options supported generally correspond to
+those used by @b{mount}(8) and are listed below. Some additional
+pseudo-options are interpreted by @i{Amd} and are also listed.
+
+Unless specifically overridden, each of the system default mount options
+applies. Any options not recognised are ignored. If no options list is
+supplied the string @samp{rw,defaults} is used and all the system
+default mount options apply. Options which are not applicable for a
+particular operating system are silently ignored. For example, only 4.4
+BSD is known to implement the @code{compress} and @code{spongy} options.
+
+@table @code
+@item compress
+Use NFS compression protocol.
+@item grpid
+Use BSD directory group-id semantics.
+@item intr
+Allow keyboard interrupts on hard mounts.
+@item noconn
+Don't make a connection on datagram transports.
+@item nocto
+No close-to-open consistency.
+@item nodevs
+Don't allow local special devices on this filesystem.
+@item nosuid
+Don't allow set-uid or set-gid executables on this filesystem.
+@item quota
+Enable quota checking on this mount.
+@item resvport
+Use a reserved port number (one less than 1024). Some NFS servers
+require this.
+@item retrans=@i{n}
+The number of NFS retransmits made before a user error is generated by a
+@samp{soft} mounted filesystem, and before a @samp{hard} mounted
+filesystem reports @samp{NFS server @dfn{yoyo} not responding still
+trying}.
+@item ro
+Mount this filesystem readonly.
+@item rsize=@var{n}
+The NFS read packet size. You may need to set this if you are using
+NFS/UDP through a gateway.
+@item soft
+Give up after @dfn{retrans} retransmissions.
+@item spongy
+Like @samp{soft} for status requests, and @samp{hard} for data transfers.
+@item tcp
+Use TCP/IP instead of UDP/IP, ignored if the NFS implementation does not
+support TCP/IP mounts.
+@item timeo=@var{n}
+The NFS timeout, in tenth-seconds, before a request is retransmitted.
+@item wsize=@var{n}
+The NFS write packet size. You may need to set this if you are using
+NFS/UDP through a gateway.
+@end table
+
+The following options are implemented by @i{Amd}, rather than being
+passed to the kernel.
+
+@table @code
+@item nounmount
+Configures the mount so that its time-to-live will
+never expire. This is also the default for some filesystem types.
+@c
+@c Implementation broken:
+@item ping=@var{n}
+The interval, in seconds, between keep-alive pings. When four
+consecutive pings have failed the mount point is marked as hung. This
+interval defaults to 30 seconds. If the ping interval is less than zero,
+no pings are sent and the host is assumed to be always
+up. By default, pings are not sent for an NFS/TCP mount.
+@item retry=@var{n}
+The number of times to retry the mount system call.
+@item utimeout=@var{n}
+The interval, in seconds, by which the mount's
+time-to-live is extended after an unmount attempt
+has failed. In fact the interval is extended before the unmount is
+attempted to avoid thrashing. The default value is 120 seconds (two
+minutes) or as set by the ``-w'' command line option.
+@end table
+
+@node remopts Option, sublink Option, opts Option, Map Options
+@comment node-name, next, previous, up
+@subsubsection remopts Option
+@cindex Setting system mount options for non-local networks
+@cindex remopts, mount option
+@cindex Mount option; remopts
+
+This option has the same use as @code{$@{opts@}} but applies only when
+the remote host is on a non-local network. For example, when using NFS
+across a gateway it is often necessary to use smaller values for the
+data read and write sizes. This can simply be done by specifying the
+small values in @var{remopts}. When a non-local host is accessed, the
+smaller sizes will automatically be used.
+
+@i{Amd} determines whether a host is local by examining the network
+interface configuration at startup. Any interface changes made after
+@i{Amd} has been started will not be noticed. The likely effect will
+be that a host may incorrectly be declared non-local.
+
+Unless otherwise set, the value of @code{$@{rem@}} is the same as the
+value of @code{$@{opts@}}.
+
+@node sublink Option, type Option, remopts Option, Map Options
+@comment node-name, next, previous, up
+@subsubsection sublink Option
+@cindex Setting the sublink option
+@cindex sublink, mount option
+@cindex Mount option; sublink
+
+The subdirectory within the mounted filesystem to which the reference
+should point. This can be used to prevent duplicate mounts in cases
+where multiple directories in the same mounted filesystem are used.
+
+@node type Option, , sublink Option, Map Options
+@comment node-name, next, previous, up
+@subsubsection type Option
+@cindex Setting the filesystem type option
+@cindex type, mount option
+@cindex Mount option; type
+
+The filesystem type to be used. @xref{Filesystem Types}, for a full
+description of each type.@refill
+
+@node Amd Command Line Options, Filesystem Types, Mount Maps, Top
+@comment node-name, next, previous, up
+@chapter @i{Amd} Command Line Options
+@cindex Command line options, Amd
+@cindex Amd command line options
+@cindex Overriding defaults on the command line
+
+Many of @i{Amd}'s parameters can be set from the command line. The
+command line is also used to specify automount points and maps.
+
+The general format of a command line is
+
+@example
+amd [@i{options}] @{ @i{directory} @i{map-name} [-@i{map-options}] @} ...
+@end example
+
+For each directory and map-name given, @i{Amd} establishes an
+automount point. The @dfn{map-options} may be any sequence of options
+or selectors---@pxref{Location Format}. The @dfn{map-options}
+apply only to @i{Amd}'s mount point.
+
+@samp{type:=toplvl;cache:=mapdefault;fs:=$@{map@}} is the default value for the
+map options. Default options for a map are read from a special entry in
+the map whose key is the string @samp{/defaults}. When default options
+are given they are prepended to any options specified in the mount-map
+locations as explained in. @xref{Map Defaults}, for more details.
+
+The @dfn{options} are any combination of those listed below.
+
+Once the command line has been parsed, the automount points are mounted.
+The mount points are created if they do not already exist, in which case they
+will be removed when @i{Amd} exits.
+Finally, @i{Amd} disassociates itself from its controlling terminal and
+forks into the background.
+
+Note: Even if @i{Amd} has been built with @samp{-DDEBUG} it will still
+background itself and disassociate itself from the controlling terminal.
+To use a debugger it is necessary to specify @samp{-D nodaemon} on the
+command line.
+
+@menu
+* -a Option:: Automount directory.
+* -c Option:: Cache timeout interval.
+* -d Option:: Domain name.
+* -k Option:: Kernel architecture.
+* -l Option:: Log file.
+* -n Option:: Hostname normalisation.
+* -p Option:: Output process id.
+* -r Option:: Restart existing mounts.
+* -t Option:: Kernel RPC timeout.
+* -v Option:: Version information.
+* -w Option:: Wait interval after failed unmount.
+* -x Option:: Log options.
+* -y Option:: NIS domain.
+* -C-Option:: Cluster name.
+* -D-Option:: Debug flags.
+@end menu
+
+@node -a Option, -c Option, Amd Command Line Options, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-a} @var{directory}
+@cindex Automount directory
+@cindex Setting the default mount directory
+
+Specifies the default mount directory. This option changes the variable
+@code{$@{autodir@}} which otherwise defaults to @file{/a}. For example,
+some sites prefer @file{/amd}.
+
+@example
+amd -a /amd ...
+@end example
+
+@node -c Option, -d Option, -a Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-c} @var{cache-interval}
+@cindex Cache interval
+@cindex Interval before a filesystem times out
+@cindex Setting the interval before a filesystem times out
+@cindex Changing the interval before a filesystem times out
+
+Selects the period, in seconds, for which a name is cached by @i{Amd}.
+If no reference is made to the volume in this period, @i{Amd} discards
+the volume name to filesystem mapping.
+
+Once the last reference to a filesystem has been removed, @i{Amd}
+attempts to unmount the filesystem. If the unmount fails the interval
+is extended by a further period as specified by the @samp{-w} command
+line option or by the @samp{utimeout} mount option.
+
+The default @dfn{cache-interval} is 300 seconds (five minutes).
+
+@node -d Option, -k Option, -c Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-d} @var{domain}
+@cindex Domain name
+@cindex Setting the local domain name
+@cindex Overriding the local domain name
+
+Specifies the host's domain. This sets the internal variable
+@code{$@{domain@}} and affects the @code{$@{hostd@}} variable.
+
+If this option is not specified and the hostname already contains the
+local domain then that is used, otherwise the default value of
+@code{$@{domain@}} is @samp{unknown.domain}.
+
+For example, if the local domain was @samp{doc.ic.ac.uk}, @i{Amd} could
+be started as follows:
+
+@example
+amd -d doc.ic.ac.uk ...
+@end example
+
+@node -k Option, -l Option, -d Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-k} @var{kernel-architecture}
+@cindex Setting the Kernel architecture
+
+Specifies the kernel architecture of the system. This is usually the
+output of @samp{arch -k} and its only effect is to set the variable
+@code{$@{karch@}}. If this option is not given, @code{$@{karch@}} has
+the same value as @code{$@{arch@}}.
+
+This would be used as follows:
+
+@example
+amd -k `arch -k` ...
+@end example
+
+@node -l Option, -n Option, -k Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-l} @var{log-option}
+@cindex Log filename
+@cindex Setting the log file
+@cindex Using syslog to log errors
+@cindex syslog
+
+Selects the form of logging to be made. Two special @dfn{log-options}
+are recognised.
+
+@enumerate
+@item
+If @dfn{log-option} is the string @samp{syslog}, @i{Amd} will use the
+@b{syslog}(3) mechanism.@refill
+
+@item
+If @dfn{log-option} is the string @samp{/dev/stderr}, @i{Amd} will use
+standard error, which is also the default target for log messages. To
+implement this, @i{Amd} simulates the effect of the @samp{/dev/fd}
+driver.
+@end enumerate
+
+Any other string is taken as a filename to use for logging. Log
+messages are appended to the file if it already exists, otherwise a new
+file is created. The file is opened once and then held open, rather
+than being re-opened for each message.
+
+If the @samp{syslog} option is specified but the system does not support
+syslog or if the named file cannot be opened or created, @i{Amd} will
+use standard error. Error messages generated before @i{Amd} has
+finished parsing the command line are printed on standard error.
+
+Using @samp{syslog} is usually best, in which case @i{Amd} would be
+started as follows:
+
+@example
+amd -l syslog ...
+@end example
+
+@node -n Option, -p Option, -l Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-n}
+@cindex Hostname normalisation
+@cindex Aliased hostnames
+@cindex Resolving aliased hostnames
+@cindex Normalising hostnames
+
+Normalises the remote hostname before using it. Normalisation is done
+by replacing the value of @code{$@{rhost@}} with the primary name
+returned by a hostname lookup.
+
+This option should be used if several names are used to refer to a
+single host in a mount map.
+
+@node -p Option, -r Option, -n Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-p}
+@cindex Process id
+@cindex Displaying the process id
+@cindex process id of Amd daemon
+@cindex pid file, creating with -p option
+@cindex Creating a pid file
+
+Causes @i{Amd}'s process id to be printed on standard output.
+This can be redirected to a suitable file for use with kill:
+
+@example
+amd -p > /var/run/amd.pid ...
+@end example
+
+This option only has an affect if @i{Amd} is running in daemon mode.
+If @i{Amd} is started with the @code{-D nodaemon} debug flag, this
+option is ignored.
+
+@node -r Option, -t Option, -p Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-r}
+@cindex Restarting existing mounts
+@cindex Picking up existing mounts
+
+Tells @i{Amd} to restart existing mounts (@pxref{Inheritance Filesystem}).
+@c @dfn{This option will be made the default in the next release.}
+
+@node -t Option, -v Option, -r Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-t} @var{timeout.retransmit}
+@cindex Setting Amd's RPC parameters
+
+Specifies the RPC @dfn{timeout} and @dfn{retransmit} intervals used by
+the kernel to communicate to @i{Amd}. These are used to set the
+@samp{timeo} and @samp{retrans} mount options.
+
+@i{Amd} relies on the kernel RPC retransmit mechanism to trigger mount
+retries. The value of this parameter changes the retry interval. Too
+long an interval gives poor interactive response, too short an interval
+causes excessive retries.
+
+@node -v Option, -w Option, -t Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-v}
+@cindex Version information
+@cindex Discovering version information
+@cindex How to discover your version of Amd
+
+Print version information on standard error and then exit. The output
+is of the form:
+
+@example
+amd 5.2.1.11 of 91/03/17 18:04:05 5.3Alpha11 #0: Sun Mar 17 18:07:28 GMT 1991
+Built by pendry@@vangogh.Berkeley.EDU for a hp300 running bsd44 (big-endian).
+Map support for: root, passwd, union, file, error.
+FS: ufs, nfs, nfsx, host, link, program, union, auto, direct, toplvl, error.
+Primary network is 128.32.130.0.
+@end example
+
+The information includes the version number, release date and name of
+the release. The architecture (@pxref{Supported Machine Architectures}),
+operating system (@pxref{Supported Operating Systems})
+and byte ordering are also printed as they appear in the @code{$@{os@}},
+@code{$@{arch@}} and @code{$@{byte@}} variables.@refill
+
+@node -w Option, -x Option, -v Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-w} @var{wait-timeout}
+@cindex Setting the interval between unmount attempts
+@cindex unmount attempt backoff interval
+
+Selects the interval in seconds between unmount attempts after the
+initial time-to-live has expired.
+
+This defaults to 120 seconds (two minutes).
+
+@node -x Option, -y Option, -w Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-x} @var{opts}
+@cindex Log message selection
+@cindex Selecting specific log messages
+@cindex How to select log messages
+@cindex syslog priorities
+
+Specifies the type and verbosity of log messages. @dfn{opts} is
+a comma separated list selected from the following options:
+
+@table @code
+@item fatal
+Fatal errors
+@item error
+Non-fatal errors
+@item user
+Non-fatal user errors
+@item warn
+Recoverable errors
+@item warning
+Alias for @code{warn}
+@item info
+Information messages
+@item map
+Mount map usage
+@item stats
+Additional statistics
+@item all
+All of the above
+@end table
+
+Initially a set of default logging flags is enabled. This is as if
+@samp{-x all,nomap,nostats} had been selected. The command line is
+parsed and logging is controlled by the ``-x'' option. The very first
+set of logging flags is saved and can not be subsequently disabled using
+@i{Amq}. This default set of options is useful for general production
+use.@refill
+
+The @samp{info} messages include details of what is mounted and
+unmounted and when filesystems have timed out. If you want to have the
+default set of messages without the @samp{info} messages then you simply
+need @samp{-x noinfo}. The messages given by @samp{user} relate to
+errors in the mount maps, so these are useful when new maps are
+installed. The following table lists the syslog priorites used for each
+of the message types.@refill
+
+@table @code
+@item fatal
+LOG_CRIT
+@item error
+LOG_ERR
+@item user
+LOG_WARNING
+@item warning
+LOG_WARNING
+@item info
+LOG_INFO
+@item debug
+LOG_DEBUG
+@item map
+LOG_DEBUG
+@item stats
+LOG_INFO
+@end table
+
+
+The options can be prefixed by the string @samp{no} to indicate
+that this option should be turned off. For example, to obtain all
+but @samp{info} messages the option @samp{-x all,noinfo} would be used.
+
+If @i{Amd} was built with debugging enabled the @code{debug} option is
+automatically enabled regardless of the command line options.
+
+@node -y Option, -C-Option, -x Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-y} @var{NIS-domain}
+@cindex NIS (YP) domain name
+@cindex Overriding the NIS (YP) domain name
+@cindex Setting the NIS (YP) domain name
+@cindex YP domain name
+
+Selects an alternate NIS domain. This is useful for debugging and
+cross-domain shared mounting. If this flag is specified, @i{Amd}
+immediately attempts to bind to a server for this domain.
+@c @i{Amd} refers to NIS maps when it starts, unless the ``-m'' option
+@c is specified, and whenever required in a mount map.
+
+@node -C-Option, -D-Option, -y Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-C} @var{cluster-name}
+@cindex Cluster names
+@cindex Setting the cluster name
+
+Specifies the name of the cluster of which the local machine is a member.
+The only effect is to set the variable @code{$@{cluster@}}.
+The @dfn{cluster-name} is will usually obtained by running another command which uses
+a database to map the local hostname into a cluster name.
+@code{$@{cluster@}} can then be used as a selector to restrict mounting of
+replicated data.
+If this option is not given, @code{$@{cluster@}} has the same value as @code{$@{domain@}}.
+This would be used as follows:
+
+@example
+amd -C `clustername` ...
+@end example
+
+@node -D-Option, , -C-Option, Amd Command Line Options
+@comment node-name, next, previous, up
+@section @code{-D} @var{opts}
+@cindex Debug options
+@cindex Setting debug flags
+
+Controls the verbosity and coverage of the debugging trace; @dfn{opts}
+is a comma separated list of debugging options. The ``-D'' option is
+only available if @i{Amd} was compiled with @samp{-DDEBUG}. The memory
+debugging facilities are only available if @i{Amd} was compiled with
+@samp{-DDEBUG_MEM} (in addition to @samp{-DDEBUG}).
+
+The most common options to use are @samp{-D trace} and @samp{-D test}
+(which turns on all the useful debug options). See the program source
+for a more detailed explanation of the available options.
+
+@node Filesystem Types, Run-time Administration, Amd Command Line Options, Top
+@comment node-name, next, previous, up
+@chapter Filesystem Types
+@cindex Filesystem types
+@cindex Mount types
+@cindex Types of filesystem
+
+To mount a volume, @i{Amd} must be told the type of filesystem to be
+used. Each filesystem type typically requires additional information
+such as the fileserver name for NFS.
+
+From the point of view of @i{Amd}, a @dfn{filesystem} is anything that
+can resolve an incoming name lookup. An important feature is support
+for multiple filesystem types. Some of these filesystems are
+implemented in the local kernel and some on remote fileservers, whilst
+the others are implemented internally by @i{Amd}.@refill
+
+The two common filesystem types are UFS and NFS. Four other user
+accessible filesystems (@samp{link}, @samp{program}, @samp{auto} and
+@samp{direct}) are also implemented internally by @i{Amd} and these are
+described below. There are two additional filesystem types internal to
+@i{Amd} which are not directly accessible to the user (@samp{inherit}
+and @samp{error}). Their use is described since they may still have an
+effect visible to the user.@refill
+
+@menu
+* Network Filesystem:: A single NFS filesystem.
+* Network Host Filesystem:: NFS mount a host's entire export tree.
+* Network Filesystem Group:: An atomic group of NFS filesystems.
+* Unix Filesystem:: Native disk filesystem.
+* Program Filesystem:: Generic Program mounts.
+* Symbolic Link Filesystem:: Local link referencing existing filesystem.
+* Automount Filesystem::
+* Direct Automount Filesystem::
+* Union Filesystem::
+* Error Filesystem::
+* Top-level Filesystem::
+* Root Filesystem::
+* Inheritance Filesystem::
+@end menu
+
+@node Network Filesystem, Network Host Filesystem, Filesystem Types, Filesystem Types
+@comment node-name, next, previous, up
+@section Network Filesystem (@samp{type:=nfs})
+@cindex NFS
+@cindex Mounting an NFS filesystem
+@cindex How to mount and NFS filesystem
+@cindex nfs, filesystem type
+@cindex Filesystem type; nfs
+
+The @dfn{nfs} filesystem type provides access to Sun's NFS.
+
+@noindent
+The following options must be specified:
+
+@table @code
+@cindex rhost, mount option
+@cindex Mount option; rhost
+@item rhost
+the remote fileserver. This must be an entry in the hosts database. IP
+addresses are not accepted. The default value is taken
+from the local host name (@code{$@{host@}}) if no other value is
+specified.
+
+@cindex rfs, mount option
+@cindex Mount option; rfs
+@item rfs
+the remote filesystem.
+If no value is specified for this option, an internal default of
+@code{$@{path@}} is used.
+@end table
+
+NFS mounts require a two stage process. First, the @dfn{file handle} of
+the remote file system must be obtained from the server. Then a mount
+system call must be done on the local system. @i{Amd} keeps a cache
+of file handles for remote file systems. The cache entries have a
+lifetime of a few minutes.
+
+If a required file handle is not in the cache, @i{Amd} sends a request
+to the remote server to obtain it. @i{Amd} @dfn{does not} wait for
+a response; it notes that one of the locations needs retrying, but
+continues with any remaining locations. When the file handle becomes
+available, and assuming none of the other locations was successfully
+mounted, @i{Amd} will retry the mount. This mechanism allows several
+NFS filesystems to be mounted in parallel.
+@c @footnote{The mechanism
+@c is general, however NFS is the only filesystem
+@c for which the required hooks have been written.}
+The first one which responds with a valid file handle will be used.
+
+@noindent
+An NFS entry might be:
+
+@example
+jsp host!=charm;type:=nfs;rhost:=charm;rfs:=/home/charm;sublink:=jsp
+@end example
+
+The mount system call and any unmount attempts are always done
+in a new task to avoid the possibilty of blocking @i{Amd}.
+
+@node Network Host Filesystem, Network Filesystem Group, Network Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Network Host Filesystem (@samp{type:=host})
+@cindex Network host filesystem
+@cindex Mounting entire export trees
+@cindex How to mount all NFS exported filesystems
+@cindex host, filesystem type
+@cindex Filesystem type; host
+
+@c NOTE: the current implementation of the @dfn{host} filesystem type
+@c sometimes fails to maintain a consistent view of the remote mount tree.
+@c This happens when the mount times out and only some of the remote mounts
+@c are successfully unmounted. To prevent this from occuring, use the
+@c @samp{nounmount} mount option.
+
+The @dfn{host} filesystem allows access to the entire export tree of an
+NFS server. The implementation is layered above the @samp{nfs}
+implementation so keep-alives work in the same way. The only option
+which needs to specified is @samp{rhost} which is the name of the
+fileserver to mount.
+
+The @samp{host} filesystem type works by querying the mount daemon on
+the given fileserver to obtain its export list. @i{Amd} then obtains
+filehandles for each of the exported filesystems. Any errors at this
+stage cause that particular filesystem to be ignored. Finally each
+filesystem is mounted. Again, errors are logged but ignored. One
+common reason for mounts to fail is that the mount point does not exist.
+Although @i{Amd} attempts to automatically create the mount point, it
+may be on a remote filesystem to which @i{Amd} does not have write
+permission.
+
+When an attempt to unmount a @samp{host} filesystem mount fails, @i{Amd}
+remounts any filesystems which had succesfully been unmounted. To do
+this @i{Amd} queries the mount daemon again and obtains a fresh copy of
+the export list. @i{Amd} then tries to mount any exported filesystems
+which are not currently mounted.
+
+Sun's automounter provides a special @samp{-hosts} map. To achieve the
+same effect with @i{Amd} requires two steps. First a mount map must
+be created as follows:
+
+@example
+/defaults type:=host;fs:=$@{autodir@}/$@{rhost@}/root;rhost:=$@{key@}
+* opts:=rw,nosuid,grpid
+@end example
+
+@noindent
+and then start @i{Amd} with the following command
+
+@example
+amd /n net.map
+@end example
+
+@noindent
+where @samp{net.map} is the name of map described above. Note that the
+value of @code{$@{fs@}} is overridden in the map. This is done to avoid
+a clash between the mount tree and any other filesystem already mounted
+from the same fileserver.
+
+If different mount options are needed for different hosts then
+additional entries can be added to the map, for example
+
+@example
+host2 opts:=ro,nosuid,soft
+@end example
+
+@noindent
+would soft mount @samp{host2} read-only.
+
+@node Network Filesystem Group, Unix Filesystem, Network Host Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Network Filesystem Group (@samp{type:=nfsx})
+@cindex Network filesystem group
+@cindex Atomic NFS mounts
+@cindex Mounting an atomic group of NFS filesystems
+@cindex How to mount an atomic group of NFS filesystems
+@cindex nfsx, filesystem type
+@cindex Filesystem type; nfsx
+
+The @dfn{nfsx} filesystem allows a group of filesystems to be mounted
+from a single NFS server. The implementation is layered above the
+@samp{nfs} implementation so keep-alives work in the same way.
+
+The options are the same as for the @samp{nfs} filesystem with one
+difference.
+
+@noindent
+The following options must be specified:
+
+@table @code
+@item rhost
+the remote fileserver. This must be an entry in the hosts database. IP
+addresses are not accepted. The default value is taken from the local
+host name (@code{$@{host@}}) if no other value is specified.
+
+@item rfs
+as a list of filesystems to mount. The list is in the form of a comma
+separated strings.
+@end table
+
+@noindent
+For example:
+
+@example
+pub type:=nfsx;rhost:=gould;\
+ rfs:=/public,/,graphics,usenet;fs:=$@{autodir@}/$@{rhost@}/root
+@end example
+
+The first string defines the root of the tree, and is applied as a
+prefix to the remaining members of the list which define the individual
+filesystems. The first string is @emph{not} used as a filesystem name.
+A parallel operation is used to determine the local mount points to
+ensure a consistent layout of a tree of mounts.
+
+Here, the @emph{three} filesystems, @samp{/public},
+@samp{/public/graphics} and @samp{/public/usenet}, would be mounted.@refill
+
+A local mount point, @code{$@{fs@}}, @emph{must} be specified. The
+default local mount point will not work correctly in the general case.
+A suggestion is to use @samp{fs:=$@{autodir@}/$@{rhost@}/root}.@refill
+
+@node Unix Filesystem, Program Filesystem, Network Filesystem Group, Filesystem Types
+@comment node-name, next, previous, up
+@section Unix Filesystem (@samp{type:=ufs})
+@cindex Unix filesystem
+@cindex UFS
+@cindex Mounting a UFS filesystem
+@cindex Mounting a local disk
+@cindex How to mount a UFS filesystems
+@cindex How to mount a local disk
+@cindex Disk filesystems
+@cindex ufs, filesystem type
+@cindex Filesystem type; ufs
+
+The @dfn{ufs} filesystem type provides access to the system's
+standard disk filesystem---usually a derivative of the Berkeley Fast Filesystem.
+
+@noindent
+The following option must be specified:
+
+@table @code
+@cindex dev, mount option
+@cindex Mount option; dev
+@item dev
+the block special device to be mounted.
+@end table
+
+A UFS entry might be:
+
+@example
+jsp host==charm;type:=ufs;dev:=/dev/xd0g;sublink:=jsp
+@end example
+
+@node Program Filesystem, Symbolic Link Filesystem, Unix Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Program Filesystem (@samp{type:=program})
+@cindex Program filesystem
+@cindex Mount a filesystem under program control
+@cindex program, filesystem type
+@cindex Filesystem type; program
+
+The @dfn{program} filesystem type allows a program to be run whenever a
+mount or unmount is required. This allows easy addition of support for
+other filesystem types, such as MIT's Remote Virtual Disk (RVD)
+which has a programmatic interface via the commands
+@samp{rvdmount} and @samp{rvdunmount}.
+
+@noindent
+The following options must be specified:
+
+@table @code
+@cindex mount, mount option
+@cindex Mount option; mount
+@item mount
+the program which will perform the mount.
+
+@cindex unmount, mount option
+@cindex Mount option; unmount
+@item unmount
+the program which will perform the unmount.
+@end table
+
+The exit code from these two programs is interpreted as a Unix error
+code. As usual, exit code zero indicates success. To execute the
+program @i{Amd} splits the string on whitespace to create an array of
+substrings. Single quotes @samp{'} can be used to quote whitespace
+if that is required in an argument. There is no way to escape or change
+the quote character.
+
+To run the program @samp{rvdmount} with a host name and filesystem as
+arguments would be specified by @samp{mount:="/etc/rvdmount rvdmount
+fserver $@{path@}"}.
+
+The first element in the array is taken as the pathname of the program
+to execute. The other members of the array form the argument vector to
+be passed to the program, @dfn{including argument zero}. This means
+that the split string must have at least two elements. The program is
+directly executed by @i{Amd}, not via a shell. This means that scripts
+must begin with a @code{#!} interpreter specification.
+
+If a filesystem type is to be heavily used, it may be worthwhile adding
+a new filesystem type into @i{Amd}, but for most uses the program
+filesystem should suffice.
+
+When the program is run, standard input and standard error are inherited
+from the current values used by @i{Amd}. Standard output is a
+duplicate of standard error. The value specified with the ``-l''
+command line option has no effect on standard error.
+
+@node Symbolic Link Filesystem, Symbolic Link Filesystem II, Program Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Symbolic Link Filesystem (@samp{type:=link})
+@cindex Symbolic link filesystem
+@cindex Referencing part of the local name space
+@cindex Mounting part of the local name space
+@cindex How to reference part of the local name space
+@cindex link, filesystem type
+@cindex symlink, link filesystem type
+@cindex Filesystem type; link
+
+Each filesystem type creates a symbolic link to point from the volume
+name to the physical mount point. The @samp{link} filesystem does the
+same without any other side effects. This allows any part of the
+machines name space to be accessed via @i{Amd}.
+
+One common use for the symlink filesystem is @file{/homes} which can be
+made to contain an entry for each user which points to their
+(auto-mounted) home directory. Although this may seem rather expensive,
+it provides a great deal of administrative flexibility.
+
+@noindent
+The following option must be defined:
+
+@table @code
+@item fs
+The value of @var{fs} option specifies the destination of the link, as
+modified by the @var{sublink} option. If @var{sublink} is non-null, it
+is appended to @code{$@{fs@}}@code{/} and the resulting string is used
+as the target.
+@end table
+
+The @samp{link} filesystem can be though of as identical to the
+@samp{ufs} filesystem but without actually mounting anything.
+
+An example entry might be:
+
+@example
+jsp host==charm;type:=link;fs:=/home/charm;sublink:=jsp
+@end example
+which would return a symbolic link pointing to @file{/home/charm/jsp}.
+
+@node Symbolic Link Filesystem II, Automount Filesystem, Program Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Symbolic Link Filesystem II (@samp{type:=link})
+@cindex Symbolic link filesystem II
+@cindex Referencing an existing part of the local name space
+@cindex Mounting an existing part of the local name space
+@cindex How to reference an existing part of the local name space
+@cindex linkx, filesystem type
+@cindex symlink, linkx filesystem type
+@cindex Filesystem type; linkx
+
+The @samp{linkx} filesystem type is identical to @samp{link} with the
+exception that the target of the link must exist. Existence is checked
+with the @samp{lstat} system call.
+
+The @samp{linkx} filesystem type is particularly useful for wildcard map
+entries. In this case, a list of possible targets can be give and
+@i{Amd} will choose the first one which exists on the local machine.
+
+@node Automount Filesystem, Direct Automount Filesystem, Symbolic Link Filesystem II, Filesystem Types
+@comment node-name, next, previous, up
+@section Automount Filesystem (@samp{type:=auto})
+@cindex Automount filesystem
+@cindex Map cache types
+@cindex Setting map cache parameters
+@cindex How to set map cache parameters
+@cindex How to start an indirect automount point
+@cindex auto, filesystem type
+@cindex Filesystem type; auto
+@cindex SIGHUP signal
+@cindex Map cache synchronising
+@cindex Synchronising the map cache
+@cindex Map cache options
+@cindex Regular expressions in maps
+
+The @dfn{auto} filesystem type creates a new automount point below an
+existing automount point. Top-level automount points appear as system
+mount points. An automount mount point can also appear as a
+sub-directory of an existing automount point. This allows some
+additional structure to be added, for example to mimic the mount tree of
+another machine.
+
+The following options may be specified:
+
+@table @code
+@cindex cache, mount option
+@cindex Mount option; cache
+@item cache
+specifies whether the data in this mount-map should be
+cached. The default value is @samp{none}, in which case
+no caching is done in order to conserve memory.
+However, better performance and reliability can be obtained by caching
+some or all of a mount-map.
+
+If the cache option specifies @samp{all},
+the entire map is enumerated when the mount point is created.
+
+If the cache option specifies @samp{inc}, caching is done incrementally
+as and when data is required.
+Some map types do not support cache mode @samp{all}, in which case @samp{inc}
+is used whenever @samp{all} is requested.
+
+Caching can be entirely disabled by using cache mode @samp{none}.
+
+If the cache option specifies @samp{regexp} then the entire map will be
+enumerated and each key will be treated as an egrep-style regular
+expression. The order in which a cached map is searched does not
+correspond to the ordering in the source map so the regular expressions
+should be mutually exclusive to avoid confusion.
+
+Each mount map type has a default cache type, usually @samp{inc}, which
+can be selected by specifying @samp{mapdefault}.
+
+The cache mode for a mount map can only be selected on the command line.
+Starting @i{Amd} with the command:
+
+@example
+amd /homes hesiod.homes -cache:=inc
+@end example
+
+will cause @samp{/homes} to be automounted using the @dfn{Hesiod} name
+server with local incremental caching of all succesfully resolved names.
+
+All cached data is forgotten whenever @i{Amd} receives a @samp{SIGHUP}
+signal and, if cache @samp{all} mode was selected, the cache will be
+reloaded. This can be used to inform @i{Amd} that a map has been
+updated. In addition, whenever a cache lookup fails and @i{Amd} needs
+to examine a map, the map's modify time is examined. If the cache is
+out of date with respect to the map then it is flushed as if a
+@samp{SIGHUP} had been received.
+
+An additional option (@samp{sync}) may be specified to force @i{Amd} to
+check the map's modify time whenever a cached entry is being used. For
+example, an incremental, synchronised cache would be created by the
+following command:
+
+@example
+amd /homes hesiod.homes -cache:=inc,sync
+@end example
+
+@item fs
+specifies the name of the mount map to use for the new mount point.
+
+Arguably this should have been specified with the @code{$@{rfs@}} option but
+we are now stuck with it due to historical accident.
+
+@c %If the string @samp{.} is used then the same map is used;
+@c %in addition the lookup prefix is set to the name of the mount point followed
+@c %by a slash @samp{/}.
+@c %This is the same as specifying @samp{fs:=\$@{map@};pref:=\$@{key@}/}.
+@c
+
+@item pref
+alters the name that is looked up in the mount map. If
+@code{$@{pref@}}, the @dfn{prefix}, is non-null then it is prepended to
+the name requested by the kernel @dfn{before} the map is searched.
+@end table
+
+The server @samp{dylan.doc.ic.ac.uk} has two user disks:
+@samp{/dev/dsk/2s0} and @samp{/dev/dsk/5s0}. These are accessed as
+@samp{/home/dylan/dk2} and @samp{/home/dylan/dk5} respectively. Since
+@samp{/home} is already an automount point, this naming is achieved with
+the following map entries:@refill
+
+@example
+dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/
+dylan/dk2 type:=ufs;dev:=/dev/dsk/2s0
+dylan/dk5 type:=ufs;dev:=/dev/dsk/5s0
+@end example
+
+@node Direct Automount Filesystem, Union Filesystem, Automount Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Direct Automount Filesystem (@samp{type:=direct})
+@cindex Direct automount filesystem
+@cindex How to start a direct automount point
+@cindex direct, filesystem type
+@cindex Filesystem type; direct
+
+The @dfn{direct} filesystem is almost identical to the automount
+filesystem. Instead of appearing to be a directory of mount points, it
+appears as a symbolic link to a mounted filesystem. The mount is done
+at the time the link is accessed. @xref{Automount Filesystem} for a
+list of required options.
+
+Direct automount points are created by specifying the @samp{direct}
+filesystem type on the command line:
+
+@example
+amd ... /usr/man auto.direct -type:=direct
+@end example
+
+where @samp{auto.direct} would contain an entry such as:
+
+@example
+usr/man -type:=nfs;rfs:=/usr/man \
+ rhost:=man-server1 rhost:=man-server2
+@end example
+
+In this example, @samp{man-server1} and @samp{man-server2} are file
+servers which export copies of the manual pages. Note that the key
+which is looked up is the name of the automount point without the
+leading @samp{/}.
+
+@node Union Filesystem, Error Filesystem, Direct Automount Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Union Filesystem (@samp{type:=union})
+@cindex Union filesystem
+@cindex union, filesystem type
+@cindex Filesystem type; union
+
+The @dfn{union} filesystem type allows the contents of several
+directories to be merged and made visible in a single directory. This
+can be used to overcome one of the major limitations of the Unix mount
+mechanism which only allows complete directories to be mounted.
+
+For example, supposing @file{/tmp} and @file{/var/tmp} were to be merged
+into a new directory called @file{/mtmp}, with files in @file{/var/tmp}
+taking precedence. The following command could be used to achieve this
+effect:
+
+@example
+amd ... /mtmp union:/tmp:/var/tmp -type:=union
+@end example
+
+Currently, the unioned directories must @emph{not} be automounted. That
+would cause a deadlock. This seriously limits the current usefulness of
+this filesystem type and the problem will be addressed in a future
+release of @i{Amd}.
+
+Files created in the union directory are actually created in the last
+named directory. This is done by creating a wildcard entry which points
+to the correct directory. The wildcard entry is visible if the union
+directory is listed, so allowing you to see which directory has
+priority.
+
+The files visible in the union directory are computed at the time
+@i{Amd} is started, and are not kept uptodate with respect to the
+underlying directories. Similarly, if a link is removed, for example
+with the @samp{rm} command, it will be lost forever.
+
+@node Error Filesystem, Top-level Filesystem, Union Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Error Filesystem (@samp{type:=error})
+@cindex Error filesystem
+@cindex error, filesystem type
+@cindex Filesystem type; error
+
+The @dfn{error} filesystem type is used internally as a catch-all in
+the case where none of the other filesystems was selected, or some other
+error occurred.
+Lookups and mounts always fail with ``No such file or directory''.
+All other operations trivially succeed.
+
+The error filesystem is not directly accessible.
+
+@node Top-level Filesystem, Root Filesystem, Error Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Top-level Filesystem (@samp{type:=toplvl})
+@cindex Top level filesystem
+@cindex toplvl, filesystem type
+@cindex Filesystem type; toplvl
+
+The @dfn{toplvl} filesystems is derived from the @samp{auto} filesystem
+and is used to mount the top-level automount nodes. Requests of this
+type are automatically generated from the command line arguments and
+can also be passed in by using the ``-M'' option of the @dfn{Amq} command.
+
+@node Root Filesystem, Inheritance Filesystem, Top-level Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Root Filesystem
+@cindex Root filesystem
+@cindex root, filesystem type
+@cindex Filesystem type; root
+
+The @dfn{root} (@samp{type:=root}) filesystem type acts as an internal
+placeholder onto which @i{Amd} can pin @samp{toplvl} mounts. Only one
+node of this type need ever exist and one is created automatically
+during startup. The effect of creating a second root node is undefined.
+
+@node Inheritance Filesystem, , Root Filesystem, Filesystem Types
+@comment node-name, next, previous, up
+@section Inheritance Filesystem
+@cindex Inheritance filesystem
+@cindex Nodes generated on a restart
+@cindex inherit, filesystem type
+@cindex Filesystem type; inherit
+
+The @dfn{inheritance} (@samp{type:=inherit}) filesystem is not directly
+accessible. Instead, internal mount nodes of this type are
+automatically generated when @i{Amd} is started with the ``-r'' option.
+At this time the system mount table is scanned to locate any filesystems
+which are already mounted. If any reference to these filesystems is
+made through @i{Amd} then instead of attempting to mount it, @i{Amd}
+simulates the mount and @dfn{inherits} the filesystem. This allows a
+new version of @i{Amd} to be installed on a live system simply by
+killing the old daemon with @code{SIGTERM} and starting the new one.@refill
+
+This filesystem type is not generally visible externally, but it is
+possible that the output from @samp{amq -m} may list @samp{inherit} as
+the filesystem type. This happens when an inherit operation cannot
+be completed for some reason, usually because a fileserver is down.
+
+@node Run-time Administration, FSinfo, Filesystem Types, Top
+@comment node-name, next, previous, up
+@chapter Run-time Administration
+@cindex Run-time administration
+@cindex Amq command
+
+@menu
+* Starting Amd::
+* Stopping Amd::
+* Controlling Amd::
+@end menu
+
+@node Starting Amd, Stopping Amd, Run-time Administration, Run-time Administration
+@comment node-name, next, previous, up
+@section Starting @i{Amd}
+@cindex Starting Amd
+@cindex Additions to /etc/rc.local
+@cindex /etc/rc.local additions
+@cindex /etc/amd.start
+
+@i{Amd} is best started from @samp{/etc/rc.local}:
+
+@example
+if [ -f /etc/amd.start ]; then
+ sh /etc/amd.start; (echo -n ' amd') >/dev/console
+fi
+@end example
+
+@noindent
+The shell script, @samp{amd.start}, contains:
+
+@example
+#!/bin/sh -
+PATH=/etc:/bin:/usr/bin:/usr/ucb:$PATH export PATH
+
+#
+# Either name of logfile or "syslog"
+#
+LOGFILE=syslog
+#LOGFILE=/var/log/amd
+
+#
+# Figure out whether domain name is in host name
+# If the hostname is just the machine name then
+# pass in the name of the local domain so that the
+# hostnames in the map are domain stripped correctly.
+#
+case `hostname` in
+*.*) dmn= ;;
+*) dmn='-d doc.ic.ac.uk'
+esac
+
+#
+# Zap earlier log file
+#
+case "$LOGFILE" in
+*/*)
+ mv "$LOGFILE" "$LOGFILE"-
+ > "$LOGFILE"
+ ;;
+syslog)
+ : nothing
+ ;;
+esac
+
+cd /usr/sbin
+#
+# -r restart
+# -d dmn local domain
+# -w wait wait between unmount attempts
+# -l log logfile or "syslog"
+#
+eval ./amd -r $dmn -w 240 -l "$LOGFILE" \
+ /homes amd.homes -cache:=inc \
+ /home amd.home -cache:=inc \
+ /vol amd.vol -cache:=inc \
+ /n amd.net -cache:=inc
+@end example
+
+If the list of automount points and maps is contained in a file or NIS map
+it is easily incorporated onto the command line:
+
+@example
+...
+eval ./amd -r $dmn -w 240 -l "$LOGFILE" `ypcat -k auto.master`
+@end example
+
+@node Stopping Amd, Controlling Amd, Starting Amd, Run-time Administration
+@comment node-name, next, previous, up
+@section Stopping @i{Amd}
+@cindex Stopping Amd
+@cindex SIGTERM signal
+@cindex SIGINT signal
+
+@i{Amd} stops in response to two signals.
+
+@table @samp
+@item SIGTERM
+causes the top-level automount points to be unmounted and then @i{Amd}
+to exit. Any automounted filesystems are left mounted. They can be
+recovered by restarting @i{Amd} with the ``-r'' command line option.@refill
+
+@item SIGINT
+causes @i{Amd} to attempt to unmount any filesystems which it has
+automounted, in addition to the actions of @samp{SIGTERM}. This signal
+is primarly used for debugging.@refill
+@end table
+
+Actions taken for other signals are undefined.
+
+@node Controlling Amd, , Stopping Amd, Run-time Administration
+@comment node-name, next, previous, up
+@section Controlling @i{Amd}
+@cindex Controlling Amd
+@cindex Discovering what is going on at run-time
+@cindex Listing currently mounted filesystems
+
+It is sometimes desirable or necessary to exercise external control
+over some of @i{Amd}'s internal state. To support this requirement,
+@i{Amd} implements an RPC interface which is used by the @dfn{Amq} program.
+A variety of information is available.
+
+@i{Amq} generally applies an operation, specified by a single letter option,
+to a list of mount points. The default operation is to obtain statistics
+about each mount point. This is similar to the output shown above
+but includes information about the number and type of accesses to each
+mount point.
+
+@menu
+* Amq default:: Default command behaviour.
+* Amq -f option:: Flushing the map cache.
+* Amq -h option:: Controlling a non-local host.
+* Amq -m option:: Obtaining mount statistics.
+* Amq -M-option:: Mounting a volume.
+* Amq -s option:: Obtaining global statistics.
+* Amq -u option:: Forcing volumes to time out.
+* Amq -v option:: Version information.
+* Other Amq options:: Three other special options.
+@end menu
+
+@node Amq default, Amq -f option, Controlling Amd, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} default information
+
+With no arguments, @dfn{Amq} obtains a brief list of all existing
+mounts created by @i{Amd}. This is different from the list displayed by
+@b{df}(1) since the latter only includes system mount points.
+
+@noindent
+The output from this option includes the following information:
+
+@itemize @bullet
+@item
+the automount point,
+@item
+the filesystem type,
+@item
+the mount map or mount information,
+@item
+the internal, or system mount point.
+@end itemize
+
+@noindent
+For example:
+
+@example
+/ root "root" sky:(pid75)
+/homes toplvl /usr/local/etc/amd.homes /homes
+/home toplvl /usr/local/etc/amd.home /home
+/homes/jsp nfs charm:/home/charm /a/charm/home/charm/jsp
+/homes/phjk nfs toytown:/home/toytown /a/toytown/home/toytown/ai/phjk
+@end example
+
+@noindent
+If an argument is given then statistics for that volume name will
+be output. For example:
+
+@example
+What Uid Getattr Lookup RdDir RdLnk Statfs Mounted@@
+/homes 0 1196 512 22 0 30 90/09/14 12:32:55
+/homes/jsp 0 0 0 0 1180 0 90/10/13 12:56:58
+@end example
+
+@table @code
+@item What
+the volume name.
+
+@item Uid
+ignored.
+
+@item Getattr
+the count of NFS @dfn{getattr} requests on this node. This should only be
+non-zero for directory nodes.
+
+@item Lookup
+the count of NFS @dfn{lookup} requests on this node. This should only be
+non-zero for directory nodes.
+
+@item RdDir
+the count of NFS @dfn{readdir} requests on this node. This should only
+be non-zero for directory nodes.
+
+@item RdLnk
+the count of NFS @dfn{readlink} requests on this node. This should be
+zero for directory nodes.
+
+@item Statfs
+the could of NFS @dfn{statfs} requests on this node. This should only
+be non-zero for top-level automount points.
+
+@item Mounted@@
+the date and time the volume name was first referenced.
+@end table
+
+@node Amq -f option, Amq -h option, Amq default, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -f option
+@cindex Flushing the map cache
+@cindex Map cache, flushing
+
+The ``-f'' option causes @i{Amd} to flush the internal mount map cache.
+This is useful for Hesiod maps since @i{Amd} will not automatically
+notice when they have been updated. The map cache can also be
+synchronised with the map source by using the @samp{sync} option
+(@pxref{Automount Filesystem}).@refill
+
+@node Amq -h option, Amq -m option, Amq -f option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -h option
+@cindex Querying an alternate host
+
+By default the local host is used. In an HP-UX cluster the root server
+is used since that is the only place in the cluster where @i{Amd} will
+be running. To query @i{Amd} on another host the ``-h'' option should
+be used.
+
+@node Amq -m option, Amq -M-option, Amq -h option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -m option
+
+The ``-m'' option displays similar information about mounted
+filesystems, rather than automount points. The output includes the
+following information:
+
+@itemize @bullet
+@item
+the mount information,
+@item
+the mount point,
+@item
+the filesystem type,
+@item
+the number of references to this filesystem,
+@item
+the server hostname,
+@item
+the state of the file server,
+@item
+any error which has occured.
+@end itemize
+
+For example:
+
+@example
+"root" truth:(pid602) root 1 localhost is up
+hesiod.home /home toplvl 1 localhost is up
+hesiod.vol /vol toplvl 1 localhost is up
+hesiod.homes /homes toplvl 1 localhost is up
+amy:/home/amy /a/amy/home/amy nfs 5 amy is up
+swan:/home/swan /a/swan/home/swan nfs 0 swan is up (Permission denied)
+ex:/home/ex /a/ex/home/ex nfs 0 ex is down
+@end example
+
+When the reference count is zero the filesystem is not mounted but
+the mount point and server information is still being maintained
+by @i{Amd}.
+
+@node Amq -M-option, Amq -s option, Amq -m option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -M option
+
+The ``-M'' option passes a new map entry to @i{Amd} and waits for it to
+be evaluated, possibly causing a mount. For example, the following
+command would cause @samp{/home/toytown} on host @samp{toytown} to be
+mounted locally on @samp{/mnt/toytown}.
+
+@example
+amq -M '/mnt/toytown type:=nfs;rfs:=/home/toytown;rhost:=toytown;fs:=$@{key@}'
+@end example
+
+@i{Amd} applies some simple security checks before allowing this
+operation. The check tests whether the incoming request is from a
+privileged UDP port on the local machine. ``Permission denied'' is
+returned if the check fails.
+
+A future release of @i{Amd} will include code to allow the @b{mount}(8)
+command to mount automount points:
+
+@example
+mount -t amd /vol hesiod.vol
+@end example
+
+This will then allow @i{Amd} to be controlled from the standard system
+filesystem mount list.
+
+@node Amq -s option, Amq -u option, Amq -M-option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -s option
+@cindex Global statistics
+@cindex Statistics
+
+The ``-s'' option displays global statistics. If any other options are specified
+or any filesystems named then this option is ignored. For example:
+
+@example
+requests stale mount mount unmount
+deferred fhandles ok failed failed
+1054 1 487 290 7017
+@end example
+
+@table @samp
+@item Deferred requests
+are those for which an immediate reply could not be constructed. For
+example, this would happen if a background mount was required.
+
+@item Stale filehandles
+counts the number of times the kernel passes a stale filehandle to @i{Amd}.
+Large numbers indicate problems.
+
+@item Mount ok
+counts the number of automounts which were successful.
+
+@item Mount failed
+counts the number of automounts which failed.
+
+@item Unmount failed
+counts the number of times a filesystem could not be unmounted. Very
+large numbers here indicate that the time between unmount attempts
+should be increased.
+@end table
+
+@node Amq -u option, Amq -v option, Amq -s option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -u option
+@cindex Forcing filesystem to time out
+@cindex Unmounting a filesystem
+
+The ``-u'' option causes the time-to-live interval of the named mount
+points to be expired, thus causing an unmount attempt. This is the only
+safe way to unmount an automounted filesystem. It is not possible to
+unmount a filesystem which has been mounted with the @samp{nounmount}
+flag.
+
+@c The ``-H'' option informs @i{Amd} that the specified mount point has hung -
+@c as if its keepalive timer had expired.
+
+@node Amq -v option, Other Amq options, Amq -u option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection @i{Amq} -v option
+@cindex Version information at run-time
+
+The ``-v'' option displays the version of @i{Amd} in a similar way to
+@i{Amd}'s ``-v'' option.
+
+@node Other Amq options, , Amq -v option, Controlling Amd
+@comment node-name, next, previous, up
+@subsection Other @i{Amq} options
+
+Three other operations are implemented. These modify the state of
+@i{Amd} as a whole, rather than any particular filesystem. The ``-l'',
+``-x'' and ``-D'' options have exactly the same effect as @i{Amd}'s
+corresponding command line options. The ``-l'' option is rejected by
+@i{Amd} in the current version for obvious security reasons. When
+@i{Amd} receives a ``-x''flag it limits the log options being modified
+to those which were not enabled at startup. This prevents a user
+turning @emph{off} any logging option which was specified at startup,
+though any which have been turned off since then can still be turned
+off. The ``-D'' option has a similar behaviour.
+
+@node FSinfo, Examples, Run-time Administration, Top
+@comment node-name, next, previous, up
+@chapter FSinfo
+@cindex FSinfo
+@cindex Filesystem info package
+
+@menu
+* FSinfo Overview:: Introduction to FSinfo.
+* Using FSinfo:: Basic concepts.
+* FSinfo Grammar:: Language syntax, semantics and examples.
+* FSinfo host definitions:: Defining a new host.
+* FSinfo host attributes:: Definable host attributes.
+* FSinfo filesystems:: Defining locally attached filesystems.
+* FSinfo static mounts:: Defining additional static mounts.
+* FSinfo automount definitions::
+* FSinfo command line options::
+* FSinfo errors::
+@end menu
+
+@node FSinfo Overview, Using FSinfo, FSinfo, FSinfo
+@comment node-name, next, previous, up
+@section @i{FSinfo} overview
+@cindex FSinfo overview
+
+@i{FSinfo} is a filesystem management tool. It has been designed to
+work with @i{Amd} to help system administrators keep track of the ever
+increasing filesystem namespace under their control.
+
+The purpose of @i{FSinfo} is to generate all the important standard
+filesystem data files from a single set of input data. Starting with a
+single data source guarantees that all the generated files are
+self-consistent. One of the possible output data formats is a set of
+@i{Amd} maps which can be used amongst the set of hosts described in the
+input data.
+
+@i{FSinfo} implements a declarative language. This language is
+specifically designed for describing filesystem namespace and physical
+layouts. The basic declaration defines a mounted filesystem including
+its device name, mount point, and all the volumes and access
+permissions. @i{FSinfo} reads this information and builds an internal
+map of the entire network of hosts. Using this map, many different data
+formats can be produced including @file{/etc/fstab},
+@file{/etc/exports}, @i{Amd} mount maps and
+@file{/etc/bootparams}.@refill
+
+@node Using FSinfo, FSinfo Grammar, FSinfo Overview, FSinfo
+@comment node-name, next, previous, up
+@section Using @i{FSinfo}
+@cindex Using FSinfo
+
+The basic strategy when using @i{FSinfo} is to gather all the
+information about all disks on all machines into one set of
+declarations. For each machine being managed, the following data is
+required:
+
+@itemize @bullet
+@item
+Hostname
+@item
+List of all filesystems and, optionally, their mount points.
+@item
+Names of volumes stored on each filesystem.
+@item
+NFS export information for each volume.
+@item
+The list of static filesystem mounts.
+@end itemize
+
+The following information can also be entered into the same
+configuration files so that all data can be kept in one place.
+
+@itemize @bullet
+@item
+List of network interfaces
+@item
+IP address of each interface
+@item
+Hardware address of each interface
+@item
+Dumpset to which each filesystem belongs
+@item
+and more @dots{}
+@end itemize
+
+To generate @i{Amd} mount maps, the automount tree must also be defined
+(@pxref{FSinfo automount definitions}). This will have been designed at
+the time the volume names were allocated. Some volume names will not be
+automounted, so @i{FSinfo} needs an explicit list of which volumes
+should be automounted.@refill
+
+Hostnames are required at several places in the @i{FSinfo} language. It
+is important to stick to either fully qualified names or unqualified
+names. Using a mixture of the two will inevitably result in confusion.
+
+Sometimes volumes need to be referenced which are not defined in the set
+of hosts being managed with @i{FSinfo}. The required action is to add a
+dummy set of definitions for the host and volume names required. Since
+the files generated for those particular hosts will not be used on them,
+the exact values used is not critical.
+
+@node FSinfo Grammar, FSinfo host definitions, Using FSinfo, FSinfo
+@comment node-name, next, previous, up
+@section @i{FSinfo} grammar
+@cindex FSinfo grammar
+@cindex Grammar, FSinfo
+
+@i{FSinfo} has a relatively simple grammar. Distinct syntactic
+constructs exist for each of the different types of data, though they
+share a common flavour. Several conventions are used in the grammar
+fragments below.
+
+The notation, @i{list(}@t{xxx}@i{)}, indicates a list of zero or more
+@t{xxx}'s. The notation, @i{opt(}@t{xxx}@i{)}, indicates zero or one
+@t{xxx}. Items in double quotes, @i{eg} @t{"host"}, represent input
+tokens. Items in angle brackets, @i{eg} @var{<hostname>}, represent
+strings in the input. Strings need not be in double quotes, except to
+differentiate them from reserved words. Quoted strings may include the
+usual set of C ``@t{\}'' escape sequences with one exception: a
+backslash-newline-whitespace sequence is squashed into a single space
+character. To defeat this feature, put a further backslash at the start
+of the second line.
+
+At the outermost level of the grammar, the input consists of a
+sequence of host and automount declarations. These declarations are
+all parsed before they are analyzed. This means they can appear in
+any order and cyclic host references are possible.
+
+@example
+fsinfo : @i{list(}fsinfo_attr@i{)} ;
+
+fsinfo_attr : host | automount ;
+@end example
+
+@menu
+* FSinfo host definitions::
+* FSinfo automount definitions::
+@end menu
+
+@node FSinfo host definitions, FSinfo host attributes, FSinfo grammar, FSinfo
+@comment node-name, next, previous, up
+@section @i{FSinfo} host definitions
+@cindex FSinfo host definitions
+@cindex Defining a host, FSinfo
+
+A host declaration consists of three parts: a set of machine attribute
+data, a list of filesystems physically attached to the machine, and a
+list of additional statically mounted filesystems.
+
+@example
+host : "host" host_data @i{list(}filesystem@i{@i{)}} @i{list(}mount@i{@i{)}} ;
+@end example
+
+Each host must be declared in this way exactly once. Such things as the
+hardware address, the architecture and operating system types and the
+cluster name are all specified within the @dfn{host data}.
+
+All the disks the machine has should then be described in the @dfn{list
+of filesystems}. When describing disks, you can specify what
+@dfn{volname} the disk/partition should have and all such entries are
+built up into a dictionary which can then be used for building the
+automounter maps.
+
+The @dfn{list of mounts} specifies all the filesystems that should be
+statically mounted on the machine.
+
+@menu
+* FSinfo host attributes::
+* FSinfo filesystems::
+* FSinfo static mounts::
+@end menu
+
+@node FSinfo host attributes, FSinfo filesystems, FSinfo host definitions , FSinfo host definitions
+@comment node-name, next, previous, up
+@section @i{FSinfo} host attributes
+@cindex FSinfo host attributes
+@cindex Defining host attributes, FSinfo
+
+The host data, @dfn{host_data}, always includes the @dfn{hostname}. In
+addition, several other host attributes can be given.
+
+@example
+host_data : @var{<hostname>}
+ | "@{" @i{list(}host_attrs@i{)} "@}" @var{<hostname>}
+ ;
+
+host_attrs : host_attr "=" @var{<string>}
+ | netif
+ ;
+
+host_attr : "config"
+ | "arch"
+ | "os"
+ | "cluster"
+ ;
+@end example
+
+The @dfn{hostname} is, typically, the fully qualified hostname of the
+machine.
+
+Examples:
+
+@example
+host dylan.doc.ic.ac.uk
+
+host @{
+ os = hpux
+ arch = hp300
+@} dougal.doc.ic.ac.uk
+@end example
+
+The options that can be given as host attributes are shown below.
+
+@menu
+* netif Option: FSinfo host netif:
+* config Option: FSinfo host config:
+* arch Option: FSinfo host arch:
+* os Option: FSinfo host os:
+* cluster Option: FSinfo host cluster:
+@end menu
+
+@node FSinfo host netif, FSinfo host config, , FSinfo host attributes
+@comment node-name, next, previous, up
+@subsection netif Option
+
+This defines the set of network interfaces configured on the machine.
+The interface attributes collected by @i{FSinfo} are the IP address,
+subnet mask and hardware address. Multiple interfaces may be defined
+for hosts with several interfaces by an entry for each interface. The
+values given are sanity checked, but are currently unused for anything
+else.
+
+@example
+netif : "netif" @var{<string>} "@{" @i{list(}netif_attrs@i{)} "@}" ;
+
+netif_attrs : netif_attr "=" @var{<string>} ;
+
+netif_attr : "inaddr" | "netmask" | "hwaddr" ;
+@end example
+
+Examples:
+
+@example
+netif ie0 @{
+ inaddr = 129.31.81.37
+ netmask = 0xfffffe00
+ hwaddr = "08:00:20:01:a6:a5"
+@}
+
+netif ec0 @{ @}
+@end example
+
+@node FSinfo host config, FSinfo host arch, FSinfo host netif, FSinfo host attributes
+@comment node-name, next, previous, up
+@subsection config Option
+@cindex FSinfo config host attribute
+@cindex config, FSinfo host attribute
+
+This option allows you to specify configuration variables for the
+startup scripts (@file{rc} scripts). A simple string should immediately
+follow the keyword.
+
+Example:
+
+@example
+config "NFS_SERVER=true"
+config "ZEPHYR=true"
+@end example
+
+This option is currently unsupported.
+
+@node FSinfo host arch, FSinfo host os, FSinfo host config, FSinfo host attributes
+@comment node-name, next, previous, up
+@subsection arch Option
+@cindex FSinfo arch host attribute
+@cindex arch, FSinfo host attribute
+
+This defines the architecture of the machine. For example:
+
+@example
+arch = hp300
+@end example
+
+This is intended to be of use when building architecture specific
+mountmaps, however, the option is currently unsupported.
+
+@node FSinfo host os, FSinfo host cluster, FSinfo host arch, FSinfo host attributes
+@comment node-name, next, previous, up
+@subsection os Option
+@cindex FSinfo os host attribute
+@cindex os, FSinfo host attribute
+
+This defines the operating system type of the host. For example:
+
+@example
+os = hpux
+@end example
+
+This information is used when creating the @file{fstab} files, for
+example in choosing which format to use for the @file{fstab} entries
+within the file.
+
+@node FSinfo host cluster, , FSinfo host os, FSinfo host attributes
+@comment node-name, next, previous, up
+@subsection cluster Option
+@cindex FSinfo cluster host attribute
+@cindex cluster, FSinfo host attribute
+
+This is used for specifying in which cluster the machine belongs. For
+example:
+
+@example
+cluster = "theory"
+@end example
+
+The cluster is intended to be used when generating the automount maps,
+although it is currently unsupported.
+
+@node FSinfo filesystems, FSinfo static mounts, FSinfo host attributes, FSinfo host definitions
+@comment node-name, next, previous, up
+@section @i{FSinfo} filesystems
+@cindex FSinfo filesystems
+
+The list of physically attached filesystems follows the machine
+attributes. These should define all the filesystems available from this
+machine, whether exported or not. In addition to the device name,
+filesystems have several attributes, such as filesystem type, mount
+options, and @samp{fsck} pass number which are needed to generate
+@file{fstab} entries.
+
+@example
+filesystem : "fs" @var{<device>} "@{" @i{list(}fs_data@i{)} "@}" ;
+
+fs_data : fs_data_attr "=" @var{<string>}
+ | mount
+ ;
+
+fs_data_attr
+ : "fstype" | "opts" | "passno"
+ | "freq" | "dumpset" | "log"
+ ;
+@end example
+
+Here, @var{<device>} is the device name of the disk (for example,
+@file{/dev/dsk/2s0}). The device name is used for building the mount
+maps and for the @file{fstab} file. The attributes that can be
+specified are shown in the following section.
+
+The @i{FSinfo} configuration file for @code{dylan.doc.ic.ac.uk} is listed below.
+
+@example
+host dylan.doc.ic.ac.uk
+
+fs /dev/dsk/0s0 @{
+ fstype = swap
+@}
+
+fs /dev/dsk/0s0 @{
+ fstype = hfs
+ opts = rw,noquota,grpid
+ passno = 0;
+ freq = 1;
+ mount / @{ @}
+@}
+
+fs /dev/dsk/1s0 @{
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount /usr @{
+ local @{
+ exportfs "dougal eden dylan zebedee brian"
+ volname /nfs/hp300/local
+ @}
+ @}
+@}
+
+fs /dev/dsk/2s0 @{
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default @{
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk2
+ @}
+@}
+
+fs /dev/dsk/3s0 @{
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default @{
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk3
+ @}
+@}
+
+fs /dev/dsk/5s0 @{
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default @{
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk5
+ @}
+@}
+@end example
+
+@menu
+* fstype Option: FSinfo filesystems fstype:
+* opts Option: FSinfo filesystems opts:
+* passno Option: FSinfo filesystems passno:
+* freq Option: FSinfo filesystems freq:
+* mount Option: FSinfo filesystems mount:
+* dumpset Option: FSinfo filesystems dumpset:
+* log Option: FSinfo filesystems log:
+@end menu
+
+@node FSinfo filesystems fstype, FSinfo filesystems opts, , FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection fstype Option
+@cindex FSinfo fstype filesystems option
+@cindex fstype, FSinfo filesystems option
+@cindex export, FSinfo special fstype
+
+This specifies the type of filesystem being declared and will be placed
+into the @file{fstab} file as is. The value of this option will be
+handed to @code{mount} as the filesystem type---it should have such
+values as @code{4.2}, @code{nfs} or @code{swap}. The value is not
+examined for correctness.
+
+There is one special case. If the filesystem type is specified as
+@samp{export} then the filesystem information will not be added to the
+host's @file{fstab} information, but it will still be visible on the
+network. This is useful for defining hosts which contain referenced
+volumes but which are not under full control of @i{FSinfo}.
+
+Example:
+
+@example
+fstype = swap
+@end example
+
+@node FSinfo filesystems opts, FSinfo filesystems passno,FSinfo filesystems fstype, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection opts Option
+@cindex FSinfo opts filesystems option
+@cindex opts, FSinfo filesystems option
+
+This defines any options that should be given to @b{mount}(8) in the
+@file{fstab} file. For example:
+
+@example
+opts = rw,nosuid,grpid
+@end example
+
+@node FSinfo filesystems passno, FSinfo filesystems freq, FSinfo filesystems opts, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection passno Option
+@cindex FSinfo passno filesystems option
+@cindex passno, FSinfo filesystems option
+
+This defines the @b{fsck}(8) pass number in which to check the
+filesystem. This value will be placed into the @file{fstab} file.
+
+Example:
+
+@example
+passno = 1
+@end example
+
+@node FSinfo filesystems freq, FSinfo filesystems mount, FSinfo filesystems passno, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection freq Option
+@cindex FSinfo freq filesystems option
+@cindex freq, FSinfo filesystems option
+
+This defines the interval (in days) between dumps. The value is placed
+as is into the @file{fstab} file.
+
+Example:
+
+@example
+freq = 3
+@end example
+
+@node FSinfo filesystems mount, FSinfo filesystems dumpset, FSinfo filesystems freq, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection mount Option
+@cindex FSinfo mount filesystems option
+@cindex mount, FSinfo filesystems option
+@cindex exportfs, FSinfo mount option
+@cindex volname, FSinfo mount option
+@cindex sel, FSinfo mount option
+
+This defines the mountpoint at which to place the filesystem. If the
+mountpoint of the filesystem is specified as @code{default}, then the
+filesystem will be mounted in the automounter's tree under its volume
+name and the mount will automatically be inherited by the automounter.
+
+Following the mountpoint, namespace information for the filesystem may
+be described. The options that can be given here are @code{exportfs},
+@code{volname} and @code{sel}.
+
+The format is:
+
+@example
+mount : "mount" vol_tree ;
+
+vol_tree : @i{list(}vol_tree_attr@i{)} ;
+
+vol_tree_attr
+ : @var{<string>} "@{" @i{list(}vol_tree_info@i{)} vol_tree "@}" ;
+
+vol_tree_info
+ : "exportfs" @var{<export-data>}
+ | "volname" @var{<volname>}
+ | "sel" @var{<selector-list>}
+ ;
+@end example
+
+Example:
+
+@example
+mount default @{
+ exportfs "dylan dougal florence zebedee"
+ volname /vol/andrew
+@}
+@end example
+
+In the above example, the filesystem currently being declared will have
+an entry placed into the @file{exports} file allowing the filesystem to
+be exported to the machines @code{dylan}, @code{dougal}, @code{florence}
+and @code{zebedee}. The volume name by which the filesystem will be
+referred to remotely, is @file{/vol/andrew}. By declaring the
+mountpoint to be @code{default}, the filesystem will be mounted on the
+local machine in the automounter tree, where @i{Amd} will automatically
+inherit the mount as @file{/vol/andrew}.@refill
+
+@table @samp
+@item exportfs
+a string defining which machines the filesystem may be exported to.
+This is copied, as is, into the @file{exports} file---no sanity checking
+is performed on this string.@refill
+
+@item volname
+a string which declares the remote name by which to reference the
+filesystem. The string is entered into a dictionary and allows you to
+refer to this filesystem in other places by this volume name.@refill
+
+@item sel
+a string which is placed into the automounter maps as a selector for the
+filesystem.@refill
+
+@end table
+
+@node FSinfo filesystems dumpset, FSinfo filesystems log, FSinfo filesystems mount, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection dumpset Option
+@cindex FSinfo dumpset filesystems option
+@cindex dumpset, FSinfo filesystems option
+
+This provides support for Imperial College's local file backup tools and
+is not documented further here.
+
+@node FSinfo filesystems log, , FSinfo filesystems dumpset, FSinfo filesystems
+@comment node-name, next, previous, up
+@subsection log Option
+@cindex FSinfo log filesystems option
+@cindex log, FSinfo filesystems option
+
+Specifies the log device for the current filesystem. This is ignored if
+not required by the particular filesystem type.
+
+@node FSinfo static mounts, FSinfo automount definitions , FSinfo filesystems, FSinfo host definitions
+@comment node-name, next, previous, up
+@section @i{FSinfo} static mounts
+@cindex FSinfo static mounts
+@cindex Statically mounts filesystems, FSinfo
+
+Each host may also have a number of statically mounted filesystems. For
+example, the host may be a diskless workstation in which case it will
+have no @code{fs} declarations. In this case the @code{mount}
+declaration is used to determine from where its filesystems will be
+mounted. In addition to being added to the @file{fstab} file, this
+information can also be used to generate a suitable @file{bootparams}
+file.@refill
+
+@example
+mount : "mount" @var{<volname>} @i{list(}localinfo@i{)} ;
+
+localinfo : localinfo_attr @var{<string>} ;
+
+localinfo_attr
+ : "as"
+ | "from"
+ | "fstype"
+ | "opts"
+ ;
+@end example
+
+The filesystem specified to be mounted will be searched for in the
+dictionary of volume names built when scanning the list of hosts'
+definitions.
+
+The attributes have the following semantics:
+@table @samp
+@item from @var{machine}
+mount the filesystem from the machine with the hostname of
+@dfn{machine}.@refill
+
+@item as @var{mountpoint}
+mount the filesystem locally as the name given, in case this is
+different from the advertised volume name of the filesystem.
+
+@item opts @var{options}
+native @b{mount}(8) options.
+
+@item fstype @var{type}
+type of filesystem to be mounted.
+@end table
+
+An example:
+
+@example
+mount /export/exec/hp300/local as /usr/local
+@end example
+
+If the mountpoint specified is either @file{/} or @file{swap}, the
+machine will be considered to be booting off the net and this will be
+noted for use in generating a @file{bootparams} file for the host which
+owns the filesystems.
+
+@node FSinfo automount definitions, FSinfo Command Line Options, FSinfo static mounts, FSinfo
+@comment node-name, next, previous, up
+@section Defining an @i{Amd} Mount Map in @i{FSinfo}
+@cindex FSinfo automount definitions
+@cindex Defining an Amd mount map, FSinfo
+
+The maps used by @i{Amd} can be constructed from @i{FSinfo} by defining
+all the automount trees. @i{FSinfo} takes all the definitions found and
+builds one map for each top level tree.
+
+The automount tree is usually defined last. A single automount
+configuration will usually apply to an entire management domain. One
+@code{automount} declaration is needed for each @i{Amd} automount point.
+@i{FSinfo} determines whether the automount point is @dfn{direct}
+(@pxref{Direct Automount Filesystem}) or @dfn{indirect}
+(@pxref{Top-level Filesystem}). Direct automount points are
+distinguished by the fact that there is no underlying
+@dfn{automount_tree}.@refill
+
+@example
+automount : "automount" opt(auto_opts@i{)} automount_tree ;
+
+auto_opts : "opts" @var{<mount-options>} ;
+
+automount_tree
+ : @i{list(}automount_attr@i{)}
+ ;
+
+automount_attr
+ : @var{<string>} "=" @var{<volname>}
+ | @var{<string>} "->" @var{<symlink>}
+ | @var{<string>} "@{" automount_tree "@}"
+ ;
+@end example
+
+If @var{<mount-options>} is given, then it is the string to be placed in
+the maps for @i{Amd} for the @code{opts} option.
+
+A @dfn{map} is typically a tree of filesystems, for example @file{home}
+normally contains a tree of filesystems representing other machines in
+the network.
+
+A map can either be given as a name representing an already defined
+volume name, or it can be a tree. A tree is represented by placing
+braces after the name. For example, to define a tree @file{/vol}, the
+following map would be defined:
+
+@example
+automount /vol @{ @}
+@end example
+
+Within a tree, the only items that can appear are more maps.
+For example:
+
+@example
+automount /vol @{
+ andrew @{ @}
+ X11 @{ @}
+@}
+@end example
+
+In this case, @i{FSinfo} will look for volumes named @file{/vol/andrew}
+and @file{/vol/X11} and a map entry will be generated for each. If the
+volumes are defined more than once, then @i{FSinfo} will generate
+a series of alternate entries for them in the maps.@refill
+
+Instead of a tree, either a link (@var{name} @code{->}
+@var{destination}) or a reference can be specified (@var{name} @code{=}
+@var{destination}). A link creates a symbolic link to the string
+specified, without further processing the entry. A reference will
+examine the destination filesystem and optimise the reference. For
+example, to create an entry for @code{njw} in the @file{/homes} map,
+either of the two forms can be used:@refill
+
+@example
+automount /homes @{
+ njw -> /home/dylan/njw
+@}
+@end example
+
+or
+
+@example
+automount /homes @{
+ njw = /home/dylan/njw
+@}
+@end example
+
+In the first example, when @file{/homes/njw} is referenced from @i{Amd},
+a link will be created leading to @file{/home/dylan/njw} and the
+automounter will be referenced a second time to resolve this filename.
+The map entry would be:
+
+@example
+njw type:=link;fs:=/home/dylan/njw
+@end example
+
+In the second example, the destination directory is analysed and found
+to be in the filesystem @file{/home/dylan} which has previously been
+defined in the maps. Hence the map entry will look like:
+
+@example
+njw rhost:=dylan;rfs:=/home/dylan;sublink:=njw
+@end example
+
+Creating only one symbolic link, and one access to @i{Amd}.
+
+@c ---------------------------------------------
+@node FSinfo Command Line Options, FSinfo errors, FSinfo automount definitions, FSinfo
+@comment node-name, next, previous, up
+@section @i{FSinfo} Command Line Options
+@cindex FSinfo command line options
+@cindex Command line options, FSinfo
+
+@i{FSinfo} is started from the command line by using the command:
+
+@example
+fsinfo [@i{options}] files ...
+@end example
+
+The input to @i{FSinfo} is a single set of definitions of machines and
+automount maps. If multiple files are given on the command-line, then
+the files are concatenated together to form the input source. The files
+are passed individually through the C pre-processor before being parsed.
+
+Several options define a prefix for the name of an output file. If the
+prefix is not specified no output of that type is produced. The suffix
+used will correspond either to the hostname to which a file belongs, or
+to the type of output if only one file is produced. Dumpsets and the
+@file{bootparams} file are in the latter class. To put the output into
+a subdirectory simply put a @file{/} at the end of the prefix, making
+sure that the directory has already been made before running
+@samp{fsinfo}.
+
+@menu
+* -a FSinfo Option:: Amd automount directory:
+* -b FSinfo Option:: Prefix for bootparams files.
+* -d FSinfo Option:: Prefix for dumpset data files.
+* -e FSinfo Option:: Prefix for exports files.
+* -f FSinfo Option:: Prefix for fstab files.
+* -h FSinfo Option:: Local hostname.
+* -m FSinfo Option:: Prefix for automount maps.
+* -q FSinfo Option:: Ultra quiet mode.
+* -v FSinfo Option:: Verbose mode.
+* -I FSinfo Option:: Define new #include directory.
+* -D-FSinfo Option:: Define macro.
+* -U FSinfo Option:: Undefine macro.
+@end menu
+
+@node -a FSinfo Option, -b FSinfo Option, FSinfo Command Line Options, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-a} @var{autodir}
+
+Specifies the directory name in which to place the automounter's
+mountpoints. This defaults to @file{/a}. Some sites have the autodir set
+to be @file{/amd}, and this would be achieved by:
+
+@example
+fsinfo -a /amd ...
+@end example
+
+@node -b FSinfo Option, -d FSinfo Option, -a FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-b} @var{bootparams}
+@cindex bootparams, FSinfo prefix
+
+This specifies the prefix for the @file{bootparams} filename. If it is
+not given, then the file will not be generated. The @file{bootparams}
+file will be constructed for the destination machine and will be placed
+into a file named @file{bootparams} and prefixed by this string. The
+file generated contains a list of entries describing each diskless
+client that can boot from the destination machine.
+
+As an example, to create a @file{bootparams} file in the directory
+@file{generic}, the following would be used:
+
+@example
+fsinfo -b generic/ ...
+@end example
+
+@node -d FSinfo Option, -e FSinfo Option, -b FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-d} @var{dumpsets}
+@cindex dumpset, FSinfo prefix
+
+This specifies the prefix for the @file{dumpsets} file. If it is not
+specified, then the file will not be generated. The file will be for
+the destination machine and will be placed into a filename
+@file{dumpsets}, prefixed by this string. The @file{dumpsets} file is
+for use by Imperial College's local backup system.
+
+For example, to create a dumpsets file in the directory @file{generic},
+then you would use the following:
+
+@example
+fsinfo -d generic/ ...
+@end example
+
+@node -e FSinfo Option, -f FSinfo Option, -d FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-e} @var{exportfs}
+@cindex exports, FSinfo prefix
+
+Defines the prefix for the @file{exports} files. If it is not given,
+then the file will not be generated. For each machine defined in the
+configuration files as having disks, an @file{exports} file is
+constructed and given a filename determined by the name of the machine,
+prefixed with this string. If a machine is defined as diskless, then no
+@file{exports} file will be created for it. The files contain entries
+for directories on the machine that may be exported to clients.
+
+Example: To create the @file{exports} files for each diskful machine
+and place them into the directory @file{exports}:
+
+@example
+fsinfo -e exports/ ...
+@end example
+
+@node -f FSinfo Option, -h FSinfo Option, -e FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-f} @var{fstab}
+@cindex fstab, FSinfo prefix
+
+This defines the prefix for the @file{fstab} files. The files will only
+be created if this prefix is defined. For each machine defined in the
+configuration files, a @file{fstab} file is created with the filename
+determined by prefixing this string with the name of the machine. These
+files contain entries for filesystems and partitions to mount at boot
+time.
+
+Example, to create the files in the directory @file{fstabs}:
+
+@example
+fsinfo -f fstabs/ ...
+@end example
+
+@node -h FSinfo Option, -m FSinfo Option, -f FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-h} @var{hostname}
+@cindex hostname, FSinfo command line option
+
+Defines the hostname of the destination machine to process for. If this
+is not specified, it defaults to the local machine name, as returned by
+@b{gethostname}(2).
+
+Example:
+
+@example
+fsinfo -h dylan.doc.ic.ac.uk ...
+@end example
+
+@node -m FSinfo Option, -q FSinfo Option, -h FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-m} @var{mount-maps}
+@cindex maps, FSinfo command line option
+
+Defines the prefix for the automounter files. The maps will only be
+produced if this prefix is defined. The mount maps suitable for the
+network defined by the configuration files will be placed into files
+with names calculated by prefixing this string to the name of each map.
+
+For example, to create the automounter maps and place them in the
+directory @file{automaps}:
+
+@example
+fsinfo -m automaps/ ...
+@end example
+
+@node -q FSinfo Option, -v FSinfo Option, -m FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-q}
+@cindex quiet, FSinfo command line option
+
+Selects quiet mode. @i{FSinfo} suppress the ``running commentary'' and
+only outputs any error messages which are generated.
+
+@node -v FSinfo Option, -D-FSinfo Option, -q FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-v}
+@cindex verbose, FSinfo command line option
+
+Selects verbose mode. When this is activated, the program will display
+more messages, and display all the information discovered when
+performing the semantic analysis phase. Each verbose message is output
+to @file{stdout} on a line starting with a @samp{#} character.
+
+@node -D-FSinfo Option, -I FSinfo Option, -v FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-D} @var{name[=defn]}
+
+Defines a symbol @dfn{name} for the preprocessor when reading the
+configuration files. Equivalent to @code{#define} directive.
+
+@node -I FSinfo Option, -U FSinfo Option, -D-FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-I} @var{directory}
+
+This option is passed into the preprocessor for the configuration files.
+It specifies directories in which to find include files
+
+@node -U FSinfo Option, , -I FSinfo Option, FSinfo Command Line Options
+@comment node-name, next, previous, up
+@subsection @code{-U} @var{name}
+
+Removes any initial definition of the symbol @dfn{name}. Inverse of the
+@code{-D} option.
+
+@node FSinfo errors, , FSinfo command line options, FSinfo
+@comment node-name, next, previous, up
+@section Errors produced by @i{FSinfo}
+@cindex FSinfo error messages
+
+The following table documents the errors and warnings which @i{FSinfo} may produce.
+
+@table @t
+
+@item can't open @var{filename} for writing
+Occurs if any errors are encountered when opening an output file.@refill
+
+@item unknown host attribute
+Occurs if an unrecognised keyword is used when defining a host.@refill
+
+@item unknown filesystem attribute
+Occurs if an unrecognised keyword is used when defining a host's
+filesystems.@refill
+
+@item not allowed '/' in a directory name
+When reading the configuration input, if there is a filesystem
+definition which contains a pathname with multiple directories for any
+part of the mountpoint element, and it is not a single absolute path,
+then this message will be produced by the parser.@refill
+
+@item unknown directory attribute
+If an unknown keyword is found while reading the definition of a hosts's
+filesystem mount option.
+
+@item unknown mount attribute
+Occurs if an unrecognised keyword is found while parsing the list of
+static mounts.@refill
+
+@item " expected
+Occurs if an unescaped newline is found in a quoted string.
+
+@item unknown \ sequence
+Occurs if an unknown escape sequence is found inside a string. Within a
+string, you can give the standard C escape sequences for strings, such
+as newlines and tab characters.@refill
+
+@item @var{filename}: cannot open for reading
+If a file specified on the command line as containing configuration data
+could not be opened.@refill
+
+@item end of file within comment
+A comment was unterminated before the end of one of the configuration
+files.
+
+@item host field "@var{field-name}" already set
+If duplicate definitions are given for any of the fields with a host
+definition.
+
+@item duplicate host @var{hostname}!
+If a host has more than one definition.
+
+@item netif field @var{field-name} already set
+Occurs if you attempt to define an attribute of an interface more than
+once.
+
+@item malformed IP dotted quad: @var{address}
+If the Internet address of an interface is incorrectly specified. An
+Internet address definition is handled to @b{inet_addr}(3N) to see if it
+can cope. If not, then this message will be displayed.
+
+@item malformed netmask: @var{netmask}
+If the netmask cannot be decoded as though it were a hexadecimal number,
+then this message will be displayed. It will typically be caused by
+incorrect characters in the @var{netmask} value.@refill
+
+@item fs field "@var{field-name}" already set
+Occurs when multiple definitions are given for one of the attributes of a
+host's filesystem.
+
+@item mount tree field "@var{field-name}" already set
+Occurs when the @var{field-name} is defined more than once during the
+definition of a filesystems mountpoint.
+
+@item mount field "@var{field-name}" already set
+Occurs when a static mount has multiple definitions of the same field.
+
+@item no disk mounts on @var{hostname}
+If there are no static mounts, nor local disk mounts specified for a
+machine, this message will be displayed.
+
+@item @var{host}:@var{device} needs field "@var{field-name}"
+Occurs when a filesystem is missing a required field. @var{field-name} could
+be one of @code{fstype}, @code{opts}, @code{passno} or
+@code{mount}.@refill
+
+@item @var{filesystem} has a volname but no exportfs data
+Occurs when a volume name is declared for a file system, but the string
+specifying what machines the filesystem can be exported to is
+missing.
+
+@item sub-directory @var{directory} of @var{directory-tree} starts with '/'
+Within the filesystem specification for a host, if an element
+@var{directory} of the mountpoint begins with a @samp{/} and it is not
+the start of the tree.@refill
+
+@item @var{host}:@var{device} has no mount point
+Occurs if the @samp{mount} option is not specified for a host's
+filesystem.@refill
+
+@item @var{host}:@var{device} has more than one mount point
+Occurs if the mount option for a host's filesystem specifies multiple
+trees at which to place the mountpoint.@refill
+
+@item no volname given for @var{host}:@var{device}
+Occurs when a filesystem is defined to be mounted on @file{default}, but
+no volume name is given for the file system, then the mountpoint cannot
+be determined.@refill
+
+@item @var{host}:mount field specified for swap partition
+Occurs if a mountpoint is given for a filesystem whose type is declared
+to be @code{swap}.@refill
+
+@item ambiguous mount: @var{volume} is a replicated filesystem
+If several filesystems are declared as having the same volume name, they
+will be considered replicated filesystems. To mount a replicated
+filesystem statically, a specific host will need to be named, to say
+which particular copy to try and mount, else this error will
+result.@refill
+
+@item cannot determine localname since volname @var{volume} is not uniquely defined
+If a volume is replicated and an attempt is made to mount the filesystem
+statically without specifying a local mountpoint, @i{FSinfo} cannot
+calculate a mountpoint, as the desired pathname would be
+ambiguous.@refill
+
+@item volname @var{volume} is unknown
+Occurs if an attempt is made to mount or reference a volume name which
+has not been declared during the host filesystem definitions.@refill
+
+@item volname @var{volume} not exported from @var{machine}
+Occurs if you attempt to mount the volume @var{volume} from a machine
+which has not declared itself to have such a filesystem
+available.@refill
+
+@item network booting requires both root and swap areas
+Occurs if a machine has mount declarations for either the root partition
+or the swap area, but not both. You cannot define a machine to only
+partially boot via the network.@refill
+
+@item unknown volname @var{volume} automounted @i{[} on <name> @i{]}
+Occurs if @var{volume} is used in a definition of an automount map but the volume
+name has not been declared during the host filesystem definitions.@refill
+
+@item not allowed '/' in a directory name
+Occurs when a pathname with multiple directory elements is specified as
+the name for an automounter tree. A tree should only have one name at
+each level.
+
+@item @var{device} has duplicate exportfs data
+Produced if the @samp{exportfs} option is used multiple times within the
+same branch of a filesytem definition. For example, if you attempt to
+set the @samp{exportfs} data at different levels of the mountpoint
+directory tree.@refill
+
+@item sub-directory of @var{directory-tree} is named "default"
+@samp{default} is a keyword used to specify if a mountpoint should be
+automatically calculated by @i{FSinfo}. If you attempt to specify a
+directory name as this, it will use the filename of @file{default} but
+will produce this warning.@refill
+
+@item pass number for @var{host}:@var{device} is non-zero
+Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap}
+or @samp{export} and the @b{fsck}(8) pass number is set. Swap devices should not be
+fsck'd. @xref{FSinfo filesystems fstype}@refill
+
+@item dump frequency for @var{host}:@var{device} is non-zero
+Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap}
+or @samp{export} and the @samp{dump} option is set to a value greater
+than zero. Swap devices should not be dumped.@refill
+
+@end table
+
+@node Examples, Internals, FSinfo, Top
+@comment node-name, next, previous, up
+@chapter Examples
+
+@menu
+* User Filesystems::
+* Home Directories::
+* Architecture Sharing::
+* Wildcard names::
+* rwho servers::
+* /vol::
+@end menu
+
+@node User Filesystems, Home Directories, Examples, Examples
+@comment node-name, next, previous, up
+@section User Filesystems
+@cindex User filesystems
+@cindex Mounting user filesystems
+
+With more than one fileserver, the directories most frequently
+cross-mounted are those containing user home directories. A common
+convention used at Imperial College is to mount the user disks under
+@t{/home/}@i{machine}.
+
+Typically, the @samp{/etc/fstab} file contained a long list of entries
+such as:
+
+@example
+@i{machine}:/home/@i{machine} /home/@i{machine} nfs ...
+@end example
+
+for each fileserver on the network.
+
+There are numerous problems with this system. The mount list can become
+quite large and some of the machines may be down when a system is
+booted. When a new fileserver is installed, @samp{/etc/fstab} must be
+updated on every machine, the mount directory created and the filesystem
+mounted.
+
+In many environments most people use the same few workstations, but
+it is convenient to go to a colleague's machine and access your own
+files. When a server goes down, it can cause a process on a client
+machine to hang. By minimising the mounted filesystems to only include
+those actively being used, there is less chance that a filesystem will
+be mounted when a server goes down.
+
+The following is a short extract from a map taken from a research fileserver
+at Imperial College.
+
+Note the entry for @samp{localhost} which is used for users such as
+the operator (@samp{opr}) who have a home directory on most machine as
+@samp{/home/localhost/opr}.
+
+@example
+/defaults opts:=rw,intr,grpid,nosuid
+charm host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \
+ host==$@{key@};type:=ufs;dev:=/dev/xd0g
+#
+...
+
+#
+localhost type:=link;fs:=$@{host@}
+...
+#
+# dylan has two user disks so have a
+# top directory in which to mount them.
+#
+dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/
+#
+dylan/dk2 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \
+ host==dylan;type:=ufs;dev:=/dev/dsk/2s0
+#
+dylan/dk5 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \
+ host==dylan;type:=ufs;dev:=/dev/dsk/5s0
+...
+#
+toytown host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \
+ host==$@{key@};type:=ufs;dev:=/dev/xy1g
+...
+#
+zebedee host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \
+ host==$@{key@};type:=ufs;dev:=/dev/dsk/1s0
+#
+# Just for access...
+#
+gould type:=auto;fs:=$@{map@};pref:=$@{key@}/
+gould/staff host!=gould;type:=nfs;rhost:=gould;rfs:=/home/$@{key@}
+#
+gummo host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@}
+...
+@end example
+
+This map is shared by most of the machines listed so on those
+systems any of the user disks is accessible via a consistent name.
+@i{Amd} is started with the following command
+
+@example
+amd /home amd.home
+@end example
+
+Note that when mounting a remote filesystem, the @dfn{automounted}
+mount point is referenced, so that the filesystem will be mounted if
+it is not yet (at the time the remote @samp{mountd} obtains the file handle).
+
+@node Home Directories, Architecture Sharing, User Filesystems, Examples
+@comment node-name, next, previous, up
+@section Home Directories
+@cindex Home directories
+@cindex Example of mounting home directories
+@cindex Mount home directories
+
+One convention for home directories is to locate them in @samp{/homes}
+so user @samp{jsp}'s home directory is @samp{/homes/jsp}. With more
+than a single fileserver it is convenient to spread user files across
+several machines. All that is required is a mount-map which converts
+login names to an automounted directory.
+
+Such a map might be started by the command:
+
+@example
+amd /homes amd.homes
+@end example
+
+where the map @samp{amd.homes} contained the entries:
+
+@example
+/defaults type:=link # All the entries are of type:=link
+jsp fs:=/home/charm/jsp
+njw fs:=/home/dylan/dk5/njw
+...
+phjk fs:=/home/toytown/ai/phjk
+sjv fs:=/home/ganymede/sjv
+@end example
+
+Whenever a login name is accessed in @samp{/homes} a symbolic link
+appears pointing to the real location of that user's home directory. In
+this example, @samp{/homes/jsp} would appear to be a symbolic link
+pointing to @samp{/home/charm/jsp}. Of course, @samp{/home} would also
+be an automount point.
+
+This system causes an extra level of symbolic links to be used.
+Although that turns out to be relatively inexpensive, an alternative is
+to directly mount the required filesystems in the @samp{/homes}
+map. The required map is simple, but long, and its creation is best automated.
+The entry for @samp{jsp} could be:
+
+@example
+jsp -sublink:=$@{key@};rfs:=/home/charm \
+ host==charm;type:=ufs;dev:=/dev/xd0g \
+ host!=charm;type:=nfs;rhost:=charm
+@end example
+
+This map can become quite big if it contains a large number of entries.
+By combining two other features of @i{Amd} it can be greatly simplified.
+
+First the UFS partitions should be mounted under the control of
+@samp{/etc/fstab}, taking care that they are mounted in the same place
+that @i{Amd} would have automounted them. In most cases this would be
+something like @samp{/a/@dfn{host}/home/@dfn{host}} and
+@samp{/etc/fstab} on host @samp{charm} would have a line:@refill
+
+@example
+/dev/xy0g /a/charm/home/charm 4.2 rw,nosuid,grpid 1 5
+@end example
+
+The map can then be changed to:
+
+@example
+/defaults type:=nfs;sublink:=$@{key@};opts:=rw,intr,nosuid,grpid
+jsp rhost:=charm;rfs:=/home/charm
+njw rhost:=dylan;rfs:=/home/dylan/dk5
+...
+phjk rhost:=toytown;rfs:=/home/toytown;sublink:=ai/$@{key@}
+sjv rhost:=ganymede;rfs:=/home/ganymede
+@end example
+
+This map operates as usual on a remote machine (@i{ie} @code{$@{host@}}
+not equal to @code{$@{rhost@}}). On the machine where the filesystem is
+stored (@i{ie} @code{$@{host@}} equal to @code{$@{rhost@}}), @i{Amd}
+will construct a local filesystem mount point which corresponds to the
+name of the locally mounted UFS partition. If @i{Amd} is started with
+the ``-r'' option then instead of attempting an NFS mount, @i{Amd} will
+simply inherit the UFS mount (@pxref{Inheritance Filesystem}). If
+``-r'' is not used then a loopback NFS mount will be made. This type of
+mount is known to cause a deadlock on many systems.
+
+@node Architecture Sharing, Wildcard Names, Home Directories, Examples
+@comment node-name, next, previous, up
+@section Architecture Sharing
+@cindex Architecture sharing
+@cindex Sharing a fileserver between architectures
+@cindex Architecture dependent volumes
+
+@c %At the moment some of the research machines have sets of software
+@c %mounted in @samp{/vol}. This contains subdirectories for \TeX,
+@c %system sources, local sources, prolog libraries and so on.
+Often a filesystem will be shared by machines of different architectures.
+Separate trees can be maintained for the executable images for each
+architecture, but it may be more convenient to have a shared tree,
+with distinct subdirectories.
+
+A shared tree might have the following structure on the fileserver (called
+@samp{fserver} in the example):
+
+@example
+local/tex
+local/tex/fonts
+local/tex/lib
+local/tex/bin
+local/tex/bin/sun3
+local/tex/bin/sun4
+local/tex/bin/hp9000
+...
+@end example
+
+In this example, the subdirectories of @samp{local/tex/bin} should be
+hidden when accessed via the automount point (conventionally @samp{/vol}).
+A mount-map for @samp{/vol} to achieve this would look like:
+
+@example
+/defaults sublink:=$@{/key@};rhost:=fserver;type:=link
+tex type:=auto;fs:=$@{map@};pref:=$@{key@}/
+tex/fonts host!=fserver;type:=nfs;rfs:=/vol/tex \
+ host==fserver;fs:=/usr/local/tex
+tex/lib host!=fserver;type:=nfs;rfs:=/vol/tex \
+ host==fserver;fs:=/usr/local/tex
+tex/bin -sublink:=$@{/key@}/$@{arch@} host!=fserver;type:=nfs;rfs:=/vol/tex \
+ host:=fserver;fs:=/usr/local/tex
+@end example
+
+When @samp{/vol/tex/bin} is referenced, the current machine architecture
+is automatically appended to the path by the @code{$@{sublink@}}
+variable. This means that users can have @samp{/vol/tex/bin} in their
+@samp{PATH} without concern for architecture dependencies.
+
+@node Wildcard Names, rwho servers, Architecture Sharing, Examples
+@comment node-name, next, previous, up
+@section Wildcard names & Replicated Servers
+
+By using the wildcard facility, @i{Amd} can @dfn{overlay} an existing
+directory with additional entries.
+The system files are usually mounted under @samp{/usr}. If instead
+@i{Amd} is mounted on @samp{/usr}, additional
+names can be overlayed to augment or replace names in the ``master'' @samp{/usr}.
+A map to do this would have the form:
+
+@example
+local type:=auto;fs:=local-map
+share type:=auto;fs:=share-map
+* -type:=nfs;rfs:=/export/exec/$@{arch@};sublink:="$@{key@}" \
+ rhost:=fserv1 rhost:=fserv2 rhost:=fserv3
+@end example
+
+Note that the assignment to @code{$@{sublink@}} is surrounded by double
+quotes to prevent the incoming key from causing the map to be
+misinterpreted. This map has the effect of directing any access to
+@samp{/usr/local} or @samp{/usr/share} to another automount point.
+
+In this example, it is assumed that the @samp{/usr} files are replicated
+on three fileservers: @samp{fserv1}, @samp{fserv2} and @samp{fserv3}.
+For any references other than to @samp{local} and @samp{share} one of
+the servers is used and a symbolic link to
+@t{$@{autodir@}/$@{rhost@}/export/exec/$@{arch@}/@i{whatever}} is
+returned once an appropriate filesystem has been mounted.@refill
+
+@node rwho servers, /vol, Wildcard Names, Examples
+@comment node-name, next, previous, up
+@section @samp{rwho} servers
+@cindex rwho servers
+@cindex Architecture specific mounts
+@cindex Example of architecture specific mounts
+
+The @samp{/usr/spool/rwho} directory is a good candidate for automounting.
+For efficiency reasons it is best to capture the rwho data on a small
+number of machines and then mount that information onto a large number
+of clients. The data written into the rwho files is byte order dependent
+so only servers with the correct byte ordering can be used by a client:
+
+@example
+/defaults type:=nfs
+usr/spool/rwho -byte==little;rfs:=/usr/spool/rwho \
+ rhost:=vaxA rhost:=vaxB \
+ || -rfs:=/usr/spool/rwho \
+ rhost:=sun4 rhost:=hp300
+@end example
+
+@node /vol, , rwho servers, Examples
+@comment node-name, next, previous, up
+@section @samp{/vol}
+@cindex /vol
+@cindex Catch-all mount point
+@cindex Generic volume name
+
+@samp{/vol} is used as a catch-all for volumes which do not have other
+conventional names.
+
+Below is part of the @samp{/vol} map for the domain @samp{doc.ic.ac.uk}.
+The @samp{r+d} tree is used for new or experimental software that needs
+to be available everywhere without installing it on all the fileservers.
+Users wishing to try out the new software then simply include
+@samp{/vol/r+d/@{bin,ucb@}} in their path.@refill
+
+The main tree resides on one host @samp{gould.doc.ic.ac.uk}, which has
+different @samp{bin}, @samp{etc}, @samp{lib} and @samp{ucb}
+sub-directories for each machine architecture. For example,
+@samp{/vol/r+d/bin} for a Sun-4 would be stored in the sub-directory
+@samp{bin/sun4} of the filesystem @samp{/usr/r+d}. When it was accessed
+a symbolic link pointing to @samp{/a/gould/usr/r+d/bin/sun4} would be
+returned.@refill
+
+@example
+/defaults type:=nfs;opts:=rw,grpid,nosuid,intr,soft
+wp -opts:=rw,grpid,nosuid;rhost:=charm \
+ host==charm;type:=link;fs:=/usr/local/wp \
+ host!=charm;type:=nfs;rfs:=/vol/wp
+...
+#
+src -opts:=rw,grpid,nosuid;rhost:=charm \
+ host==charm;type:=link;fs:=/usr/src \
+ host!=charm;type:=nfs;rfs:=/vol/src
+#
+r+d type:=auto;fs:=$@{map@};pref:=r+d/
+# per architecture bin,etc,lib&ucb...
+r+d/bin rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@}
+r+d/etc rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@}
+r+d/include rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}
+r+d/lib rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@}
+r+d/man rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}
+r+d/src rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}
+r+d/ucb rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@}
+# hades pictures
+pictures -opts:=rw,grpid,nosuid;rhost:=thpfs \
+ host==thpfs;type:=link;fs:=/nbsd/pictures \
+ host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=pictures
+# hades tools
+hades -opts:=rw,grpid,nosuid;rhost:=thpfs \
+ host==thpfs;type:=link;fs:=/nbsd/hades \
+ host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=hades
+# bsd tools for hp.
+bsd -opts:=rw,grpid,nosuid;arch==hp9000;rhost:=thpfs \
+ host==thpfs;type:=link;fs:=/nbsd/bsd \
+ host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=bsd
+@end example
+
+@node Internals, Acknowledgements & Trademarks, Examples, Top
+@comment node-name, next, previous, up
+@chapter Internals
+
+@menu
+* Log Messages::
+@end menu
+
+@node Log Messages, , Internals, Internals
+@comment node-name, next, previous, up
+@section Log Messages
+
+In the following sections a brief explanation is given of some of the
+log messages made by @i{Amd}. Where the message is in @samp{typewriter}
+font, it corresponds exactly to the message produced by @i{Amd}. Words
+in @dfn{italic} are replaced by an appropriate string. Variables,
+@code{$@{var@}}, indicate that the value of the appropriate variable is
+output.
+
+Log messages are either sent direct to a file,
+or logged via the @b{syslog}(3) mechanism.
+Messages are logged with facility @samp{LOG_DAEMON} when using @b{syslog}(3).
+In either case, entries in the file are of the form:
+@example
+@i{date-string} @i{hostname} @t{amd[}@i{pid}@t{]} @i{message}
+@end example
+
+@menu
+* Fatal errors::
+* Info messages::
+@end menu
+
+@node Fatal errors, Info messages, Log Messages, Log Messages
+@comment node-name, next, previous, up
+@subsection Fatal errors
+
+@i{Amd} attempts to deal with unusual events. Whenever it is not
+possible to deal with such an error, @i{Amd} will log an appropriate
+message and, if it cannot possibly continue, will either exit or abort.
+These messages are selected by @samp{-x fatal} on the command line.
+When @b{syslog}(3) is being used, they are logged with level
+@samp{LOG_FATAL}. Even if @i{Amd} continues to operate it is likely to
+remain in a precarious state and should be restarted at the earliest
+opportunity.
+
+@table @asis
+@item @t{Attempting to inherit not-a-filesystem}
+The prototype mount point created during a filesystem restart did not
+contain a reference to the restarted filesystem. This erorr ``should
+never happen''.
+
+@item @t{Can't bind to domain "@i{NIS-domain}"}
+A specific NIS domain was requested on the command line, but no server
+for that domain is available on the local net.
+
+@item @t{Can't determine IP address of this host (@i{hostname})}
+When @i{Amd} starts it determines its own IP address. If this lookup
+fails then @i{Amd} cannot continue. The hostname it looks up is that
+obtained returned by @b{gethostname}(2) system call.
+
+@item @t{Can't find root file handle for @i{automount point}}
+@i{Amd} creates its own file handles for the automount points. When it
+mounts itself as a server, it must pass these file handles to the local
+kernel. If the filehandle is not obtainable the mount point is ignored.
+This error ``should never happen''.
+
+@item @t{Must be root to mount filesystems (euid = @i{euid})}
+To prevent embarrassment, @i{Amd} makes sure it has appropriate system
+privileges. This amounts to having an euid of 0. The check is made
+after argument processing complete to give non-root users a chance to
+access the ``-v'' option.
+
+@item @t{No work to do - quitting}
+No automount points were given on the command line and so there is no
+work to do.
+
+@item @t{Out of memory in realloc}
+While attempting to realloc some memory, the memory space available to
+@i{Amd} was exhausted. This is an unrecoverable error.
+
+@item @t{Out of memory}
+While attempting to malloc some memory, the memory space available to
+@i{Amd} was exhausted. This is an unrecoverable error.
+
+@item @t{cannot create rpc/udp service}
+Either the NFS or AMQ endpoint could not be created.
+
+@item @t{gethostname:} @i{description}
+The @b{gethostname}(2) system call failed during startup.
+
+@item @t{host name is not set}
+The @b{gethostname}(2) system call returned a zero length host name.
+This can happen if @i{Amd} is started in single user mode just after
+booting the system.
+
+@item @t{ifs_match called!}
+An internal error occurred while restarting a pre-mounted filesystem.
+This error ``should never happen''.
+
+@item @t{mount_afs:} @i{description}
+An error occured while @i{Amd} was mounting itself.
+
+@item @t{run_rpc failed}
+Somehow the main NFS server loop failed. This error ``should never
+happen''.
+
+@item @t{unable to free rpc arguments in amqprog_1}
+The incoming arguments to the AMQ server could not be free'ed.
+
+@item @t{unable to free rpc arguments in nfs_program_1}
+The incoming arguments to the NFS server could not be free'ed.
+
+@item @t{unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)}
+The AMQ server could not be registered with the local portmapper or the
+internal RPC dispatcher.
+
+@item @t{unable to register (NFS_PROGRAM, NFS_VERSION, 0)}
+The NFS server could not be registered with the internal RPC dispatcher.
+
+@end table
+
+@node Info messages, , Fatal errors, Log Messages
+@comment node-name, next, previous, up
+@subsection Info messages
+
+@i{Amd} generates information messages to record state changes. These
+messages are selected by @samp{-x info} on the command line. When
+@b{syslog}(3) is being used, they are logged with level @samp{LOG_INFO}.
+
+The messages listed below can be generated and are in a format suitable
+for simple statistical analysis. @dfn{mount-info} is the string
+that is displayed by @dfn{Amq} in its mount information column and
+placed in the system mount table.
+
+@table @asis
+@item @t{mount of "@t{$@{@i{path}@}}" on @t{$@{@i{fs}@}} timed out}
+Attempts to mount a filesystem for the given automount point have failed
+to complete within 30 seconds.
+
+@item @t{"@t{$@{@i{path}@}}" forcibly timed out}
+An automount point has been timed out by the @i{Amq} command.
+
+@item @t{restarting @i{mount-info} on @t{$@{@i{fs}@}}}
+A pre-mounted file system has been noted.
+
+@item @t{"@t{$@{@i{path}@}}" has timed out}
+No access to the automount point has been made within the timeout
+period.
+
+@item @t{file server @t{$@{@i{rhost}@}} is down - timeout of "@t{$@{@i{path}@}}" ignored}
+An automount point has timed out, but the corresponding file server is
+known to be down. This message is only produced once for each mount
+point for which the server is down.
+
+@item @t{Re-synchronizing cache for map @t{$@{@i{map}@}}}
+The named map has been modified and the internal cache is being re-synchronized.
+
+@item @t{Filehandle denied for "@t{$@{@i{rhost}@}}:@t{$@{@i{rfs}@}}"}
+The mount daemon refused to return a file handle for the requested filesystem.
+
+@item @t{Filehandle error for "$@{@i{rhost}@}:$@{@i{rfs}@}":} @i{description}
+The mount daemon gave some other error for the requested filesystem.
+
+@item @t{file server @t{$@{@i{rhost}@}} type nfs starts up}
+A new NFS file server has been referenced and is known to be up.
+
+@item @t{file server @t{$@{@i{rhost}@}} type nfs starts down}
+A new NFS file server has been referenced and is known to be down.
+
+@item @t{file server @t{$@{@i{rhost}@}} type nfs is up}
+An NFS file server that was previously down is now up.
+
+@item @t{file server @t{$@{@i{rhost}@}} type nfs is down}
+An NFS file server that was previously up is now down.
+
+@item @t{Finishing with status @i{exit-status}}
+@i{Amd} is about to exit with the given exit status.
+
+@item @t{@i{mount-info} mounted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}}}
+A new file system has been mounted.
+
+@item @t{@i{mount-info} restarted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}}}
+@i{Amd} is using a pre-mounted filesystem to satisfy a mount request.
+
+@item @t{@i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}}}
+A file system has been unmounted.
+
+@item @t{@i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}} link @t{$@{@i{fs}@}}/@t{$@{@i{sublink}@}}}
+A file system of which only a sub-directory was in use has been unmounted.
+
+@end table
+
+@node Acknowledgements & Trademarks, Index, Internals, Top
+@comment node-name, next, previous, up
+@unnumbered Acknowledgements & Trademarks
+
+Thanks to the Formal Methods Group at Imperial College for
+suffering patiently while @i{Amd} was being developed on their machines.
+
+Thanks to the many people who have helped with the development of
+@i{Amd}, especially Piete Brooks at the Cambridge University Computing
+Lab for many hours of testing, experimentation and discussion.
+
+@itemize @bullet
+@item
+@b{DEC}, @b{VAX} and @b{Ultrix} are registered trademarks of Digital
+Equipment Corporation.
+@item
+@b{AIX} and @b{IBM} are registered trademarks of International Business
+Machines Corporation.
+@item
+@b{Sun}, @b{NFS} and @b{SunOS} are registered trademarks of Sun
+Microsystems, Inc.
+@item
+@b{Unix} is a registered trademark of AT&T Unix Systems Laboratories
+in the USA and other countries.
+@end itemize
+
+@node Index, Intro, Acknowledgements & Trademarks, Top
+@comment node-name, next, previous, up
+@unnumbered Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/usr.sbin/amd/doc/texinfo.tex b/usr.sbin/amd/doc/texinfo.tex
new file mode 100644
index 00000000000..73528edcd03
--- /dev/null
+++ b/usr.sbin/amd/doc/texinfo.tex
@@ -0,0 +1,2192 @@
+%% TeX macros to handle texinfo files
+
+% Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
+
+%GNU CC is free software; you can redistribute it and/or modify
+%it under the terms of the GNU General Public License as published by
+%the Free Software Foundation; either version 1, or (at your option)
+%any later version.
+
+%GNU CC is distributed in the hope that it will be useful,
+%but WITHOUT ANY WARRANTY; without even the implied warranty of
+%MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%GNU General Public License for more details.
+
+%You should have received a copy of the GNU General Public License
+%along with GNU CC; see the file COPYING. If not, write to
+%the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them. Help stamp out software-hoarding!
+
+\def\texinfoversion{1.26}
+\message{Loading texinfo package [Version \texinfoversion]:}
+\message{}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ } % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset \bindingoffset=0pt
+\newdimen \normaloffset \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+%---------------------Begin change-----------------------
+%
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks
+\outerhsize=7in
+\outervsize=9.5in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+ {\let\hsize=\pagewidth \makefootline}}
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box. (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+ \shipout
+ \vbox to \outervsize{\hsize=\outerhsize
+ \vbox{\line{\ewtop\hfill\ewtop}}
+ \nointerlineskip
+ \line{\vbox{\moveleft\cornerthick\nstop}
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}}
+ \vskip \topandbottommargin
+ \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+ \vbox{
+ {\let\hsize=\pagewidth \makeheadline}
+ \pagebody{#1}
+ {\let\hsize=\pagewidth \makefootline}}
+ \ifodd\pageno\else\hskip\bindingoffset\fi}
+ \vskip \topandbottommargin plus1fill minus1fill
+ \boxmaxdepth\cornerthick
+ \line{\vbox{\moveleft\cornerthick\nsbot}
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}}
+ \nointerlineskip
+ \vbox{\line{\ewbot\hfill\ewbot}}
+ }
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.
+% The argument can be delimited with [...] or with "..." or braces
+% or it can be a whole line.
+% #1 should be a macro which expects
+% an ordinary undelimited TeX argument.
+
+\def\parsearg #1{\let\next=#1\begingroup\obeylines\futurelet\temp\parseargx}
+
+\def\parseargx{%
+\ifx \obeyedspace\temp \aftergroup\parseargdiscardspace \else%
+\aftergroup \parseargline %
+\fi \endgroup}
+
+{\obeyspaces %
+\gdef\parseargdiscardspace {\begingroup\obeylines\futurelet\temp\parseargx}}
+
+\gdef\obeyedspace{\ }
+
+\def\parseargline{\begingroup \obeylines \parsearglinex}
+{\obeylines %
+\gdef\parsearglinex #1^^M{\endgroup \next {#1}}}
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment. Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+%% @end foo executes the definition of \Efoo.
+%% foo can be delimited by doublequotes or brackets.
+
+\def\end{\parsearg\endxxx}
+
+\def\endxxx #1{%
+\expandafter\ifx\csname E#1\endcsname\relax
+\expandafter\ifx\csname #1\endcsname\relax
+\errmessage{Undefined command @end #1}\else
+\errorE{#1}\fi\fi
+\csname E#1\endcsname}
+\def\errorE#1{
+{\errhelp=\EMsimple \errmessage{@end #1 not within #1 environment}}}
+
+% Single-spacing is done by various environments.
+
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+{\advance \baselineskip by -\singlespaceskip
+\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\sf \char '100}}
+
+% Define @` and @' to be the same as ` and '
+% but suppressing ligatures.
+\def\`{{`}}
+\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @w prevents a word break
+\def\w #1{\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page.
+
+\def\group{\begingroup% \inENV ???
+\def \Egroup{\egroup\endgroup}
+\vbox\bgroup}
+
+% @br forces paragraph break
+
+\let\br = \par
+
+% @dots{} output some dots
+
+\def\dots{$\ldots$}
+
+% @page forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+\def\exdent{\errmessage{@exdent in filled text}}
+ % @lisp, etc, define \exdent locally from \internalexdent
+
+{\obeyspaces
+\gdef\internalexdent{\parsearg\exdentzzz}}
+
+\def\exdentzzz #1{{\advance \leftskip by -\lispnarrowing
+\advance \hsize by -\leftskip
+\advance \hsize by -\rightskip
+\leftline{{\rm#1}}}}
+
+% @include file insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+\def\includezzz #1{{\def\thisfile{#1}\input #1
+}}
+
+\def\thisfile{}
+
+% @center line outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+
+\def\comment{\parsearg \commentxxx}
+
+\def\commentxxx #1{}
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+}
+
+\def\ignore{\begingroup\ignoresections\ignorexxx}
+\long\def\ignorexxx #1\end ignore{\endgroup}
+
+% Conditionals to test whether a flag is set.
+
+\outer\def\ifset{\begingroup\ignoresections\parsearg\ifsetxxx}
+
+\def\ifsetxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\ifsetfail
+\else \let\temp=\relax \fi
+\temp}
+\def\Eifset{}
+\def\ifsetfail{\begingroup\ignoresections\ifsetfailxxx}
+\long\def\ifsetfailxxx #1\end ifset{\endgroup}
+
+\outer\def\ifclear{\begingroup\ignoresections\parsearg\ifclearxxx}
+
+\def\ifclearxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\relax
+\else \let\temp=\ifclearfail \fi
+\temp}
+\def\Eifclear{}
+\def\ifclearfail{\begingroup\ignoresections\ifclearfailxxx}
+\long\def\ifclearfailxxx #1\end ifclear{\endgroup}
+
+% Some texinfo constructs that are trivial in tex
+
+\def\iftex{}
+\def\Eiftex{}
+\def\ifinfo{\begingroup\ignoresections\ifinfoxxx}
+\long\def\ifinfoxxx #1\end ifinfo{\endgroup}
+\long\def\menu #1\end menu{}
+\def\asis#1{#1}
+
+\def\node{\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+ \readauxfile
+ \opencontents
+ \openindices
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\losespace#3{}}, node `\losespace#1{}'}
+\def\losespace #1{#1}
+
+\message{fonts,}
+
+% Font-change commands.
+
+%% Try out Computer Modern fonts at \magstephalf
+\font\tenrm=cmr10 scaled \magstephalf
+\font\tentt=cmtt10 scaled \magstephalf
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\tenbf=cmb10 scaled \magstephalf
+\font\tenit=cmti10 scaled \magstephalf
+\font\tensl=cmsl10 scaled \magstephalf
+\font\tensf=cmss10 scaled \magstephalf
+\def\li{\sf}
+\font\tensc=cmcsc10 scaled \magstephalf
+
+% Fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\let\deftt=\tentt
+\def\df{\let\tt=\deftt \defbf}
+
+% Font for title
+\font\titlerm = cmbx10 scaled \magstep5
+
+% Fonts for indices
+\font\indit=cmti9 \font\indrm=cmr9
+\def\indbf{\indrm} \def\indsl{\indit}
+\def\indexfonts{\let\it=\indit \let\sl=\indsl \let\bf=\indbf \let\rm=\indrm}
+
+% Fonts for headings
+\font\chaprm=cmbx10 scaled \magstep3
+\font\chapit=cmti10 scaled \magstep3
+\font\chapsl=cmsl10 scaled \magstep3
+\font\chaptt=cmtt10 scaled \magstep3
+\font\chapsf=cmss10 scaled \magstep3
+\let\chapbf=\chaprm
+
+\font\secrm=cmbx10 scaled \magstep2
+\font\secit=cmti10 scaled \magstep2
+\font\secsl=cmsl10 scaled \magstep2
+\font\sectt=cmtt10 scaled \magstep2
+\font\secsf=cmss10 scaled \magstep2
+\let\secbf=\secrm
+
+% \font\ssecrm=cmbx10 scaled \magstep1 % This size an fontlooked bad.
+% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded.
+% \font\ssecsl=cmsl10 scaled \magstep1
+% \font\ssectt=cmtt10 scaled \magstep1
+% \font\ssecsf=cmss10 scaled \magstep1
+
+\font\ssecrm=cmb10 at 13pt % Note the use of cmb rather than cmbx.
+\font\ssecit=cmti10 at 13pt % Also, the size is a little larger than
+\font\ssecsl=cmsl10 at 13pt % being scaled magstep1.
+\font\ssectt=cmtt10 at 13pt
+\font\ssecsf=cmss10 at 13pt
+
+\let\ssecbf=\ssecrm
+
+\def\textfonts{\let\rm=\tenrm\let\it=\tenit\let\sl=\tensl\let\bf=\tenbf%
+\let\smallcaps=\tensc\let\sf=\tensf}
+\def\chapfonts{\let\rm=\chaprm\let\it=\chapit\let\sl=\chapsl\let\bf=\chapbf\let\tt=\chaptt\let\sf=\chapsf}
+\def\secfonts{\let\rm=\secrm\let\it=\secit\let\sl=\secsl\let\bf=\secbf\let\tt=\sectt\let\sf=\secsf}
+\def\subsecfonts{\let\rm=\ssecrm\let\it=\ssecit\let\sl=\ssecsl\let\bf=\ssecbf\let\tt=\ssectt\let\sf=\ssecsf}
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font for table of contents.
+\font\truesecrm=cmr12
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+\def\i#1{{\sl #1}}
+\let\var=\i
+\let\dfn=\i
+\let\emph=\i
+\let\cite=\i
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+\def\t#1{{\tt \rawbackslash \frenchspacing #1}\null}
+\let\ttfont = \t
+\let\kbd=\t
+\let\code=\t
+\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\key #1{{\tt \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+\def\l#1{{\li #1}\null} %
+
+\def\r#1{{\rm #1}} % roman font
+\def\sc#1{{\\smallcaps #1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+\def\titlefont#1{{\titlerm #1}}
+
+% Make altmode in file print out right
+
+\catcode `\^^[=\active \def^^[{$\diamondsuit$}
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\font\titlerm = cmbx12 scaled \magstep2
+\def\titlefont#1{{\titlerm #1}}
+
+\newtoks\realeverypar
+\newif\ifseenauthor
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+ \font\subtitlerm = cmr10 scaled \magstephalf
+ \def\subtitlefont{\subtitlerm \normalbaselineskip = 12pt \normalbaselines}%
+ %
+ \font\authorrm = cmbx12 scaled \magstep1
+ \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+ %
+ % The first subtitle should have some space before it, but not the
+ % others. They all should be ragged left.
+% ??? This code turned off because (1) it is wrong for all old title
+% pages, and (2) it makes an extra group which never is ended.
+% \begingroup \realeverypar = {\leftskip = 2in plus 3em minus 1em
+% \parfillskip = 0pt}%
+% \everypar = {\vglue \baselineskip \the\realeverypar
+% \everypar={\the\realeverypar}}%
+ %
+ % Now you can print the title using @title.
+ \def\title{\parsearg\titlezzz}%
+ \def\titlezzz##1{\leftline{\titlefont{##1}
+ \vskip4pt \hrule height 4pt \vskip4pt}%
+ \vglue\titlepagetopglue
+ %
+ % Now you can put text using @subtitle.
+ \def\subtitle{\parsearg\subtitlezzz}%
+ \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+ %
+ % @author should come last, but may come many times.
+ \def\author{\parsearg\authorzzz}%
+ \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+ {\authorfont \leftline{##1}}}%
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+% \def\page{\vskip4pt \hrule height 2pt \vskip\titlepagebottomglue
+% \oldpage \endgroup\hrule height0pt\relax}%
+ \def\page{\oldpage \hbox{}}}
+}
+
+\def\Etitlepage{\endgroup\page\HEADINGSon}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline % Token sequence for heading line of even pages
+\newtoks \oddheadline % Token sequence for heading line of odd pages
+\newtoks \evenfootline % Token sequence for footing line of even pages
+\newtoks \oddfootline % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}}
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line... specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% Tables -- @table, @ftable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table and @ftable define @item, @itemx, etc., with these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\par \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\par \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}\itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}\itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+\advance \hsize by -\rightskip %
+\advance \hsize by -\leftskip %
+\setbox0=\hbox{\itemfont{#1}}%
+\itemindex{#1}%
+\parskip=0in %
+\noindent %
+\ifdim \wd0>\itemmax %
+\vadjust{\penalty 10000}%
+\hbox to \hsize{\hskip -\tableindent\box0\hss}\ %
+\else %
+\hbox to 0pt{\hskip -\tableindent\box0\hss}%
+\fi %
+\endgroup %
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1 \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1 \endtabley}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\endgroup\afterenvbreak}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{\itemizey {#1}{\Eitemize}}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\begingroup %
+\itemno = 0 %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\endgroup\afterenvbreak}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+\def\enumerate{\itemizey{\the\itemno.}\Eenumerate\flushcr}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 300}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexnofonts{%
+\let\code=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+
+\def\doind #1#2{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+\penalty\count10}}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{\tex %
+\catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+\catcode`\$=\other\catcode`\_=\other
+\catcode`\~=\other
+\def\indexbackslash{\rawbackslashxx}
+\indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+\begindoublecolumns
+\openin 1 \jobname.#1s
+\ifeof 1 \else \closein 1 \input \jobname.#1s
+\fi
+\enddoublecolumns
+\Etex}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\outer\def\initial #1{%
+{\let\tentt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty3000}}
+
+\outer\def\entry #1#2{
+{\parfillskip=0in \parskip=0in \parindent=0in
+\hangindent=1in \hangafter=1%
+\noindent\hbox{#1}\dotfill #2\par
+}}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\dotfill #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXBook, page 416
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize \doublecolumnhsize = 3.11in
+\newdimen\doublecolumnvsize \doublecolumnvsize = 19.1in
+
+\def\begindoublecolumns{\begingroup
+ \output={\global\setbox\partialpage=\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}\eject
+ \output={\doublecolumnout} \hsize=\doublecolumnhsize \vsize=\doublecolumnvsize}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+ \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+ \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage %
+ \hsize=\doublecolumnhsize % have to restore this since output routine
+% changes it to set cropmarks (P. A. MacKay, 12 Nov. 1986)
+ \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{\setbox0=\vbox{\unvbox255} \dimen@=\ht0
+ \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by2 \splittopskip=\topskip
+ {\vbadness=10000 \loop \global\setbox3=\copy0
+ \global\setbox1=\vsplit3 to\dimen@
+ \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}
+ \setbox0=\vbox to\dimen@{\unvbox1} \setbox2=\vbox to\dimen@{\unvbox3}
+ \pagesofar}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno
+\newcount \subsecno
+\newcount \subsubsecno
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\outer\def\chapter{\parsearg\chapterzzz}
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}\gdef\thischapter{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+}
+
+\outer\def\appendix{\parsearg\appendixzzz}
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+}
+
+\outer\def\unnumbered{\parsearg\unnumberedzzz}
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0 \message{(#1)}
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+}
+
+\outer\def\section{\parsearg\sectionzzz}
+\def\sectionzzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsection{\parsearg\appendixsectionzzz}
+\outer\def\appendixsec{\parsearg\appendixsectionzzz}
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedseczzz}
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsection{\parsearg\subsectionzzz}
+\def\subsectionzzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubseczzz}
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsubsection{\parsearg\subsubsectionzzz}
+\def\subsubsectionzzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubseczzz}
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading #1{\chapbreak %
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+\pchapsepmacro %
+{\chapfonts \line{\rm #2.\enspace #1\hfill}}\bigskip \par\penalty 5000 %
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \line{\rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1,
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \line{\rm#2.#3.#4\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+ % Perhaps make sssec fonts scaled
+ % magstep half
+\def\subsubsecheading #1#2#3#4#5{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \line{\rm#2.#3.#4.#5\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\def\startcontents#1{%
+ \ifnum \pageno>0
+ \pagealignmacro
+ \immediate\closeout \contentsfile
+ \pageno = -1 % Request roman numbered pages.
+ \fi
+ \unnumbchapmacro{#1}\def\thischapter{#1}%
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -1in % Don't use the full line length.
+}
+
+
+% Normal (long) toc.
+\outer\def\contents{%
+ \startcontents{Table of Contents}%
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+ \startcontents{Short Contents}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts \let\rm = \truesecrm \rm
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+\def\shortchapentry#1#2#3{%
+ \line{{#2\labelspace #1}\dotfill\doshortpageno{#3}}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{%
+ \line{#1\dotfill\doshortpageno{#2}}%
+}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{\dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we would want to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip\baselineskip
+ \line{\chapentryfonts #1\dotfill \dopageno{#2}}%
+ \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{%
+ \line{\secentryfonts \hskip\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+\def\dosubsecentry#1#2{%
+ \line{\subsecentryfonts \hskip2\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+\def\dosubsubsecentry#1#2{%
+ \line{\subsubsecentryfonts \hskip3\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \let\rm = \sf \sf}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode`\"=12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\def\@={@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^M gets inside @lisp
+% phr: changed space to \null, to avoid overfull hbox problems.
+{\obeyspaces%
+\gdef\lisppar{\null\endgraf}}
+
+% Cause \obeyspaces to make each Space cause a word-separation
+% rather than the default which is that it acts punctuation.
+% This is because space in tt font looks funny.
+{\obeyspaces %
+\gdef\sepspaces{\def {\ }}}
+
+\newskip\aboveenvskipamount \aboveenvskipamount= 0pt
+\def\aboveenvbreak{{\advance\aboveenvskipamount by \parskip
+\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}}
+
+\def\afterenvbreak{\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}
+
+\def\lisp{\aboveenvbreak\begingroup\inENV %This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Elisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \tt \rawbackslash
+\def\next##1{}\next}
+
+
+\let\example=\lisp
+\def\Eexample{\Elisp}
+
+\let\smallexample=\lisp
+\def\Esmallexample{\Elisp}
+
+% Macro for 9 pt. examples, necessary to print with 5" lines.
+% From Pavel@xerox. This is not really used unless the
+% @smallbook command is given.
+
+\def\smalllispx{\aboveenvbreak\begingroup\inENV
+% This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Esmalllisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \ninett \rawbackslash
+\def\next##1{}\next}
+
+% This is @display; same as @lisp except use roman font.
+
+\def\display{\begingroup\inENV %This group ends at the end of the @display body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Edisplay{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% This is @format; same as @lisp except use roman font and don't narrow margins
+
+\def\format{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Eformat{\endgroup\afterenvbreak}
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @flushleft and @flushright
+
+\def\flushleft{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushleft{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+\def\flushright{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushright{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\advance \leftskip by 0pt plus 1fill
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @quotation - narrow the margins.
+
+\def\quotation{\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\def\Equotation{\par\endgroup\afterenvbreak}%
+\advance \rightskip by \lispnarrowing
+\advance \leftskip by \lispnarrowing}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=36pt
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\tt\char`\[}} \def\rbrb{{\tt\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+\leftskip = 0in %
+\noindent %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1 %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}%
+\tolerance=10000 \hbadness=10000 % Make all lines underfull and no complaints
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl #1%
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special form}%
+\defunargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Operation on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopparsebody\Edefcv\defcvx\defcvheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defmethparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defmethparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\defmethparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+% \xref and \pxref generate cross references to specified points.
+
+\def\pxref #1{see \xrefX [#1,,,,,,,]}
+\def\xref #1{See \xrefX [#1,,,,,,,]}
+\def\xrefX [#1,#2,#3,#4,#5,#6]{%
+\setbox1=\hbox{\i{\losespace#5{}}}%
+\setbox0=\hbox{\losespace#3{}}%
+\ifdim \wd0 =0pt \setbox0=\hbox{\losespace#1{}}\fi%
+\ifdim \wd1 >0pt%
+section \unhbox0{} in \unhbox1%
+\else%
+\refx{#1-snt} [\unhbox0], page\tie \refx{#1-pg}%
+\fi }
+
+% \dosetq is the interface for calls from other macros
+
+\def\dosetq #1#2{{\let\folio=0%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Define @refx to reference a specific cross-reference string.
+
+\def\refx#1{%
+{%
+\expandafter\ifx\csname X#1\endcsname\relax
+% If not defined, say something at least.
+\expandafter\gdef\csname X#1\endcsname {$<$undefined$>$}%
+\message {WARNING: Cross-reference "#1" used but not yet defined}%
+\message {}%
+\fi %
+\csname X#1\endcsname %It's defined, so just use it.
+}}
+
+% Read the last existing aux file, if any. No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\ =\other
+\catcode `\^^L=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux
+\fi
+% Open the new aux file. Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+\gdef\footnote{\global\advance \footnoteno by \@ne
+\edef\thisfootno{$^{\the\footnoteno}$}%
+\let\@sf\empty
+\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+\thisfootno\@sf\parsearg\footnotezzz}
+
+\gdef\footnotezzz #1{\insert\footins{
+\interlinepenalty\interfootnotelinepenalty
+\splittopskip\ht\strutbox % top baseline for broken footnotes
+\splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+\leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+\footstrut\hang\textindent{\thisfootno}#1\strut}}
+
+}%end \catcode `\@=11
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+\hsize = 6.5in
+\parindent 15pt
+\parskip 18pt plus 1pt
+\baselineskip 15pt
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Use @smallbook to reset parameters for 7x9.5 format
+\def\smallbook{
+\global\lispnarrowing = 0.3in
+\global\baselineskip 12pt
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\doublecolumnhsize=2.4in \global\doublecolumnvsize=15.0in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+\global\font\ninett=cmtt9
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+%% For a final copy, take out the rectangles
+%% that mark overfull boxes (in case you have decided
+%% that the text looks ok even though it passes the margin).
+\def\finalout{\overfullrule=0pt}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary)
+% Define certain chars to be always in tt font.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+\catcode`\_=\active
+\def_{{\tt \char '137}}
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+{\catcode`\\=\other
+@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+@c \catcode 17=0 @c Define control-q
+\catcode`\\=\active
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special. The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
diff --git a/usr.sbin/amd/fsinfo/Makefile b/usr.sbin/amd/fsinfo/Makefile
new file mode 100644
index 00000000000..0d7186533fe
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/Makefile
@@ -0,0 +1,33 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/28/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+
+.include "../config/Makefile.config"
+
+PROG= fsinfo
+MAN= fsinfo.8
+SRCS= fsinfo.c fsi_gram.c fsi_lex.c \
+ fsi_util.c fsi_analyze.c fsi_dict.c \
+ wr_atab.c wr_bparam.c wr_dumpset.c \
+ wr_exportfs.c wr_fstab.c
+CLEANFILES= \
+ fsi_gram.c y.tab.c fsi_gram.h y.tab.h \
+ fsi_lex.c lex.yy.c y.output
+CFLAGS+=-I.
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-DOS_HDR=\"os-${OS}.h\"
+
+fsi_lex.o fsinfo.o: fsi_gram.h
+fsi_gram.c fsi_gram.h: ../fsinfo/fsi_gram.y
+ @echo "# expect 2 shift/reduce conflicts"
+ ${YACC} -d ${.CURDIR}/fsi_gram.y
+ mv y.tab.c fsi_gram.c
+ mv y.tab.h fsi_gram.h
+
+fsi_lex.c: ../fsinfo/fsi_lex.l
+ ${LEX} ${.CURDIR}/fsi_lex.l
+ mv lex.yy.c fsi_lex.c
+
+.PATH: ${.CURDIR}/../config
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/fsinfo/conf/automounts b/usr.sbin/amd/fsinfo/conf/automounts
new file mode 100644
index 00000000000..ee4b4eedc1b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/automounts
@@ -0,0 +1,48 @@
+host localhost.doc.ic.ac.uk
+
+fs localhost:/localhost {
+ fstype = export
+ mount default {
+ exportfs ""
+ volname /home/localhost
+ }
+}
+
+automount opts "opts:=rw,nosuid,grpid" /vol {
+ rwho {}
+ r+d {}
+ public {}
+ src { gnu{} athena{} gould{} utx{} sos4{} xinu43{} }
+ export {
+ exec {
+ sun3 {}
+ sun4 {}
+ }
+ roots {}
+ swaps {
+ tsun1 {} tsun2 {} tsun3 {} tsun4 {} tsun5 {} tsun6 {}
+ tsun7 {} tsun8 {} tsun9 {} tsun10 {} tsun11 {} tsun12 {}
+ tsun13 {} tsun14 {} tsun15 {} tsun16 {} tsun17 {} tsun18 {}
+ tsun19 {}
+ tcsun1 {} tcsun2 {} tcsun3 {} tcsun4 {} tcsun5 {}
+ }
+ misc {}
+ }
+}
+
+automount opts "opts:=rw,nosuid,grpid" /home {
+ achilles {}
+ toytown {}
+ gummo {}
+ dylan { dk2{} dk5 {} }
+ ganymede {}
+ gould { staff{} teach{} }
+ "localhost" -> localhost
+}
+
+automount opts "opts:=rw,nosuid,grpid" /homes {
+ opr -> /home/localhost/opr
+#include "users"
+}
+
+automount /usr/achilles = /home/achilles
diff --git a/usr.sbin/amd/fsinfo/conf/csg_sun3 b/usr.sbin/amd/fsinfo/conf/csg_sun3
new file mode 100644
index 00000000000..6cb426ebc4f
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/csg_sun3
@@ -0,0 +1,18 @@
+// $Id: csg_sun3,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+// standard setups for DoC tsuns.
+// note that no /var/spool/rwho is mounted as we now expect amd to do this as /vol/rwho
+
+// a sun3
+#ifndef SOS4_SYS_OPTS
+#define SOS4_SYS_OPTS grpid,hard,intr
+#endif
+#define CSG_SUN3(HOST,DOMAIN,BOOT,EXEC) \
+host HOST.DOMAIN \
+\
+mount /vol/export/roots/HOST as / from BOOT opts rw,SOS4_SYS_OPTS \
+mount /vol/export/swaps/HOST fstype swap as swap from BOOT opts swap \
+mount /vol/export/exec/sun3 as /usr from EXEC opts ro,SOS4_SYS_OPTS \
+mount /vol/export/misc/crash/HOST as /var/crash/HOST from EXEC opts rw,nosuid,SOS4_SYS_OPTS \
+mount /vol/export/misc/tmp/HOST as /tmp from EXEC opts rw,nosuid,SOS4_SYS_OPTS \
+mount /vol/export/misc/usr.tmp/HOST as /var/tmp from EXEC opts rw,nosuid,SOS4_SYS_OPTS \
+mount /var/mmdf from BOOT opts rw,nosuid,SOS4_SYS_OPTS
diff --git a/usr.sbin/amd/fsinfo/conf/csg_vax b/usr.sbin/amd/fsinfo/conf/csg_vax
new file mode 100644
index 00000000000..ddbc3039975
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/csg_vax
@@ -0,0 +1,67 @@
+// $Id: csg_vax,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+// csg vax config - really just for {s,r}vax
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw
+
+#define CSG_VAX(HOST,DOMAIN) \
+host HOST.DOMAIN\
+\
+/*\
+arch vax\
+os xinu43\
+cluster csg\
+dumphost flamingo.doc.ic.ac.uk\
+*/\
+\
+// root\
+fs /dev/hp0a {\
+ fstype = FSTYPE_UFS\
+ opts = DEFAULT_OPTS\
+ freq = 1\
+ passno = 1\
+ mount / {}\
+}\
+\
+// swap\
+fs /dev/hp0b {\
+ fstype = swap\
+}\
+\
+// usr\
+fs /dev/hp0e {\
+ fstype = FSTYPE_UFS\
+ opts = DEFAULT_OPTS\
+ freq = 1\
+ passno = 2\
+ mount /usr {\
+ exportfs "\\\
+ sky.doc.ic.ac.uk\\\
+ svax.doc.ic.ac.uk\\\
+ rvax.doc.ic.ac.uk\\\
+ ivax.doc.ic.ac.uk\\\
+ "\
+ }\
+}\
+\
+// var\
+fs /dev/hp0d {\
+ fstype = FSTYPE_UFS\
+ opts = DEFAULT_OPTS\
+ freq = 1\
+ passno = 3\
+ mount /var {}\
+}\
+\
+// home directories\
+fs /dev/hp0f {\
+ fstype = FSTYPE_UFS\
+ opts = DEFAULT_OPTS\
+ freq = 1\
+ passno = 3\
+ mount /a/HOST/home/HOST {\
+ exportfs "\\\
+ teach_hosts\\\
+ "\
+ }\
+} \ No newline at end of file
diff --git a/usr.sbin/amd/fsinfo/conf/diskless_sun3_sos4 b/usr.sbin/amd/fsinfo/conf/diskless_sun3_sos4
new file mode 100644
index 00000000000..0cacb2093c5
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/diskless_sun3_sos4
@@ -0,0 +1,9 @@
+#define DISKLESS_SUN3_SOS4(HOST,DOMAIN,BOOTSERVER) \
+host HOST.DOMAIN \
+\
+mount /export/root/HOST as / from BOOTSERVER opts rw,grpid,intr \
+mount /export/swap/HOST as swap fstype swap from BOOTSERVER opts swap \
+mount /export/exec/sun3 as /usr from BOOTSERVER opts rw,grpid,intr \
+mount /var/clients/HOST as /var from BOOTSERVER opts rw,grpid,intr,nosuid \
+mount /var/clients/HOST.tmp as /tmp from BOOTSERVER opts rw,grpid,intr,nosuid \
+mount /var/spool/mail from BOOTSERVER opts rw,grpid,intr,nosuid
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/achilles.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/achilles.doc.ic.ac.uk
new file mode 100644
index 00000000000..6a46ce883d6
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/achilles.doc.ic.ac.uk
@@ -0,0 +1,116 @@
+// mkfsinfo
+
+host achilles.doc.ic.ac.uk
+
+/*
+arch sun4
+os sos4
+cluster theory
+dumphost achilles.doc.ic.ac.uk
+*/
+
+// SWAP Partitions
+fs /dev/xd0b {
+ fstype = swap
+}
+
+fs /dev/xd1b {
+ fstype = swap
+}
+
+// ROOT
+fs /dev/xd0a {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ passno = 1;
+ freq = 1;
+ mount / { }
+}
+
+// ROOT Backup
+fs /dev/xd1a {
+ fstype = ignore
+ opts = rw,noquota,grpid
+ passno = 1;
+ freq = 1;
+ mount /backup { }
+}
+
+fs /dev/xd1d {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ passno = 1;
+ freq = 1;
+ mount /export {
+ root {
+ truth { exportfs "-root=truth,access=truth" }
+ }
+ swap {
+ truth { exportfs "-root=truth,access=truth" }
+ }
+ exec {
+ sun4 { exportfs "-access=toytown_clients:hangers_on:gummo:harpo:opus,rw=dylan:truth:florence:toytown" }
+ }
+ }
+}
+
+fs /dev/xd1f {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ passno = 1;
+ freq = 1;
+ mount /var {
+ clients {
+ truth { exportfs "-root=truth,access=truth" }
+ truth.tmp { exportfs "-root=truth,access=truth" }
+ }
+ spool {
+ mail { exportfs "-root=truth,access=truth" }
+ rwho { exportfs "ro" volname /vol/rwho sel "byte==big" }
+ }
+ }
+}
+
+fs /dev/xd0d {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ passno = 1;
+ freq = 1;
+ mount /tmp {
+ X11NeWS { exportfs "-ro" }
+ }
+}
+
+fs /dev/xd0g {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ passno = 1
+ freq = 1
+ mount default {
+ exportfs "-access=toytown_clients:hangers_on"
+ volname /home/achilles
+ }
+}
+
+fs /dev/xd1g {
+ fstype = 4.2
+ opts = rw,noquota
+ passno = 1
+ freq = 1
+ mount /usr {
+ exportfs "-access=toytown_clients:hangers_on:gummo:harpo:opus,rw=dylan:truth:florence:toytown"
+ share {
+ volname "/usr/share"
+ //exportfs "blah"
+ }
+ src {
+ local {
+ //exportfs "-access=toytown:zebedee:dougal:dylan:florence:opus,rw=dylan:florence,root=dylan:florence"
+ bits { gnu { volname "/vol/src/gnu" } }
+ athena { volname "/vol/src/athena" }
+ }
+ }
+ }
+}
+
+/*mount /export/exec/sun3 fstype nfs from gould.doc.ic.ac.uk as /usr opts "rw"*/
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/bigears.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/bigears.doc.ic.ac.uk
new file mode 100644
index 00000000000..bda2fd886b2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/bigears.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../diskless_sun3_sos4"
+
+DISKLESS_SUN3_SOS4(bigears,doc.ic.ac.uk,toytown.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/dylan.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/dylan.doc.ic.ac.uk
new file mode 100644
index 00000000000..5284147d1c2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/dylan.doc.ic.ac.uk
@@ -0,0 +1,68 @@
+// mkfsinfo
+
+host dylan.doc.ic.ac.uk
+
+// SWAP
+fs /dev/dsk/0s0 {
+ fstype = swap
+}
+
+// SWAP
+fs /dev/dsk/1s0 {
+ fstype = swap
+}
+
+// ROOT
+fs /dev/dsk/0s0 {
+ fstype = hfs
+ opts = rw,noquota,grpid
+ passno = 0;
+ freq = 1;
+ mount / { }
+}
+
+fs /dev/dsk/1s0 {
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount /usr {
+ local {
+ exportfs "dougal eden dylan zebedee brian"
+ volname /nfs/hp300/local
+ }
+ }
+}
+
+fs /dev/dsk/2s0 {
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default {
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk2
+ }
+}
+
+fs /dev/dsk/3s0 {
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default {
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk3
+ }
+}
+
+fs /dev/dsk/5s0 {
+ fstype = hfs
+ opts = defaults
+ passno = 1;
+ freq = 1;
+ mount default {
+ exportfs "toytown_clients hangers_on"
+ volname /home/dylan/dk5
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk
new file mode 100644
index 00000000000..a047483b61b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk
@@ -0,0 +1,104 @@
+// mkfsinfo for flamingo
+// $Id: flamingo.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+
+host flamingo.doc.ic.ac.uk
+
+/*
+arch sun3
+os sos4
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw,noquota,nosuid,grpid
+
+// swap
+fs /dev/xy0b {
+ fstype = swap
+}
+
+// root
+fs /dev/xy0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ passno = 1
+ freq = 1
+ dumpset = csg_sun3_vax
+ mount / {}
+}
+
+// usr
+fs /dev/xy0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ dumpset = csg_sun3_vax
+ mount /usr {
+ volname /vol/export/exec/sun3
+ exportfs "-ro,access=teach_hosts:ssun2.doc.ic.ac.uk:pelican:gould,\
+ root=gould:pelican:ssun2.doc.ic.ac.uk"
+ }
+}
+
+// tmp
+fs /dev/xy0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS,nosuid
+ freq = 1
+ passno = 3
+ mount /tmp {
+ exportfs "-access=ssun1:tsunfs,root=tsunfs"
+ }
+}
+
+// var
+fs /dev/xy0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ dumpset = csg_sun3_vax
+ mount /var {
+ tmp {
+ exportfs "-access=ssun1:sky.doc.ic.ac.uk"
+ }
+ crash {
+ exportfs "-access=ssun1"
+ }
+ misc {
+ exportfs "-access=teach_hosts"
+ }
+ spool {
+ rwho {
+ volname /vol/rwho
+ exportfs "-ro,access=teach_hosts"
+ sel "byte==big"
+ }
+ }
+ }
+}
+
+// source - sos4
+fs /dev/xy0h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 6
+ mount /usr/src {
+ volname /vol/src/sos4
+ exportfs "-access=svax:pelican:gould,root=pelican:svax"
+ }
+}
+
+// home directories
+fs /dev/xy0g {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 5
+ mount /a/flamingo/home/flamingo {
+ exportfs "-access=teach_hosts:thp_hosts:ssun2:obsidian:truth,root=gould"
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/ganymede.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/ganymede.doc.ic.ac.uk
new file mode 100644
index 00000000000..e847c85874b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/ganymede.doc.ic.ac.uk
@@ -0,0 +1,33 @@
+host ganymede.doc.ic.ac.uk
+
+fs /dev/xy0a {
+ fstype = 4.2
+ opts = rw
+ freq = 1
+ passno = 1
+ mount / {
+ }
+}
+
+fs /dev/xy0g {
+ fstype = 4.2
+ opts = rw
+ freq = 1
+ passno = 2
+ mount /usr {
+ exportfs "-access=toytown:toytown_clients"
+ }
+}
+
+fs /dev/xy0h {
+ fstype = 4.2
+ opts = rw
+ freq = 1
+ passno = 3
+ mount /home/ganymede {
+ exportfs "-access=toytown_clients:samson:hangers_on"
+ }
+}
+
+mount /home/toytown opts rw,bg,nosuid
+mount /usr/local from toytown.doc.ic.ac.uk opts ro,bg
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk
new file mode 100644
index 00000000000..4386806c19a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk
@@ -0,0 +1,477 @@
+// mkfsinfo for gould
+// $Id: gould.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+
+host gould.doc.ic.ac.uk
+
+/*
+arch powernode
+os utx21
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+#define FSTYPE_UFS 4.3
+#define DEFAULT_OPTS rw,noquota
+
+// swap
+fs /dev/dk0b {
+ fstype = swap
+}
+
+fs /dev/dk1b {
+ fstype = swap
+}
+
+fs /dev/dk4b {
+ fstype = swap
+}
+
+// root
+fs /dev/dk0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ passno = 1
+ freq = 1
+ dumpset = csg_nightly
+ mount / {}
+}
+
+// root backup
+fs /dev/dk4a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ mount /backup {}
+}
+
+// usr
+fs /dev/dk4d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ dumpset = csg_nightly
+ mount /usr {}
+}
+
+// tmp
+fs /dev/dk1a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS,nosuid
+ freq = 0
+ passno = 2
+ mount /tmp {}
+}
+
+// var
+fs /dev/dk4g {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ dumpset = csg_nightly
+ mount /var {}
+}
+
+// shared stuff - usually for Suns
+fs /dev/dk5f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 6
+ mount /usr/share {
+ exportfs "-rdonly=1 \
+ ivax.doc.ic.ac.uk \
+ rvax.doc.ic.ac.uk \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ svax.doc.ic.ac.uk \
+ tsun1.doc.ic.ac.uk \
+ tsun10.doc.ic.ac.uk \
+ tsun11.doc.ic.ac.uk \
+ tsun12.doc.ic.ac.uk \
+ tsun13.doc.ic.ac.uk \
+ tsun14.doc.ic.ac.uk \
+ tsun15.doc.ic.ac.uk \
+ tsun16.doc.ic.ac.uk \
+ tsun17.doc.ic.ac.uk \
+ tsun18.doc.ic.ac.uk \
+ tsun19.doc.ic.ac.uk \
+ tsun2.doc.ic.ac.uk \
+ tsun3.doc.ic.ac.uk \
+ tsun4.doc.ic.ac.uk \
+ tsun5.doc.ic.ac.uk \
+ tsun6.doc.ic.ac.uk \
+ tsun7.doc.ic.ac.uk \
+ tsun8.doc.ic.ac.uk \
+ tsun9.doc.ic.ac.uk \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ oriona \
+ sky.doc.ic.ac.uk \
+ whoops.doc.ic.ac.uk \
+ whoops \
+ "
+ }
+}
+
+// spool stuff, including the news
+fs /dev/dk4f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 5
+ mount /var/spool {
+ exportfs "\
+ oriona \
+ rpcsfg \
+ "
+ }
+}
+
+fs /dev/dk3h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /var/spool/News {}
+}
+
+// this is the public ftp area
+fs /dev/dk3f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ mount /usr/reserve {
+ PUBLIC {
+ volname /vol/public
+ exportfs "\
+ oriona \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ obsidian \
+ gummo \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ "
+ }
+ }
+}
+
+// sources - local and public
+fs /dev/dk7c {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ dumpset = csg_nightly
+ mount /usr/src {
+ volname /vol/src/gould
+ exportfs "\
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ oriona \
+ ssun1.doc.ic.ac.uk \
+ svax.doc.ic.ac.uk \
+ rvax.doc.ic.ac.uk \
+ obsidian \
+ tsunfs \
+ "
+ }
+}
+
+// sources - utx
+fs /dev/dk4e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 6
+ dumpset = csg_nightly
+ mount /usr/src/utx {
+ volname /vol/src/utx
+ exportfs "-rdonly=1 \
+ flamingo.doc.ic.ac.uk \
+ "
+ }
+}
+
+// home directories
+fs /dev/dk1h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ dumpset = csg_nightly
+ mount /home/gould/teach {
+ exportfs "\
+ thp1 \
+ thp2 \
+ thp3 \
+ thp4 \
+ thp5 \
+ thp6 \
+ thp7 \
+ thp8 \
+ thp9 \
+ thp10 \
+ thpfs \
+ ivax.doc.ic.ac.uk \
+ rvax.doc.ic.ac.uk \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ svax.doc.ic.ac.uk \
+ tsun1.doc.ic.ac.uk \
+ tsun10.doc.ic.ac.uk \
+ tsun11.doc.ic.ac.uk \
+ tsun12.doc.ic.ac.uk \
+ tsun13.doc.ic.ac.uk \
+ tsun14.doc.ic.ac.uk \
+ tsun15.doc.ic.ac.uk \
+ tsun16.doc.ic.ac.uk \
+ tsun17.doc.ic.ac.uk \
+ tsun18.doc.ic.ac.uk \
+ tsun19.doc.ic.ac.uk \
+ tsun2.doc.ic.ac.uk \
+ tsun3.doc.ic.ac.uk \
+ tsun4.doc.ic.ac.uk \
+ tsun5.doc.ic.ac.uk \
+ tsun6.doc.ic.ac.uk \
+ tsun7.doc.ic.ac.uk \
+ tsun8.doc.ic.ac.uk \
+ tsun9.doc.ic.ac.uk \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ oriona \
+ sky.doc.ic.ac.uk \
+ whoops.doc.ic.ac.uk \
+ whoops \
+ vlsi.doc.ic.ac.uk \
+ vlsi \
+ "
+ }
+}
+
+fs /dev/dk0h {
+ fstype = FSTYPE_UFS
+ opts = rw,quota
+ freq = 1
+ passno = 2
+ dumpset = csg_nightly
+ mount /home/gould/staff {
+ exportfs "\
+ achilles \
+ thp1 \
+ thp2 \
+ thp3 \
+ thp4 \
+ thp5 \
+ thp6 \
+ thp7 \
+ thp8 \
+ thp9 \
+ thp10 \
+ thpfs \
+ ivax.doc.ic.ac.uk \
+ rvax.doc.ic.ac.uk \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ svax.doc.ic.ac.uk \
+ tsun1.doc.ic.ac.uk \
+ tsun10.doc.ic.ac.uk \
+ tsun11.doc.ic.ac.uk \
+ tsun12.doc.ic.ac.uk \
+ tsun13.doc.ic.ac.uk \
+ tsun14.doc.ic.ac.uk \
+ tsun15.doc.ic.ac.uk \
+ tsun16.doc.ic.ac.uk \
+ tsun17.doc.ic.ac.uk \
+ tsun18.doc.ic.ac.uk \
+ tsun19.doc.ic.ac.uk \
+ tsun2.doc.ic.ac.uk \
+ tsun3.doc.ic.ac.uk \
+ tsun4.doc.ic.ac.uk \
+ tsun5.doc.ic.ac.uk \
+ tsun6.doc.ic.ac.uk \
+ tsun7.doc.ic.ac.uk \
+ tsun8.doc.ic.ac.uk \
+ tsun9.doc.ic.ac.uk \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ oriona \
+ sky.doc.ic.ac.uk \
+ whoops.doc.ic.ac.uk \
+ whoops \
+ vlsi.doc.ic.ac.uk \
+ vlsi \
+ vlsi02 \
+ "
+ }
+}
+
+// booting diskless suns
+fs /dev/dk5e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ dumpset = csg_nightly
+ mount /export {
+#ifndef ok
+ volname /vol/export
+#endif
+ exportfs "\
+ -rootid=0 \
+ whoops \
+ whoops.doc.ic.ac.uk \
+ "
+ misc {
+ volname /vol/export/misc
+ }
+ }
+}
+
+fs /dev/dk5a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ dumpset = csg_nightly
+ mount /export/roots {
+ volname /vol/export/roots
+ exportfs "\
+ -rootid=0 \
+ whoops \
+ whoops.doc.ic.ac.uk \
+ "
+ }
+}
+
+fs /dev/dk5d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 5
+ dumpset = csg_nightly
+ mount /export/exec/sun3 {
+ volname /vol/export/exec/sun3
+ exportfs "\
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ tsun1.doc.ic.ac.uk \
+ tsun10.doc.ic.ac.uk \
+ tsun11.doc.ic.ac.uk \
+ tsun12.doc.ic.ac.uk \
+ tsun13.doc.ic.ac.uk \
+ tsun14.doc.ic.ac.uk \
+ tsun15.doc.ic.ac.uk \
+ tsun16.doc.ic.ac.uk \
+ tsun17.doc.ic.ac.uk \
+ tsun18.doc.ic.ac.uk \
+ tsun19.doc.ic.ac.uk \
+ tsun2.doc.ic.ac.uk \
+ tsun3.doc.ic.ac.uk \
+ tsun4.doc.ic.ac.uk \
+ tsun5.doc.ic.ac.uk \
+ tsun6.doc.ic.ac.uk \
+ tsun7.doc.ic.ac.uk \
+ tsun8.doc.ic.ac.uk \
+ tsun9.doc.ic.ac.uk \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ whoops.doc.ic.ac.uk \
+ whoops \
+ "
+ }
+}
+
+// various r+d things - used for athena, etc
+fs /dev/dk5g {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr/r+d {
+ volname /vol/r+d
+ exportfs "\
+ ivax.doc.ic.ac.uk \
+ rvax.doc.ic.ac.uk \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ svax.doc.ic.ac.uk \
+ tsun1.doc.ic.ac.uk \
+ tsun10.doc.ic.ac.uk \
+ tsun11.doc.ic.ac.uk \
+ tsun12.doc.ic.ac.uk \
+ tsun13.doc.ic.ac.uk \
+ tsun14.doc.ic.ac.uk \
+ tsun15.doc.ic.ac.uk \
+ tsun16.doc.ic.ac.uk \
+ tsun17.doc.ic.ac.uk \
+ tsun18.doc.ic.ac.uk \
+ tsun19.doc.ic.ac.uk \
+ tsun2.doc.ic.ac.uk \
+ tsun3.doc.ic.ac.uk \
+ tsun4.doc.ic.ac.uk \
+ tsun5.doc.ic.ac.uk \
+ tsun6.doc.ic.ac.uk \
+ tsun7.doc.ic.ac.uk \
+ tsun8.doc.ic.ac.uk \
+ tsun9.doc.ic.ac.uk \
+ tsunfs.doc.ic.ac.uk \
+ flamingo.doc.ic.ac.uk \
+ pelican.doc.ic.ac.uk \
+ oriona \
+ sky.doc.ic.ac.uk \
+ whoops.doc.ic.ac.uk \
+ whoops \
+ "
+ }
+}
+
+fs /dev/dk3d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /usr/r+d/r1 {
+ exportfs "\
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ "
+ }
+}
+
+fs /dev/dk4h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 7
+ mount /usr/r+d/r2 {
+ exportfs "\
+ achilles \
+ gummo \
+ harpo \
+ oriona \
+ ssun1.doc.ic.ac.uk \
+ ssun2.doc.ic.ac.uk \
+ thpfs \
+ toytown \
+ obsidian \
+ "
+ }
+}
+
+// this bit of disc needs a name !
+fs /dev/dk5h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 7
+ mount /mnt2 {}
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/gummo.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/gummo.doc.ic.ac.uk
new file mode 100644
index 00000000000..aae6a5d7583
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/gummo.doc.ic.ac.uk
@@ -0,0 +1,12 @@
+// mkfsinfo
+
+host gummo.doc.ic.ac.uk
+
+// ROOT
+fs /dev/xxx1 {
+ fstype = export
+ mount default {
+ exportfs ""
+ volname /home/gummo
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk
new file mode 100644
index 00000000000..1a72d00dd4c
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk
@@ -0,0 +1,84 @@
+// $Id: ivax.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+// ivax
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw
+
+host {
+ config "NFS_SERVER=true"
+ config "NFS_CLIENT=true"
+ config "YP_SERVER=false"
+ config "YP_CLIENT=false"
+
+ arch = vax
+ os = xinu43
+ cluster = teach.doc.ic.ac.uk
+ netif il0 { hwaddr = "08:08:08:08:08:08" netmask = 0xfffffe00 inaddr = 129.31.80.36 }
+
+} ivax.doc.ic.ac.uk
+
+// root
+fs /dev/hp0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount / {}
+}
+
+// swap
+fs /dev/hp0b {
+ fstype = swap
+}
+
+// usr
+fs /dev/hp0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr {
+ exportfs "\
+ sky.doc.ic.ac.uk\
+ svax.doc.ic.ac.uk\
+ rvax.doc.ic.ac.uk\
+ ivax.doc.ic.ac.uk\
+ "
+ }
+}
+
+// var
+fs /dev/hp0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /var {}
+}
+
+// home directories
+fs /dev/hp0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount default {
+ volname /home/ivax
+ exportfs "\
+ sky.doc.ic.ac.uk\
+ "
+ }
+}
+
+// sources which are used by the gould for the infoserver
+fs /dev/hp2c {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /public {
+ exportfs "\
+ gould\
+ "
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk
new file mode 100644
index 00000000000..f143e8be1d3
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk
@@ -0,0 +1,28 @@
+// $Id: obsidian.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+// conf for obsidian
+
+#define FSTYPE_UFS hfs
+#define DEFAULT_OPTS rw
+
+host obsidian.doc.ic.ac.uk
+
+fs /dev/dsk/0s0 {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount / {}
+}
+
+fs /dev/dsk/1s0 {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount default {
+ volname /home/obsidian
+ exportfs "\
+ gould\
+ "
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk
new file mode 100644
index 00000000000..789946a68fd
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk
@@ -0,0 +1,208 @@
+// mkfsinfo for pelican
+// $Id: pelican.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+
+host pelican.doc.ic.ac.uk
+
+/*
+arch sun3
+os sos4
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw,noquota,nosuid,grpid
+
+// swap
+fs /dev/xd0b {
+ fstype = swap
+}
+
+// root
+fs /dev/xd0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ passno = 1
+ freq = 1
+ dumpset = csg_sun3_vax
+ mount / {
+ exportfs "-ro,access=tsunfs,root=tsunfs"
+ }
+}
+
+// usr
+fs /dev/xd0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ dumpset = csg_sun3_vax
+ mount /usr {
+ volname /vol/export/exec/sun3
+ exportfs "-ro,access=teach_hosts,root=gould:flamingo:tsunfs"
+ }
+}
+
+// tmp
+fs /dev/xd0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS,nosuid
+ freq = 1
+ passno = 3
+ mount /tmp {
+ exportfs "\
+ -access=\
+ flamingo:\
+ tsun16.doc.ic.ac.uk:\
+ tsun17.doc.ic.ac.uk:\
+ tsun18.doc.ic.ac.uk:\
+ tsun19.doc.ic.ac.uk"
+ }
+}
+
+// var
+fs /dev/xd0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ dumpset = csg_sun3_vax
+ mount /var {
+ misc {
+ // this is due to differences between tsunfs and pelican
+ volname /vol/export/misc
+ exportfs "\
+ -access=teach_hosts,\
+ root=\
+ tcsun1.doc.ic.ac.uk:\
+ tcsun2.doc.ic.ac.uk:\
+ tcsun3.doc.ic.ac.uk:\
+ tcsun4.doc.ic.ac.uk:\
+ tcsun5.doc.ic.ac.uk:\
+ tsun16.doc.ic.ac.uk:\
+ tsun17.doc.ic.ac.uk:\
+ tsun18.doc.ic.ac.uk:\
+ tsun19.doc.ic.ac.uk"
+ }
+ mmdf {
+ exportfs "\
+ -access=teach_hosts,\
+ root=\
+ tcsun1.doc.ic.ac.uk:\
+ tcsun2.doc.ic.ac.uk:\
+ tcsun3.doc.ic.ac.uk:\
+ tcsun4.doc.ic.ac.uk:\
+ tcsun5.doc.ic.ac.uk:\
+ tsun16.doc.ic.ac.uk:\
+ tsun17.doc.ic.ac.uk:\
+ tsun18.doc.ic.ac.uk:\
+ tsun19.doc.ic.ac.uk"
+ }
+ spool {
+ rwho {
+ volname /vol/rwho
+ exportfs "-ro,access=teach_hosts"
+ sel "byte==big"
+ }
+ }
+ }
+}
+
+// export for diskless clients
+fs /dev/xd0h {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 6
+ mount /export {
+ roots {
+ tcsun1 {
+ volname /vol/export/roots/tcsun1
+ exportfs "-root=tcsun1.doc.ic.ac.uk,access=tcsun1.doc.ic.ac.uk"
+ }
+ tcsun2 {
+ volname /vol/export/roots/tcsun2
+ exportfs "-root=tcsun2.doc.ic.ac.uk,access=tcsun2.doc.ic.ac.uk"
+ }
+ tcsun3 {
+ volname /vol/export/roots/tcsun3
+ exportfs "-root=tcsun3.doc.ic.ac.uk,access=tcsun3.doc.ic.ac.uk"
+ }
+ tcsun4 {
+ volname /vol/export/roots/tcsun4
+ exportfs "-root=tcsun4.doc.ic.ac.uk,access=tcsun4.doc.ic.ac.uk"
+ }
+ tcsun5 {
+ volname /vol/export/roots/tcsun5
+ exportfs "-root=tcsun5.doc.ic.ac.uk,access=tcsun5.doc.ic.ac.uk"
+ }
+
+ tsun16 {
+ volname /vol/export/roots/tsun16
+ exportfs "-root=tsun16.doc.ic.ac.uk,access=tsun16.doc.ic.ac.uk"
+ }
+ tsun17 {
+ volname /vol/export/roots/tsun17
+ exportfs "-root=tsun17.doc.ic.ac.uk,access=tsun17.doc.ic.ac.uk"
+ }
+ tsun18 {
+ volname /vol/export/roots/tsun18
+ exportfs "-root=tsun18.doc.ic.ac.uk,access=tsun18.doc.ic.ac.uk"
+ }
+ tsun19 {
+ volname /vol/export/roots/tsun19
+ exportfs "-root=tsun19.doc.ic.ac.uk,access=tsun19.doc.ic.ac.uk"
+ }
+ }
+ swaps {
+ tcsun1 {
+ volname /vol/export/swaps/tcsun1
+ exportfs "-root=tcsun1.doc.ic.ac.uk,access=tcsun1.doc.ic.ac.uk"
+ }
+ tcsun2 {
+ volname /vol/export/swaps/tcsun2
+ exportfs "-root=tcsun2.doc.ic.ac.uk,access=tcsun2.doc.ic.ac.uk"
+ }
+ tcsun3 {
+ volname /vol/export/swaps/tcsun3
+ exportfs "-root=tcsun3.doc.ic.ac.uk,access=tcsun3.doc.ic.ac.uk"
+ }
+ tcsun4 {
+ volname /vol/export/swaps/tcsun4
+ exportfs "-root=tcsun4.doc.ic.ac.uk,access=tcsun4.doc.ic.ac.uk"
+ }
+ tcsun5 {
+ volname /vol/export/swaps/tcsun5
+ exportfs "-root=tcsun5.doc.ic.ac.uk,access=tcsun5.doc.ic.ac.uk"
+ }
+ tsun16 {
+ volname /vol/export/swaps/tsun16
+ exportfs "-root=tsun16.doc.ic.ac.uk,access=tsun16.doc.ic.ac.uk"
+ }
+ tsun17 {
+ volname /vol/export/swaps/tsun17
+ exportfs "-root=tsun17.doc.ic.ac.uk,access=tsun17.doc.ic.ac.uk"
+ }
+ tsun18 {
+ volname /vol/export/swaps/tsun18
+ exportfs "-root=tsun18.doc.ic.ac.uk,access=tsun18.doc.ic.ac.uk"
+ }
+ tsun19 {
+ volname /vol/export/swaps/tsun19
+ exportfs "-root=tsun19.doc.ic.ac.uk,access=tsun19.doc.ic.ac.uk"
+ }
+ }
+ }
+}
+
+// home directories
+fs /dev/xd0g {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 5
+ mount default {
+ volname /home/pelican
+ exportfs "-access=teach_hosts:thp_hosts:ssun2:obsidian:truth,root=gould"
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk
new file mode 100644
index 00000000000..440a5eb2fb4
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk
@@ -0,0 +1,66 @@
+// $Id: rvax.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+// rvax
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw
+
+host rvax.doc.ic.ac.uk
+
+/*
+arch vax
+os xinu43
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+// root
+fs /dev/hp0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount / {}
+}
+
+// swap
+fs /dev/hp0b {
+ fstype = swap
+}
+
+// usr
+fs /dev/hp0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr {
+ exportfs "\
+ sky.doc.ic.ac.uk\
+ svax.doc.ic.ac.uk\
+ rvax.doc.ic.ac.uk\
+ ivax.doc.ic.ac.uk\
+ "
+ }
+}
+
+// var
+fs /dev/hp0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /var {}
+}
+
+// home directories
+fs /dev/hp0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /a/rvax/home/rvax {
+ exportfs "\
+ teach_hosts\
+ "
+ }
+} \ No newline at end of file
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk
new file mode 100644
index 00000000000..47fcfaf818f
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk
@@ -0,0 +1,79 @@
+// $Id: sky.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+// sky
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw
+
+host sky.doc.ic.ac.uk
+
+/*
+arch vax
+os xinu43
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+// root
+fs /dev/hp0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount / {}
+}
+
+// swap
+fs /dev/hp0b {
+ fstype = swap
+}
+
+// usr
+fs /dev/hp0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr {
+ exportfs "\
+ sky.doc.ic.ac.uk\
+ svax.doc.ic.ac.uk\
+ rvax.doc.ic.ac.uk\
+ ivax.doc.ic.ac.uk\
+ "
+ }
+}
+
+// var
+fs /dev/hp0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /var {}
+}
+
+// home directories
+fs /dev/hp0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /a/sky/home/sky {}
+}
+
+// 4.3 sources
+fs /dev/hp1g {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr/src {
+ volname /vol/src/xinu43
+ exportfs "\
+ svax.doc.ic.ac.uk\
+ rvax.doc.ic.ac.uk\
+ sky.doc.ic.ac.uk\
+ ivax.doc.ic.ac.uk\
+ "
+ }
+} \ No newline at end of file
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk
new file mode 100644
index 00000000000..7b4c5bc56d2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk
@@ -0,0 +1,66 @@
+// $Id: svax.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:20 deraadt Exp $
+// svax
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw
+
+host svax.doc.ic.ac.uk
+
+/*
+arch vax
+os xinu43
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+// root
+fs /dev/hp0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 1
+ mount / {}
+}
+
+// swap
+fs /dev/hp0b {
+ fstype = swap
+}
+
+// usr
+fs /dev/hp0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 2
+ mount /usr {
+ exportfs "\
+ sky.doc.ic.ac.uk\
+ svax.doc.ic.ac.uk\
+ rvax.doc.ic.ac.uk\
+ ivax.doc.ic.ac.uk\
+ "
+ }
+}
+
+// var
+fs /dev/hp0d {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /var {}
+}
+
+// home directories
+fs /dev/hp0f {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 3
+ mount /a/svax/home/svax {
+ exportfs "\
+ teach_hosts\
+ "
+ }
+} \ No newline at end of file
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tcsun1.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tcsun1.doc.ic.ac.uk
new file mode 100644
index 00000000000..1b10d84111a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tcsun1.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tcsun1,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tcsun2.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tcsun2.doc.ic.ac.uk
new file mode 100644
index 00000000000..933d2f46438
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tcsun2.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tcsun2,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tcsun3.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tcsun3.doc.ic.ac.uk
new file mode 100644
index 00000000000..ccef4d4e221
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tcsun3.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tcsun3,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tcsun4.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tcsun4.doc.ic.ac.uk
new file mode 100644
index 00000000000..9de9a9a69d3
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tcsun4.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tcsun4,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tcsun5.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tcsun5.doc.ic.ac.uk
new file mode 100644
index 00000000000..7f268a0b945
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tcsun5.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tcsun5,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/toytown.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/toytown.doc.ic.ac.uk
new file mode 100644
index 00000000000..7b27f160463
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/toytown.doc.ic.ac.uk
@@ -0,0 +1,116 @@
+host toytown.doc.ic.ac.uk
+
+fs /dev/xy0a {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ freq = 25
+ passno = 1
+ mount / {
+ }
+}
+
+fs /dev/xy0g {
+ fstype = 4.2
+ opts = rw,noquota,grpid
+ freq = 25
+ passno = 2
+ mount /usr {
+ exportfs "-access=toytown_clients:hangers_on:pythagoras,ro"
+ sun3 { }
+ local { }
+ }
+}
+
+fs /dev/xy1g {
+ fstype = 4.2
+ opts = rw,grpid,nosuid
+ freq = 6
+ passno = 2
+ mount /home/toytown {
+ exportfs "-access=toytown_clients:hangers_on,root=achilles"
+ }
+}
+
+fs /dev/xy0f {
+ fstype = 4.2
+ opts = rw,noquota,grpid,nosuid
+ freq = 25
+ passno = 4
+ mount /var {
+ spool {
+ exportfs "-access=toytown_clients:hangers_on"
+ mail { }
+ rwho { volname /vol/rwho sel "byte==big" }
+/*
+ mail { exportfs "-access=toytown_clients:hangers_on" }
+ rwho { exportfs "ro" volname /vol/rwho sel "byte==big" }
+*/
+ }
+ clients {
+ archimedes { exportfs "-access=archimedes,root=archimedes" }
+ archimedes.tmp { exportfs "-access=archimedes,root=archimedes" }
+ aver { exportfs "-access=aver,root=aver" }
+ aver.tmp { exportfs "-access=aver,root=aver" }
+ bigears { exportfs "-access=bigears,root=bigears" }
+ bigears.tmp { exportfs "-access=bigears,root=bigears" }
+ diadem { exportfs "-access=diadem,root=diadem" }
+ diadem.tmp { exportfs "-access=diadem,root=diadem" }
+ montague { exportfs "-access=montague,root=montague" }
+ montague.tmp { exportfs "-access=montague,root=montague" }
+ noddy { exportfs "-access=noddy,root=noddy" }
+ noddy.tmp { exportfs "-access=noddy,root=noddy" }
+ pcplod { exportfs "-access=pcplod,root=pcplod" }
+ pcplod.tmp { exportfs "-access=pcplod,root=pcplod" }
+ samson { exportfs "-access=samson,root=samson" }
+ samson.tmp { exportfs "-access=samson,root=samson" }
+ turing { exportfs "-access=turing,root=turing" }
+ turing.tmp { exportfs "-access=turing,root=turing" }
+ }
+ }
+}
+
+fs /dev/xy0d {
+ fstype = 4.2
+ opts = rw,noquota,grpid,nosuid
+ freq = 25
+ passno = 3
+ mount /export {
+ exec {
+ sun3 { exportfs "-access=toytown_clients:hangers_on:pythagoras" }
+ }
+ root {
+ archimedes { exportfs "-access=archimedes,root=archimedes" }
+ aver { exportfs "-access=aver,root=aver" }
+ bigears { exportfs "-access=bigears,root=bigears" }
+ diadem { exportfs "-access=diadem,root=diadem" }
+ montague { exportfs "-access=montague,root=montague" }
+ noddy { exportfs "-access=noddy,root=noddy" }
+ pcplod { exportfs "-access=pcplod,root=pcplod" }
+ samson { exportfs "-access=samson,root=samson" }
+ turing { exportfs "-access=turing,root=turing" }
+ }
+ swap {
+ archimedes { exportfs "-access=archimedes,root=archimedes" }
+ aver { exportfs "-access=aver,root=aver" }
+ bigears { exportfs "-access=bigears,root=bigears" }
+ diadem { exportfs "-access=diadem,root=diadem" }
+ montague { exportfs "-access=montague,root=montague" }
+ noddy { exportfs "-access=noddy,root=noddy" }
+ pcplod { exportfs "-access=pcplod,root=pcplod" }
+ samson { exportfs "-access=samson,root=samson" }
+ turing { exportfs "-access=turing,root=turing" }
+ }
+ }
+}
+
+fs /dev/xy0b {
+ fstype = swap
+}
+
+fs /dev/xy1b {
+ fstype = swap
+}
+
+mount /home/ganymede opts rw,grpid,nosuid,bg,intr
+mount /home/achilles opts rw,grpid,nosuid,bg,intr
+mount /usr/src from achilles.doc.ic.ac.uk opts rw,grpid,nosuid,bg,intr
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/truth.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/truth.doc.ic.ac.uk
new file mode 100644
index 00000000000..01392799c19
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/truth.doc.ic.ac.uk
@@ -0,0 +1,9 @@
+host truth.doc.ic.ac.uk
+
+mount /export/exec/sun4 from achilles.doc.ic.ac.uk as /usr opts "rw,grpid,intr"
+mount /export/root/truth from achilles.doc.ic.ac.uk as / opts "rw,grpid,intr"
+mount /export/swap/truth from achilles.doc.ic.ac.uk fstype swap as swap opts swap
+mount /var/clients/truth.tmp from achilles.doc.ic.ac.uk as /tmp opts "rw,nosuid,grpid,intr"
+mount /var/clients/truth from achilles.doc.ic.ac.uk as /var opts "rw,nosuid,grpid,intr"
+mount /var/spool/mail from achilles.doc.ic.ac.uk as /var/spool/mail opts "rw,nosuid,grpid,intr"
+mount /usr/src from achilles.doc.ic.ac.uk as /usr/src opts "rw,nosuid,grpid,intr,bg"
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun1.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun1.doc.ic.ac.uk
new file mode 100644
index 00000000000..ff5016cf1b9
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun1.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun1,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun10.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun10.doc.ic.ac.uk
new file mode 100644
index 00000000000..2496cdb3a0a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun10.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun10,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun11.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun11.doc.ic.ac.uk
new file mode 100644
index 00000000000..d6e7b9d685a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun11.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun11,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun12.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun12.doc.ic.ac.uk
new file mode 100644
index 00000000000..a8439bbab39
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun12.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun12,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun13.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun13.doc.ic.ac.uk
new file mode 100644
index 00000000000..44e495689c3
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun13.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun13,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun14.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun14.doc.ic.ac.uk
new file mode 100644
index 00000000000..66a50516cde
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun14.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun14,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun15.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun15.doc.ic.ac.uk
new file mode 100644
index 00000000000..3246df37324
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun15.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun15,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun16.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun16.doc.ic.ac.uk
new file mode 100644
index 00000000000..4ab7bd0e6c2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun16.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun16,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun17.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun17.doc.ic.ac.uk
new file mode 100644
index 00000000000..11ef757bc16
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun17.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun17,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun18.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun18.doc.ic.ac.uk
new file mode 100644
index 00000000000..fbdf8798323
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun18.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun18,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun19.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun19.doc.ic.ac.uk
new file mode 100644
index 00000000000..da9aba84dbc
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun19.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun19,doc.ic.ac.uk,pelican.doc.ic.ac.uk,pelican.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun2.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun2.doc.ic.ac.uk
new file mode 100644
index 00000000000..b6fca7790b6
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun2.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun2,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun3.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun3.doc.ic.ac.uk
new file mode 100644
index 00000000000..e40bd16ffa5
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun3.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun3,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun4.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun4.doc.ic.ac.uk
new file mode 100644
index 00000000000..cd973580b41
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun4.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun4,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun5.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun5.doc.ic.ac.uk
new file mode 100644
index 00000000000..3a8c7e20c47
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun5.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun5,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun6.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun6.doc.ic.ac.uk
new file mode 100644
index 00000000000..4c6ea76644c
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun6.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun6,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun7.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun7.doc.ic.ac.uk
new file mode 100644
index 00000000000..9df32a9413c
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun7.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun7,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun8.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun8.doc.ic.ac.uk
new file mode 100644
index 00000000000..e2b5e1f133e
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun8.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun8,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsun9.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsun9.doc.ic.ac.uk
new file mode 100644
index 00000000000..e82e815ddf8
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsun9.doc.ic.ac.uk
@@ -0,0 +1,3 @@
+#include "../csg_sun3"
+
+CSG_SUN3(tsun9,doc.ic.ac.uk,tsunfs.doc.ic.ac.uk,gould.doc.ic.ac.uk)
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk
new file mode 100644
index 00000000000..d56e3ed5f16
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk
@@ -0,0 +1,211 @@
+// mkfsinfo for tsunfs
+// $Id: tsunfs.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+
+host tsunfs.doc.ic.ac.uk
+
+/*
+arch sun3
+os sos4
+cluster csg
+dumphost flamingo.doc.ic.ac.uk
+*/
+
+#define FSTYPE_UFS 4.2
+#define DEFAULT_OPTS rw,noquota,nosuid,grpid
+
+// swap
+fs /dev/xy0b {
+ fstype = swap
+}
+
+// root
+fs /dev/xy0a {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ passno = 1
+ freq = 1
+ dumpset = csg_sun3_vax
+ mount / {}
+}
+
+// usr
+fs /dev/xy0f {
+ fstype = FSTYPE_UFS
+ opts = rw,grpid
+ freq = 1
+ passno = 2
+ dumpset = csg_sun3_vax
+ mount /usr {}
+}
+
+// var
+fs /dev/xy0e {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 4
+ dumpset = csg_sun3_vax
+ mount /var {
+ mmdf {
+ exportfs "-access=teach_hosts,root=\
+ tsun1.doc.ic.ac.uk:\
+ tsun2.doc.ic.ac.uk:\
+ tsun3.doc.ic.ac.uk:\
+ tsun4.doc.ic.ac.uk:\
+ tsun5.doc.ic.ac.uk:\
+ tsun6.doc.ic.ac.uk:\
+ tsun7.doc.ic.ac.uk:\
+ tsun8.doc.ic.ac.uk:\
+ tsun9.doc.ic.ac.uk:\
+ tsun10.doc.ic.ac.uk:\
+ tsun11.doc.ic.ac.uk:\
+ tsun12.doc.ic.ac.uk:\
+ tsun13.doc.ic.ac.uk:\
+ tsun14.doc.ic.ac.uk:\
+ tsun15.doc.ic.ac.uk:\
+ ssun1.doc.ic.ac.uk:\
+ whoops.doc.ic.ac.uk:\
+ "
+ }
+ }
+}
+
+// root filesystems for diskless clients
+fs /dev/xy0d {
+ fstype = FSTYPE_UFS
+ opts = rw,grpid
+ freq = 1
+ passno = 3
+ mount /export/roots {
+ tsun1 {
+ volname /vol/export/roots/tsun1
+ exportfs "-root=tsun1.doc.ic.ac.uk,-access=tsun1.doc.ic.ac.uk"
+ }
+ tsun2 {
+ volname /vol/export/roots/tsun2
+ exportfs "-root=tsun2.doc.ic.ac.uk,-access=tsun2.doc.ic.ac.uk"
+ }
+ tsun3 {
+ volname /vol/export/roots/tsun3
+ exportfs "-root=tsun3.doc.ic.ac.uk,-access=tsun3.doc.ic.ac.uk"
+ }
+ tsun4 {
+ volname /vol/export/roots/tsun4
+ exportfs "-root=tsun4.doc.ic.ac.uk,-access=tsun4.doc.ic.ac.uk"
+ }
+ tsun5 {
+ volname /vol/export/roots/tsun5
+ exportfs "-root=tsun5.doc.ic.ac.uk,-access=tsun5.doc.ic.ac.uk"
+ }
+ tsun6 {
+ volname /vol/export/roots/tsun6
+ exportfs "-root=tsun6.doc.ic.ac.uk,-access=tsun6.doc.ic.ac.uk"
+ }
+ tsun7 {
+ volname /vol/export/roots/tsun7
+ exportfs "-root=tsun7.doc.ic.ac.uk,-access=tsun7.doc.ic.ac.uk"
+ }
+ tsun8 {
+ volname /vol/export/roots/tsun8
+ exportfs "-root=tsun8.doc.ic.ac.uk,-access=tsun8.doc.ic.ac.uk"
+ }
+ tsun9 {
+ volname /vol/export/roots/tsun9
+ exportfs "-root=tsun9.doc.ic.ac.uk,-access=tsun9.doc.ic.ac.uk"
+ }
+ tsun10 {
+ volname /vol/export/roots/tsun10
+ exportfs "-root=tsun10.doc.ic.ac.uk,-access=tsun10.doc.ic.ac.uk"
+ }
+ tsun11 {
+ volname /vol/export/roots/tsun11
+ exportfs "-root=tsun11.doc.ic.ac.uk,-access=tsun11.doc.ic.ac.uk"
+ }
+ tsun12 {
+ volname /vol/export/roots/tsun12
+ exportfs "-root=tsun12.doc.ic.ac.uk,-access=tsun12.doc.ic.ac.uk"
+ }
+ tsun13 {
+ volname /vol/export/roots/tsun13
+ exportfs "-root=tsun13.doc.ic.ac.uk,-access=tsun13.doc.ic.ac.uk"
+ }
+ tsun14 {
+ volname /vol/export/roots/tsun14
+ exportfs "-root=tsun14.doc.ic.ac.uk,-access=tsun14.doc.ic.ac.uk"
+ }
+ tsun15 {
+ volname /vol/export/roots/tsun15
+ exportfs "-root=tsun15.doc.ic.ac.uk,-access=tsun15.doc.ic.ac.uk"
+ }
+ }
+}
+
+// swap for diskless clients
+fs /dev/xy1c {
+ fstype = FSTYPE_UFS
+ opts = DEFAULT_OPTS
+ freq = 1
+ passno = 5
+ mount /export/swaps {
+ tsun1 {
+ volname /vol/export/swaps/tsun1
+ exportfs "-root=tsun1.doc.ic.ac.uk,-access=tsun1.doc.ic.ac.uk"
+ }
+ tsun2 {
+ volname /vol/export/swaps/tsun2
+ exportfs "-root=tsun2.doc.ic.ac.uk,-access=tsun2.doc.ic.ac.uk"
+ }
+ tsun3 {
+ volname /vol/export/swaps/tsun3
+ exportfs "-root=tsun3.doc.ic.ac.uk,-access=tsun3.doc.ic.ac.uk"
+ }
+ tsun4 {
+ volname /vol/export/swaps/tsun4
+ exportfs "-root=tsun4.doc.ic.ac.uk,-access=tsun4.doc.ic.ac.uk"
+ }
+ tsun5 {
+ volname /vol/export/swaps/tsun5
+ exportfs "-root=tsun5.doc.ic.ac.uk,-access=tsun5.doc.ic.ac.uk"
+ }
+ tsun6 {
+ volname /vol/export/swaps/tsun6
+ exportfs "-root=tsun6.doc.ic.ac.uk,-access=tsun6.doc.ic.ac.uk"
+ }
+ tsun7 {
+ volname /vol/export/swaps/tsun7
+ exportfs "-root=tsun7.doc.ic.ac.uk,-access=tsun7.doc.ic.ac.uk"
+ }
+ tsun8 {
+ volname /vol/export/swaps/tsun8
+ exportfs "-root=tsun8.doc.ic.ac.uk,-access=tsun8.doc.ic.ac.uk"
+ }
+ tsun9 {
+ volname /vol/export/swaps/tsun9
+ exportfs "-root=tsun9.doc.ic.ac.uk,-access=tsun9.doc.ic.ac.uk"
+ }
+ tsun10 {
+ volname /vol/export/swaps/tsun10
+ exportfs "-root=tsun10.doc.ic.ac.uk,-access=tsun10.doc.ic.ac.uk"
+ }
+ tsun11 {
+ volname /vol/export/swaps/tsun11
+ exportfs "-root=tsun11.doc.ic.ac.uk,-access=tsun11.doc.ic.ac.uk"
+ }
+ tsun12 {
+ volname /vol/export/swaps/tsun12
+ exportfs "-root=tsun12.doc.ic.ac.uk,-access=tsun12.doc.ic.ac.uk"
+ }
+ tsun13 {
+ volname /vol/export/swaps/tsun13
+ exportfs "-root=tsun13.doc.ic.ac.uk,-access=tsun13.doc.ic.ac.uk"
+ }
+ tsun14 {
+ volname /vol/export/swaps/tsun14
+ exportfs "-root=tsun14.doc.ic.ac.uk,-access=tsun14.doc.ic.ac.uk"
+ }
+ tsun15 {
+ volname /vol/export/swaps/tsun15
+ exportfs "-root=tsun15.doc.ic.ac.uk,-access=tsun15.doc.ic.ac.uk"
+ }
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk b/usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk
new file mode 100644
index 00000000000..88525f3008b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk
@@ -0,0 +1,21 @@
+// $Id: whoops.doc.ic.ac.uk,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+// sm's bastardised csg_sun3
+// note that no /var/spool/rwho is mounted as we now expect amd to do this as /vol/rwho
+
+#define HOST whoops
+#define DOMAIN doc.ic.ac.uk
+#define BOOT gould.doc.ic.ac.uk
+#define EXEC gould.doc.ic.ac.uk
+#define MAIL tsunfs.doc.ic.ac.uk
+
+// a sun3
+host HOST.DOMAIN
+
+mount /vol/export/roots/HOST as / from BOOT opts rw,grpid,hard,intr
+mount /vol/export/swaps/HOST fstype swap as swap from BOOT opts swap
+mount /vol/export/exec/sun3 as /usr from EXEC opts ro,grpid,hard,intr
+mount /vol/export/misc/crash/HOST as /var/crash/HOST from EXEC opts rw,nosuid,grpid,hard,intr
+mount /vol/export/misc/tmp/HOST as /tmp from EXEC opts rw,nosuid,grpid,hard,intr
+mount /vol/export/misc/usr.tmp/HOST as /var/tmp from EXEC opts rw,nosuid,grpid,hard,intr
+mount /var/mmdf from MAIL opts rw,nosuid,grpid,hard,intr
+
diff --git a/usr.sbin/amd/fsinfo/conf/users b/usr.sbin/amd/fsinfo/conf/users
new file mode 100644
index 00000000000..9dc83d9c5d4
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/users
@@ -0,0 +1,106 @@
+audit -> /etc/security/audit
+bin -> /bin
+daemon -> /
+games -> /usr/games
+ingres -> /usr/ingres
+news -> /var/spool/news
+nobody -> /nonexistent
+root -> /
+sync -> /
+sys -> /
+sysdiag -> /usr/diag/sysdiag
+uucp -> /var/spool/uucppublic
+acwf = /home/toytown/others/acwf
+adh = /home/dylan/dk2/adh
+ae = /home/toytown/samson/ae
+aj = /home/toytown/samson/aj
+athena = /vol/src/athena
+bh = /home/toytown/jim/bh
+bp = /home/toytown/others/bp
+brg = /home/gummo/users/brg
+bt = /home/toytown/samson/bt
+ca = /home/toytown/diadem/ca
+ccm = /home/toytown/ai/ccm
+chlo = /home/toytown/samson/chlo
+clh = /home/toytown/ai/clh
+cr = /home/toytown/samson/cr
+cw = /home/toytown/genesis/cw
+dds = /home/toytown/genesis/dds
+dg = /home/toytown/dov/dg
+dgb = /home/dylan/dk2/dgb
+dme = /home/achilles/dme
+dp = /home/gummo/usersdiana
+ds = /home/toytown/ai/ds
+dwj = /home/achilles/dwj
+eaa = /home/toytown/dov/eaa
+esh = /home/toytown/ai/esh
+fcs = /home/ganymede/fcs
+fst = /home/dylan/dk2/fst
+glb = /home/toytown/ai/glb
+grace = /home/toytown/others/grace
+guest = /home/toytown/others/guest
+hd = /home/toytown/others/hd
+hf = /home/toytown/genesis/hf
+iccp = /home/toytown/samson/iccp
+ids = /home/toytown/samson/ids
+ih = /home/toytown/others/ih
+ja = /home/toytown/ai/ja
+jfc = /home/toytown/jim/jfc
+jg = /home/toytown/genesis/jg
+jjc = /home/toytown/genesis/jjc
+js = /home/toytown/samson/js
+jsp = /home/achilles/jsp
+jvp = /home/toytown/jim/jvp
+kdr = /home/dylan/dk2/kdr
+kevin = /home/toytown/others/kpt
+kpt = /home/toytown/others/kpt
+ksa = /home/toytown/ai/ksa
+lkcl = /home/dylan/dk2/lkcl
+ll = /home/toytown/dov/ll
+ll1 = /home/toytown/others/ll1
+lmjm = /home/toytown/others/lmjm
+lsh = /home/toytown/ai/lsh
+mb = /home/toytown/jim/mb
+md = /home/achilles/md
+mdr = /home/achilles/mdr
+mg = /home/ganymede/mg
+mjh = /home/toytown/others/mjh
+mrs = /home/achilles/mrs
+mwg = /home/achilles/mwg
+mwt = /home/achilles/mwt
+nd = /home/gummo/users/nd
+njw = /home/dylan/dk2/njw
+ok = /home/ganymede/ok
+pah = /home/toytown/jim/pah
+pdg = /home/toytown/samson/pdg
+phjk = /home/toytown/ai/phjk
+pm = /home/achilles/pm
+pm2 = /home/dylan/dk2/pm2
+ps = /home/toytown/genesis/ps
+pt = /home/toytown/dov/pt
+pvr = /home/toytown/jim/pvr
+rgc = /home/toytown/jim/rgc
+rjc = /home/toytown/jim/rjc
+rjq = /home/achilles/rjq
+sa = /home/toytown/samson/sa
+shb = /home/toytown/others/shb
+shc = /home/dylan/dk2/shc
+sjk = /home/toytown/jim/sjk
+sjl2 = /home/achilles/sjl2
+sjv = /home/ganymede/sjv
+sm = /home/toytown/others/sm
+sme = /home/ganymede/sme
+sph = /home/toytown/ai/sph
+ssp = /home/toytown/others/ssp
+sw = /home/toytown/others/sw
+sza = /home/ganymede/sza
+teb = /home/dylan/dk2/teb
+thp = /home/achilles/thp
+tm = /home/toytown/ai/tm
+tsem = /home/toytown/genesis/tsem
+umacd20 = /home/ganymede/umacd20
+wmvh = /home/dylan/dk2/wmvh
+wrdo = /home/ganymede/wrdo
+ygal = /home/toytown/samson/ygal
+zmact03 = /home/toytown/jim/zmact03
+zmacy26 = /home/toytown/jim/zmacy26
diff --git a/usr.sbin/amd/fsinfo/fsi_analyze.c b/usr.sbin/amd/fsinfo/fsi_analyze.c
new file mode 100644
index 00000000000..48389c06224
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_analyze.c
@@ -0,0 +1,643 @@
+/*
+ * 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.
+ *
+ * from: @(#)fsi_analyze.c 8.1 (Berkeley) 6/6/93
+ * $Id: fsi_analyze.c,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+/*
+ * Analyze filesystem declarations
+ *
+ * Note: most of this is magic!
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+char *disk_fs_strings[] = {
+ "fstype", "opts", "dumpset", "passno", "freq", "mount", "log", 0,
+};
+
+char *mount_strings[] = {
+ "volname", "exportfs", 0,
+};
+
+char *fsmount_strings[] = {
+ "as", "volname", "fstype", "opts", "from", 0,
+};
+
+char *host_strings[] = {
+ "host", "netif", "config", "arch", "cluster", "os", 0,
+};
+
+char *ether_if_strings[] = {
+ "inaddr", "netmask", "hwaddr", 0,
+};
+
+/*
+ * Strip off the trailing part of a domain
+ * to produce a short-form domain relative
+ * to the local host domain.
+ * Note that this has no effect if the domain
+ * names do not have the same number of
+ * components. If that restriction proves
+ * to be a problem then the loop needs recoding
+ * to skip from right to left and do partial
+ * matches along the way -- ie more expensive.
+ */
+void domain_strip(otherdom, localdom)
+char *otherdom, *localdom;
+{
+#ifdef PARTIAL_DOMAINS
+ char *p1 = otherdom-1;
+ char *p2 = localdom-1;
+
+ do {
+ if (p1 = strchr(p1+1, '.'))
+ if (p2 = strchr(p2+1, '.'))
+ if (STREQ(p1+1, p2+1)) {
+ *p1 = '\0';
+ break;
+ }
+ } while (p1 && p2);
+#else
+ char *p1, *p2;
+
+ if ((p1 = strchr(otherdom, '.')) &&
+ (p2 = strchr(localdom, '.')) &&
+ (strcmp(p1+1, p2+1) == 0))
+ *p1 = '\0';
+#endif /* PARTIAL_DOMAINS */
+}
+
+/*
+ * Take a little-endian domain name and
+ * transform into a big-endian Un*x pathname.
+ * For example: kiska.doc.ic -> ic/doc/kiska
+ */
+static char *compute_hostpath(hn)
+char *hn;
+{
+ char *p = strdup(hn);
+ char *d;
+ char path[MAXPATHLEN];
+
+ domain_strip(p, hostname);
+ path[0] = '\0';
+
+ do {
+ d = strrchr(p, '.');
+ if (d) {
+ *d = 0;
+ strcat(path, d+1);
+ strcat(path, "/");
+ } else {
+ strcat(path, p);
+ }
+ } while (d);
+
+ log("hostpath of '%s' is '%s'", hn, path);
+
+ strcpy(p, path);
+ return p;
+}
+
+static dict_ent *find_volname(nn)
+char *nn;
+{
+ dict_ent *de;
+ char *p = strdup(nn);
+ char *q;
+
+ do {
+ log("Searching for volname %s", p);
+ de = dict_locate(dict_of_volnames, p);
+ q = strrchr(p, '/');
+ if (q) *q = '\0';
+ } while (!de && q);
+
+ free(p);
+ return de;
+}
+
+static show_required(l, mask, info, hostname, strings)
+ioloc *l;
+int mask;
+char *info;
+char *hostname;
+char *strings[];
+{
+ int i;
+ log("mask left for %s:%s is %#x", hostname, info, mask);
+
+ for (i = 0; strings[i]; i++)
+ if (ISSET(mask, i))
+ lerror(l, "%s:%s needs field \"%s\"", hostname, info, strings[i]);
+}
+
+/*
+ * Check and fill in "exportfs" details.
+ * Make sure the m_exported field references
+ * the most local node with an "exportfs" entry.
+ */
+static int check_exportfs(q, e)
+qelem *q;
+mount *e;
+{
+ mount *mp;
+ int errors = 0;
+
+ ITER(mp, mount, q) {
+ if (ISSET(mp->m_mask, DM_EXPORTFS)) {
+ if (e)
+ lwarning(mp->m_ioloc, "%s has duplicate exportfs data", mp->m_name);
+ mp->m_exported = mp;
+ if (!ISSET(mp->m_mask, DM_VOLNAME))
+ set_mount(mp, DM_VOLNAME, strdup(mp->m_name));
+ } else {
+ mp->m_exported = e;
+ }
+
+ /*
+ * Recursively descend the mount tree
+ */
+ if (mp->m_mount)
+ errors += check_exportfs(mp->m_mount, mp->m_exported);
+
+ /*
+ * If a volume name has been specified, but this node and none
+ * of its parents has been exported, report an error.
+ */
+ if (ISSET(mp->m_mask, DM_VOLNAME) && !mp->m_exported) {
+ lerror(mp->m_ioloc, "%s has a volname but no exportfs data", mp->m_name);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+static int analyze_dkmount_tree(q, parent, dk)
+qelem *q;
+mount *parent;
+disk_fs *dk;
+{
+ mount *mp;
+ int errors = 0;
+
+ ITER(mp, mount, q) {
+ log("Mount %s:", mp->m_name);
+ if (parent) {
+ char n[MAXPATHLEN];
+ sprintf(n, "%s/%s", parent->m_name, mp->m_name);
+ if (*mp->m_name == '/')
+ lerror(mp->m_ioloc, "sub-directory %s of %s starts with '/'", mp->m_name, parent->m_name);
+ else if (STREQ(mp->m_name, "default"))
+ lwarning(mp->m_ioloc, "sub-directory of %s is named \"default\"", parent->m_name);
+ log("Changing name %s to %s", mp->m_name, n);
+ free(mp->m_name);
+ mp->m_name = strdup(n);
+ }
+ mp->m_name_len = strlen(mp->m_name);
+ mp->m_parent = parent;
+ mp->m_dk = dk;
+ if (mp->m_mount)
+ analyze_dkmount_tree(mp->m_mount, mp, dk);
+ }
+
+ return errors;
+}
+
+/*
+ * The mount tree is a singleton list
+ * containing the top-level mount
+ * point for a disk.
+ */
+static int analyze_dkmounts(dk, q)
+disk_fs *dk;
+qelem *q;
+{
+ int errors = 0;
+ mount *mp, *mp2 = 0;
+ int i = 0;
+
+ /*
+ * First scan the list of subdirs to make
+ * sure there is only one - and remember it
+ */
+ if (q) {
+ ITER(mp, mount, q) {
+ mp2 = mp;
+ i++;
+ }
+ }
+
+ /*
+ * Check...
+ */
+ if (i < 1) {
+ lerror(dk->d_ioloc, "%s:%s has no mount point", dk->d_host->h_hostname, dk->d_dev);
+ return 1;
+ }
+ if (i > 1) {
+ lerror(dk->d_ioloc, "%s:%s has more than one mount point", dk->d_host->h_hostname, dk->d_dev);
+ errors++;
+ }
+ /*
+ * Now see if a default mount point is required
+ */
+ if (STREQ(mp2->m_name, "default")) {
+ if (ISSET(mp2->m_mask, DM_VOLNAME)) {
+ char nbuf[1024];
+ compute_automount_point(nbuf, dk->d_host, mp2->m_volname);
+ free(mp2->m_name);
+ mp2->m_name = strdup(nbuf);
+ log("%s:%s has default mount on %s", dk->d_host->h_hostname, dk->d_dev, mp2->m_name);
+ } else {
+ lerror(dk->d_ioloc, "no volname given for %s:%s", dk->d_host->h_hostname, dk->d_dev);
+ errors++;
+ }
+ }
+ /*
+ * Fill in the disk mount point
+ */
+ if (!errors && mp2 && mp2->m_name)
+ dk->d_mountpt = strdup(mp2->m_name);
+ else
+ dk->d_mountpt = strdup("error");
+
+ /*
+ * Analyze the mount tree
+ */
+ errors += analyze_dkmount_tree(q, 0, dk);
+
+ /*
+ * Analyze the export tree
+ */
+ errors += check_exportfs(q, 0);
+
+ return errors;
+}
+
+static void fixup_required_disk_info(dp)
+disk_fs *dp;
+{
+ /*
+ * "fstype"
+ */
+ if (ISSET(dp->d_mask, DF_FSTYPE)) {
+ if (STREQ(dp->d_fstype, "swap")) {
+ /*
+ * Fixup for a swap device
+ */
+ if (!ISSET(dp->d_mask, DF_PASSNO)) {
+ dp->d_passno = 0;
+ BITSET(dp->d_mask, DF_PASSNO);
+ } else if (dp->d_freq != 0) {
+ lwarning(dp->d_ioloc,
+ "Pass number for %s:%s is non-zero",
+ dp->d_host->h_hostname, dp->d_dev);
+ }
+
+ /*
+ * "freq"
+ */
+ if (!ISSET(dp->d_mask, DF_FREQ)) {
+ dp->d_freq = 0;
+ BITSET(dp->d_mask, DF_FREQ);
+ } else if (dp->d_freq != 0) {
+ lwarning(dp->d_ioloc,
+ "dump frequency for %s:%s is non-zero",
+ dp->d_host->h_hostname, dp->d_dev);
+ }
+
+ /*
+ * "opts"
+ */
+ if (!ISSET(dp->d_mask, DF_OPTS))
+ set_disk_fs(dp, DF_OPTS, strdup("swap"));
+
+ /*
+ * "mount"
+ */
+ if (!ISSET(dp->d_mask, DF_MOUNT)) {
+ qelem *q = new_que();
+ mount *m = new_mount();
+ m->m_name = strdup("swap");
+ m->m_mount = new_que();
+ ins_que(&m->m_q, q->q_back);
+ dp->d_mount = q;
+ BITSET(dp->d_mask, DF_MOUNT);
+ } else {
+ lerror(dp->d_ioloc, "%s: mount field specified for swap partition", dp->d_host->h_hostname);
+ }
+ } else if (STREQ(dp->d_fstype, "export")) {
+ /*
+ * "passno"
+ */
+ if (!ISSET(dp->d_mask, DF_PASSNO)) {
+ dp->d_passno = 0;
+ BITSET(dp->d_mask, DF_PASSNO);
+ } else if (dp->d_passno != 0) {
+ lwarning(dp->d_ioloc,
+ "pass number for %s:%s is non-zero",
+ dp->d_host->h_hostname, dp->d_dev);
+ }
+
+ /*
+ * "freq"
+ */
+ if (!ISSET(dp->d_mask, DF_FREQ)) {
+ dp->d_freq = 0;
+ BITSET(dp->d_mask, DF_FREQ);
+ } else if (dp->d_freq != 0) {
+ lwarning(dp->d_ioloc,
+ "dump frequency for %s:%s is non-zero",
+ dp->d_host->h_hostname, dp->d_dev);
+ }
+
+ /*
+ * "opts"
+ */
+ if (!ISSET(dp->d_mask, DF_OPTS))
+ set_disk_fs(dp, DF_OPTS, strdup("rw,defaults"));
+
+ }
+ }
+}
+
+static void fixup_required_mount_info(fp, de)
+fsmount *fp;
+dict_ent *de;
+{
+ if (!ISSET(fp->f_mask, FM_FROM)) {
+ if (de->de_count != 1) {
+ lerror(fp->f_ioloc, "ambiguous mount: %s is a replicated filesystem", fp->f_volname);
+ } else {
+ dict_data *dd;
+ mount *mp = 0;
+ ITER(dd, dict_data, &de->de_q) {
+ mp = (mount *) dd->dd_data;
+ break;
+ }
+ if (!mp)
+ abort();
+ fp->f_ref = mp;
+ set_fsmount(fp, FM_FROM, mp->m_dk->d_host->h_hostname);
+ log("set: %s comes from %s", fp->f_volname, fp->f_from);
+ }
+ }
+
+ if (!ISSET(fp->f_mask, FM_FSTYPE)) {
+ set_fsmount(fp, FM_FSTYPE, strdup("nfs"));
+ log("set: fstype is %s", fp->f_fstype);
+ }
+
+ if (!ISSET(fp->f_mask, FM_OPTS)) {
+ set_fsmount(fp, FM_OPTS, strdup("rw,nosuid,grpid,defaults"));
+ log("set: opts are %s", fp->f_opts);
+ }
+
+ if (!ISSET(fp->f_mask, FM_LOCALNAME)) {
+ if (fp->f_ref) {
+ set_fsmount(fp, FM_LOCALNAME, strdup(fp->f_volname));
+ log("set: localname is %s", fp->f_localname);
+ } else {
+ lerror(fp->f_ioloc, "cannot determine localname since volname %s is not uniquely defined", fp->f_volname);
+ }
+ }
+}
+
+/*
+ * For each disk on a host
+ * analyze the mount information
+ * and fill in any derivable
+ * details.
+ */
+static void analyze_drives(hp)
+host *hp;
+{
+ qelem *q = hp->h_disk_fs;
+ disk_fs *dp;
+
+ ITER(dp, disk_fs, q) {
+ int req;
+ log("Disk %s:", dp->d_dev);
+ dp->d_host = hp;
+ fixup_required_disk_info(dp);
+ req = ~dp->d_mask & DF_REQUIRED;
+ if (req)
+ show_required(dp->d_ioloc, req, dp->d_dev, hp->h_hostname, disk_fs_strings);
+ analyze_dkmounts(dp, dp->d_mount);
+ }
+}
+
+/*
+ * Check that all static mounts make sense and
+ * that the source volumes exist.
+ */
+static void analyze_mounts(hp)
+host *hp;
+{
+ qelem *q = hp->h_mount;
+ fsmount *fp;
+ int netbootp = 0;
+
+ ITER(fp, fsmount, q) {
+ char *p;
+ char *nn = strdup(fp->f_volname);
+ int req;
+ dict_ent *de;
+ int found = 0;
+ int matched = 0;
+ do {
+ p = 0;
+ de = find_volname(nn);
+ log("Mount: %s (trying %s)", fp->f_volname, nn);
+
+ if (de) {
+ found = 1;
+ /*
+ * Check that the from field is really exporting
+ * the filesystem requested.
+ */
+ if (ISSET(fp->f_mask, FM_FROM)) {
+ dict_data *dd;
+ mount *mp2 = 0;
+ ITER(dd, dict_data, &de->de_q) {
+ mount *mp = (mount *) dd->dd_data;
+ if (STREQ(mp->m_dk->d_host->h_hostname, fp->f_from)) {
+ mp2 = mp;
+ break;
+ }
+ }
+
+ if (mp2) {
+ fp->f_ref = mp2;
+ matched = 1;
+ break;
+ }
+ } else {
+ matched = 1;
+ break;
+ }
+ }
+ p = strrchr(nn, '/');
+ if (p)
+ *p = 0;
+ } while (de && p);
+ free(nn);
+
+ if (!found) {
+ lerror(fp->f_ioloc, "volname %s unknown", fp->f_volname);
+ } else if (matched) {
+ fixup_required_mount_info(fp, de);
+ req = ~fp->f_mask & FM_REQUIRED;
+ if (req) {
+ show_required(fp->f_ioloc, req, fp->f_volname, hp->h_hostname,
+ fsmount_strings);
+ } else if (strcmp(fp->f_localname, "/") == 0) {
+ hp->h_netroot = fp;
+ netbootp |= FM_NETROOT;
+ } else if (strcmp(fp->f_localname, "swap") == 0) {
+ hp->h_netswap = fp;
+ netbootp |= FM_NETSWAP;
+ }
+ } else {
+ lerror(fp->f_ioloc, "volname %s not exported from %s", fp->f_volname,
+ fp->f_from ? fp->f_from : "anywhere");
+ }
+ }
+
+ if (netbootp && (netbootp != FM_NETBOOT))
+ lerror(hp->h_ioloc, "network booting requires both root and swap areas");
+}
+
+void analyze_hosts(q)
+qelem *q;
+{
+ host *hp;
+
+ show_area_being_processed("analyze hosts", 5);
+
+ /*
+ * Check all drives
+ */
+ ITER(hp, host, q) {
+ log("disks on host %s", hp->h_hostname);
+ show_new("ana-host");
+ hp->h_hostpath = compute_hostpath(hp->h_hostname);
+
+ if (hp->h_disk_fs)
+ analyze_drives(hp);
+
+ }
+
+ show_area_being_processed("analyze mounts", 5);
+
+ /*
+ * Check static mounts
+ */
+ ITER(hp, host, q) {
+ log("mounts on host %s", hp->h_hostname);
+ show_new("ana-mount");
+ if (hp->h_mount)
+ analyze_mounts(hp);
+
+ }
+}
+
+/*
+ * Check an automount request
+ */
+static void analyze_automount(ap)
+automount *ap;
+{
+ dict_ent *de = find_volname(ap->a_volname);
+ if (de) {
+ ap->a_mounted = de;
+ } else {
+ if (STREQ(ap->a_volname, ap->a_name))
+ lerror(ap->a_ioloc, "unknown volname %s automounted", ap->a_volname);
+ else
+ lerror(ap->a_ioloc, "unknown volname %s automounted on %s", ap->a_volname, ap->a_name);
+ }
+}
+
+static void analyze_automount_tree(q, pref, lvl)
+qelem *q;
+char *pref;
+int lvl;
+{
+ automount *ap;
+
+ ITER(ap, automount, q) {
+ char nname[1024];
+ if (lvl > 0 || ap->a_mount)
+ if (ap->a_name[1] && strchr(ap->a_name+1, '/'))
+ lerror(ap->a_ioloc, "not allowed '/' in a directory name");
+ sprintf(nname, "%s/%s", pref, ap->a_name);
+ free(ap->a_name);
+ ap->a_name = strdup(nname[1] == '/' ? nname+1 : nname);
+ log("automount point %s:", ap->a_name);
+ show_new("ana-automount");
+ if (ap->a_mount) {
+ analyze_automount_tree(ap->a_mount, ap->a_name, lvl+1);
+ } else if (ap->a_volname) {
+ log("\tautomount from %s", ap->a_volname);
+ analyze_automount(ap);
+ } else if (ap->a_symlink) {
+ log("\tsymlink to %s", ap->a_symlink);
+ } else {
+ ap->a_volname = strdup(ap->a_name);
+ log("\timplicit automount from %s", ap->a_volname);
+ analyze_automount(ap);
+ }
+ }
+}
+
+void analyze_automounts(q)
+qelem *q;
+{
+ auto_tree *tp;
+
+ show_area_being_processed("analyze automount", 5);
+ /*
+ * q is a list of automounts
+ */
+ ITER(tp, auto_tree, q)
+ analyze_automount_tree(tp->t_mount, "", 0);
+}
diff --git a/usr.sbin/amd/fsinfo/fsi_data.h b/usr.sbin/amd/fsinfo/fsi_data.h
new file mode 100644
index 00000000000..95886292b40
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_data.h
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ *
+ * from: @(#)fsi_data.h 8.1 (Berkeley) 6/6/93
+ * $Id: fsi_data.h,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+typedef struct auto_tree auto_tree;
+typedef struct automount automount;
+typedef struct dict dict;
+typedef struct dict_data dict_data;
+typedef struct dict_ent dict_ent;
+typedef struct disk_fs disk_fs;
+typedef struct ether_if ether_if;
+typedef struct fsmount fsmount;
+typedef struct host host;
+typedef struct ioloc ioloc;
+typedef struct mount mount;
+typedef struct qelem qelem;
+
+/*
+ * Linked lists...
+ */
+struct qelem {
+ qelem *q_forw;
+ qelem *q_back;
+};
+
+/*
+ * Automount tree
+ */
+struct automount {
+ qelem a_q;
+ ioloc *a_ioloc;
+ char *a_name; /* Automount key */
+ char *a_volname; /* Equivalent volume to be referenced */
+ char *a_symlink; /* Symlink representation */
+ qelem *a_mount; /* Tree representation */
+ dict_ent *a_mounted;
+};
+
+/*
+ * List of automount trees
+ */
+struct auto_tree {
+ qelem t_q;
+ ioloc *t_ioloc;
+ char *t_defaults;
+ qelem *t_mount;
+};
+
+/*
+ * A host
+ */
+struct host {
+ qelem q;
+ int h_mask;
+ ioloc *h_ioloc;
+ fsmount *h_netroot, *h_netswap;
+#define HF_HOST 0
+ char *h_hostname; /* The full name of the host */
+ char *h_lochost; /* The name of the host with local domains stripped */
+ char *h_hostpath; /* The filesystem path to the host (cf compute_hostpath) */
+#define HF_ETHER 1
+ qelem *h_ether;
+#define HF_CONFIG 2
+ qelem *h_config;
+#define HF_ARCH 3
+ char *h_arch;
+#define HF_CLUSTER 4
+ char *h_cluster;
+#define HF_OS 5
+ char *h_os;
+ qelem *h_disk_fs;
+ qelem *h_mount;
+};
+
+/*
+ * An ethernet interface
+ */
+struct ether_if {
+ qelem e_q;
+ int e_mask;
+ ioloc *e_ioloc;
+ char *e_if;
+#define EF_INADDR 0
+ struct in_addr e_inaddr;
+#define EF_NETMASK 1
+ u_long e_netmask;
+#define EF_HWADDR 2
+ char *e_hwaddr;
+};
+
+/*
+ * Disk filesystem structure.
+ *
+ * If the DF_* numbers are changed
+ * disk_fs_strings in analyze.c will
+ * need updating.
+ */
+struct disk_fs {
+ qelem d_q;
+ int d_mask;
+ ioloc *d_ioloc;
+ host *d_host;
+ char *d_mountpt;
+ char *d_dev;
+#define DF_FSTYPE 0
+ char *d_fstype;
+#define DF_OPTS 1
+ char *d_opts;
+#define DF_DUMPSET 2
+ char *d_dumpset;
+#define DF_PASSNO 3
+ int d_passno;
+#define DF_FREQ 4
+ int d_freq;
+#define DF_MOUNT 5
+ qelem *d_mount;
+#define DF_LOG 6
+ char *d_log;
+};
+#define DF_REQUIRED ((1<<DF_FSTYPE)|(1<<DF_OPTS)|(1<<DF_PASSNO)|(1<<DF_MOUNT))
+
+/*
+ * A mount tree
+ */
+struct mount {
+ qelem m_q;
+ ioloc *m_ioloc;
+ int m_mask;
+#define DM_VOLNAME 0
+ char *m_volname;
+#define DM_EXPORTFS 1
+ char *m_exportfs;
+#define DM_SEL 2
+ char *m_sel;
+ char *m_name;
+ int m_name_len;
+ mount *m_parent;
+ disk_fs *m_dk;
+ mount *m_exported;
+ qelem *m_mount;
+};
+
+/*
+ * Additional filesystem mounts
+ *
+ * If the FM_* numbers are changed
+ * disk_fs_strings in analyze.c will
+ * need updating.
+ */
+struct fsmount {
+ qelem f_q;
+ mount *f_ref;
+ ioloc *f_ioloc;
+ int f_mask;
+#define FM_LOCALNAME 0
+ char *f_localname;
+#define FM_VOLNAME 1
+ char *f_volname;
+#define FM_FSTYPE 2
+ char *f_fstype;
+#define FM_OPTS 3
+ char *f_opts;
+#define FM_FROM 4
+ char *f_from;
+};
+#define FM_REQUIRED ((1<<FM_VOLNAME)|(1<<FM_FSTYPE)|(1<<FM_OPTS)|(1<<FM_FROM)|(1<<FM_LOCALNAME))
+#define FM_NETROOT 0x01
+#define FM_NETSWAP 0x02
+#define FM_NETBOOT (FM_NETROOT|FM_NETSWAP)
+
+#define DICTHASH 5
+struct dict_ent {
+ dict_ent *de_next;
+ char *de_key;
+ int de_count;
+ qelem de_q;
+};
+
+/*
+ * Dictionaries ...
+ */
+struct dict_data {
+ qelem dd_q;
+ char *dd_data;
+};
+
+struct dict {
+ dict_ent *de[DICTHASH];
+};
+
+/*
+ * Source text location for error reports
+ */
+struct ioloc {
+ int i_line;
+ char *i_file;
+};
diff --git a/usr.sbin/amd/fsinfo/fsi_dict.c b/usr.sbin/amd/fsinfo/fsi_dict.c
new file mode 100644
index 00000000000..730dd992440
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_dict.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.
+ *
+ * from: @(#)fsi_dict.c 8.1 (Berkeley) 6/6/93
+ * $Id: fsi_dict.c,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+/*
+ * Dictionary support
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+static int dict_hash(k)
+char *k;
+{
+ unsigned int h;
+
+ for (h = 0; *k; h += *k++)
+ ;
+ return h % DICTHASH;
+}
+
+dict *new_dict()
+{
+ dict *dp = ALLOC(dict);
+ return dp;
+}
+
+static void dict_add_data(de, v)
+dict_ent *de;
+char *v;
+{
+ dict_data *dd = ALLOC(dict_data);
+ dd->dd_data = v;
+ ins_que(&dd->dd_q, de->de_q.q_back);
+ de->de_count++;
+}
+
+static dict_ent *new_dict_ent(k)
+char *k;
+{
+ dict_ent *de = ALLOC(dict_ent);
+ de->de_key = k;
+ init_que(&de->de_q);
+ return de;
+}
+
+dict_ent *dict_locate(dp, k)
+dict *dp;
+char *k;
+{
+ dict_ent *de = dp->de[dict_hash(k)];
+ while (de && !STREQ(de->de_key, k))
+ de = de->de_next;
+
+ return de;
+}
+
+void dict_add(dp, k, v)
+dict *dp;
+char *k, *v;
+{
+ dict_ent *de = dict_locate(dp, k);
+ if (!de) {
+ dict_ent **dep = &dp->de[dict_hash(k)];
+ de = new_dict_ent(k);
+ de->de_next = *dep;
+ *dep = de;
+ }
+ dict_add_data(de, v);
+}
+
+int dict_iter(dp, fn)
+dict *dp;
+int (*fn)();
+{
+ int i;
+ int errors = 0;
+
+ for (i = 0; i < DICTHASH; i++) {
+ dict_ent *de = dp->de[i];
+ while (de) {
+ errors += (*fn)(&de->de_q);
+ de = de->de_next;
+ }
+ }
+ return errors;
+}
diff --git a/usr.sbin/amd/fsinfo/fsi_gram.y b/usr.sbin/amd/fsinfo/fsi_gram.y
new file mode 100644
index 00000000000..be1c4a4f98a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_gram.y
@@ -0,0 +1,392 @@
+/*
+ * 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.
+ *
+ * from: @(#)fsi_gram.y 8.1 (Berkeley) 6/6/93
+ * $Id: fsi_gram.y,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+%{
+#include "../fsinfo/fsinfo.h"
+#include <stdio.h>
+
+extern qelem *list_of_hosts, *list_of_automounts;
+%}
+
+%union {
+ auto_tree *a;
+ disk_fs *d;
+ ether_if *e;
+ host *h;
+ qelem *q;
+ char *s;
+ mount *m;
+ fsmount *f;
+}
+
+%token tARCH
+%token tAS
+%token tAUTOMOUNT
+%token tCLUSTER
+%token tCONFIG
+%token tDUMPSET
+%token tEQ
+%token tEXPORTFS
+%token tFREQ
+%token tFROM
+%token tFS
+%token tFSTYPE
+%token tHWADDR
+%token tINADDR
+%token tHOST
+%token tLOCALHOST
+%token tLOG
+%token tMOUNT
+%token tNETMASK
+%token tNETIF
+%token tVOLNAME
+%token tOPTS
+%token tOS
+%token tPASSNO
+%token tSEL
+%token <s> tSTR
+
+%start list_of_hosts
+
+%type <a> automount
+%type <q> automount_tree
+%type <e> ether_attr
+%type <m> dir_tree_info
+%type <d> filesystem fs_info_list
+%type <h> host host_attr host_attr_list
+%type <q> list_of_hosts list_of_filesystems list_of_mounts dir_tree
+%type <f> localinfo_list
+%type <s> opt_auto_opts
+
+%%
+
+list_of_hosts :
+ /* empty */
+ { $$ = new_que(); }
+
+ | list_of_hosts host
+ { if ($2) ins_que((qelem *) $2, list_of_hosts->q_back);
+ $$ = $1; }
+
+ | list_of_hosts automount
+ { if ($2) ins_que((qelem *) $2, list_of_automounts->q_back);
+ $$ = $1; }
+ ;
+
+/*
+ * A new host:
+ *
+ * host foo.domain
+ */
+host :
+ tHOST host_attr list_of_filesystems list_of_mounts
+ { $$ = $2; $$->h_disk_fs = $3; $$->h_mount = $4; }
+
+ | error tHOST host_attr list_of_filesystems list_of_mounts
+ { $$ = $3; $$->h_disk_fs = $4; $$->h_mount = $5; }
+
+ ;
+
+host_attr :
+ tSTR
+ { $$ = new_host(); set_host($$, HF_HOST, $1); }
+
+ | '{' host_attr_list '}' tSTR
+ { $$ = $2; set_host($$, HF_HOST, $4); }
+
+ ;
+
+host_attr_list :
+ /* empty */
+ { $$ = new_host(); }
+
+ | host_attr_list tNETIF tSTR '{' ether_attr '}'
+ { if ($5) {
+ $5->e_if = $3;
+ $$ = $1; set_host($$, HF_ETHER, $5); }
+ }
+
+ | host_attr_list tCONFIG tSTR
+ { $$ = $1; set_host($$, HF_CONFIG, $3); }
+
+ | host_attr_list tARCH '=' tSTR
+ { $$ = $1; set_host($$, HF_ARCH, $4); }
+
+ | host_attr_list tOS '=' tSTR
+ { $$ = $1; set_host($$, HF_OS, $4); }
+
+ | host_attr_list tCLUSTER '=' tSTR
+ { $$ = $1; set_host($$, HF_CLUSTER, $4); }
+
+ | host_attr_list error '=' tSTR
+ { yyerror("unknown host attribute"); }
+ ;
+
+ether_attr :
+ /* empty */
+ { $$ = new_ether_if(); }
+
+ | ether_attr tINADDR '=' tSTR
+ { $$ = $1; set_ether_if($$, EF_INADDR, $4); }
+ | ether_attr tNETMASK '=' tSTR
+ { $$ = $1; set_ether_if($$, EF_NETMASK, $4); }
+ | ether_attr tHWADDR '=' tSTR
+ { $$ = $1; set_ether_if($$, EF_HWADDR, $4); }
+ ;
+
+/*
+ * A new automount tree:
+ *
+ * automount /mountpoint { ... }
+ */
+automount :
+ tAUTOMOUNT opt_auto_opts automount_tree
+ { if ($3) {
+ $$ = new_auto_tree($2, $3);
+ } else {
+ $$ = 0;
+ }
+ }
+
+ | tAUTOMOUNT error
+ { $$ = 0; }
+ ;
+
+opt_auto_opts :
+ /* empty */
+ { $$ = strdup(""); }
+
+ | tOPTS tSTR
+ { $$ = $2; }
+ ;
+
+list_of_filesystems :
+ /* empty */
+ { $$ = 0; }
+
+ | list_of_filesystems filesystem
+ { if ($2) {
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&$2->d_q, $$->q_back);
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+/*
+ * A new filesystem:
+ *
+ * fs /dev/whatever { ... }
+ */
+filesystem :
+ tFS tSTR '{' fs_info_list '}'
+ { $4->d_dev = $2; $$ = $4; }
+
+ | tFS error '}'
+ { $$ = (disk_fs *) 0; }
+ ;
+
+/*
+ * Per-filesystem information:
+ *
+ * fstype - the type of the filesystem (4.2, nfs, swap, export)
+ * opts - the mount options ("rw,grpid")
+ * passno - fsck pass number
+ * freq - dump frequency
+ * dumpset - tape set for filesystem dumps
+ * mount - where to mount this filesystem
+ * log - log device
+ */
+fs_info_list :
+ /* empty */
+ { $$ = new_disk_fs(); }
+
+ | fs_info_list tFSTYPE '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_FSTYPE, $4); }
+
+ | fs_info_list tOPTS '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_OPTS, $4); }
+
+ | fs_info_list tPASSNO '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_PASSNO, $4); }
+
+ | fs_info_list tFREQ '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_FREQ, $4); }
+
+ | fs_info_list tMOUNT dir_tree
+ { $$ = $1; set_disk_fs($$, DF_MOUNT, (char *) $3); }
+
+ | fs_info_list tDUMPSET '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_DUMPSET, $4); }
+
+ | fs_info_list tLOG '=' tSTR
+ { $$ = $1; set_disk_fs($$, DF_LOG, $4); }
+
+ | fs_info_list error '=' tSTR
+ { yyerror("unknown filesystem attribute"); }
+ ;
+
+/*
+ * An automount tree:
+ *
+ * name = "volname" name is a reference to volname
+ * name -> "string" name is a link to "string"
+ * name { ... } name is an automount tree
+ */
+automount_tree :
+ /* empty */
+ { $$ = 0; }
+
+ | automount_tree tSTR '=' tSTR
+ { automount *a = new_automount($2);
+ a->a_volname = $4;
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&a->a_q, $$->q_back);
+ }
+
+ | automount_tree tSTR tEQ tSTR
+ { automount *a = new_automount($2);
+ a->a_symlink = $4;
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&a->a_q, $$->q_back);
+ }
+
+ | automount_tree tSTR '{' automount_tree '}'
+ { automount *a = new_automount($2);
+ a->a_mount = $4;
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&a->a_q, $$->q_back);
+ }
+ ;
+
+dir_tree :
+ /* empty */
+ { $$ = 0; }
+
+ | dir_tree tSTR '{' dir_tree_info dir_tree '}'
+ { $4->m_mount = $5;
+ $4->m_name = $2;
+ if ($2[0] != '/' && $2[1] && strchr($2+1, '/'))
+ yyerror("not allowed '/' in a directory name");
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&$4->m_q, $$->q_back);
+ }
+ ;
+
+dir_tree_info :
+ /* empty */
+ { $$ = new_mount(); }
+
+ | dir_tree_info tEXPORTFS tSTR
+ { $$ = $1; set_mount($$, DM_EXPORTFS, $3); }
+
+ | dir_tree_info tVOLNAME tSTR
+ { $$ = $1; set_mount($$, DM_VOLNAME, $3); }
+
+ | dir_tree_info tSEL tSTR
+ { $$ = $1; set_mount($$, DM_SEL, $3); }
+
+ | dir_tree_info error '=' tSTR
+ { yyerror("unknown directory attribute"); }
+ ;
+
+/*
+ * Additional mounts on a host
+ *
+ * mount "volname" ...
+ */
+list_of_mounts :
+ /* empty */
+ { $$ = 0; }
+
+ | list_of_mounts tMOUNT tSTR localinfo_list
+ { set_fsmount($4, FM_VOLNAME, $3);
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new_que();
+ ins_que(&$4->f_q, $$->q_back);
+ }
+ ;
+
+/*
+ * Mount info:
+ *
+ * from "hostname" - obtain the object from the named host
+ * as "string" - where to mount, if different from the volname
+ * opts "string" - mount options
+ * fstype "type" - type of filesystem mount, if not nfs
+ */
+localinfo_list :
+ /* empty */
+ { $$ = new_fsmount(); }
+
+ | localinfo_list tAS tSTR
+ { $$ = $1; set_fsmount($$, FM_LOCALNAME, $3); }
+
+ | localinfo_list tFROM tSTR
+ { $$ = $1; set_fsmount($$, FM_FROM, $3); }
+
+ | localinfo_list tFSTYPE tSTR
+ { $$ = $1; set_fsmount($$, FM_FSTYPE, $3); }
+
+ | localinfo_list tOPTS tSTR
+ { $$ = $1; set_fsmount($$, FM_OPTS, $3); }
+
+ | localinfo_list error '=' tSTR
+ { yyerror("unknown mount attribute"); }
+ ;
diff --git a/usr.sbin/amd/fsinfo/fsi_lex.l b/usr.sbin/amd/fsinfo/fsi_lex.l
new file mode 100644
index 00000000000..85790561712
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_lex.l
@@ -0,0 +1,401 @@
+%{
+/*
+ * 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.
+ *
+ * from: @(#)fsi_lex.l 8.2 (Berkeley) 2/17/94
+ * $Id: fsi_lex.l,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+/*
+ * Lexical analyzer for fsinfo.
+ * TODO: Needs rewriting.
+ */
+
+static int xinput();
+static void xunput();
+
+#ifdef FLEX_SCANNER
+static int yylineno;
+/* Flex support with help from Vern Paxson <vern@helios.ee.lbl.gov> */
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ int i; \
+ for (i = 0; i < max_size; i++) { \
+ int ch = xinput(i == 0); \
+ if (ch == 0) \
+ break; \
+ buf[i] = ch; \
+ } \
+ result = i; \
+}
+
+#define INIT_STATE { \
+ switch ((yy_start - 1) / 2) { \
+ case 0: \
+ BEGIN F; \
+ break; \
+ } \
+}
+
+
+#else
+/*
+ * Using old lex...
+ */
+#undef unput
+#define unput(ch) xunput(ch)
+#undef input
+#define input() xinput(1)
+
+#define INIT_STATE { \
+ switch (yybgin - yysvec - 1) { \
+ case 0: \
+ BEGIN F; \
+ break; \
+ } \
+}
+
+#endif /* FLEX_SCANNER */
+
+#include "../fsinfo/fsinfo.h"
+#include "fsi_gram.h"
+#include <ctype.h>
+
+static char *filename;
+static char *optr;
+static char ostr[1024];
+static find_resword();
+static unsigned char ibuf[64];
+static unsigned char *iptr = ibuf;
+static int quoted;
+static int lastch, nextch = '\n';
+YYSTYPE yylval;
+
+struct r {
+ char *rw;
+ int tok;
+} rr[] = {
+ { "->", tEQ },
+ { "arch", tARCH },
+ { "as", tAS },
+ { "automount", tAUTOMOUNT },
+ { "cluster", tCLUSTER },
+ { "config", tCONFIG },
+ { "dumpset", tDUMPSET },
+ { "exportfs", tEXPORTFS },
+ { "freq", tFREQ },
+ { "from", tFROM },
+ { "fs", tFS },
+ { "fstype", tFSTYPE },
+ { "host", tHOST },
+ { "hwaddr", tHWADDR },
+ { "inaddr", tINADDR },
+ { "localhost", tLOCALHOST },
+ { "log", tLOG },
+ { "mount", tMOUNT },
+ { "netif", tNETIF },
+ { "netmask", tNETMASK },
+ { "opts", tOPTS },
+ { "os", tOS },
+ { "passno", tPASSNO },
+ { "sel", tSEL },
+ { "volname", tVOLNAME },
+ { 0, 0 },
+};
+#define NRES_WORDS (sizeof(rr)/sizeof(rr[0])-1)
+
+%}
+
+%start F Q
+
+%%
+ INIT_STATE; /* witchcraft */
+
+<F>[^ \t\n"={}]+ { return find_resword(yytext); }
+<F>[ \t] ;
+<F>"\n" { yylineno++; }
+<F>[={}] { return *yytext; }
+
+<F>\" { BEGIN Q; optr = ostr; quoted = 1; }
+<Q>\n { yylineno++; yyerror("\" expected"); BEGIN F; }
+<Q>\\b { *optr++ = '\b'; /* escape */ }
+<Q>\\t { *optr++ = '\t'; /* escape */ }
+<Q>\\\" { *optr++ = '\"'; /* escape */ }
+<Q>\\\\ { *optr++ = '\\'; /* escape */ }
+<Q>\\\n { yylineno++; /* continue */ }
+<Q>\\r { *optr++ = '\r'; /* escape */ }
+<Q>\\n { *optr++ = '\n'; /* escape */ }
+<Q>\\f { *optr++ = '\f'; /* escape */ }
+<Q>"\\ " { *optr++ = ' '; /* force space */ }
+<Q>\\. { yyerror("Unknown \\ sequence"); }
+<Q>([ \t]|"\\\n"){2,} { char *p = yytext-1; while (p = strchr(p+1, '\n')) yylineno++; }
+<Q>\" { BEGIN F; quoted = 0;
+ *optr = '\0';
+ yylval.s = strdup(ostr);
+ return tSTR;
+ }
+<Q>. { *optr++ = *yytext; }
+
+%%
+
+static int find_resword(s)
+char *s;
+{
+ int tok = 0;
+
+ int l = 0, m = NRES_WORDS/2, h = NRES_WORDS-1;
+ int rc = 0;
+
+ m = NRES_WORDS/2;
+
+#define FSTRCMP(p, q) ((*(p) == *(q)) ? strcmp((p)+1, (q)+1) : *(p) - *(q))
+
+ while ((l <= h) && (rc = FSTRCMP(s, rr[m].rw))) {
+ /*fprintf(stderr, "failed to cmp(%s, %s), %d, %d, %d\n", s, rr[m].rw, l, m, h);*/
+ if (rc < 0)
+ h = m - 1;
+ else
+ l = m + 1;
+ m = (h + l) / 2;
+ }
+
+ if (rc == 0)
+ tok = rr[m].tok;
+
+ switch (tok) {
+ case tLOCALHOST:
+ s = "${host}";
+ /* fall through... */
+ case 0:
+ yylval.s = strdup(s);
+ tok = tSTR;
+ /* fall through... */
+ default:
+ return tok;
+ }
+
+}
+
+int yyerror(s, s1, s2, s3, s4)
+char *s;
+char *s1, *s2, *s3, *s4;
+{
+ col_cleanup(0);
+ fprintf(stderr, "%s:%d: ", filename ? filename : "/dev/stdin", yylineno);
+ fprintf(stderr, s, s1, s2, s3, s4);
+ fputc('\n', stderr);
+ parse_errors++;
+}
+
+ioloc *current_location()
+{
+ ioloc *ip = ALLOC(ioloc);
+ ip->i_line = yylineno;
+ ip->i_file = filename;
+ return ip;
+}
+
+#ifdef FLEX_SCANNER
+#undef yywrap
+#endif
+
+int yywrap()
+{
+static int first = 1;
+ if (first) {
+ char prog[16*1024];
+ strcpy(prog, "for file in ");
+ while (*++g_argv) {
+ if (access(*g_argv, 4) < 0) {
+ error("\"%s\": Cannot open for reading", *g_argv);
+ file_io_errors++;
+ } else {
+ strcat(prog, *g_argv);
+ strcat(prog, " ");
+ }
+ }
+ strcat(prog, "; do /usr/bin/cpp ");
+ strcat(prog, idvbuf);
+ strcat(prog, " -DHOSTNAME=\'");
+ strcat(prog, hostname);
+ strcat(prog, "\' \"$file\"; done");
+ yyin = popen(prog, "r");
+ if (yyin) {
+ /*if (filename) free(filename);*/
+ filename = strdup("unknown");
+ yylineno = 1;
+ first = 0;
+ return 0;
+ } else {
+ perror(prog);
+ }
+ }
+
+ if (!first && yyin && pclose(yyin) != 0)
+ parse_errors++;
+
+ return 1;
+}
+
+#define xgetc(fp) ((iptr > ibuf) ? (*--iptr) : (lastch = nextch, nextch = getc(fp), (nextch == EOF ? nextch = lastch, EOF : nextch)))
+
+static int xinput(need)
+int need;
+{
+static int c_comment = 0;
+ int ch, ch2;
+
+ do {
+ ch = xgetc(yyin);
+ /* fprintf(stderr, "ch = %c, %#x, %d\n", ch, ibuf,iptr-ibuf); */
+ if (ch == EOF) return 0;
+ if (quoted)
+ return ch;
+ if (c_comment) {
+ ch2 = ch;
+ do {
+ if (ch2 == '\n') {
+ nextch = '\n';
+ return ch2;
+ }
+ /* C style comment */
+ do {
+ ch2 = getc(yyin);
+ if (ch2 == '\n') {
+ nextch = '\n';
+ return ch2;
+ }
+ } while (ch2 != '*' && ch2 != EOF);
+
+ while (ch2 == '*')
+ ch2 = getc(yyin);
+ } while (ch2 != '/' && ch2 != EOF);
+ c_comment = 0;
+ if (ch2 == EOF)
+ break;
+ continue;
+ }
+
+ if (ch == '#') {
+ /*log("lastch = '%c' (%#x)", lastch, lastch);*/
+ if (lastch == '\n') {
+ char fname[MAXPATHLEN];
+ char *fptr;
+ if (!need) {
+ xunput('#');
+ nextch = '\n';
+ return 0;
+ }
+ fname[0] = '\0';
+ /* Skip past space */
+ do {
+ ch2 = getc(yyin);
+ } while (ch2 != EOF && ch2 != '\n' && !isdigit(ch2));
+ if (isdigit(ch2)) {
+ /* Read in line number */
+ fptr = fname;
+ do {
+ *fptr++ = ch2;
+ ch2 = getc(yyin);
+ } while (isdigit(ch2));
+ *fptr = '\0';
+ if (fptr != fname)
+ yylineno = atoi(fname) - 1;
+ }
+ /* Skip past space */
+ while (ch2 != EOF && ch2 != '\"' && ch2 != '\n')
+ ch2 = getc(yyin);
+ if (ch2 == '\"') {
+ /* Read file name */
+ fptr = fname;
+ ch2 = getc(yyin);
+ while (ch2 != '\"' && ch2 != EOF && ch2 != EOF) {
+ *fptr++ = ch2;
+ ch2 = getc(yyin);
+ }
+ *fptr = '\0';
+ if (fname[0]) {
+ log("Setting filename to \"%s\"", fname);
+ /*if (filename) free(filename);*/
+ filename = strdup(fname);
+ }
+ }
+ while (ch2 != '\n' && ch2 != EOF)
+ ch2 = getc(yyin);
+ } else do {
+ ch2 = getc(yyin);
+ } while (ch2 != '\n' && ch2 != EOF);
+ if (ch2 == '\n') {
+ nextch = '\n';
+ return ch2;
+ }
+ } else if (ch == '/') {
+ ch2 = getc(yyin);
+ if (ch2 == '/') {
+ /* C++ style comment */
+ do {
+ ch2 = getc(yyin);
+ } while (ch2 != '\n' && ch2 != EOF);
+ if (ch2 == '\n') {
+ nextch = '\n';
+ return ch2;
+ }
+ } else if (ch2 == '*') {
+ c_comment = 1;
+ continue;
+ } else {
+ xunput(ch2);
+ return ch;
+ }
+ } else {
+ return ch;
+ }
+ } while (ch2 != EOF);
+ error("End of file within comment");
+ return 0;
+}
+
+static void xunput(c)
+int c;
+{
+ if (c && c != EOF) {
+ if (iptr == ibuf + sizeof(ibuf) - 1)
+ fatal("Out of space in lexical pushback");
+ *iptr++ = c;
+ }
+}
diff --git a/usr.sbin/amd/fsinfo/fsi_util.c b/usr.sbin/amd/fsinfo/fsi_util.c
new file mode 100644
index 00000000000..df1bfdb59d3
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_util.c
@@ -0,0 +1,569 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ * from: @(#)fsi_util.c 8.1 (Berkeley) 6/6/93
+ * $Id: fsi_util.c,v 1.1.1.1 1995/10/18 08:47:18 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+/*
+ * Lots of ways of reporting errors...
+ */
+void error(s, s1, s2, s3, s4)
+char *s, *s1, *s2, *s3, *s4;
+{
+ col_cleanup(0);
+ fprintf(stderr, "%s: Error, ", progname);
+ fprintf(stderr, s, s1, s2, s3, s4);
+ fputc('\n', stderr);
+ errors++;
+}
+
+void lerror(l, s, s1, s2, s3, s4)
+ioloc *l;
+char *s, *s1, *s2, *s3, *s4;
+{
+ col_cleanup(0);
+ fprintf(stderr, "%s:%d: ", l->i_file, l->i_line);
+ fprintf(stderr, s, s1, s2, s3, s4);
+ fputc('\n', stderr);
+ errors++;
+}
+
+void lwarning(l, s, s1, s2, s3, s4)
+ioloc *l;
+char *s, *s1, *s2, *s3, *s4;
+{
+ col_cleanup(0);
+ fprintf(stderr, "%s:%d: ", l->i_file, l->i_line);
+ fprintf(stderr, s, s1, s2, s3, s4);
+ fputc('\n', stderr);
+
+}
+
+void fatal(s, s1, s2, s3, s4)
+char *s, *s1, *s2, *s3, *s4;
+{
+ col_cleanup(1);
+ fprintf(stderr, "%s: Fatal, ", progname);
+ fprintf(stderr, s, s1, s2, s3, s4);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+/*
+ * Dup a string
+ */
+char *strdup(s)
+char *s;
+{
+ int len = strlen(s);
+ char *sp = (char *) xmalloc(len+1);
+
+ bcopy(s, sp, len);
+ sp[len] = 0;
+
+ return sp;
+}
+
+/*
+ * Debug log
+ */
+void log(s, s1, s2, s3, s4)
+char *s, *s1, *s2, *s3, *s4;
+{
+ if (verbose > 0) {
+ fputc('#', stdout);
+ fprintf(stdout, "%s: ", progname);
+ fprintf(stdout, s, s1, s2, s3, s4);
+ putc('\n', stdout);
+ }
+}
+
+void info_hdr(ef, info)
+FILE *ef;
+char *info;
+{
+ fprintf(ef, "# *** NOTE: This file contains %s info\n", info);
+}
+
+void gen_hdr(ef, hn)
+FILE *ef;
+char *hn;
+{
+ fprintf(ef, "# *** NOTE: Only for use on %s\n", hn);
+}
+
+static void make_banner(fp)
+FILE *fp;
+{
+ time_t t = time((time_t*) 0);
+ char *ctime(), *cp = ctime(&t);
+
+ fprintf(fp,
+"\
+# *** This file was automatically generated -- DO NOT EDIT HERE ***\n\
+# \"%s\" run by %s@%s on %s\
+#\n\
+",
+ progname, username, hostname, cp);
+}
+
+static int show_range = 10;
+static int col = 0;
+static int total_shown = 0;
+static int total_mmm = 8;
+
+static int col_output(len)
+int len;
+{
+ int wrapped = 0;
+ col += len;
+ if (col > 77) {
+ fputc('\n', stdout);
+ col = len;
+ wrapped = 1;
+ }
+ return wrapped;
+}
+
+static void show_total()
+{
+ if (total_mmm != -show_range+1) {
+ char n[8];
+ int len;
+ if (total_mmm < 0)
+ fputc('*', stdout);
+ sprintf(n, "%d", total_shown);
+ len = strlen(n);
+ if (col_output(len))
+ fputc(' ', stdout);
+ fputs(n, stdout); fflush(stdout);
+ total_mmm = -show_range;
+ }
+}
+
+col_cleanup(eoj)
+int eoj;
+{
+ if (verbose < 0) return;
+ if (eoj) {
+ show_total();
+ fputs(")]", stdout);
+ }
+ if (col) {
+ fputc('\n', stdout);
+ col = 0;
+ }
+}
+
+void show_new(msg)
+char *msg;
+{
+ if (verbose < 0) return;
+ total_shown++;
+ if (total_mmm > show_range) {
+ show_total();
+ } else if (total_mmm == 0) {
+ fputc('*', stdout); fflush(stdout);
+ col += 1;
+ }
+ total_mmm++;
+}
+
+void show_area_being_processed(area, n)
+char *area;
+int n;
+{
+static char *last_area = 0;
+ if (verbose < 0) return;
+ if (last_area) {
+ if (total_shown)
+ show_total();
+ fputs(")", stdout);
+ col += 1;
+ }
+ if (!last_area || strcmp(area, last_area) != 0) {
+ if (last_area) {
+ col_cleanup(0);
+ total_shown = 0;
+ total_mmm = show_range+1;
+ }
+ (void) col_output(strlen(area)+2);
+ fprintf(stdout, "[%s", area);
+ last_area = area;
+ }
+
+ fputs(" (", stdout);
+ col += 2;
+ show_range = n;
+ total_mmm = n + 1;
+
+ fflush(stdout);
+}
+
+/*
+ * Open a file with the given prefix and name
+ */
+FILE *pref_open(pref, hn, hdr, arg)
+char *pref;
+char *hn;
+void (*hdr)();
+char *arg;
+{
+ char p[MAXPATHLEN];
+ FILE *ef;
+ sprintf(p, "%s%s", pref, hn);
+ log("Writing %s info for %s to %s", pref, hn, p);
+ ef = fopen(p, "w");
+ if (ef) {
+ (*hdr)(ef, arg);
+ make_banner(ef, hn);
+ } else {
+ error("can't open %s for writing", p);
+ }
+
+ return ef;
+}
+
+int pref_close(fp)
+FILE *fp;
+{
+ return fclose(fp) == 0;
+}
+
+/*
+ * Determine where Amd would automount the host/volname pair
+ */
+void compute_automount_point(buf, hp, vn)
+char *buf;
+host *hp;
+char *vn;
+{
+#ifdef AMD_USES_HOSTPATH
+ sprintf(buf, "%s/%s%s", autodir, hp->h_hostpath, vn);
+#else
+ sprintf(buf, "%s/%s%s", autodir, hp->h_lochost, vn);
+#endif
+}
+
+char *xcalloc(i, s)
+int i;
+int s;
+{
+ char *p = (char *) calloc(i, (unsigned) s);
+ if (!p)
+ fatal("Out of memory");
+ return p;
+}
+
+char *xmalloc(i)
+int i;
+{
+ char *p = (char *) malloc(i);
+ if (!p)
+ fatal("Out of memory");
+ return p;
+}
+
+/*
+ * Data constructors..
+ */
+
+automount *new_automount(name)
+char *name;
+{
+ automount *ap = ALLOC(automount);
+ ap->a_ioloc = current_location();
+ ap->a_name = name;
+ ap->a_volname = 0;
+ ap->a_mount = 0;
+ show_new("automount");
+ return ap;
+}
+
+auto_tree *new_auto_tree(def, ap)
+char *def;
+qelem *ap;
+{
+ auto_tree *tp = ALLOC(auto_tree);
+ tp->t_ioloc = current_location();
+ tp->t_defaults = def;
+ tp->t_mount = ap;
+ show_new("auto_tree");
+ return tp;
+}
+
+host *new_host()
+{
+ host *hp = ALLOC(host);
+ hp->h_ioloc = current_location();
+ hp->h_mask = 0;
+ show_new("host");
+ return hp;
+}
+
+void set_host(hp, k, v)
+host *hp;
+int k;
+char *v;
+{
+ int m = 1 << k;
+ if (hp->h_mask & m) {
+ yyerror("host field \"%s\" already set", host_strings[k]);
+ return;
+ }
+
+ hp->h_mask |= m;
+
+ switch (k) {
+ case HF_HOST: {
+ char *p = strdup(v);
+ dict_ent *de = dict_locate(dict_of_hosts, v);
+ if (de)
+ yyerror("duplicate host %s!", v);
+ else
+ dict_add(dict_of_hosts, v, (char *) hp);
+ hp->h_hostname = v;
+ domain_strip(p, hostname);
+ if (strchr(p, '.') != 0)
+ free(p);
+ else
+ hp->h_lochost = p;
+ } break;
+ case HF_CONFIG: {
+ qelem *q;
+ qelem *vq = (qelem *) v;
+ hp->h_mask &= ~m;
+ if (hp->h_config)
+ q = hp->h_config;
+ else
+ q = hp->h_config = new_que();
+ ins_que(vq, q->q_back);
+ } break;
+ case HF_ETHER: {
+ qelem *q;
+ qelem *vq = (qelem *) v;
+ hp->h_mask &= ~m;
+ if (hp->h_ether)
+ q = hp->h_ether;
+ else
+ q = hp->h_ether = new_que();
+ ins_que(vq, q->q_back);
+ } break;
+ case HF_ARCH: hp->h_arch = v; break;
+ case HF_OS: hp->h_os = v; break;
+ case HF_CLUSTER: hp->h_cluster = v; break;
+ default: abort(); break;
+ }
+}
+
+ether_if *new_ether_if()
+{
+ ether_if *ep = ALLOC(ether_if);
+ ep->e_mask = 0;
+ ep->e_ioloc = current_location();
+ show_new("ether_if");
+ return ep;
+}
+
+void set_ether_if(ep,k, v)
+ether_if *ep;
+int k;
+char *v;
+{
+ int m = 1 << k;
+ if (ep->e_mask & m) {
+ yyerror("netif field \"%s\" already set", ether_if_strings[k]);
+ return;
+ }
+
+ ep->e_mask |= m;
+
+ switch (k) {
+ case EF_INADDR: {
+ if (inet_aton(v, &ep->e_inaddr) == 0)
+ yyerror("malformed IP dotted quad: %s", v);
+ free(v);
+ } break;
+ case EF_NETMASK: {
+ u_long nm = 0;
+ if ((sscanf(v, "0x%lx", &nm) == 1 || sscanf(v, "%lx", &nm) == 1) && nm != 0)
+ ep->e_netmask = htonl(nm);
+ else
+ yyerror("malformed netmask: %s", v);
+ free(v);
+ } break;
+ case EF_HWADDR:
+ ep->e_hwaddr = v;
+ break;
+ default: abort(); break;
+ }
+}
+
+void set_disk_fs(dp, k, v)
+disk_fs *dp;
+int k;
+char *v;
+{
+ int m = 1 << k;
+ if (dp->d_mask & m) {
+ yyerror("fs field \"%s\" already set", disk_fs_strings[k]);
+ return;
+ }
+
+ dp->d_mask |= m;
+
+ switch (k) {
+ case DF_FSTYPE: dp->d_fstype = v; break;
+ case DF_OPTS: dp->d_opts = v; break;
+ case DF_DUMPSET: dp->d_dumpset = v; break;
+ case DF_LOG: dp->d_log = v; break;
+ case DF_PASSNO: dp->d_passno = atoi(v); free(v); break;
+ case DF_FREQ: dp->d_freq = atoi(v); free(v); break;
+ case DF_MOUNT: dp->d_mount = &((mount *) v)->m_q; break;
+ default: abort(); break;
+ }
+}
+
+disk_fs *new_disk_fs()
+{
+ disk_fs *dp = ALLOC(disk_fs);
+ dp->d_ioloc = current_location();
+ show_new("disk_fs");
+ return dp;
+}
+
+void set_mount(mp, k, v)
+mount *mp;
+int k;
+char *v;
+{
+ int m = 1 << k;
+ if (mp->m_mask & m) {
+ yyerror("mount tree field \"%s\" already set", mount_strings[k]);
+ return;
+ }
+
+ mp->m_mask |= m;
+
+ switch (k) {
+ case DM_VOLNAME:
+ dict_add(dict_of_volnames, v, (char *) mp);
+ mp->m_volname = v;
+ break;
+ case DM_EXPORTFS:
+ mp->m_exportfs = v;
+ break;
+ case DM_SEL:
+ mp->m_sel = v;
+ break;
+ default: abort(); break;
+ }
+}
+
+mount *new_mount()
+{
+ mount *fp = ALLOC(mount);
+ fp->m_ioloc = current_location();
+ show_new("mount");
+ return fp;
+}
+
+void set_fsmount(fp, k, v)
+fsmount *fp;
+int k;
+char *v;
+{
+ int m = 1 << k;
+ if (fp->f_mask & m) {
+ yyerror("mount field \"%s\" already set", fsmount_strings[k]);
+ return;
+ }
+
+ fp->f_mask |= m;
+
+ switch (k) {
+ case FM_LOCALNAME: fp->f_localname = v; break;
+ case FM_VOLNAME: fp->f_volname = v; break;
+ case FM_FSTYPE: fp->f_fstype = v; break;
+ case FM_OPTS: fp->f_opts = v; break;
+ case FM_FROM: fp->f_from = v; break;
+ default: abort(); break;
+ }
+}
+
+fsmount *new_fsmount()
+{
+ fsmount *fp = ALLOC(fsmount);
+ fp->f_ioloc = current_location();
+ show_new("fsmount");
+ return fp;
+}
+
+void init_que(q)
+qelem *q;
+{
+ q->q_forw = q->q_back = q;
+}
+
+qelem *new_que()
+{
+ qelem *q = ALLOC(qelem);
+ init_que(q);
+ return q;
+}
+
+void ins_que(elem, pred)
+qelem *elem, *pred;
+{
+ qelem *p;
+ p = pred->q_forw;
+ elem->q_back = pred;
+ elem->q_forw = p;
+ pred->q_forw = elem;
+ p->q_back = elem;
+}
+
+void rem_que(elem)
+qelem *elem;
+{
+ qelem *p, *p2;
+ p = elem->q_forw;
+ p2 = elem->q_back;
+
+ p2->q_forw = p;
+ p->q_back = p2;
+}
diff --git a/usr.sbin/amd/fsinfo/fsinfo.8 b/usr.sbin/amd/fsinfo/fsinfo.8
new file mode 100644
index 00000000000..aebd841ecff
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.8
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1993 Jan-Simon Pendry.
+.\" 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.
+.\"
+.\" from: @(#)fsinfo.8 8.1 (Berkeley) 6/28/93
+.\" $Id: fsinfo.8,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+.\"
+.Dd June 28, 1993
+.Dt FSINFO 8
+.Os
+.Sh NAME
+.Nm fsinfo
+.Nd co-ordinate site-wide filesystem information
+.Sh SYNOPSIS
+.Nm \&fsinfo
+.Op Fl v
+.Op Fl a Ar autodir
+.Op Fl b Ar bootparams
+.Op Fl d Ar dumpsets
+.Op Fl e Ar exports
+.Op Fl f Ar fstabs
+.Op Fl h Ar hostname
+.Op Fl m Ar automounts
+.Op Fl I Ar dir
+.Op Fl D Ar string[=string]]
+.Op Fl U Ar string[=string]]
+.Ar config ...
+.Sh DESCRIPTION
+The
+.Nm fsinfo
+utility takes a set of system configuration information, and generates
+a co-ordinated set of
+.Xr amd ,
+.Xr mount
+and
+.Xr mountd
+configuration files.
+.Pp
+The
+.Nm fsinfo
+command is fully described in the document
+.%T "Amd - The 4.4BSD Automounter"
+.Sh "SEE ALSO"
+.Xr amd 8 ,
+.Xr mount 8 ,
+.Xr mountd 8 .
+.Sh HISTORY
+The
+.Nm fsinfo
+command first appeared in 4.4BSD.
diff --git a/usr.sbin/amd/fsinfo/fsinfo.c b/usr.sbin/amd/fsinfo/fsinfo.c
new file mode 100644
index 00000000000..02e1dfc2931
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.c
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * from: @(#)fsinfo.c 8.1 (Berkeley) 6/6/93
+ * $Id: fsinfo.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * fsinfo
+ */
+
+#include "../fsinfo/fsinfo.h"
+#include "fsi_gram.h"
+#include <pwd.h>
+
+qelem *list_of_hosts;
+qelem *list_of_automounts;
+dict *dict_of_volnames;
+dict *dict_of_hosts;
+char *autodir = "/a";
+char hostname[MAXHOSTNAMELEN+1];
+char *username;
+int file_io_errors;
+int parse_errors;
+int errors;
+int verbose;
+char idvbuf[1024];
+
+char **g_argv;
+char *progname;
+
+/*
+ * Output file prefixes
+ */
+char *exportfs_pref;
+char *fstab_pref;
+char *dumpset_pref;
+char *mount_pref;
+char *bootparams_pref;
+
+/*
+ * Argument cracking...
+ */
+static void get_args(c, v)
+int c;
+char *v[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int usage = 0;
+ char *iptr = idvbuf;
+
+ /*
+ * Determine program name
+ */
+ if (v[0]) {
+ progname = strrchr(v[0], '/');
+ if (progname && progname[1])
+ progname++;
+ else
+ progname = v[0];
+ }
+ if (!progname)
+ progname = "fsinfo";
+
+ while ((ch = getopt(c, v, "a:b:d:e:f:h:m:D:U:I:qv")) != EOF)
+ switch (ch) {
+ case 'a':
+ autodir = optarg;
+ break;
+ case 'b':
+ if (bootparams_pref)
+ fatal("-b option specified twice");
+ bootparams_pref = optarg;
+ break;
+ case 'd':
+ if (dumpset_pref)
+ fatal("-d option specified twice");
+ dumpset_pref = optarg;
+ break;
+ case 'h':
+ strncpy(hostname, optarg, sizeof(hostname)-1);
+ break;
+ case 'e':
+ if (exportfs_pref)
+ fatal("-e option specified twice");
+ exportfs_pref = optarg;
+ break;
+ case 'f':
+ if (fstab_pref)
+ fatal("-f option specified twice");
+ fstab_pref = optarg;
+ break;
+ case 'm':
+ if (mount_pref)
+ fatal("-m option specified twice");
+ mount_pref = optarg;
+ break;
+ case 'q':
+ verbose = -1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'I': case 'D': case 'U':
+ sprintf(iptr, "-%c%s ", ch, optarg);
+ iptr += strlen(iptr);
+ break;
+ default:
+ usage++;
+ break;
+ }
+
+ if (c != optind) {
+ g_argv = v + optind - 1;
+ if (yywrap())
+ fatal("Cannot read any input files");
+ } else {
+ usage++;
+ }
+
+ if (usage) {
+ fprintf(stderr,
+"\
+Usage: %s [-v] [-a autodir] [-h hostname] [-b bootparams] [-d dumpsets]\n\
+\t[-e exports] [-f fstabs] [-m automounts]\n\
+\t[-I dir] [-D|-U string[=string]] config ...\n", progname);
+ exit(1);
+ }
+
+
+ if (g_argv[0])
+ log("g_argv[0] = %s", g_argv[0]);
+ else
+ log("g_argv[0] = (nil)");
+}
+
+/*
+ * Determine username of caller
+ */
+static char *find_username()
+{
+ extern char *getlogin();
+ extern char *getenv();
+ char *u = getlogin();
+ if (!u) {
+ struct passwd *pw = getpwuid(getuid());
+ if (pw)
+ u = pw->pw_name;
+ }
+ if (!u)
+ u = getenv("USER");
+ if (!u)
+ u = getenv("LOGNAME");
+ if (!u)
+ u = "root";
+
+ return strdup(u);
+}
+
+/*
+ * MAIN
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ /*
+ * Process arguments
+ */
+ get_args(argc, argv);
+
+ /*
+ * If no hostname given then use the local name
+ */
+ if (!*hostname && gethostname(hostname, sizeof(hostname)) < 0) {
+ perror("gethostname");
+ exit(1);
+ }
+
+ /*
+ * Get the username
+ */
+ username = find_username();
+
+ /*
+ * New hosts and automounts
+ */
+ list_of_hosts = new_que();
+ list_of_automounts = new_que();
+
+ /*
+ * New dictionaries
+ */
+ dict_of_volnames = new_dict();
+ dict_of_hosts = new_dict();
+
+ /*
+ * Parse input
+ */
+ show_area_being_processed("read config", 11);
+ if (yyparse())
+ errors = 1;
+ errors += file_io_errors + parse_errors;
+
+ if (errors == 0) {
+ /*
+ * Do semantic analysis of input
+ */
+ analyze_hosts(list_of_hosts);
+ analyze_automounts(list_of_automounts);
+ }
+
+ /*
+ * Give up if errors
+ */
+ if (errors == 0) {
+ /*
+ * Output data files
+ */
+
+ write_atab(list_of_automounts);
+ write_bootparams(list_of_hosts);
+ write_dumpset(list_of_hosts);
+ write_exportfs(list_of_hosts);
+ write_fstab(list_of_hosts);
+ }
+
+ col_cleanup(1);
+
+ exit(errors);
+}
diff --git a/usr.sbin/amd/fsinfo/fsinfo.h b/usr.sbin/amd/fsinfo/fsinfo.h
new file mode 100644
index 00000000000..4c7259dcd72
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * from: @(#)fsinfo.h 8.1 (Berkeley) 6/6/93
+ * $Id: fsinfo.h,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+/*
+ * Get this in now so that OS_HDR can use it
+ */
+#ifdef __STDC__
+#define P(x) x
+#define P_void void
+#define Const const
+#else
+#define P(x) ()
+#define P_void /* as nothing */
+#define Const /* as nothing */
+#endif /* __STDC__ */
+
+#ifdef __GNUC__
+#define INLINE /* __inline */
+#else
+#define INLINE
+#endif /* __GNUC__ */
+
+/*
+ * Pick up target dependent definitions
+ */
+#include "os-defaults.h"
+#include OS_HDR
+
+#ifdef VOIDP
+typedef void *voidp;
+#else
+typedef char *voidp;
+#endif /* VOIDP */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+/*
+ * Bogosity to deal with ether { ... }
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+
+#include "fsi_data.h"
+
+extern char* strchr P((Const char*, int)); /* C */
+extern char* strrchr P((Const char*, int)); /* C */
+extern char *strdup P((char*)); /* C */
+extern void fatal();
+extern void warning();
+extern void error();
+extern void analyze_automounts P((qelem*));
+extern void analyze_hosts P((qelem*));
+extern void compute_automount_point P((char*, host*, char*));
+extern automount *new_automount P((char*));
+extern auto_tree *new_auto_tree P((char*, qelem*));
+extern host *new_host P((void));
+extern disk_fs *new_disk_fs P((void));
+extern void set_disk_fs P((disk_fs*, int, char*));
+extern ether_if *new_ether_if P((void));
+extern mount *new_mount P((void));
+extern void set_mount P((mount*, int, char*));
+extern fsmount *new_fsmount P((void));
+extern void set_fsmount P((fsmount*, int, char*));
+extern qelem *new_que P((void));
+extern void init_que P((qelem*));
+extern void ins_que P((qelem*, qelem*));
+extern void rem_que P((qelem*));
+extern dict *new_dict P((void));
+extern dict_ent *dict_locate P((dict*, char*));
+extern void dict_add P((dict*, char*, char*));
+extern int dict_iter P((dict*, int (*)()));
+extern void info_hdr();
+extern void gen_hdr();
+extern FILE *pref_open();
+extern int pref_close();
+extern ioloc *current_location();
+
+extern char *disk_fs_strings[];
+extern char *mount_strings[];
+extern char *fsmount_strings[];
+extern char *host_strings[];
+extern char *ether_if_strings[];
+extern char *autodir;
+extern char *progname;
+extern char hostname[];
+extern char *username;
+extern char **g_argv;
+extern char *fstab_pref;
+extern char *exportfs_pref;
+extern char *mount_pref;
+extern char *dumpset_pref;
+extern char *bootparams_pref;
+extern char idvbuf[];
+
+extern int file_io_errors;
+extern int parse_errors;
+extern int errors;
+extern int verbose;
+
+extern dict *dict_of_hosts;
+extern dict *dict_of_volnames;
+
+extern char *xcalloc();
+extern char *xmalloc();
+#define ALLOC(x) ((struct x *) xcalloc(1, sizeof(struct x)))
+#define STREQ(s,t) (*(s) == *(t) && strcmp((s)+1,(t)+1) == 0)
+#define ISSET(m,b) ((m) & (1<<(b)))
+#define BITSET(m,b) ((m) |= (1<<(b)))
+
+#define FIRST(ty, q) ((ty *) ((q)->q_forw))
+#define LAST(ty, q) ((ty *) ((q)->q_back))
+#define NEXT(ty, q) ((ty *) (((qelem *) q)->q_forw))
+#define HEAD(ty, q) ((ty *) q)
+#define ITER(v, ty, q) \
+ for ((v) = FIRST(ty,(q)); (v) != HEAD(ty,(q)); (v) = NEXT(ty,(v)))
diff --git a/usr.sbin/amd/fsinfo/wr_atab.c b/usr.sbin/amd/fsinfo/wr_atab.c
new file mode 100644
index 00000000000..e6e7597dd2f
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_atab.c
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ *
+ * from: @(#)wr_atab.c 8.1 (Berkeley) 6/6/93
+ * $Id: wr_atab.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+/*
+ * Write a sequence of automount mount map entries
+ */
+static int write_amount_info(af, ap, sk)
+FILE *af;
+automount *ap;
+int sk;
+{
+ int errors = 0;
+ if (ap->a_mount) {
+ /*
+ * A pseudo-directory.
+ * This can also be a top-level directory, in which
+ * case the type:=auto is not wanted...
+ *
+ * type:=auto;fs:=${map};pref:=whatever/
+ */
+ automount *ap2;
+ if (strlen(ap->a_name) > sk) {
+ fprintf(af, "%s type:=auto;fs:=${map};pref:=%s/\n",
+ ap->a_name + sk, ap->a_name + sk);
+ }
+ ITER(ap2, automount, ap->a_mount)
+ errors += write_amount_info(af, ap2, sk);
+ } else if (ap->a_mounted) {
+ /*
+ * A mounted partition
+ * type:=link [ link entries ] type:=nfs [ nfs entries ]
+ */
+ dict_data *dd;
+ dict_ent *de = ap->a_mounted;
+ int done_type_link = 0;
+ char *key = ap->a_name + sk;
+
+ /*
+ * Output the map key
+ */
+ fputs(key, af);
+
+ /*
+ * First output any Link locations that would not
+ * otherwise be correctly mounted. These refer
+ * to filesystem which are not mounted in the same
+ * place which the automounter would use.
+ */
+ ITER(dd, dict_data, &de->de_q) {
+ mount *mp = (mount *) dd->dd_data;
+ /*
+ * If the mount point and the exported volname are the
+ * same then this filesystem will be recognised by
+ * the restart code - so we don't need to put out a
+ * special rule for it.
+ */
+ if (mp->m_dk->d_host->h_lochost) {
+ char amountpt[1024];
+ compute_automount_point(amountpt, mp->m_dk->d_host, mp->m_exported->m_volname);
+ if (strcmp(mp->m_dk->d_mountpt, amountpt) != 0) {
+ /*
+ * ap->a_volname is the name of the aliased volume
+ * mp->m_name is the mount point of the filesystem
+ * mp->m_volname is the volume name of the filesystems
+ */
+
+ /*
+ * Find length of key and volume names
+ */
+ int avlen = strlen(ap->a_volname);
+ int mnlen = strlen(mp->m_volname);
+ /*
+ * Make sure a -type:=link is output once
+ */
+ if (!done_type_link) {
+ done_type_link = 1;
+ fputs(" -type:=link", af);
+ }
+ /*
+ * Output a selector for the hostname,
+ * the device from which to mount and
+ * where to mount. This will correspond
+ * to the values output for the fstab.
+ */
+ if (mp->m_dk->d_host->h_lochost)
+ fprintf(af, " host==%s", mp->m_dk->d_host->h_lochost);
+ else
+ fprintf(af, " hostd==%s", mp->m_dk->d_host->h_hostname);
+ fprintf(af, ";fs:=%s", mp->m_name);
+ /*
+ * ... and a sublink if needed
+ */
+ if (mnlen < avlen) {
+ char *sublink = ap->a_volname + mnlen + 1;
+ fprintf(af, "/%s", sublink);
+ }
+ fputs(" ||", af);
+ }
+ }
+ }
+
+ /*
+ * Next do the NFS locations
+ */
+
+ if (done_type_link)
+ fputs(" -", af);
+
+ ITER(dd, dict_data, &de->de_q) {
+ mount *mp = (mount *) dd->dd_data;
+ int namelen = mp->m_name_len;
+ int exp_namelen = mp->m_exported->m_name_len;
+ int volnlen = strlen(ap->a_volname);
+ int mvolnlen = strlen(mp->m_volname);
+ fputc(' ', af);
+#ifdef notdef
+ fprintf(af, "\\\n /* avolname = %s, mname = %s,\n * mvolname = %s, mexp_name = %s,\n * mexp_volname = %s\n */\\\n",
+ ap->a_volname, mp->m_name, mp->m_volname, mp->m_exported->m_name, mp->m_exported->m_volname);
+#endif
+ /*
+ * Output any selectors
+ */
+ if (mp->m_sel)
+ fprintf(af, "%s;", mp->m_sel);
+ /*
+ * Print host and volname of exported filesystem
+ */
+ fprintf(af, "rhost:=%s",
+ mp->m_dk->d_host->h_lochost ?
+ mp->m_dk->d_host->h_lochost :
+ mp->m_dk->d_host->h_hostname);
+ fprintf(af, ";rfs:=%s", mp->m_exported->m_volname);
+ /*
+ * Now determine whether a sublink is required.
+ */
+ if (exp_namelen < namelen || mvolnlen < volnlen) {
+ char sublink[1024];
+ sublink[0] = '\0';
+ if (exp_namelen < namelen) {
+ strcat(sublink, mp->m_name + exp_namelen + 1);
+ if (mvolnlen < volnlen)
+ strcat(sublink, "/");
+ }
+ if (mvolnlen < volnlen)
+ strcat(sublink, ap->a_volname + mvolnlen + 1);
+
+ fprintf(af, ";sublink:=%s", sublink);
+ }
+ }
+ fputc('\n', af);
+ } else if (ap->a_symlink) {
+ /*
+ * A specific link.
+ *
+ * type:=link;fs:=whatever
+ */
+ fprintf(af, "%s type:=link;fs:=%s\n", ap->a_name + sk, ap->a_symlink);
+ }
+ return errors;
+}
+
+/*
+ * Write a single automount configuration file
+ */
+static int write_amount(q, def)
+qelem *q;
+char *def;
+{
+ automount *ap;
+ int errors = 0;
+ int direct = 0;
+
+ /*
+ * Output all indirect maps
+ */
+ ITER(ap, automount, q) {
+ FILE *af;
+ char *p;
+ /*
+ * If there is no a_mount node then this is really
+ * a direct mount, so just keep a count and continue.
+ * Direct mounts are output into a special file during
+ * the second pass below.
+ */
+ if (!ap->a_mount) {
+ direct++;
+ continue;
+ }
+ p = strrchr(ap->a_name, '/');
+ if (!p) p = ap->a_name;
+ else p++;
+ af = pref_open(mount_pref, p, gen_hdr, ap->a_name);
+ if (af) {
+ show_new(ap->a_name);
+ fputs("/defaults ", af);
+ if (*def)
+ fprintf(af, "%s;", def);
+ fputs("type:=nfs\n", af);
+ errors += write_amount_info(af, ap, strlen(ap->a_name) + 1);
+ errors += pref_close(af);
+ }
+ }
+
+ /*
+ * Output any direct map entries which were found during the
+ * previous pass over the data.
+ */
+ if (direct) {
+ FILE *af = pref_open(mount_pref, "direct.map", info_hdr, "direct mount");
+ if (af) {
+ show_new("direct mounts");
+ fputs("/defaults ", af);
+ if (*def)
+ fprintf(af, "%s;", def);
+ fputs("type:=nfs\n", af);
+ ITER(ap, automount, q)
+ if (!ap->a_mount)
+ errors += write_amount_info(af, ap, 1);
+ errors += pref_close(af);
+ }
+ }
+
+ return errors;
+}
+
+/*
+ * Write all the needed automount configuration files
+ */
+write_atab(q)
+qelem *q;
+{
+ int errors = 0;
+
+ if (mount_pref) {
+ auto_tree *tp;
+ show_area_being_processed("write automount", "");
+ ITER(tp, auto_tree, q)
+ errors += write_amount(tp->t_mount, tp->t_defaults);
+ }
+
+ return errors;
+}
diff --git a/usr.sbin/amd/fsinfo/wr_bparam.c b/usr.sbin/amd/fsinfo/wr_bparam.c
new file mode 100644
index 00000000000..476c4effe71
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_bparam.c
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ * from: @(#)wr_bparam.c 8.1 (Berkeley) 6/6/93
+ * $Id: wr_bparam.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+/*
+ * Write a host/path in NFS format
+ */
+static int write_nfsname(ef, fp, hn)
+FILE *ef;
+fsmount *fp;
+char *hn;
+{
+ int errors = 0;
+ char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname);
+ domain_strip(h, hn);
+ fprintf(ef, "%s:%s", h, fp->f_volname);
+ free(h);
+ return errors;
+}
+
+/*
+ * Write a bootparams entry for a host
+ */
+static int write_boot_info(ef, hp)
+FILE *ef;
+host *hp;
+{
+ int errors = 0;
+ fprintf(ef, "%s\troot=", hp->h_hostname);
+ errors += write_nfsname(ef, hp->h_netroot, hp->h_hostname);
+ fputs(" swap=", ef);
+ errors += write_nfsname(ef, hp->h_netswap, hp->h_hostname);
+ fputs("\n", ef);
+
+ return 0;
+}
+
+/*
+ * Output a bootparams file
+ */
+int write_bootparams(q)
+qelem *q;
+{
+ int errors = 0;
+
+ if (bootparams_pref) {
+ FILE *ef = pref_open(bootparams_pref, "bootparams", info_hdr, "bootparams");
+ if (ef) {
+ host *hp;
+ ITER(hp, host, q)
+ if (hp->h_netroot && hp->h_netswap)
+ errors += write_boot_info(ef, hp);
+ errors += pref_close(ef);
+ } else {
+ errors++;
+ }
+ }
+
+ return errors;
+}
diff --git a/usr.sbin/amd/fsinfo/wr_dumpset.c b/usr.sbin/amd/fsinfo/wr_dumpset.c
new file mode 100644
index 00000000000..bb7ac8d9a09
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_dumpset.c
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ * from: @(#)wr_dumpset.c 8.1 (Berkeley) 6/6/93
+ * $Id: wr_dumpset.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+static int write_dumpset_info(ef, q)
+FILE *ef;
+qelem *q;
+{
+ int errors = 0;
+ disk_fs *dp;
+
+ ITER(dp, disk_fs, q) {
+ if (dp->d_dumpset) {
+ fprintf(ef, "%s\t%s:%-30s\t# %s\n",
+ dp->d_dumpset,
+ dp->d_host->h_lochost ?
+ dp->d_host->h_lochost :
+ dp->d_host->h_hostname,
+ dp->d_mountpt,
+ dp->d_dev);
+ }
+ }
+ return errors;
+}
+
+int write_dumpset(q)
+qelem *q;
+{
+ int errors = 0;
+
+ if (dumpset_pref) {
+ FILE *ef = pref_open(dumpset_pref, "dumpsets", info_hdr, "exabyte dumpset");
+ if (ef) {
+ host *hp;
+ ITER(hp, host, q) {
+ if (hp->h_disk_fs) {
+ errors += write_dumpset_info(ef, hp->h_disk_fs);
+ }
+ }
+ errors += pref_close(ef);
+ } else {
+ errors++;
+ }
+ }
+
+ return errors;
+}
diff --git a/usr.sbin/amd/fsinfo/wr_exportfs.c b/usr.sbin/amd/fsinfo/wr_exportfs.c
new file mode 100644
index 00000000000..6a1ba698e8a
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_exportfs.c
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * from: @(#)wr_exportfs.c 8.1 (Berkeley) 6/6/93
+ * $Id: wr_exportfs.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+static int write_export_info(ef, q, errors)
+FILE *ef;
+qelem *q;
+int errors;
+{
+ mount *mp;
+
+ ITER(mp, mount, q) {
+ if (mp->m_mask & (1<<DM_EXPORTFS))
+ fprintf(ef, "%s\t%s\n", mp->m_volname, mp->m_exportfs);
+ if (mp->m_mount)
+ errors += write_export_info(ef, mp->m_mount, 0);
+ }
+
+ return errors;
+}
+
+static int write_dkexports(ef, q)
+FILE *ef;
+qelem *q;
+{
+ int errors = 0;
+ disk_fs *dp;
+
+ ITER(dp, disk_fs, q) {
+ if (dp->d_mount)
+ errors += write_export_info(ef, dp->d_mount, 0);
+ }
+ return errors;
+}
+
+int write_exportfs(q)
+qelem *q;
+{
+ int errors = 0;
+
+ if (exportfs_pref) {
+ host *hp;
+ show_area_being_processed("write exportfs", "");
+ ITER(hp, host, q) {
+ if (hp->h_disk_fs) {
+ FILE *ef = pref_open(exportfs_pref, hp->h_hostname, gen_hdr, hp->h_hostname);
+ if (ef) {
+ show_new(hp->h_hostname);
+ errors += write_dkexports(ef, hp->h_disk_fs);
+ errors += pref_close(ef);
+ } else {
+ errors++;
+ }
+ }
+ }
+ }
+
+ return errors;
+}
diff --git a/usr.sbin/amd/fsinfo/wr_fstab.c b/usr.sbin/amd/fsinfo/wr_fstab.c
new file mode 100644
index 00000000000..36b3accb7b5
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_fstab.c
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ *
+ * from: @(#)wr_fstab.c 8.1 (Berkeley) 6/6/93
+ * $Id: wr_fstab.c,v 1.1.1.1 1995/10/18 08:47:19 deraadt Exp $
+ */
+
+#include "../fsinfo/fsinfo.h"
+
+/* ---------- AIX 1 ------------------------------ */
+
+/*
+ * AIX 1 format
+ */
+static void write_aix1_dkfstab(ef, dp)
+FILE *ef;
+disk_fs *dp;
+{
+ char *hp = strdup(dp->d_host->h_hostname);
+ char *p = strchr(hp, '.');
+ if (p)
+ *p = '\0';
+
+ fprintf(ef, "\n%s:\n\tdev = %s\n\tvfs = %s\n\ttype = %s\n\tlog = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n",
+ dp->d_mountpt,
+ dp->d_dev,
+ dp->d_fstype,
+ dp->d_fstype,
+ dp->d_log,
+ dp->d_mountpt,
+ dp->d_opts);
+ free(hp);
+}
+
+static void write_aix1_dkrmount(ef, hn, fp)
+FILE *ef;
+char *hn;
+fsmount *fp;
+{
+ char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname);
+ char *hp = strdup(h);
+ char *p = strchr(hp, '.');
+ if (p)
+ *p = '\0';
+ domain_strip(h, hn);
+ fprintf(ef, "\n%s:\n\tsite = %s\n\tdev = %s:%s\n\tvfs = %s\n\ttype = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n",
+ fp->f_localname,
+ hp,
+ h,
+ fp->f_volname,
+ fp->f_fstype,
+ fp->f_fstype,
+ fp->f_localname,
+ fp->f_opts);
+
+ free(hp);
+ free(h);
+}
+
+/* ---------- AIX 3 ------------------------------ */
+
+/*
+ * AIX 3 format
+ */
+static void write_aix3_dkfstab(ef, dp)
+FILE *ef;
+disk_fs *dp;
+{
+ if (strcmp(dp->d_fstype, "jfs") == 0 && strncmp(dp->d_dev, "/dev/", 5) == 0 && !dp->d_log)
+ error("aix 3 needs a log device for journalled filesystem (jfs) mounts");
+
+ fprintf(ef, "\n%s:\n\tdev = %s\n\tvfs = %s\n\ttype = %s\n\tlog = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n",
+ dp->d_mountpt,
+ dp->d_dev,
+ dp->d_fstype,
+ dp->d_fstype,
+ dp->d_log,
+ dp->d_mountpt,
+ dp->d_opts);
+}
+
+static void write_aix3_dkrmount(ef, hn, fp)
+FILE *ef;
+char *hn;
+fsmount *fp;
+{
+ char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname);
+ domain_strip(h, hn);
+ fprintf(ef, "\n%s:\n\tdev = %s:%s\n\tvfs = %s\n\ttype = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n",
+ fp->f_localname,
+ h,
+ fp->f_volname,
+ fp->f_fstype,
+ fp->f_fstype,
+ fp->f_localname,
+ fp->f_opts);
+
+ free(h);
+}
+
+/* ---------- Ultrix ----------------------------- */
+
+static void write_ultrix_dkfstab(ef, dp)
+FILE *ef;
+disk_fs *dp;
+{
+ fprintf(ef, "%s:%s:%s:%s:%d:%d\n",
+ dp->d_dev,
+ dp->d_mountpt,
+ dp->d_fstype,
+ dp->d_opts,
+ dp->d_freq,
+ dp->d_passno);
+}
+
+static void write_ultrix_dkrmount(ef, hn, fp)
+FILE *ef;
+char *hn;
+fsmount *fp;
+{
+ char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname);
+ domain_strip(h, hn);
+ fprintf(ef, "%s@%s:%s:%s:%s:0:0\n",
+ fp->f_volname,
+ h,
+ fp->f_localname,
+ fp->f_fstype,
+ fp->f_opts);
+ free(h);
+}
+
+/* ---------- Generic ---------------------------- */
+
+/*
+ * Generic (BSD, SunOS, HPUX) format
+ */
+static void write_generic_dkfstab(ef, dp)
+FILE *ef;
+disk_fs *dp;
+{
+ fprintf(ef, "%s %s %s %s %d %d\n",
+ dp->d_dev,
+ dp->d_mountpt,
+ dp->d_fstype,
+ dp->d_opts,
+ dp->d_freq,
+ dp->d_passno);
+}
+
+static void write_generic_dkrmount(ef, hn, fp)
+FILE *ef;
+char *hn;
+fsmount *fp;
+{
+ char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname);
+ domain_strip(h, hn);
+ fprintf(ef, "%s:%s %s %s %s 0 0\n",
+ h,
+ fp->f_volname,
+ fp->f_localname,
+ fp->f_fstype,
+ fp->f_opts);
+ free(h);
+}
+
+/* ----------------------------------------------- */
+
+static struct os_fstab_type {
+ char *os_name;
+ void (*op_fstab)();
+ void (*op_mount)();
+} os_tabs[] = {
+ { "aix1", write_aix1_dkfstab, write_aix1_dkrmount }, /* AIX 1 */
+ { "aix3", write_aix3_dkfstab, write_aix3_dkrmount }, /* AIX 3 */
+ { "generic", write_generic_dkfstab, write_generic_dkrmount }, /* Generic */
+ { "u2_0", write_ultrix_dkfstab, write_ultrix_dkrmount }, /* Ultrix */
+ { "u3_0", write_ultrix_dkfstab, write_ultrix_dkrmount }, /* Ultrix */
+ { "u4_0", write_ultrix_dkfstab, write_ultrix_dkrmount }, /* Ultrix */
+ { 0, 0, 0 }
+};
+
+#define GENERIC_OS_NAME "generic"
+
+static struct os_fstab_type *find_fstab_type(hp)
+host *hp;
+{
+ struct os_fstab_type *op = 0;
+ char *os_name = 0;
+
+again:;
+ if (os_name == 0) {
+ if (ISSET(hp->h_mask, HF_OS))
+ os_name = hp->h_os;
+ else
+ os_name = GENERIC_OS_NAME;
+ }
+
+ for (op = os_tabs; op->os_name; op++)
+ if (strcmp(os_name, op->os_name) == 0)
+ return op;
+
+ os_name = GENERIC_OS_NAME;
+ goto again;
+}
+
+static int write_dkfstab(ef, q, output)
+FILE *ef;
+qelem *q;
+void (*output)();
+{
+ int errors = 0;
+ disk_fs *dp;
+
+ ITER(dp, disk_fs, q)
+ if (strcmp(dp->d_fstype, "export") != 0)
+ (*output)(ef, dp);
+
+ return errors;
+}
+
+static int write_dkrmount(ef, q, hn, output)
+FILE *ef;
+qelem *q;
+char *hn;
+void (*output)();
+{
+ int errors = 0;
+ fsmount *fp;
+
+ ITER(fp, fsmount, q)
+ (*output)(ef, hn, fp);
+
+ return errors;
+}
+
+int write_fstab(q)
+qelem *q;
+{
+ int errors = 0;
+
+ if (fstab_pref) {
+ host *hp;
+ show_area_being_processed("write fstab", 4);
+ ITER(hp, host, q) {
+ if (hp->h_disk_fs || hp->h_mount) {
+ FILE *ef = pref_open(fstab_pref, hp->h_hostname, gen_hdr, hp->h_hostname);
+ if (ef) {
+ struct os_fstab_type *op = find_fstab_type(hp);
+ show_new(hp->h_hostname);
+ if (hp->h_disk_fs)
+ errors += write_dkfstab(ef, hp->h_disk_fs, op->op_fstab);
+ else
+ log("No local disk mounts on %s", hp->h_hostname);
+
+ if (hp->h_mount)
+ errors += write_dkrmount(ef, hp->h_mount, hp->h_hostname, op->op_mount);
+
+ pref_close(ef);
+ }
+ } else {
+ error("no disk mounts on %s", hp->h_hostname);
+ }
+ }
+ }
+
+ return errors;
+}
diff --git a/usr.sbin/amd/include/am.h b/usr.sbin/amd/include/am.h
new file mode 100644
index 00000000000..7d6b5b6ba1b
--- /dev/null
+++ b/usr.sbin/amd/include/am.h
@@ -0,0 +1,566 @@
+/*
+ * 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.
+ *
+ * from: @(#)am.h 5.6 (Berkeley) 6/6/93
+ * $Id: am.h,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+ *
+ */
+
+#include "config.h"
+
+/*
+ * Global declarations
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include "nfs_prot.h"
+#ifdef MNTENT_HDR
+#include MNTENT_HDR
+#endif /* MNTENT_HDR */
+#include <assert.h>
+
+#ifdef DEBUG_MEM
+#include <malloc.h>
+#endif /* DEBUG_MEM */
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif /* MAXHOSTNAMELEN */
+
+#ifndef MNTTYPE_AUTO
+#define MNTTYPE_AUTO "auto"
+#endif /* MNTTYPE_AUTO */
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif /* FALSE */
+
+#ifndef ROOT_MAP
+#define ROOT_MAP "\"root\""
+#endif /* ROOT_MAP */
+
+/*
+ * Flags from command line
+ */
+extern int print_pid; /* Print pid to stdout */
+extern int normalize_hosts; /* Normalize host names before use */
+extern int restart_existing_mounts;
+#ifdef HAS_NIS_MAPS
+extern char *domain; /* NIS domain to use */
+#endif /* HAS_NIS_MAPS */
+extern int am_timeo; /* Cache period */
+extern int afs_timeo; /* AFS timeout */
+extern int afs_retrans; /* AFS retrans */
+extern int am_timeo_w; /* Unmount timeout */
+extern char *mtab; /* Mount table */
+
+typedef enum {
+ Start,
+ Run,
+ Finishing,
+ Quit,
+ Done
+} serv_state;
+
+extern serv_state amd_state; /* Should we go now */
+extern int immediate_abort; /* Should close-down unmounts be retried */
+extern time_t do_mapc_reload; /* Flush & reload mount map cache */
+
+/*
+ * Useful constants
+ */
+extern char pid_fsname[]; /* kiska.southseas.nz:(pid%d) */
+extern char hostd[]; /* "kiska.southseas.nz" */
+extern char *hostdomain; /* "southseas.nz" */
+extern char *op_sys; /* "sos4" */
+extern char *arch; /* "sun4" */
+extern char *karch; /* "sun4c" */
+extern char *cluster; /* "r+d-kluster" */
+extern char *endian; /* "big" */
+extern char *auto_dir; /* "/a" */
+extern char copyright[]; /* Copyright info */
+extern char version[]; /* Version info */
+
+typedef struct am_ops am_ops;
+typedef struct am_node am_node;
+typedef struct am_opts am_opts;
+typedef struct mntfs mntfs;
+typedef struct fserver fserver;
+typedef struct fsrvinfo fsrvinfo;
+
+/*
+ * Debug defns.
+ */
+#ifdef DEBUG
+#define DEBUG_MTAB "./mtab"
+
+extern int debug_flags; /* Debug options */
+
+#define D_DAEMON 0x0001 /* Enter daemon mode */
+#define D_TRACE 0x0002 /* Do protocol trace */
+#define D_FULL 0x0004 /* Do full trace */
+#define D_MTAB 0x0008 /* Use local mtab */
+#define D_AMQ 0x0010 /* Register amq program */
+#define D_STR 0x0020 /* Debug string munging */
+#define D_MEM 0x0040 /* Trace memory allocations */
+
+/*
+ * Normally, don't enter daemon mode, and don't register amq
+ */
+#define D_TEST (~(D_DAEMON|D_MEM|D_STR))
+#endif /* DEBUG */
+
+/*
+ * Global variables.
+ */
+extern unsigned short nfs_port; /* Our NFS service port */
+extern struct in_addr myipaddr; /* (An) IP address of this host */
+
+extern int foreground; /* Foreground process */
+extern time_t next_softclock; /* Time to call softclock() */
+extern int task_notify_todo; /* Task notifier needs running */
+#ifdef HAS_TFS
+extern int nfs_server_code_available;
+#endif /* HAS_TFS */
+extern int last_used_map; /* Last map being used for mounts */
+extern AUTH *nfs_auth; /* Dummy uthorisation for remote servers */
+extern am_node **exported_ap; /* List of nodes */
+extern int first_free_map; /* First free node */
+extern am_node *root_node; /* Node for "root" */
+extern char *wire; /* Name of primary connected network */
+#define NEXP_AP (254)
+#define NEXP_AP_MARGIN (128)
+
+typedef int (*task_fun)P((voidp));
+typedef void (*cb_fun)P((int, int, voidp));
+typedef void (*fwd_fun)P((voidp, int, struct sockaddr_in *,
+ struct sockaddr_in *, voidp, int));
+
+/*
+ * String comparison macros
+ */
+#define STREQ(s1, s2) (strcmp((s1), (s2)) == 0)
+#define FSTREQ(s1, s2) ((*(s1) == *(s2)) && STREQ((s1),(s2)))
+
+/*
+ * Linked list
+ */
+typedef struct qelem qelem;
+struct qelem {
+ qelem *q_forw;
+ qelem *q_back;
+};
+#define FIRST(ty, q) ((ty *) ((q)->q_forw))
+#define LAST(ty, q) ((ty *) ((q)->q_back))
+#define NEXT(ty, q) ((ty *) (((qelem *) q)->q_forw))
+#define PREV(ty, q) ((ty *) (((qelem *) q)->q_back))
+#define HEAD(ty, q) ((ty *) q)
+#define ITER(v, ty, q) \
+ for ((v) = FIRST(ty,(q)); (v) != HEAD(ty,(q)); (v) = NEXT(ty,(v)))
+
+/*
+ * List of mount table entries
+ */
+typedef struct mntlist mntlist;
+struct mntlist {
+ struct mntlist *mnext;
+ struct mntent *mnt;
+};
+
+/*
+ * Mount map
+ */
+typedef struct mnt_map mnt_map;
+
+/*
+ * Global routines
+ */
+extern int atoi P((Const char *)); /* C */
+extern void am_mounted P((am_node*));
+extern void am_unmounted P((am_node*));
+extern int background(P_void);
+extern int bind_resv_port P((int, unsigned short*));
+extern int compute_mount_flags P((struct mntent *));
+extern int softclock(P_void);
+#ifdef DEBUG
+extern int debug_option P((char*));
+#endif /* DEBUG */
+extern void deslashify P((char*));
+/*extern void domain_strip P((char*, char*));*/
+extern mntfs* dup_mntfs P((mntfs*));
+extern fserver* dup_srvr P((fserver*));
+extern int eval_fs_opts P((am_opts*, char*, char*, char*, char*, char*));
+extern char* expand_key P((char*));
+extern am_node* exported_ap_alloc(P_void);
+extern am_node* find_ap P((char*));
+extern am_node* find_mf P((mntfs*));
+extern mntfs* find_mntfs P((am_ops*, am_opts*, char*, char*, char*, char*, char*));
+extern void flush_mntfs(P_void);
+extern void flush_nfs_fhandle_cache P((fserver*));
+extern void forcibly_timeout_mp P((am_node*));
+extern FREE_RETURN_TYPE free P((voidp)); /* C */
+extern void free_mntfs P((mntfs*));
+extern void free_opts P((am_opts*));
+extern void free_map P((am_node*));
+extern void free_mntlist P((mntlist*));
+extern void free_srvr P((fserver*));
+extern int fwd_init(P_void);
+extern int fwd_packet P((int, voidp, int, struct sockaddr_in *,
+ struct sockaddr_in *, voidp, fwd_fun));
+extern void fwd_reply(P_void);
+extern void get_args P((int, char*[]));
+extern char *getwire P((void));
+#ifdef NEED_MNTOPT_PARSER
+extern char *hasmntopt P((struct mntent*, char*));
+#endif /* NEED_MNTOPT_PARSER */
+extern int hasmntval P((struct mntent*, char*));
+extern void host_normalize P((char **));
+extern char *inet_dquad P((char*, unsigned long));
+extern void init_map P((am_node*, char*));
+extern void insert_am P((am_node*, am_node*));
+extern void ins_que P((qelem*, qelem*));
+extern int islocalnet P((unsigned long));
+extern int make_nfs_auth P((void));
+extern void make_root_node(P_void);
+extern int make_rpc_packet P((char*, int, u_long, struct rpc_msg*, voidp, xdrproc_t, AUTH*));
+extern void map_flush_srvr P((fserver*));
+extern void mapc_add_kv P((mnt_map*, char*, char*));
+extern mnt_map* mapc_find P((char*, char*));
+extern void mapc_free P((mnt_map*));
+extern int mapc_keyiter P((mnt_map*, void (*)(char*,voidp), voidp));
+extern int mapc_search P((mnt_map*, char*, char**));
+extern void mapc_reload(P_void);
+extern void mapc_showtypes P((FILE*));
+extern int mkdirs P((char*, int));
+extern void mk_fattr P((am_node*, enum ftype));
+extern void mnt_free P((struct mntent*));
+extern int mount_auto_node P((char*, voidp));
+extern int mount_automounter P((int));
+extern int mount_exported(P_void);
+extern int mount_fs P((struct mntent*, int, caddr_t, int, MTYPE_TYPE));
+/*extern int mount_nfs_fh P((struct fhstatus*, char*, char*, char*, mntfs*));*/
+extern int mount_node P((am_node*));
+extern mntfs* new_mntfs(P_void);
+extern void new_ttl P((am_node*));
+extern am_node* next_map P((int*));
+extern int nfs_srvr_port P((fserver*, u_short*, voidp));
+extern void normalize_slash P((char*));
+extern void ops_showfstypes P((FILE*));
+extern int pickup_rpc_reply P((voidp, int, voidp, xdrproc_t));
+extern mntlist* read_mtab P((char*));
+extern mntfs* realloc_mntfs P((mntfs*, am_ops*, am_opts*, char*, char*, char*, char*, char*));
+extern void rem_que P((qelem*));
+extern void reschedule_timeout_mp(P_void);
+extern void restart(P_void);
+#ifdef UPDATE_MTAB
+extern void rewrite_mtab P((mntlist *));
+#endif /* UPDATE_MTAB */
+extern void rmdirs P((char*));
+extern am_node* root_ap P((char*, int));
+extern int root_keyiter P((void (*)(char*,voidp), voidp));
+extern void root_newmap P((char*, char*, char*));
+extern void rpc_msg_init P((struct rpc_msg*, u_long, u_long, u_long));
+extern void run_task P((task_fun, voidp, cb_fun, voidp));
+extern void sched_task P((cb_fun, voidp, voidp));
+extern void show_rcs_info P((Const char*, char*));
+extern void sigchld P((int));
+extern void srvrlog P((fserver*, char*));
+extern char* str3cat P((char*, char*, char*, char*));
+extern char* strcat P((char*, Const char*)); /* C */
+extern int strcmp P((Const char*, Const char*)); /* C */
+extern char* strdup P((Const char*));
+extern int strlen P((Const char*)); /* C */
+extern char* strnsave P((Const char*, int));
+extern char* strrchr P((Const char*, int)); /* C */
+extern char* strealloc P((char*, char *));
+extern char** strsplit P((char*, int, int));
+extern int switch_option P((char*));
+extern int switch_to_logfile P((char*));
+extern void do_task_notify(P_void);
+extern int timeout P((unsigned int, void (*fn)(), voidp));
+extern void timeout_mp(P_void);
+extern void umount_exported(P_void);
+extern int umount_fs P((char*));
+/*extern int unmount_node P((am_node*));
+extern int unmount_node_wrap P((voidp));*/
+extern void unregister_amq(P_void);
+extern void untimeout P((int));
+extern int valid_key P((char*));
+extern void wakeup P((voidp));
+extern void wakeup_task P((int,int,voidp));
+extern void wakeup_srvr P((fserver*));
+extern void write_mntent P((struct mntent*));
+#ifdef UPDATE_MTAB
+extern void unlock_mntlist P((void));
+#else
+#define unlock_mntlist()
+#endif /* UPDATE_MTAB */
+
+
+#define ALLOC(ty) ((struct ty *) xmalloc(sizeof(struct ty)))
+
+/*
+ * Options
+ */
+struct am_opts {
+ char *fs_glob; /* Smashed copy of global options */
+ char *fs_local; /* Expanded copy of local options */
+ char *fs_mtab; /* Mount table entry */
+ /* Other options ... */
+ char *opt_dev;
+ char *opt_delay;
+ char *opt_dir;
+ char *opt_fs;
+ char *opt_group;
+ char *opt_mount;
+ char *opt_opts;
+ char *opt_remopts;
+ char *opt_pref;
+ char *opt_cache;
+ char *opt_rfs;
+ char *opt_rhost;
+ char *opt_sublink;
+ char *opt_type;
+ char *opt_unmount;
+ char *opt_user;
+};
+
+/*
+ * File Handle
+ *
+ * This is interpreted by indexing the exported array
+ * by fhh_id.
+ *
+ * The whole structure is mapped onto a standard fhandle_t
+ * when transmitted.
+ */
+struct am_fh {
+ int fhh_pid; /* process id */
+ int fhh_id; /* map id */
+ int fhh_gen; /* generation number */
+};
+
+extern am_node *fh_to_mp P((nfs_fh*));
+extern am_node *fh_to_mp3 P((nfs_fh*,int*,int));
+extern void mp_to_fh P((am_node*, nfs_fh*));
+#define fh_to_mp2(fhp, rp) fh_to_mp3(fhp, rp, VLOOK_CREATE)
+extern int auto_fmount P((am_node *mp));
+extern int auto_fumount P((am_node *mp));
+
+#define MAX_READDIR_ENTRIES 16
+
+typedef char* (*vfs_match)P((am_opts*));
+typedef int (*vfs_init)P((mntfs*));
+typedef int (*vmount_fs)P((am_node*));
+typedef int (*vfmount_fs)P((mntfs*));
+typedef int (*vumount_fs)P((am_node*));
+typedef int (*vfumount_fs)P((mntfs*));
+typedef am_node*(*vlookuppn)P((am_node*, char*, int*, int));
+typedef int (*vreaddir)P((am_node*, nfscookie, dirlist*, entry*, int));
+typedef am_node*(*vreadlink)P((am_node*, int*));
+typedef void (*vmounted)P((mntfs*));
+typedef void (*vumounted)P((am_node*));
+typedef fserver*(*vffserver)P((mntfs*));
+
+struct am_ops {
+ char *fs_type;
+ vfs_match fs_match;
+ vfs_init fs_init;
+ vmount_fs mount_fs;
+ vfmount_fs fmount_fs;
+ vumount_fs umount_fs;
+ vfumount_fs fumount_fs;
+ vlookuppn lookuppn;
+ vreaddir readdir;
+ vreadlink readlink;
+ vmounted mounted;
+ vumounted umounted;
+ vffserver ffserver;
+ int fs_flags;
+};
+extern am_node *efs_lookuppn P((am_node*, char*, int*, int));
+extern int efs_readdir P((am_node*, nfscookie, dirlist*, entry*, int));
+
+#define VLOOK_CREATE 0x1
+#define VLOOK_DELETE 0x2
+
+#define FS_DIRECTORY 0x0001 /* This looks like a dir, not a link */
+#define FS_MBACKGROUND 0x0002 /* Should background this mount */
+#define FS_NOTIMEOUT 0x0004 /* Don't bother with timeouts */
+#define FS_MKMNT 0x0008 /* Need to make the mount point */
+#define FS_UBACKGROUND 0x0010 /* Unmount in background */
+#define FS_BACKGROUND (FS_MBACKGROUND|FS_UBACKGROUND)
+#define FS_DISCARD 0x0020 /* Discard immediately on last reference */
+#define FS_AMQINFO 0x0040 /* Amq is interested in this fs type */
+
+#ifdef SUNOS4_COMPAT
+extern am_ops *sunos4_match P((am_opts*, char*, char*, char*, char*, char*));
+#endif /* SUNOS4_COMPAT */
+extern am_ops *ops_match P((am_opts*, char*, char*, char*, char*, char*));
+#include "fstype.h"
+
+/*
+ * Per-mountpoint statistics
+ */
+struct am_stats {
+ time_t s_mtime; /* Mount time */
+ u_short s_uid; /* Uid of mounter */
+ int s_getattr; /* Count of getattrs */
+ int s_lookup; /* Count of lookups */
+ int s_readdir; /* Count of readdirs */
+ int s_readlink; /* Count of readlinks */
+ int s_statfs; /* Count of statfs */
+};
+typedef struct am_stats am_stats;
+
+/*
+ * System statistics
+ */
+struct amd_stats {
+ int d_drops; /* Dropped requests */
+ int d_stale; /* Stale NFS handles */
+ int d_mok; /* Succesful mounts */
+ int d_merr; /* Failed mounts */
+ int d_uerr; /* Failed unmounts */
+};
+extern struct amd_stats amd_stats;
+
+/*
+ * List of fileservers
+ */
+struct fserver {
+ qelem fs_q; /* List of fileservers */
+ int fs_refc; /* Number of references to this node */
+ char *fs_host; /* Normalized hostname of server */
+ struct sockaddr_in *fs_ip; /* Network address of server */
+ int fs_cid; /* Callout id */
+ int fs_pinger; /* Ping (keepalive) interval */
+ int fs_flags; /* Flags */
+ char *fs_type; /* File server type */
+ voidp fs_private; /* Private data */
+ void (*fs_prfree)(); /* Free private data */
+};
+#define FSF_VALID 0x0001 /* Valid information available */
+#define FSF_DOWN 0x0002 /* This fileserver is thought to be down */
+#define FSF_ERROR 0x0004 /* Permanent error has occured */
+#define FSF_WANT 0x0008 /* Want a wakeup call */
+#define FSF_PINGING 0x0010 /* Already doing pings */
+#define FSRV_ISDOWN(fs) (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_DOWN|FSF_VALID))
+#define FSRV_ISUP(fs) (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_VALID))
+
+/*
+ * List of mounted filesystems
+ */
+struct mntfs {
+ qelem mf_q; /* List of mounted filesystems */
+ am_ops *mf_ops; /* Operations on this mountpoint */
+ am_opts *mf_fo; /* File opts */
+ char *mf_mount; /* "/a/kiska/home/kiska" */
+ char *mf_info; /* Mount info */
+ char *mf_auto; /* Automount opts */
+ char *mf_mopts; /* FS mount opts */
+ char *mf_remopts; /* Remote FS mount opts */
+ fserver *mf_server; /* File server */
+ int mf_flags; /* Flags */
+ int mf_error; /* Error code from background mount */
+ int mf_refc; /* Number of references to this node */
+ int mf_cid; /* Callout id */
+ void (*mf_prfree)(); /* Free private space */
+ voidp mf_private; /* Private - per-fs data */
+};
+
+#define MFF_MOUNTED 0x0001 /* Node is mounted */
+#define MFF_MOUNTING 0x0002 /* Mount is in progress */
+#define MFF_UNMOUNTING 0x0004 /* Unmount is in progress */
+#define MFF_RESTART 0x0008 /* Restarted node */
+#define MFF_MKMNT 0x0010 /* Delete this node's am_mount */
+#define MFF_ERROR 0x0020 /* This node failed to mount */
+#define MFF_LOGDOWN 0x0040 /* Logged that this mount is down */
+#define MFF_RSTKEEP 0x0080 /* Don't timeout this filesystem - restarted */
+#define MFF_WANTTIMO 0x0100 /* Need a timeout call when not busy */
+
+/*
+ * Map of auto-mount points.
+ */
+struct am_node {
+ int am_mapno; /* Map number */
+ mntfs *am_mnt; /* Mounted filesystem */
+ char *am_name; /* "kiska"
+ Name of this node */
+ char *am_path; /* "/home/kiska"
+ Path of this node's mount point */
+ char *am_link; /* "/a/kiska/home/kiska/this/that"
+ Link to sub-directory */
+ am_node *am_parent, /* Parent of this node */
+ *am_ysib, /* Younger sibling of this node */
+ *am_osib, /* Older sibling of this node */
+ *am_child; /* First child of this node */
+ struct attrstat am_attr; /* File attributes */
+#define am_fattr am_attr.attrstat_u.attributes
+ int am_flags; /* Boolean flags */
+ int am_error; /* Specific mount error */
+ time_t am_ttl; /* Time to live */
+ int am_timeo_w; /* Wait interval */
+ int am_timeo; /* Timeout interval */
+ unsigned int am_gen; /* Generation number */
+ char *am_pref; /* Mount info prefix */
+ am_stats am_stats; /* Statistics gathering */
+};
+
+#define AMF_NOTIMEOUT 0x0001 /* This node never times out */
+#define AMF_ROOT 0x0002 /* This is a root node */
+
+#define ONE_HOUR (60 * 60) /* One hour in seconds */
+
+/*
+ * The following values can be tuned...
+ */
+#define ALLOWED_MOUNT_TIME 40 /* 40s for a mount */
+#define AM_TTL (5 * 60) /* Default cache period */
+#define AM_TTL_W (2 * 60) /* Default unmount interval */
+#define AM_PINGER 30 /* NFS ping interval for live systems */
+#define AFS_TIMEO 8 /* Default afs timeout - .8s */
+#define AFS_RETRANS ((ALLOWED_MOUNT_TIME*10+5*afs_timeo)/afs_timeo * 2)
+ /* Default afs retrans - 1/10th seconds */
+
+#define RPC_XID_PORTMAP 0
+#define RPC_XID_MOUNTD 1
+#define RPC_XID_NFSPING 2
+#define RPC_XID_MASK (0x0f) /* 16 id's for now */
+#define MK_RPC_XID(type_id, uniq) ((type_id) | ((uniq) << 4))
diff --git a/usr.sbin/amd/include/config.h b/usr.sbin/amd/include/config.h
new file mode 100644
index 00000000000..6fad4408257
--- /dev/null
+++ b/usr.sbin/amd/include/config.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ * from: @(#)config.h 8.1 (Berkeley) 6/6/93
+ * $Id: config.h,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+ */
+
+/*
+ * Get this in now so that OS_HDR can use it
+ */
+#ifdef __STDC__
+#define P(x) x
+#define P_void void
+#define Const const
+#else
+#define P(x) ()
+#define P_void /* as nothing */
+#define Const /* as nothing */
+#endif /* __STDC__ */
+
+#ifdef __GNUC__
+#define INLINE /* __inline */
+#else
+#define INLINE
+#endif /* __GNUC__ */
+
+/*
+ * Pick up target dependent definitions
+ */
+#include "os-defaults.h"
+#include OS_HDR
+
+#ifdef VOIDP
+typedef void *voidp;
+#else
+typedef char *voidp;
+#endif /* VOIDP */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+extern int errno;
+#include <sys/time.h>
+
+#define clocktime() (clock_valid ? clock_valid : time(&clock_valid))
+extern time_t time P((time_t *));
+extern time_t clock_valid; /* Clock needs recalculating */
+
+extern char *progname; /* "amd"|"mmd" */
+extern char hostname[]; /* "kiska" */
+extern int mypid; /* Current process id */
+
+#ifdef HAS_SYSLOG
+extern int syslogging; /* Really using syslog */
+#endif /* HAS_SYSLOG */
+extern FILE *logfp; /* Log file */
+extern int xlog_level; /* Logging level */
+extern int xlog_level_init;
+
+extern int orig_umask; /* umask() on startup */
+
+#define XLOG_FATAL 0x0001
+#define XLOG_ERROR 0x0002
+#define XLOG_USER 0x0004
+#define XLOG_WARNING 0x0008
+#define XLOG_INFO 0x0010
+#define XLOG_DEBUG 0x0020
+#define XLOG_MAP 0x0040
+#define XLOG_STATS 0x0080
+
+#define XLOG_DEFSTR "all,nomap,nostats" /* Default log options */
+#define XLOG_ALL (XLOG_FATAL|XLOG_ERROR|XLOG_USER|XLOG_WARNING|XLOG_INFO|XLOG_MAP|XLOG_STATS)
+
+#ifdef DEBUG
+#define D_ALL (~0)
+
+#ifdef DEBUG_MEM
+#define free(x) xfree(__FILE__,__LINE__,x)
+#endif /* DEBUG_MEM */
+
+#define Debug(x) if (!(debug_flags & (x))) ; else
+#define dlog Debug(D_FULL) dplog
+#endif /* DEBUG */
+
+/*
+ * Option tables
+ */
+struct opt_tab {
+ char *opt;
+ int flag;
+};
+
+extern struct opt_tab xlog_opt[];
+
+extern int cmdoption P((char*, struct opt_tab*, int*));
+extern void going_down P((int));
+#ifdef DEBUG
+extern void dplog ();
+/*extern void dplog P((char*, ...));*/
+#endif /* DEBUG */
+extern void plog ();
+/*extern void plog P((int, char*, ...));*/
+extern void show_opts P((int ch, struct opt_tab*));
+extern char* strchr P((const char*, int)); /* C */
+extern voidp xmalloc P((int));
+extern voidp xrealloc P((voidp, int));
diff --git a/usr.sbin/amd/include/fstype.h b/usr.sbin/amd/include/fstype.h
new file mode 100644
index 00000000000..f5080de89fc
--- /dev/null
+++ b/usr.sbin/amd/include/fstype.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * from: @(#)fstype.h 8.1 (Berkeley) 6/6/93
+ * $Id: fstype.h,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+ *
+ */
+
+/*
+ * File system types
+ */
+
+/*
+ * Automount File System
+ */
+#define HAS_AFS
+extern am_ops afs_ops; /* Automount file system (this!) */
+extern am_ops toplvl_ops; /* Top-level automount file system */
+extern am_ops root_ops; /* Root file system */
+extern qelem afs_srvr_list;
+extern fserver *find_afs_srvr P((mntfs*));
+
+/*
+ * Direct Automount File System
+ */
+#define HAS_DFS
+extern am_ops dfs_ops; /* Direct Automount file system (this too) */
+
+/*
+ * Error File System
+ */
+#define HAS_EFS
+extern am_ops efs_ops; /* Error file system */
+
+/*
+ * Inheritance File System
+ */
+#define HAS_IFS
+extern am_ops ifs_ops; /* Inheritance file system */
+
+/*
+ * Loopback File System
+ * LOFS is optional - you can compile without it.
+ */
+#ifdef OS_HAS_LOFS
+/*
+ * Most systems can't support this, and in
+ * any case most of the functionality is
+ * available with Symlink FS. In fact,
+ * lofs_ops is not yet available.
+ */
+#define HAS_LOFS
+extern am_ops lofs_ops;
+#endif
+
+/*
+ * Netw*rk File System
+ * Good, slow, NFS.
+ * NFS host - a whole tree
+ */
+#define HAS_NFS
+#define HAS_HOST
+#define HAS_NFSX
+extern am_ops nfs_ops; /* NFS */
+extern am_ops nfsx_ops; /* NFS X */
+extern am_ops host_ops; /* NFS host */
+#ifdef HOST_EXEC
+extern char *host_helper; /* "/usr/local/etc/amd-host" */
+#endif
+extern qelem nfs_srvr_list;
+extern fserver *find_nfs_srvr P((mntfs*));
+
+/*
+ * Program File System
+ * PFS is optional - you can compile without it.
+ * This is useful for things like RVD.
+ */
+#define HAS_PFS
+extern am_ops pfs_ops; /* PFS */
+
+/*
+ * Translucent File System
+ * TFS is optional - you can compile without it.
+ * This is just plain cute.
+ */
+#ifdef notdef
+extern am_ops tfs_ops; /* TFS */
+#endif
+#undef HAS_TFS
+
+/*
+ * Un*x File System
+ * Normal local disk file system.
+ */
+#define HAS_UFS
+extern am_ops ufs_ops; /* Un*x file system */
+
+/*
+ * Symbolic-link file system
+ * A "filesystem" which is just a symbol link.
+ *
+ * sfsx also checks that the target of the link exists.
+ */
+#define HAS_SFS
+extern am_ops sfs_ops; /* Symlink FS */
+#define HAS_SFSX
+extern am_ops sfsx_ops; /* Symlink FS with existence check */
+
+/*
+ * Union file system
+ */
+#define HAS_UNION_FS
+extern am_ops union_ops; /* Union FS */
diff --git a/usr.sbin/amd/include/uwait.h b/usr.sbin/amd/include/uwait.h
new file mode 100644
index 00000000000..ea11f054114
--- /dev/null
+++ b/usr.sbin/amd/include/uwait.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * from: @(#)uwait.h 8.1 (Berkeley) 6/6/93
+ * $Id: uwait.h,v 1.1.1.1 1995/10/18 08:47:21 deraadt Exp $
+ */
+
+#if defined(mc68k) || defined(mc68000) || defined(mc68020) || defined(sparc) || defined(hp9000s300) || defined(hp9000s800)
+#define BITS_BIGENDIAN
+#endif
+#if defined(vax) || defined(i386)
+#define BITS_LITTLENDIAN
+#endif
+#if !defined BITS_BIGENDIAN && !defined BITS_LITTLENDIAN
+ #error Do not know my byte ordering
+#endif
+
+/*
+ * Structure of the information in the first word returned by both
+ * wait and wait3. If w_stopval==WSTOPPED, then the second structure
+ * describes the information returned, else the first. See WUNTRACED below.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#ifdef BITS_LITTLENDIAN
+ unsigned short w_Termsig:7; /* termination signal */
+ unsigned short w_Coredump:1; /* core dump indicator */
+ unsigned short w_Retcode:8; /* exit code if w_termsig==0 */
+#endif
+#ifdef BITS_BIGENDIAN
+ unsigned short w_Fill1:16; /* high 16 bits unused */
+ unsigned short w_Retcode:8; /* exit code if w_termsig==0 */
+ unsigned short w_Coredump:1; /* core dump indicator */
+ unsigned short w_Termsig:7; /* termination signal */
+#endif
+ } w_U;
+};
+#define w_termsig w_U.w_Termsig
+#define w_coredump w_U.w_Coredump
+#define w_retcode w_U.w_Retcode
+
+#define WIFSIGNALED(x) ((x).w_termsig != 0)
+#define WIFEXITED(x) ((x).w_termsig == 0)
diff --git a/usr.sbin/amd/maps/a_master b/usr.sbin/amd/maps/a_master
new file mode 100644
index 00000000000..2f60dde855f
--- /dev/null
+++ b/usr.sbin/amd/maps/a_master
@@ -0,0 +1,79 @@
+#machine opts info
+achilles -opts:=rw,grpid,nosuid \
+ type:=ufs;hostd==achilles.doc;dev:=/dev/xy1g \
+ type:=nfs;hostd!=achilles.doc;rhost:=achilles.doc;rfs:=/home/achilles
+#
+dougal -opts:=rw,grpid,nosuid \
+ type:=ufs;hostd==dougal.doc;dev:=/dev/dsk/1s0 \
+ type:=nfs;hostd!=dougal.doc;rhost:=dougal.doc;rfs:=/home/dougal
+#
+dylan type:=auto;fs:=${map};pref:=${key}/
+dylan/dk2 -opts:=rw,grpid,nosuid \
+ hostd==dylan.doc;type:=ufs;dev:=/dev/dsk/2s0 \
+ hostd!=dylan.doc;type:=nfs;rhost:=dylan.doc;rfs:=/home/dylan/dk2
+#
+dylan/dk3 -opts:=rw,grpid,nosuid \
+ hostd==dylan.doc;type:=ufs;dev:=/dev/dsk/3s0 \
+ hostd!=dylan.doc;type:=nfs;rhost:=dylan.doc;rfs:=/home/dylan/dk3
+#
+dylan/dk5 -opts:=rw,grpid,nosuid \
+ hostd==dylan.doc;type:=ufs;dev:=/dev/dsk/5s0 \
+ hostd!=dylan.doc;type:=nfs;rhost:=dylan.doc;rfs:=/home/dylan/dk5
+#
+ganymede -opts:=rw,grpid,nosuid \
+ hostd!=${key}.${domain};type:=nfs;rhost:=${key}.${domain};rfs:=/home/${key}
+gummo -opts:=rw,grpid,nosuid \
+ hostd!=gummo.doc;type:=nfs;rhost:=gummo.doc;rfs:=/home/gummo
+#
+# Wildcard match
+* -opts:=rw,grpid,nosuid \
+ hostd!=${key}.${domain};type:=nfs;rhost:=${key}.${domain};rfs:=/home/${key}
+#
+#
+gould -opts:=rw,grpid,nosuid \
+ hostd!=gould.doc;type:=nfs;rhost:=gould.doc;rfs:=/home/gould
+toytown -opts:=rw,grpid,nosuid \
+ hostd!=toytown.doc;type:=nfs;rhost:=toytown.doc;rfs:=/home/${key}
+zebedee -opts:=rw,grpid,nosuid \
+ hostd!=zebedee.doc;type:=nfs;rhost:=zebedee.doc;rfs:=/home/zebedee
+#
+# Should be ENOENT from mountd on toytown...
+#
+testing -opts:=rw,grpid,nosuid \
+ hostd!=toytown.doc;type:=nfs;rhost:=toytown.doc;rfs:=/this/that
+#
+# Somewhere else
+#
+pebbles -opts:=rw,grpid,nosuid \
+ hostd!=pebbles.cc;type:=nfs;rhost:=pebbles.cc;rfs:=/home/cc/pebbles
+#
+# Specify where to mount
+#
+xtoy -opts:=rw,grpid,nosuid \
+ type:=nfs;rhost:=toytown.doc;rfs:=/home/toytown;fs:=/tmp/junk99
+#
+# Links...
+#
+alink type:=link;hostd==achilles.doc;fs:=/etc
+tlink type:=link;hostd==truth.doc;fs:=/etc
+uucp type:=link;hostd==truth.doc;fs:=/etc;sublink:=uucp
+#
+# Duplicate mounts to the same place
+#
+dup1 -opts:=rw,grpid,nosuid \
+ type:=nfs;rhost:=toytown.doc;rfs:=/home/toytown;fs:=/tmp/tt-home
+dup2 -opts:=rw,grpid,nosuid \
+ type:=nfs;rhost:=ganymede.doc;rfs:=/home/ganymede;fs:=/tmp/tt-home
+#
+# Symlink
+#
+link type:=link;fs:=dylan/dk2/adh
+#
+# Program mount
+#
+exec type:=program;mount:="/bin/true false";unmount:="/bin/true true"
+#
+# Alternate mount locations.
+#
+alt -host==truth;type:=nfs;rfs:=/var/spool/mail \
+ rhost:=toytown rhost:=charm rhost:=gummo
diff --git a/usr.sbin/amd/maps/a_net b/usr.sbin/amd/maps/a_net
new file mode 100644
index 00000000000..ea2492b294b
--- /dev/null
+++ b/usr.sbin/amd/maps/a_net
@@ -0,0 +1,3 @@
+/defaults fs:=${autodir}/${rhost}/root/${rfs}
+* rhost:=${key};type=host;rfs:=/
+
diff --git a/usr.sbin/amd/mk-amd-map/Makefile b/usr.sbin/amd/mk-amd-map/Makefile
new file mode 100644
index 00000000000..94e334ce4fa
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/Makefile
@@ -0,0 +1,14 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/28/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+
+.include "../config/Makefile.config"
+
+PROG= mk-amd-map
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-DOS_HDR=\"os-${OS}.h\"
+MAN= mk-amd-map.8
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/mk-amd-map/mk-amd-map.8 b/usr.sbin/amd/mk-amd-map/mk-amd-map.8
new file mode 100644
index 00000000000..c04a88702f9
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/mk-amd-map.8
@@ -0,0 +1,60 @@
+.\" Copyright (c) 1993 Jan-Simon Pendry
+.\" 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.
+.\"
+.\" from: @(#)mk-amd-map.8 8.1 (Berkeley) 6/28/93
+.\" $Id: mk-amd-map.8,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+.\"
+.Dd "June 28, 1993"
+.Dt MK-AMD-MAP 8
+.Os BSD 4.4
+.Sh NAME
+.Nm mk-amd-map
+.Nd create database maps for Amd
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Ar mapname
+.Sh DESCRIPTION
+.Nm
+creates the database maps used by the keyed map lookups in
+.Xr amd 8 .
+It reads input from the named file
+and outputs them to a correspondingly named
+hashed database.
+.Pp
+The
+.Fl p
+option prints the map on standard output instead of generating
+a database. This is usually used to merge continuation lines
+into one physical line.
+.Sh SEE ALSO
+.Xr amd 8
diff --git a/usr.sbin/amd/mk-amd-map/mk-amd-map.c b/usr.sbin/amd/mk-amd-map/mk-amd-map.c
new file mode 100644
index 00000000000..8a68dd4e6c3
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/mk-amd-map.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 1990, 1993 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.
+ *
+ * from: @(#)mk-amd-map.c 8.1 (Berkeley) 6/28/93
+ * $Id: mk-amd-map.c,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+ */
+
+/*
+ * Convert a file map into an ndbm map
+ */
+
+#ifndef lint
+char copyright[] = "\
+@(#)Copyright (c) 1990, 1993 Jan-Simon Pendry\n\
+@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
+@(#)Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] = "$Id: mk-amd-map.c,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $";
+static char sccsid[] = "@(#)mk-amd-map.c 8.1 (Berkeley) 6/28/93";
+#endif /* not lint */
+
+#include "am.h"
+
+#ifndef SIGINT
+#include <signal.h>
+#endif
+
+#ifdef OS_HAS_NDBM
+#define HAS_DATABASE
+#include <ndbm.h>
+
+#ifdef DBM_SUFFIX
+#define USING_DB
+#endif
+
+#define create_database(name) dbm_open(name, O_RDWR|O_CREAT, 0644)
+
+static int store_data(db, k, v)
+voidp db;
+char *k, *v;
+{
+ datum key, val;
+
+ key.dptr = k; val.dptr = v;
+ key.dsize = strlen(k) + 1;
+ val.dsize = strlen(v) + 1;
+ return dbm_store((DBM *) db, key, val, DBM_INSERT);
+}
+
+#endif /* OS_HAS_NDBM */
+
+#ifdef HAS_DATABASE
+#include <fcntl.h>
+#include <ctype.h>
+
+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;
+}
+
+/*
+ * Read through a map
+ */
+static int read_file(fp, map, db)
+FILE *fp;
+char *map;
+voidp db;
+{
+ char key_val[2048];
+ int chuck = 0;
+ int line_no = 0;
+ int errs = 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') {
+ fprintf(stderr, "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, or whether
+ * the entry is a wildcard entry.
+ */
+ if (*cp)
+ *cp++ = '\0';
+ while (*cp && isascii(*cp) && isspace(*cp))
+ cp++;
+ if (*kp == '+') {
+ fprintf(stderr, "Can't interpolate %s\n", kp);
+ errs++;
+ } else if (*cp) {
+ if (db) {
+ if (store_data(db, kp, cp) < 0) {
+ fprintf(stderr, "Could store %s -> %s\n", kp, cp);
+ errs++;
+ }
+ } else {
+ printf("%s\t%s\n", kp, cp);
+ }
+ } else {
+ fprintf(stderr, "%s: line %d has no value field", map, line_no);
+ errs++;
+ }
+
+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 errs;
+}
+
+static int remove_file(f)
+char *f;
+{
+ if (unlink(f) < 0 && errno != ENOENT)
+ return -1;
+ return 0;
+}
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ FILE *mapf;
+ char *map;
+ int rc = 0;
+ DBM *mapd;
+ static char maptmp[] = "dbmXXXXXX";
+ char maptpag[16];
+ char *mappag;
+#ifndef USING_DB
+ char maptdir[16];
+ char *mapdir;
+#endif
+ int len;
+ char *sl;
+ int printit = 0;
+ int usage = 0;
+ int ch;
+ extern int optind;
+
+ while ((ch = getopt(argc, argv, "p")) != EOF)
+ switch (ch) {
+ case 'p':
+ printit = 1;
+ break;
+ default:
+ usage++;
+ break;
+ }
+
+ if (usage || optind != (argc - 1)) {
+ fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
+ exit(1);
+ }
+
+ map = argv[optind];
+ sl = strrchr(map, '/');
+ if (sl) {
+ *sl = '\0';
+ if (chdir(map) < 0) {
+ fputs("Can't chdir to ", stderr);
+ perror(map);
+ exit(1);
+ }
+ map = sl + 1;
+ }
+
+ if (!printit) {
+ len = strlen(map);
+#ifdef USING_DB
+ mappag = (char *) malloc(len + 5);
+ if (!mappag) {
+ perror("mk-amd-map: malloc");
+ exit(1);
+ }
+ mktemp(maptmp);
+ sprintf(maptpag, "%s%s", maptmp, DBM_SUFFIX);
+ if (remove_file(maptpag) < 0) {
+ fprintf(stderr, "Can't remove existing temporary file");
+ perror(maptpag);
+ exit(1);
+ }
+#else
+ mappag = (char *) malloc(len + 5);
+ mapdir = (char *) malloc(len + 5);
+ if (!mappag || !mapdir) {
+ perror("mk-amd-map: malloc");
+ exit(1);
+ }
+ mktemp(maptmp);
+ sprintf(maptpag, "%s.pag", maptmp);
+ sprintf(maptdir, "%s.dir", maptmp);
+ if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
+ fprintf(stderr, "Can't remove existing temporary files; %s and", maptpag);
+ perror(maptdir);
+ exit(1);
+ }
+#endif
+ }
+
+ mapf = fopen(map, "r");
+ if (mapf && !printit)
+ mapd = create_database(maptmp);
+ else
+ mapd = 0;
+
+#ifndef DEBUG
+ signal(SIGINT, SIG_IGN);
+#endif
+
+ if (mapd || printit) {
+ int error = read_file(mapf, map, mapd);
+ if (mapd)
+ dbm_close(mapd);
+ (void) fclose(mapf);
+ if (printit) {
+ if (error) {
+ fprintf(stderr, "Error creating ndbm map for %s\n", map);
+ rc = 1;
+ }
+ } else {
+ if (error) {
+ fprintf(stderr, "Error reading source file %s\n", map);
+ rc = 1;
+ } else {
+#ifdef USING_DB
+ sprintf(mappag, "%s%s", map, DBM_SUFFIX);
+ if (rename(maptpag, mappag) < 0) {
+ fprintf(stderr, "Couldn't rename %s to ", maptpag);
+ perror(mappag);
+ /* Throw away the temporary map */
+ unlink(maptpag);
+ rc = 1;
+ }
+#else
+ sprintf(mappag, "%s.pag", map);
+ sprintf(mapdir, "%s.dir", map);
+ if (rename(maptpag, mappag) < 0) {
+ fprintf(stderr, "Couldn't rename %s to ", maptpag);
+ perror(mappag);
+ /* Throw away the temporary map */
+ unlink(maptpag);
+ unlink(maptdir);
+ rc = 1;
+ } else if (rename(maptdir, mapdir) < 0) {
+ fprintf(stderr, "Couldn't rename %s to ", maptdir);
+ perror(mapdir);
+ /* Put the .pag file back */
+ rename(mappag, maptpag);
+ /* Throw away remaining part of original map */
+ unlink(mapdir);
+ fprintf(stderr,
+ "WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
+ map);
+ rc = 1;
+ }
+#endif
+ }
+ }
+ } else {
+ fprintf(stderr, "Can't open \"%s.{dir,pag}\" for ", map);
+ perror("writing");
+ rc = 1;
+ }
+ exit(rc);
+}
+#else
+main()
+{
+ fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
+ exit(1);
+}
+#endif /* HAS_DATABASE */
diff --git a/usr.sbin/amd/rpcx/amq.h b/usr.sbin/amd/rpcx/amq.h
new file mode 100644
index 00000000000..1db3876ce83
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq.h 8.1 (Berkeley) 6/6/93
+ * $Id: amq.h,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+ *
+ */
+
+#define AMQ_STRLEN 1024
+
+typedef char *amq_string;
+bool_t xdr_amq_string();
+
+
+typedef long *time_type;
+bool_t xdr_time_type();
+
+
+struct amq_mount_tree {
+ amq_string mt_mountinfo;
+ amq_string mt_directory;
+ amq_string mt_mountpoint;
+ amq_string mt_type;
+ time_type mt_mounttime;
+ u_short mt_mountuid;
+ int mt_getattr;
+ int mt_lookup;
+ int mt_readdir;
+ int mt_readlink;
+ int mt_statfs;
+ struct amq_mount_tree *mt_next;
+ struct amq_mount_tree *mt_child;
+};
+typedef struct amq_mount_tree amq_mount_tree;
+bool_t xdr_amq_mount_tree();
+
+
+typedef amq_mount_tree *amq_mount_tree_p;
+bool_t xdr_amq_mount_tree_p();
+
+
+struct amq_mount_info {
+ amq_string mi_type;
+ amq_string mi_mountpt;
+ amq_string mi_mountinfo;
+ amq_string mi_fserver;
+ int mi_error;
+ int mi_refc;
+ int mi_up;
+};
+typedef struct amq_mount_info amq_mount_info;
+bool_t xdr_amq_mount_info();
+
+
+typedef struct {
+ u_int amq_mount_info_list_len;
+ amq_mount_info *amq_mount_info_list_val;
+} amq_mount_info_list;
+bool_t xdr_amq_mount_info_list();
+
+
+typedef struct {
+ u_int amq_mount_tree_list_len;
+ amq_mount_tree_p *amq_mount_tree_list_val;
+} amq_mount_tree_list;
+bool_t xdr_amq_mount_tree_list();
+
+
+struct amq_mount_stats {
+ int as_drops;
+ int as_stale;
+ int as_mok;
+ int as_merr;
+ int as_uerr;
+};
+typedef struct amq_mount_stats amq_mount_stats;
+bool_t xdr_amq_mount_stats();
+
+
+enum amq_opt {
+ AMOPT_DEBUG = 0,
+ AMOPT_LOGFILE = 1,
+ AMOPT_XLOG = 2,
+ AMOPT_FLUSHMAPC = 3
+};
+typedef enum amq_opt amq_opt;
+bool_t xdr_amq_opt();
+
+
+struct amq_setopt {
+ amq_opt as_opt;
+ amq_string as_str;
+};
+typedef struct amq_setopt amq_setopt;
+bool_t xdr_amq_setopt();
+
+
+#define AMQ_PROGRAM ((u_long)300019)
+#define AMQ_VERSION ((u_long)1)
+#define AMQPROC_NULL ((u_long)0)
+extern voidp amqproc_null_1();
+#define AMQPROC_MNTTREE ((u_long)1)
+extern amq_mount_tree_p *amqproc_mnttree_1();
+#define AMQPROC_UMNT ((u_long)2)
+extern voidp amqproc_umnt_1();
+#define AMQPROC_STATS ((u_long)3)
+extern amq_mount_stats *amqproc_stats_1();
+#define AMQPROC_EXPORT ((u_long)4)
+extern amq_mount_tree_list *amqproc_export_1();
+#define AMQPROC_SETOPT ((u_long)5)
+extern int *amqproc_setopt_1();
+#define AMQPROC_GETMNTFS ((u_long)6)
+extern amq_mount_info_list *amqproc_getmntfs_1();
+#define AMQPROC_MOUNT ((u_long)7)
+extern int *amqproc_mount_1();
+#define AMQPROC_GETVERS ((u_long)8)
+extern amq_string *amqproc_getvers_1();
+
diff --git a/usr.sbin/amd/rpcx/amq.x b/usr.sbin/amd/rpcx/amq.x
new file mode 100644
index 00000000000..5334e48566f
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq.x
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq.x 8.1 (Berkeley) 6/6/93
+ * $Id: amq.x,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+ *
+ */
+
+/*
+ * Protocol description used by the amq program
+ */
+
+const AMQ_STRLEN = 1024; /* Maximum length of a pathname */
+
+/*
+ * The type dirpath is the pathname of a directory
+ */
+typedef string amq_string<AMQ_STRLEN>;
+
+/*
+ * The type time_type should correspond to the system time_t
+ */
+typedef long time_type;
+
+/*
+ * A tree of what is mounted
+ */
+struct amq_mount_tree {
+ amq_string mt_mountinfo; /* Mounted filesystem */
+ amq_string mt_directory; /* Virtual mount */
+ amq_string mt_mountpoint; /* Mount point */
+ amq_string mt_type; /* Filesystem type */
+ time_type mt_mounttime; /* Mount time */
+ u_short mt_mountuid; /* Mounter */
+ int mt_getattr; /* Count of getattrs */
+ int mt_lookup; /* Count of lookups */
+ int mt_readdir; /* Count of readdirs */
+ int mt_readlink; /* Count of readlinks */
+ int mt_statfs; /* Count of statfss */
+ amq_mount_tree *mt_next; /* Sibling mount tree */
+ amq_mount_tree *mt_child; /* Child mount tree */
+};
+typedef amq_mount_tree *amq_mount_tree_p;
+
+/*
+ * List of mounted filesystems
+ */
+struct amq_mount_info {
+ amq_string mi_type; /* Type of mount */
+ amq_string mi_mountpt; /* Mount point */
+ amq_string mi_mountinfo; /* Mount info */
+ amq_string mi_fserver; /* Fileserver */
+ int mi_error; /* Error code */
+ int mi_refc; /* References */
+ int mi_up; /* Filesystem available */
+};
+typedef amq_mount_info amq_mount_info_list<>;
+
+/*
+ * A list of mount trees
+ */
+typedef amq_mount_tree_p amq_mount_tree_list<>;
+
+/*
+ * System wide stats
+ */
+struct amq_mount_stats {
+ int as_drops; /* Dropped requests */
+ int as_stale; /* Stale NFS handles */
+ int as_mok; /* Succesful mounts */
+ int as_merr; /* Failed mounts */
+ int as_uerr; /* Failed unmounts */
+};
+
+enum amq_opt {
+ AMOPT_DEBUG=0,
+ AMOPT_LOGFILE=1,
+ AMOPT_XLOG=2,
+ AMOPT_FLUSHMAPC=3
+};
+
+struct amq_setopt {
+ amq_opt as_opt; /* Option */
+ amq_string as_str; /* String */
+};
+
+program AMQ_PROGRAM {
+ version AMQ_VERSION {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ AMQPROC_NULL(void) = 0;
+
+ /*
+ * Returned the mount tree descending from
+ * the given directory. The directory must
+ * be a top-level mount point of the automounter.
+ */
+ amq_mount_tree_p
+ AMQPROC_MNTTREE(amq_string) = 1;
+
+ /*
+ * Force a timeout unmount on the specified directory.
+ */
+ void
+ AMQPROC_UMNT(amq_string) = 2;
+
+ /*
+ * Obtain system wide statistics from the automounter
+ */
+ amq_mount_stats
+ AMQPROC_STATS(void) = 3;
+
+ /*
+ * Obtain full tree
+ */
+ amq_mount_tree_list
+ AMQPROC_EXPORT(void) = 4;
+
+ /*
+ * Control debug options.
+ * Return status:
+ * -1: debug not available
+ * 0: everything wonderful
+ * >0: number of options not recognised
+ */
+ int
+ AMQPROC_SETOPT(amq_setopt) = 5;
+
+ /*
+ * List of mounted filesystems
+ */
+ amq_mount_info_list
+ AMQPROC_GETMNTFS(void) = 6;
+
+ /*
+ * Mount a filesystem
+ */
+ int
+ AMQPROC_MOUNT(amq_string) = 7;
+
+ /*
+ * Get version info
+ */
+ amq_string
+ AMQPROC_GETVERS(void) = 8;
+ } = 1;
+} = 300019; /* Allocated by Sun, 89/8/29 */
diff --git a/usr.sbin/amd/rpcx/amq_clnt.c b/usr.sbin/amd/rpcx/amq_clnt.c
new file mode 100644
index 00000000000..3f987aa7581
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_clnt.c
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq_clnt.c 8.1 (Berkeley) 6/6/93
+ * $Id: amq_clnt.c,v 1.1.1.1 1995/10/18 08:47:22 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+#include "amq.h"
+
+static struct timeval TIMEOUT = { ALLOWED_MOUNT_TIME, 0 };
+
+voidp
+amqproc_null_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static char res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_NULL, xdr_void, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((voidp)&res);
+}
+
+
+amq_mount_tree_p *
+amqproc_mnttree_1(argp, clnt)
+ amq_string *argp;
+ CLIENT *clnt;
+{
+ static amq_mount_tree_p res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_MNTTREE, xdr_amq_string, argp, xdr_amq_mount_tree_p, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+
+voidp
+amqproc_umnt_1(argp, clnt)
+ amq_string *argp;
+ CLIENT *clnt;
+{
+ static char res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_UMNT, xdr_amq_string, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((voidp)&res);
+}
+
+
+amq_mount_stats *
+amqproc_stats_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static amq_mount_stats res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_STATS, xdr_void, argp, xdr_amq_mount_stats, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+
+amq_mount_tree_list *
+amqproc_export_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static amq_mount_tree_list res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_EXPORT, xdr_void, argp, xdr_amq_mount_tree_list, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+int *
+amqproc_setopt_1(argp, clnt)
+ amq_setopt *argp;
+ CLIENT *clnt;
+{
+ static int res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_SETOPT, xdr_amq_setopt, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+
+amq_mount_info_list *
+amqproc_getmntfs_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static amq_mount_info_list res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_GETMNTFS, xdr_void, argp, xdr_amq_mount_info_list, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+
+int *
+amqproc_mount_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static int res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_MOUNT, xdr_amq_string, argp, xdr_int, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
+
+amq_string *
+amqproc_getvers_1(argp, clnt)
+ voidp argp;
+ CLIENT *clnt;
+{
+ static amq_string res;
+
+ bzero((char *)&res, sizeof(res));
+ if (clnt_call(clnt, AMQPROC_GETVERS, xdr_void, argp, xdr_amq_string, &res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&res);
+}
+
diff --git a/usr.sbin/amd/rpcx/amq_svc.c b/usr.sbin/amd/rpcx/amq_svc.c
new file mode 100644
index 00000000000..02eaf8fc3bc
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_svc.c
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq_svc.c 8.1 (Berkeley) 6/6/93
+ * $Id: amq_svc.c,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+#include "amq.h"
+extern bool_t xdr_amq_mount_info_qelem();
+
+void
+amq_program_1(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ union {
+ amq_string amqproc_mnttree_1_arg;
+ amq_string amqproc_umnt_1_arg;
+ amq_setopt amqproc_setopt_1_arg;
+ amq_string amqproc_mount_1_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case AMQPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) amqproc_null_1;
+ break;
+
+ case AMQPROC_MNTTREE:
+ xdr_argument = xdr_amq_string;
+ xdr_result = xdr_amq_mount_tree_p;
+ local = (char *(*)()) amqproc_mnttree_1;
+ break;
+
+ case AMQPROC_UMNT:
+ xdr_argument = xdr_amq_string;
+ xdr_result = xdr_void;
+ local = (char *(*)()) amqproc_umnt_1;
+ break;
+
+ case AMQPROC_STATS:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_amq_mount_stats;
+ local = (char *(*)()) amqproc_stats_1;
+ break;
+
+ case AMQPROC_EXPORT:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_amq_mount_tree_list;
+ local = (char *(*)()) amqproc_export_1;
+ break;
+
+ case AMQPROC_SETOPT:
+ xdr_argument = xdr_amq_setopt;
+ xdr_result = xdr_int;
+ local = (char *(*)()) amqproc_setopt_1;
+ break;
+
+ case AMQPROC_GETMNTFS:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_amq_mount_info_qelem;
+ local = (char *(*)()) amqproc_getmntfs_1;
+ break;
+
+ case AMQPROC_MOUNT:
+ xdr_argument = xdr_amq_string;
+ xdr_result = xdr_int;
+ local = (char *(*)()) amqproc_mount_1;
+ break;
+
+ case AMQPROC_GETVERS:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_amq_string;
+ local = (char *(*)()) amqproc_getvers_1;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, &argument)) {
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_argument, &argument)) {
+ plog(XLOG_FATAL, "unable to free rpc arguments in amqprog_1");
+ going_down(1);
+ }
+}
+
diff --git a/usr.sbin/amd/rpcx/amq_xdr.c b/usr.sbin/amd/rpcx/amq_xdr.c
new file mode 100644
index 00000000000..8f0bbd98d0c
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_xdr.c
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ *
+ * from: @(#)amq_xdr.c 8.1 (Berkeley) 6/6/93
+ * $Id: amq_xdr.c,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+#include "amq.h"
+
+
+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_time_type(xdrs, objp)
+ XDR *xdrs;
+ time_type *objp;
+{
+ if (!xdr_long(xdrs, (long *) objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_amq_mount_tree(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ if (!xdr_amq_string(xdrs, &objp->mt_mountinfo)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mt_directory)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mt_mountpoint)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mt_type)) {
+ return (FALSE);
+ }
+ if (!xdr_time_type(xdrs, &objp->mt_mounttime)) {
+ return (FALSE);
+ }
+ if (!xdr_u_short(xdrs, &objp->mt_mountuid)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mt_getattr)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mt_lookup)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mt_readdir)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mt_readlink)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mt_statfs)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&objp->mt_next, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&objp->mt_child, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+ 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_info(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_info *objp;
+{
+ if (!xdr_amq_string(xdrs, &objp->mi_type)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mi_mountpt)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mi_mountinfo)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->mi_fserver)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mi_error)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mi_refc)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->mi_up)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+bool_t
+xdr_amq_mount_info_list(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_info_list *objp;
+{
+ if (!xdr_array(xdrs, (char **)&objp->amq_mount_info_list_val, (u_int *)&objp->amq_mount_info_list_len, ~0, sizeof(amq_mount_info), xdr_amq_mount_info)) {
+ 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_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_opt(xdrs, objp)
+ XDR *xdrs;
+ amq_opt *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_amq_setopt(xdrs, objp)
+ XDR *xdrs;
+ amq_setopt *objp;
+{
+ if (!xdr_amq_opt(xdrs, &objp->as_opt)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &objp->as_str)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
diff --git a/usr.sbin/amd/rpcx/mount.h b/usr.sbin/amd/rpcx/mount.h
new file mode 100644
index 00000000000..f7d1c71e290
--- /dev/null
+++ b/usr.sbin/amd/rpcx/mount.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount.h 8.1 (Berkeley) 6/6/93
+ * $Id: mount.h,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+bool_t xdr_fhandle();
+
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+bool_t xdr_fhstatus();
+
+
+typedef char *dirpath;
+bool_t xdr_dirpath();
+
+
+typedef char *name;
+bool_t xdr_name();
+
+
+typedef struct mountbody *mountlist;
+bool_t xdr_mountlist();
+
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+bool_t xdr_mountbody();
+
+
+typedef struct groupnode *groups;
+bool_t xdr_groups();
+
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+bool_t xdr_groupnode();
+
+
+typedef struct exportnode *exports;
+bool_t xdr_exports();
+
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+bool_t xdr_exportnode();
+
+
+#define MOUNTPROG ((u_long)100005)
+#define MOUNTVERS ((u_long)1)
+#define MOUNTPROC_NULL ((u_long)0)
+extern voidp mountproc_null_1();
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus *mountproc_mnt_1();
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist *mountproc_dump_1();
+#define MOUNTPROC_UMNT ((u_long)3)
+extern voidp mountproc_umnt_1();
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern voidp mountproc_umntall_1();
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports *mountproc_export_1();
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports *mountproc_exportall_1();
+
diff --git a/usr.sbin/amd/rpcx/mount_xdr.c b/usr.sbin/amd/rpcx/mount_xdr.c
new file mode 100644
index 00000000000..20e25931145
--- /dev/null
+++ b/usr.sbin/amd/rpcx/mount_xdr.c
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ *
+ * from: @(#)mount_xdr.c 8.1 (Berkeley) 6/6/93
+ * $Id: mount_xdr.c,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+#include "mount.h"
+
+
+bool_t
+xdr_fhandle(xdrs, objp)
+ XDR *xdrs;
+ fhandle objp;
+{
+ if (!xdr_opaque(xdrs, objp, FHSIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_fhstatus(xdrs, objp)
+ XDR *xdrs;
+ fhstatus *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->fhs_status)) {
+ return (FALSE);
+ }
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_dirpath(xdrs, objp)
+ XDR *xdrs;
+ dirpath *objp;
+{
+ if (!xdr_string(xdrs, objp, MNTPATHLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_name(xdrs, objp)
+ XDR *xdrs;
+ name *objp;
+{
+ if (!xdr_string(xdrs, objp, MNTNAMLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_mountlist(xdrs, objp)
+ XDR *xdrs;
+ mountlist *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), xdr_mountbody)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+bool_t
+xdr_mountbody(xdrs, objp)
+ XDR *xdrs;
+ mountbody *objp;
+{
+ if (!xdr_name(xdrs, &objp->ml_hostname)) {
+ return (FALSE);
+ }
+ if (!xdr_dirpath(xdrs, &objp->ml_directory)) {
+ return (FALSE);
+ }
+ if (!xdr_mountlist(xdrs, &objp->ml_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_groups(xdrs, objp)
+ XDR *xdrs;
+ groups *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), xdr_groupnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_groupnode(xdrs, objp)
+ XDR *xdrs;
+ groupnode *objp;
+{
+ if (!xdr_name(xdrs, &objp->gr_name)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->gr_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_exports(xdrs, objp)
+ XDR *xdrs;
+ exports *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), xdr_exportnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_exportnode(xdrs, objp)
+ XDR *xdrs;
+ exportnode *objp;
+{
+ if (!xdr_dirpath(xdrs, &objp->ex_dir)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->ex_groups)) {
+ return (FALSE);
+ }
+ if (!xdr_exports(xdrs, &objp->ex_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
diff --git a/usr.sbin/amd/rpcx/nfs_prot.h b/usr.sbin/amd/rpcx/nfs_prot.h
new file mode 100644
index 00000000000..9e1424a6ca8
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot.h
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfs_prot.h 8.1 (Berkeley) 6/6/93
+ * $Id: nfs_prot.h,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#define xdr_nfsstat xdr_enum
+#define xdr_ftype xdr_enum
+
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV -1
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+enum nfsstat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_WFLUSH = 99
+};
+typedef enum nfsstat nfsstat;
+bool_t xdr_nfsstat();
+
+
+enum ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+ NFSOCK = 6,
+ NFBAD = 7,
+ NFFIFO = 8
+};
+typedef enum ftype ftype;
+/* static bool_t xdr_ftype(); */
+
+
+struct nfs_fh {
+ char data[NFS_FHSIZE];
+};
+typedef struct nfs_fh nfs_fh;
+bool_t xdr_nfs_fh();
+
+
+struct nfstime {
+ u_int seconds;
+ u_int useconds;
+};
+typedef struct nfstime nfstime;
+/* static bool_t xdr_nfstime(); */
+
+
+struct fattr {
+ ftype type;
+ u_int mode;
+ u_int nlink;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ u_int blocksize;
+ u_int rdev;
+ u_int blocks;
+ u_int fsid;
+ u_int fileid;
+ nfstime atime;
+ nfstime mtime;
+ nfstime ctime;
+};
+typedef struct fattr fattr;
+/* static bool_t xdr_fattr(); */
+
+
+struct sattr {
+ u_int mode;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ nfstime atime;
+ nfstime mtime;
+};
+typedef struct sattr sattr;
+/* static bool_t xdr_sattr(); */
+
+
+typedef char *filename;
+/* static bool_t xdr_filename(); */
+
+
+typedef char *nfspath;
+bool_t xdr_nfspath();
+
+
+struct attrstat {
+ nfsstat status;
+ union {
+ fattr attributes;
+ } attrstat_u;
+};
+typedef struct attrstat attrstat;
+bool_t xdr_attrstat();
+
+
+struct sattrargs {
+ nfs_fh file;
+ sattr attributes;
+};
+typedef struct sattrargs sattrargs;
+bool_t xdr_sattrargs();
+
+
+struct diropargs {
+ nfs_fh dir;
+ filename name;
+};
+typedef struct diropargs diropargs;
+bool_t xdr_diropargs();
+
+
+struct diropokres {
+ nfs_fh file;
+ fattr attributes;
+};
+typedef struct diropokres diropokres;
+bool_t xdr_diropokres();
+
+
+struct diropres {
+ nfsstat status;
+ union {
+ diropokres diropres;
+ } diropres_u;
+};
+typedef struct diropres diropres;
+bool_t xdr_diropres();
+
+
+struct readlinkres {
+ nfsstat status;
+ union {
+ nfspath data;
+ } readlinkres_u;
+};
+typedef struct readlinkres readlinkres;
+bool_t xdr_readlinkres();
+
+
+struct readargs {
+ nfs_fh file;
+ u_int offset;
+ u_int count;
+ u_int totalcount;
+};
+typedef struct readargs readargs;
+bool_t xdr_readargs();
+
+
+struct readokres {
+ fattr attributes;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct readokres readokres;
+bool_t xdr_readokres();
+
+
+struct readres {
+ nfsstat status;
+ union {
+ readokres reply;
+ } readres_u;
+};
+typedef struct readres readres;
+bool_t xdr_readres();
+
+
+struct writeargs {
+ nfs_fh file;
+ u_int beginoffset;
+ u_int offset;
+ u_int totalcount;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct writeargs writeargs;
+bool_t xdr_writeargs();
+
+
+struct createargs {
+ diropargs where;
+ sattr attributes;
+};
+typedef struct createargs createargs;
+bool_t xdr_createargs();
+
+
+struct renameargs {
+ diropargs from;
+ diropargs to;
+};
+typedef struct renameargs renameargs;
+bool_t xdr_renameargs();
+
+
+struct linkargs {
+ nfs_fh from;
+ diropargs to;
+};
+typedef struct linkargs linkargs;
+bool_t xdr_linkargs();
+
+
+struct symlinkargs {
+ diropargs from;
+ nfspath to;
+ sattr attributes;
+};
+typedef struct symlinkargs symlinkargs;
+bool_t xdr_symlinkargs();
+
+
+typedef char nfscookie[NFS_COOKIESIZE];
+/* static bool_t xdr_nfscookie(); */
+
+
+struct readdirargs {
+ nfs_fh dir;
+ nfscookie cookie;
+ u_int count;
+};
+typedef struct readdirargs readdirargs;
+bool_t xdr_readdirargs();
+
+
+struct entry {
+ u_int fileid;
+ filename name;
+ nfscookie cookie;
+ struct entry *nextentry;
+};
+typedef struct entry entry;
+/* static bool_t xdr_entry(); */
+
+
+struct dirlist {
+ entry *entries;
+ bool_t eof;
+};
+typedef struct dirlist dirlist;
+/* static bool_t xdr_dirlist(); */
+
+
+struct readdirres {
+ nfsstat status;
+ union {
+ dirlist reply;
+ } readdirres_u;
+};
+typedef struct readdirres readdirres;
+bool_t xdr_readdirres();
+
+
+struct statfsokres {
+ u_int tsize;
+ u_int bsize;
+ u_int blocks;
+ u_int bfree;
+ u_int bavail;
+};
+typedef struct statfsokres statfsokres;
+bool_t xdr_statfsokres();
+
+
+struct statfsres {
+ nfsstat status;
+ union {
+ statfsokres reply;
+ } statfsres_u;
+};
+typedef struct statfsres statfsres;
+bool_t xdr_statfsres();
+
+
+#define NFS_PROGRAM ((u_long)100003)
+#define NFS_VERSION ((u_long)2)
+#define NFSPROC_NULL ((u_long)0)
+extern voidp nfsproc_null_2();
+#define NFSPROC_GETATTR ((u_long)1)
+extern attrstat *nfsproc_getattr_2();
+#define NFSPROC_SETATTR ((u_long)2)
+extern attrstat *nfsproc_setattr_2();
+#define NFSPROC_ROOT ((u_long)3)
+extern voidp nfsproc_root_2();
+#define NFSPROC_LOOKUP ((u_long)4)
+extern diropres *nfsproc_lookup_2();
+#define NFSPROC_READLINK ((u_long)5)
+extern readlinkres *nfsproc_readlink_2();
+#define NFSPROC_READ ((u_long)6)
+extern readres *nfsproc_read_2();
+#define NFSPROC_WRITECACHE ((u_long)7)
+extern voidp nfsproc_writecache_2();
+#define NFSPROC_WRITE ((u_long)8)
+extern attrstat *nfsproc_write_2();
+#define NFSPROC_CREATE ((u_long)9)
+extern diropres *nfsproc_create_2();
+#define NFSPROC_REMOVE ((u_long)10)
+extern nfsstat *nfsproc_remove_2();
+#define NFSPROC_RENAME ((u_long)11)
+extern nfsstat *nfsproc_rename_2();
+#define NFSPROC_LINK ((u_long)12)
+extern nfsstat *nfsproc_link_2();
+#define NFSPROC_SYMLINK ((u_long)13)
+extern nfsstat *nfsproc_symlink_2();
+#define NFSPROC_MKDIR ((u_long)14)
+extern diropres *nfsproc_mkdir_2();
+#define NFSPROC_RMDIR ((u_long)15)
+extern nfsstat *nfsproc_rmdir_2();
+#define NFSPROC_READDIR ((u_long)16)
+extern readdirres *nfsproc_readdir_2();
+#define NFSPROC_STATFS ((u_long)17)
+extern statfsres *nfsproc_statfs_2();
+
diff --git a/usr.sbin/amd/rpcx/nfs_prot_svc.c b/usr.sbin/amd/rpcx/nfs_prot_svc.c
new file mode 100644
index 00000000000..f9fd288b4a3
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot_svc.c
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfs_prot_svc.c 8.1 (Berkeley) 6/6/93
+ * $Id: nfs_prot_svc.c,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+
+void nfs_program_2(rqstp, transp)
+struct svc_req *rqstp;
+SVCXPRT *transp;
+{
+ union {
+ nfs_fh nfsproc_getattr_2_arg;
+ sattrargs nfsproc_setattr_2_arg;
+ diropargs nfsproc_lookup_2_arg;
+ nfs_fh nfsproc_readlink_2_arg;
+ readargs nfsproc_read_2_arg;
+ writeargs nfsproc_write_2_arg;
+ createargs nfsproc_create_2_arg;
+ diropargs nfsproc_remove_2_arg;
+ renameargs nfsproc_rename_2_arg;
+ linkargs nfsproc_link_2_arg;
+ symlinkargs nfsproc_symlink_2_arg;
+ createargs nfsproc_mkdir_2_arg;
+ diropargs nfsproc_rmdir_2_arg;
+ readdirargs nfsproc_readdir_2_arg;
+ nfs_fh nfsproc_statfs_2_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case NFSPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_null_2;
+ break;
+
+ case NFSPROC_GETATTR:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_getattr_2;
+ break;
+
+ case NFSPROC_SETATTR:
+ xdr_argument = xdr_sattrargs;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_setattr_2;
+ break;
+
+ case NFSPROC_ROOT:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_root_2;
+ break;
+
+ case NFSPROC_LOOKUP:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_lookup_2;
+ break;
+
+ case NFSPROC_READLINK:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_readlinkres;
+ local = (char *(*)()) nfsproc_readlink_2;
+ break;
+
+ case NFSPROC_READ:
+ xdr_argument = xdr_readargs;
+ xdr_result = xdr_readres;
+ local = (char *(*)()) nfsproc_read_2;
+ break;
+
+ case NFSPROC_WRITECACHE:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_writecache_2;
+ break;
+
+ case NFSPROC_WRITE:
+ xdr_argument = xdr_writeargs;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_write_2;
+ break;
+
+ case NFSPROC_CREATE:
+ xdr_argument = xdr_createargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_create_2;
+ break;
+
+ case NFSPROC_REMOVE:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_remove_2;
+ break;
+
+ case NFSPROC_RENAME:
+ xdr_argument = xdr_renameargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_rename_2;
+ break;
+
+ case NFSPROC_LINK:
+ xdr_argument = xdr_linkargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_link_2;
+ break;
+
+ case NFSPROC_SYMLINK:
+ xdr_argument = xdr_symlinkargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_symlink_2;
+ break;
+
+ case NFSPROC_MKDIR:
+ xdr_argument = xdr_createargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_mkdir_2;
+ break;
+
+ case NFSPROC_RMDIR:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_rmdir_2;
+ break;
+
+ case NFSPROC_READDIR:
+ xdr_argument = xdr_readdirargs;
+ xdr_result = xdr_readdirres;
+ local = (char *(*)()) nfsproc_readdir_2;
+ break;
+
+ case NFSPROC_STATFS:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_statfsres;
+ local = (char *(*)()) nfsproc_statfs_2;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
+ plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_1");
+ going_down(1);
+ }
+}
+
diff --git a/usr.sbin/amd/rpcx/nfs_prot_xdr.c b/usr.sbin/amd/rpcx/nfs_prot_xdr.c
new file mode 100644
index 00000000000..3294fb2e1b3
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot_xdr.c
@@ -0,0 +1,626 @@
+/*
+ * 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.
+ *
+ * from: @(#)nfs_prot_xdr.c 8.1 (Berkeley) 6/6/93
+ * $Id: nfs_prot_xdr.c,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
+ *
+ */
+
+#include "am.h"
+
+
+#ifndef xdr_nfsstat
+bool_t
+xdr_nfsstat(xdrs, objp)
+ XDR *xdrs;
+ nfsstat *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+#endif /* xdr_nfsstat */
+
+
+
+#ifndef xdr_ftype
+static bool_t
+xdr_ftype(xdrs, objp)
+ XDR *xdrs;
+ ftype *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+#endif /* xdr_ftype */
+
+
+
+bool_t
+xdr_nfs_fh(xdrs, objp)
+ XDR *xdrs;
+ nfs_fh *objp;
+{
+ if (!xdr_opaque(xdrs, objp->data, NFS_FHSIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_nfstime(xdrs, objp)
+ XDR *xdrs;
+ nfstime *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->seconds)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->useconds)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_fattr(xdrs, objp)
+ XDR *xdrs;
+ fattr *objp;
+{
+ if (!xdr_ftype(xdrs, (enum_t *) &objp->type)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->mode)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->nlink)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->uid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->gid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->size)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocksize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->rdev)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocks)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->fsid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->fileid)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->atime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->mtime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->ctime)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_sattr(xdrs, objp)
+ XDR *xdrs;
+ sattr *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->mode)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->uid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->gid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->size)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->atime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->mtime)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_filename(xdrs, objp)
+ XDR *xdrs;
+ filename *objp;
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXNAMLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_nfspath(xdrs, objp)
+ XDR *xdrs;
+ nfspath *objp;
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXPATHLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_attrstat(xdrs, objp)
+ XDR *xdrs;
+ attrstat *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_fattr(xdrs, &objp->attrstat_u.attributes)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_sattrargs(xdrs, objp)
+ XDR *xdrs;
+ sattrargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_diropargs(xdrs, objp)
+ XDR *xdrs;
+ diropargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->dir)) {
+ return (FALSE);
+ }
+ if (!xdr_filename(xdrs, &objp->name)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_diropokres(xdrs, objp)
+ XDR *xdrs;
+ diropokres *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_fattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_diropres(xdrs, objp)
+ XDR *xdrs;
+ diropres *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_diropokres(xdrs, &objp->diropres_u.diropres)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readlinkres(xdrs, objp)
+ XDR *xdrs;
+ readlinkres *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_nfspath(xdrs, &objp->readlinkres_u.data)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readargs(xdrs, objp)
+ XDR *xdrs;
+ readargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->offset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->count)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->totalcount)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readokres(xdrs, objp)
+ XDR *xdrs;
+ readokres *objp;
+{
+ if (!xdr_fattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *)&objp->data.data_len, NFS_MAXDATA)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readres(xdrs, objp)
+ XDR *xdrs;
+ readres *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_readokres(xdrs, &objp->readres_u.reply)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_writeargs(xdrs, objp)
+ XDR *xdrs;
+ writeargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->beginoffset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->offset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->totalcount)) {
+ return (FALSE);
+ }
+ if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *)&objp->data.data_len, NFS_MAXDATA)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_createargs(xdrs, objp)
+ XDR *xdrs;
+ createargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->where)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_renameargs(xdrs, objp)
+ XDR *xdrs;
+ renameargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_diropargs(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_linkargs(xdrs, objp)
+ XDR *xdrs;
+ linkargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_diropargs(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_symlinkargs(xdrs, objp)
+ XDR *xdrs;
+ symlinkargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_nfspath(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_nfscookie(xdrs, objp)
+ XDR *xdrs;
+ nfscookie objp;
+{
+ if (!xdr_opaque(xdrs, objp, NFS_COOKIESIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readdirargs(xdrs, objp)
+ XDR *xdrs;
+ readdirargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->dir)) {
+ return (FALSE);
+ }
+ if (!xdr_nfscookie(xdrs, objp->cookie)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->count)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_entry(xdrs, objp)
+ XDR *xdrs;
+ entry *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->fileid)) {
+ return (FALSE);
+ }
+ if (!xdr_filename(xdrs, &objp->name)) {
+ return (FALSE);
+ }
+ if (!xdr_nfscookie(xdrs, objp->cookie)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&objp->nextentry, sizeof(entry), xdr_entry)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+static bool_t
+xdr_dirlist(xdrs, objp)
+ XDR *xdrs;
+ dirlist *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)&objp->entries, sizeof(entry), xdr_entry)) {
+ return (FALSE);
+ }
+ if (!xdr_bool(xdrs, &objp->eof)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_readdirres(xdrs, objp)
+ XDR *xdrs;
+ readdirres *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_dirlist(xdrs, &objp->readdirres_u.reply)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_statfsokres(xdrs, objp)
+ XDR *xdrs;
+ statfsokres *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->tsize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bsize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocks)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bfree)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bavail)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+
+
+bool_t
+xdr_statfsres(xdrs, objp)
+ XDR *xdrs;
+ statfsres *objp;
+{
+ if (!xdr_nfsstat(xdrs, (enum_t *) &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_statfsokres(xdrs, &objp->statfsres_u.reply)) {
+ return (FALSE);
+ }
+ break;
+ }
+ return (TRUE);
+}
diff --git a/usr.sbin/amd/text/COPYRIGHT b/usr.sbin/amd/text/COPYRIGHT
new file mode 100644
index 00000000000..f2e96a6ccf0
--- /dev/null
+++ b/usr.sbin/amd/text/COPYRIGHT
@@ -0,0 +1,3 @@
+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.
diff --git a/usr.sbin/amd/text/INSTALL b/usr.sbin/amd/text/INSTALL
new file mode 100644
index 00000000000..a4c8534ae20
--- /dev/null
+++ b/usr.sbin/amd/text/INSTALL
@@ -0,0 +1,194 @@
+Installation Notes for Amd.
+
+NOTE: Please read all of this before starting.
+ It is not very long and may save you time in the long term.
+
+1. ``Getting started...''
+
+If you don't know what an Automounter does for you then read the
+documentation in doc/amdref.texinfo. You can either use TeX to print
+it out or read it directly using the GNU info package.
+
+2. ``Find out what version of UN*X you are running...''
+
+To install Amd you need a port for your version of UN*X. In the
+config/ directory are several files called os-*.h. One of these
+should correspond to your version of UN*X. Run the program
+"config/os-type" to find out what system Amd thinks you have. Check
+the correspondong config/os-??? file to make sure that you and Amd are
+in agreement. If os-type returns "unknown" then either no-one has yet
+done a port, or your version of UN*X is so braindead that a port is
+not possible (e.g. System V without reliable signals). The current
+known operating systems (grouped by architecture) are:
+
+ acis43 (AOS) ACIS 4.3BSD on an IBM RT
+ aix3 AIX 3.2
+ aux Apple A/UX
+ bsd44 4.4 BSD on whatever
+ concentrix Concentrix on an Alliant
+ dgux Data General AViiON
+ fpx4 Celerity FPX 4.1/2
+ hlh42 4.2 BSD on HLH Orion 1/05
+ hpux HP-UX 6.* and 7.* on a HP9000/300
+ irix3 SGI Iris
+ irix4 SGI Iris w/Irix 4.0.x
+ next NeXT
+ riscix 4.3 BSD on an Acorn Archimedes
+ sos3, sos4 SunOS 3.* and 4.* on a Sun-3 and Sun-4
+ u2_2 Ultrix 2.2 (or 2.*?) on a VAX (broken)
+ u3_0 Ultrix 3.0 (or 3.*?) on a VAX (broken)
+ u4_2 Ultrix 4.2
+ umax43 4.3 BSD on an Encore Multimax
+ xinu43 More/BSD (4.3 BSD) on a VAX or HP9000/300
+
+ + some others...
+
+If you do define a new operating system type foo, you may need to create a
+file called Makefile.foo which defines the special Makefile parameters.
+
+3. ``Hacking the Makefile...''
+
+Amd tries very hard to determine what type of machine you are using
+and how best to compile itself. If this does not work then you will
+have to find some heuristic which can differentiate your
+configuration. You may need to edit "config/arch" and
+"config/os-type". If you do make sure your changes can cope if
+/etc/motd is missing and please send it to the address below.
+
+To check whether things are working, run:
+ sh config/arch
+ sh config/os-type
+
+You may care to tailor some site specific preferences in "Makefile.com". The
+variables most likely to be changes are at the top. Any changes should be
+added to a file called config/Makefile.local (if they are applicable to all
+operating systems at your site) or Makefile.local.foo (where foo is the OS type
+as determined in part 2).
+
+Additionally, some configuration options may be altered in
+"config/Makefile.config". This means that you should not need to edit any
+distributed files apart from "config/Makefile.config". As a minimum, you
+should check:
+
+* You are using the correct C compiler. Amd, as shipped, does not use GCC.
+ Note that using GCC version 1.34 or later (e.g. 1.36) gives structure
+ passing problems with some parts of Sun's RPC library at least on Sun-4's.
+ The current workaround is to use the system CC to compile the part of the
+ automounter that gets hit by this problem. [[This is not the same problem
+ that is fixed by -fpcc-struct-return.]] Amd contains no "register"
+ declarations, so using old PCC based code generators is probably bad news.
+
+ To use GNU CC, add the following to config/Makefile.local{.os-type}:
+
+ CC = gcc ${GCCOPTS}
+
+* The installation directory (ETC) is set up correctly.
+
+* If you are running tests then it may be worth switching on the DEBUG flag
+ which will cause a running commentary to be printed to the log file. To
+ compile in the debug code, add the following to
+ config/Makefile.local{.os-type}:
+
+ DEBUG = -DDEBUG
+ CCOPTS = -g
+
+ The -g option will also allow you to use gdb. Using dbx is not advisable
+ since it puts a breakpoint on exit() which causes all of Amd's child
+ processes to dump core. gdb does not suffer from this problem.
+
+4. ``Build the executable...''
+
+Now you need to compile the automounter. To do this you type:
+
+ make
+
+in the top-level directory. You can also go into each of the program
+directories and just run make there.
+
+If you are porting to a new machine you may want to do:
+
+ make OS=foo
+
+where foo is the name of your version of UN*X as determined in part 1, until
+you have made the changes to config/os-type and/or config/arch. When the
+compilation is complete you will end up with a program called "A.arch_foo/amd".
+
+Try running:
+
+ A.arch_foo/amd -v
+
+and check the output. It should look something like:
+
+ Copyright (c) 1990 Jan-Simon Pendry
+ Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ Copyright (c) 1990 The Regents of the University of California.
+ amd 5.2.1.5 of 90/09/16 13:22:46 5.3Alpha5 #0: Sun Sep 16 13:23:28 BST 1990
+ Built by pendry@okeeffe.Berkeley.EDU for a tahoe running bsd44 (big-endian)
+ Map support for: root, passwd, nis, file, error.
+ fstypes: ufs, nfs, nfsx, host, link, program, auto, direct, toplvl, error.
+
+Make sure the O/S and architecture types were correctly derived during the
+build.
+
+5. ``Installation...''
+
+If you are not just testing Amd, then you can install it by typing:
+
+ make install
+
+to install "A.arch_foo/amd" in "/usr/local/etc/amd" (or as otherwise
+modified in part 3).
+
+6. ``Update /etc/rpc''
+
+Amq uses Sun RPC to talk to Amd using program number 300019 which has
+been registered with Sun. Add the following lines to /etc/rpc or your
+YP or Hesiod master:
+
+# Automount control protocol
+amd 300019 amq
+
+Amd does not require this addition - it just keeps rpcinfo happy.
+
+7. ``Hanging your machine...''
+
+WARNING: THIS MAY HANG YOUR MACHINE IF YOU GET IT WRONG.
+
+Running Amd with a carelessly thought out mount map can cause your Amd to
+enter a deadlock inside the kernel. For example, attempting to automount a
+directory which is automounted. This will cause the automounter to issue a mount
+request causing the kernel to send an NFS request back to the same automounter,
+which is currently stuck in a system call and unable to respond - even
+kill -s KILL won't get you out of this one.
+
+There is nothing you can do to fix it without rebooting your machine, so...
+
+Find a diskless workstation and play with that first before trying this on
+your main 200 user service machine (unless you hate your users). Something
+like a diskless Sun-4 is best for development testing - you can compile on a
+Sun-4 server and run the binary on the diskless node. They reboot very fast
+as well between tests.
+
+Now you can try running Amd. Please read the documentation in doc/Amd.tex
+for more details. The configuration file "maps/a_master" provides a sample for
+you to play with. Something like:
+
+ ./amd -c 40 -D test,nodaemon /tmp/amnt ../maps/a_master &
+
+is good for testing. Note that Amd will clean up correctly if you send it a
+SIGINT or SIGTERM. Other signals are either ignored or will blow it away,
+leaving your machine in a potentially dangerous state.
+
+Remember that Amd needs to run as root in order to do mounts/unmounts
+though it does check this condition somewhere near line one of main().
+It will also need write permission in the working directory if you
+have built it with DEBUG defined and your system's mount table is
+reflected in a file. In this case watch out for NFS stepping in and
+mapping root to nobody.
+
+8. ``Report what happened...''
+
+If anything interesting happened, eg it didn't work, please report it to me
+-- Jan-Simon Pendry <jsp@doc.ic.ac.uk> -- as detailed in the README file.
+
+$Id: INSTALL,v 1.1.1.1 1995/10/18 08:47:23 deraadt Exp $
diff --git a/usr.sbin/amd/text/README b/usr.sbin/amd/text/README
new file mode 100644
index 00000000000..7b10d80b40d
--- /dev/null
+++ b/usr.sbin/amd/text/README
@@ -0,0 +1,37 @@
+This program is an automounter.
+
+This automounter is a value-added, replacement for the SunOS 4
+automount(8) program. Though based on that program in spirit, it
+contains no proprietary UN*X source code.
+
+The version you have here is release 5.3Alpha.
+
+This program is NOT in the Public Domain - it is covered by
+the usual Berkeley software distribution license - but feel free
+to take it and change it.
+
+It is believed to work correctly on Sun-3's (SunOS 3.5, 4.0, 4.1),
+Sun-4's (SunOS 4.0, 4.1), HP-9000/300 (HP-UX, MORE/bsd & BSD 4.3 Reno),
+IBM RTs (AOS 4.3), IBM RISC System/6000 (AIX 3.1), VAXen (Ultrix 4.0,
+MORE/bsd & BSD 4.3 Reno) and a wide variety of other systems. If
+your machine is not supported please feel free to try a port, but be
+sure to send me a record of the changes you had to make.
+
+
+This is the file text/README.
+
+See the file text/INSTALL for installation instructions.
+
+The documentation is in doc/amdref.texinfo. This is in GNU TeXinfo format
+and you will need a TeX system before you can print it out.
+
+Please forward *all* bug reports to Jan-Simon Pendry <jsp@doc.ic.ac.uk>
+quoting the details of the release and your configuration, which can be
+obtained by running the command "amd -v". Also send any additional
+information which may be relevant such as command line options and the maps
+being used. Thanks.
+
+The manual page (amd/amd.8) only lists the command line options. See the
+texinfo document doc/amdref.texinfo for a more detailed discussion.
+
+$Id: README,v 1.1.1.1 1995/10/18 08:47:24 deraadt Exp $
diff --git a/usr.sbin/amd/text/amd.start.ex b/usr.sbin/amd/text/amd.start.ex
new file mode 100644
index 00000000000..7b16b789424
--- /dev/null
+++ b/usr.sbin/amd/text/amd.start.ex
@@ -0,0 +1,86 @@
+#!/bin/sh -
+#
+# 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.
+#
+# from: @(#)amd.start.ex 8.1 (Berkeley) 6/6/93
+# $Id: amd.start.ex,v 1.1.1.1 1995/10/18 08:47:24 deraadt Exp $
+#
+# Start amd
+#
+PATH=/usr/sbin:/bin:/usr/bin:$PATH export PATH
+
+#
+# Either name of logfile or "syslog"
+#
+#LOGFILE=syslog
+LOGFILE=/var/run/amd.log
+
+#
+# Figure out whether domain name is in host name
+# If the hostname is just the machine name then
+# pass in the name of the local domain so that the
+# hostnames in the map are domain stripped correctly.
+#
+case `hostname` in
+*.*) dmn= ;;
+*) dmn='-d doc.ic.ac.uk'
+esac
+
+#
+# Zap earlier log file
+#
+case "$LOGFILE" in
+*/*)
+ mv "$LOGFILE" "$LOGFILE"-
+ > "$LOGFILE"
+ ;;
+syslog)
+ : nothing
+ ;;
+esac
+
+cd /usr/sbin
+#
+# -r restart
+# -d dmn local domain
+# -w wait wait between unmount attempts
+# -l log logfile or "syslog"
+#
+eval nice --4 ./amd -p > /var/run/amd.pid -r $dmn -w 240 -l "$LOGFILE" \
+ /homes amd.homes -cache:=inc \
+ /home amd.home -cache:=inc \
+ /vol amd.vol -cache:=inc
diff --git a/usr.sbin/arp/Makefile b/usr.sbin/arp/Makefile
new file mode 100644
index 00000000000..dad7db93f87
--- /dev/null
+++ b/usr.sbin/arp/Makefile
@@ -0,0 +1,7 @@
+# $NetBSD: Makefile,v 1.8 1995/03/01 11:50:52 chopps Exp $
+# from: @(#)Makefile 8.2 (Berkeley) 4/18/94
+
+PROG= arp
+MAN= arp.4 arp.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/arp/arp.4 b/usr.sbin/arp/arp.4
new file mode 100644
index 00000000000..acdad70294c
--- /dev/null
+++ b/usr.sbin/arp/arp.4
@@ -0,0 +1,126 @@
+.\" $NetBSD: arp.4,v 1.2 1995/03/01 11:50:56 chopps Exp $
+.\"
+.\" Copyright (c) 1985, 1986, 1988, 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.
+.\"
+.\" from: @(#)arp4.4 6.5 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt ARP 4
+.Os BSD 4
+.Sh NAME
+.Nm arp
+.Nd Address Resolution Protocol
+.Sh SYNOPSIS
+.Em "pseudo-device ether"
+.Sh DESCRIPTION
+The Address Resolution Protocol (ARP) is a protocol used to dynamically
+map between Internet host addresses and 10Mb/s Ethernet addresses.
+It is used by all the 10Mb/s Ethernet interface drivers.
+It is not specific to Internet protocols or to 10Mb/s Ethernet,
+but this implementation currently supports only that combination.
+.Pp
+ARP caches Internet-Ethernet address mappings.
+When an interface requests a mapping for an address not in the cache,
+ARP queues the message which requires the mapping and broadcasts
+a message on the associated network requesting the address mapping.
+If a response is provided, the new mapping is cached and any pending
+message is transmitted.
+ARP will queue at most one packet while waiting for a response to a
+mapping request;
+only the most recently ``transmitted'' packet is kept.
+If the target host does not respond after several requests,
+the host is considered to be down for a short period (normally 20 seconds),
+allowing an error to be returned to transmission attempts during this
+interval.
+The error is
+.Li EHOSTDOWN
+for a non-responding destination host, and
+.Li EHOSTUNREACH
+for a non-responding router.
+.Pp
+The ARP cache is stored in the system routing table as
+dynamically-created host routes.
+The route to a directly-attached Ethernet network is installed as a
+.Dq cloning
+route (one with the
+.Li RTF_CLONING
+flag set),
+causing routes to individual hosts on that network to be created on
+demand.
+These routes time out periodically (normally 20 minutes after validated;
+entries are not validated when not in use).
+An entry for a host which is not responding is a
+.Dq reject
+route (one with the
+.Li RTF_REJECT
+flag set).
+.Pp
+ARP entries may be added, deleted or changed with the
+.Xr arp 8
+utility.
+Manually-added entries may be temporary or permanent,
+and may be
+.Dq published ,
+in which case the system will respond to ARP requests for that host
+as if it were the target of the request.
+.Pp
+In the past,
+ARP was used to negotiate the use of a trailer encapsulation.
+This is no longer supported.
+.Pp
+ARP watches passively for hosts impersonating the local host (i.e. a host
+which responds to an ARP mapping request for the local host's address).
+.Sh DIAGNOSTICS
+.Em "duplicate IP address %x!! sent from ethernet address: %x:%x:%x:%x:%x:%x."
+ARP has discovered another host on the local network which responds to
+mapping requests for its own Internet address with a different Ethernet
+address, generally indicating that two hosts are attempting to use the
+same Internet address.
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr route 4 ,
+.Xr arp 8 ,
+.Xr ifconfig 8 ,
+.Xr route 8
+.sp
+.Rs
+.%A Plummer, D.
+.%B "An Ethernet Address Resolution Protocol"
+.%T RFC826
+.Re
+.Rs
+.%A Leffler, S.J.
+.%A Karels, M.J.
+.%B "Trailer Encapsulations
+.%T RFC893
+.Re
+
diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8
new file mode 100644
index 00000000000..aee3aef0d75
--- /dev/null
+++ b/usr.sbin/arp/arp.8
@@ -0,0 +1,130 @@
+.\" $NetBSD: arp.8,v 1.7 1995/03/01 11:50:59 chopps Exp $
+.\"
+.\" Copyright (c) 1985, 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.
+.\"
+.\" from: @(#)arp.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt ARP 8
+.Os BSD 4.3
+.Sh NAME
+.Nm arp
+.Nd address resolution display and control
+.Sh SYNOPSIS
+.Nm arp
+.Op Fl n
+.Ar hostname
+.Nm arp
+.Op Fl n
+.Fl a
+.Nm arp
+.Fl d Ar hostname
+.Nm arp
+.Fl s Ar hostname ether_addr
+.Op Ar temp
+.Op Ar pub
+.Nm arp
+.Fl f Ar filename
+.Sh DESCRIPTION
+The
+.Nm arp
+program displays and modifies the Internet-to-Ethernet address translation
+tables used by the address resolution protocol
+.Pq Xr arp 4 .
+With no flags, the program displays the current
+.Tn ARP
+entry for
+.Ar hostname .
+The host may be specified by name or by number,
+using Internet dot notation.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+The program displays all of the current
+.Tn ARP
+entries.
+.It Fl d
+A super-user may delete an entry for the host called
+.Ar hostname
+with the
+.Fl d
+flag.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm arp
+attempts to display addresses symbolically).
+.It Fl s Ar hostname ether_addr
+Create an
+.Tn ARP
+entry for the host called
+.Ar hostname
+with the Ethernet address
+.Ar ether_addr .
+The Ethernet address is given as six hex bytes separated by colons.
+The entry will be permanent unless the word
+.Ar temp
+is given in the command.
+If the word
+.Ar pub
+is given, the entry will be "published"; i.e., this system will
+act as an
+.Tn ARP
+server,
+responding to requests for
+.Ar hostname
+even though the host address is not its own.
+.It Fl f
+Causes the file
+.Ar filename
+to be read and multiple entries to be set in the
+.Tn ARP
+tables. Entries
+in the file should be of the form
+.Pp
+.Bd -filled -offset indent -compact
+.Ar hostname ether_addr
+.Op Ar temp
+.Op Ar pub
+.Ed
+.Pp
+with argument meanings as given above.
+.El
+.Sh SEE ALSO
+.Xr inet 3 ,
+.Xr arp 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c
new file mode 100644
index 00000000000..6198ad7a22d
--- /dev/null
+++ b/usr.sbin/arp/arp.c
@@ -0,0 +1,544 @@
+/* $NetBSD: arp.c,v 1.12 1995/04/24 13:25:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * 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) 1984, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)arp.c 8.2 (Berkeley) 1/2/94";*/
+static char *rcsid = "$NetBSD: arp.c,v 1.12 1995/04/24 13:25:18 cgd Exp $";
+#endif /* not lint */
+
+/*
+ * arp - display, set, and delete arp table entries
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <err.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+int delete __P((const char *, const char *));
+void dump __P((u_long));
+int ether_aton __P((const char *, u_char *));
+void ether_print __P((const u_char *));
+int file __P((char *));
+void get __P((const char *));
+int getinetaddr __P((const char *, struct in_addr *));
+void getsocket __P((void));
+int rtmsg __P((int));
+int set __P((int, char **));
+void usage __P((void));
+
+static int pid;
+static int nflag;
+static int s = -1;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch;
+
+ pid = getpid();
+ while ((ch = getopt(argc, argv, "andsf")) != EOF)
+ switch((char)ch) {
+ case 'a':
+ dump(0);
+ return (0);
+ case 'd':
+ if (argc < 3 || argc > 4)
+ usage();
+ (void)delete(argv[2], argv[3]);
+ return (0);
+ case 'n':
+ nflag = 1;
+ break;
+ case 's':
+ if (argc < 4 || argc > 7)
+ usage();
+ return (set(argc-2, &argv[2]) ? 1 : 0);
+ case 'f':
+ if (argc != 3)
+ usage();
+ return (file(argv[2]));
+ case '?':
+ default:
+ usage();
+ }
+ if (argc == 2 || (argc == 3 && nflag))
+ get(argv[argc - 1]);
+ else
+ usage();
+ return (0);
+}
+
+/*
+ * Process a file to set standard arp entries
+ */
+int
+file(name)
+ char *name;
+{
+ char line[100], arg[5][50], *args[5];
+ int i, retval;
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "cannot open %s", name);
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ retval = 0;
+ while (fgets(line, 100, fp) != NULL) {
+ i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
+ arg[3], arg[4]);
+ if (i < 2) {
+ warnx("bad line: %s", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+void
+getsocket()
+{
+ if (s >= 0)
+ return;
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ err(1, "socket");
+}
+
+struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
+struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
+struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
+int expire_time, flags, export_only, doing_proxy, found_entry;
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual arp entry
+ */
+int
+set(argc, argv)
+ int argc;
+ char **argv;
+{
+ register struct sockaddr_inarp *sin;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm;
+ u_char *ea;
+ char *host = argv[0], *eaddr;
+
+ sin = &sin_m;
+ rtm = &(m_rtmsg.m_rtm);
+ eaddr = argv[1];
+
+ getsocket();
+ argc -= 2;
+ argv += 2;
+ sdl_m = blank_sdl; /* struct copy */
+ sin_m = blank_sin; /* struct copy */
+ if (getinetaddr(host, &sin->sin_addr) == -1)
+ return (1);
+ ea = (u_char *)LLADDR(&sdl_m);
+ if (ether_aton(eaddr, ea) == 0)
+ sdl_m.sdl_alen = 6;
+ doing_proxy = flags = export_only = expire_time = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", 4) == 0) {
+ struct timeval time;
+ (void)gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+ }
+ else if (strncmp(argv[0], "pub", 3) == 0) {
+ flags |= RTF_ANNOUNCE;
+ doing_proxy = SIN_PROXY;
+ } else if (strncmp(argv[0], "trail", 5) == 0) {
+ (void)printf(
+ "%s: Sending trailers is no longer supported\n",
+ host);
+ }
+ argv++;
+ }
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ warn("%s", host);
+ return (1);
+ }
+ sin = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
+ if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ goto overwrite;
+ }
+ if (doing_proxy == 0) {
+ (void)printf("set: can only proxy for %s\n", host);
+ return (1);
+ }
+ if (sin_m.sin_other & SIN_PROXY) {
+ (void)printf(
+ "set: proxy entry exists for non 802 device\n");
+ return (1);
+ }
+ sin_m.sin_other = SIN_PROXY;
+ export_only = 1;
+ goto tryagain;
+ }
+overwrite:
+ if (sdl->sdl_family != AF_LINK) {
+ (void)printf("cannot intuit interface index and type for %s\n",
+ host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD));
+}
+
+/*
+ * Display an individual arp entry
+ */
+void
+get(host)
+ const char *host;
+{
+ struct sockaddr_inarp *sin;
+ u_char *ea;
+
+ sin = &sin_m;
+ sin_m = blank_sin; /* struct copy */
+ if (getinetaddr(host, &sin->sin_addr) == -1)
+ exit(1);
+ dump(sin->sin_addr.s_addr);
+ if (found_entry == 0) {
+ (void)printf("%s (%s) -- no entry\n", host,
+ inet_ntoa(sin->sin_addr));
+ exit(1);
+ }
+}
+
+/*
+ * Delete an arp entry
+ */
+int
+delete(host, info)
+ const char *host;
+ const char *info;
+{
+ register struct sockaddr_inarp *sin;
+ register struct rt_msghdr *rtm;
+ struct sockaddr_dl *sdl;
+ u_char *ea;
+ char *eaddr;
+
+ sin = &sin_m;
+ rtm = &m_rtmsg.m_rtm;
+
+ if (info && strncmp(info, "pro", 3) )
+ export_only = 1;
+ getsocket();
+ sin_m = blank_sin; /* struct copy */
+ if (getinetaddr(host, &sin->sin_addr) == -1)
+ return (1);
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ warn("%s", host);
+ return (1);
+ }
+ sin = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
+ if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ goto delete;
+ }
+ }
+ if (sin_m.sin_other & SIN_PROXY) {
+ warnx("delete: can't locate %s", host);
+ return (1);
+ } else {
+ sin_m.sin_other = SIN_PROXY;
+ goto tryagain;
+ }
+delete:
+ if (sdl->sdl_family != AF_LINK) {
+ (void)printf("cannot locate %s\n", host);
+ return (1);
+ }
+ if (rtmsg(RTM_DELETE))
+ return (1);
+ (void)printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
+ return (0);
+}
+
+/*
+ * Dump the entire arp table
+ */
+void
+dump(addr)
+ u_long addr;
+{
+ int mib[6];
+ size_t needed;
+ char *host, *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_inarp *sin;
+ struct sockaddr_dl *sdl;
+ extern int h_errno;
+ struct hostent *hp;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ err(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "actual retrieval of routing table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ sin = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin + 1);
+ if (addr) {
+ if (addr != sin->sin_addr.s_addr)
+ continue;
+ found_entry = 1;
+ }
+ if (nflag == 0)
+ hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
+ sizeof sin->sin_addr, AF_INET);
+ else
+ hp = 0;
+ if (hp)
+ host = hp->h_name;
+ else {
+ host = "?";
+ if (h_errno == TRY_AGAIN)
+ nflag = 1;
+ }
+ (void)printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
+ if (sdl->sdl_alen)
+ ether_print(LLADDR(sdl));
+ else
+ (void)printf("(incomplete)");
+ if (rtm->rtm_rmx.rmx_expire == 0)
+ (void)printf(" permanent");
+ if (sin->sin_other & SIN_PROXY)
+ (void)printf(" published (proxy only)");
+ if (rtm->rtm_addrs & RTA_NETMASK) {
+ sin = (struct sockaddr_inarp *)
+ (sdl->sdl_len + (char *)sdl);
+ if (sin->sin_addr.s_addr == 0xffffffff)
+ (void)printf(" published");
+ if (sin->sin_len != 8)
+ (void)printf("(wierd)");
+ }
+ (void)printf("\n");
+ }
+}
+
+void
+ether_print(cp)
+ const u_char *cp;
+{
+ (void)printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4],
+ cp[5]);
+}
+
+int
+ether_aton(a, n)
+ const char *a;
+ u_char *n;
+{
+ int i, o[6];
+
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4],
+ &o[5]);
+ if (i != 6) {
+ warnx("invalid Ethernet address '%s'", a);
+ return (1);
+ }
+ for (i=0; i<6; i++)
+ n[i] = o[i];
+ return (0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: arp [-n] hostname\n");
+ (void)fprintf(stderr, "usage: arp [-n] -a\n");
+ (void)fprintf(stderr, "usage: arp -d hostname\n");
+ (void)fprintf(stderr,
+ "usage: arp -s hostname ether_addr [temp] [pub]\n");
+ (void)fprintf(stderr, "usage: arp -f filename\n");
+ exit(1);
+}
+
+int
+rtmsg(cmd)
+ int cmd;
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm;
+ register char *cp;
+ register int l;
+
+ rtm = &m_rtmsg.m_rtm;
+ cp = m_rtmsg.m_space;
+ errno = 0;
+
+ if (cmd == RTM_DELETE)
+ goto doit;
+ (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ errx(1, "internal wrong cmd");
+ /*NOTREACHED*/
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ sin_m.sin_other = 0;
+ if (doing_proxy) {
+ if (export_only)
+ sin_m.sin_other = SIN_PROXY;
+ else {
+ rtm->rtm_addrs |= RTA_NETMASK;
+ rtm->rtm_flags &= ~RTF_HOST;
+ }
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if (rtm->rtm_addrs & (w)) { \
+ (void)memcpy(cp, &s, sizeof(s)); cp += sizeof(s);}
+
+ NEXTADDR(RTA_DST, sin_m);
+ NEXTADDR(RTA_GATEWAY, sdl_m);
+ NEXTADDR(RTA_NETMASK, so_mask);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ warn("writing to routing socket");
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ warn("read from routing socket");
+ return (0);
+}
+
+int
+getinetaddr(host, inap)
+ const char *host;
+ struct in_addr *inap;
+{
+ extern char *__progname; /* Program name, from crt0. */
+ struct hostent *hp;
+ u_long addr;
+
+ if (inet_aton(host, inap) == 1)
+ return (0);
+ if ((hp = gethostbyname(host)) == NULL) {
+ (void)fprintf(stderr, "%s: %s: ", __progname, host);
+ herror(NULL);
+ return (-1);
+ }
+ (void)memcpy(inap, hp->h_addr, sizeof(*inap));
+ return (0);
+}
diff --git a/usr.sbin/bad144/Makefile b/usr.sbin/bad144/Makefile
new file mode 100644
index 00000000000..70a2cd0fc0d
--- /dev/null
+++ b/usr.sbin/bad144/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:24 deraadt Exp $
+
+PROG= bad144
+MAN= bad144.8
+MANSUBDIR=/i386
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bad144/bad144.8 b/usr.sbin/bad144/bad144.8
new file mode 100644
index 00000000000..a3947fd6ef9
--- /dev/null
+++ b/usr.sbin/bad144/bad144.8
@@ -0,0 +1,187 @@
+.\" Copyright (c) 1980, 1988, 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.
+.\"
+.\" from: @(#)bad144.8 8.1 (Berkeley) 6/6/93
+.\" $Id: bad144.8,v 1.1.1.1 1995/10/18 08:47:24 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt BAD144 8
+.Os BSD 4
+.Sh NAME
+.Nm bad144
+.Nd read/write dec standard 144 bad sector information
+.Sh SYNOPSIS
+.Nm bad144
+.Op Fl c
+.Op Fl f
+.Op Fl v
+.Ar disk
+.Oo
+.Ar sno
+.Op Ar bad ...
+.Oc
+.Nm bad144
+.Fl a
+.Op Fl c
+.Op Fl f
+.Op Fl v
+.Ar disk
+.Op Ar bad ...
+.Sh DESCRIPTION
+.Nm Bad144
+can be used to inspect the information stored on a disk that is used by
+the disk drivers to implement bad sector forwarding.
+.Pp
+Available options:
+.Pp
+.Bl -tag -width Ds
+.It Fl a
+The argument list consists of new bad sectors to be added to an existing
+list.
+The new sectors are sorted into the list,
+which must have been in order.
+Replacement sectors are moved to accommodate the additions;
+the new replacement sectors are cleared.
+.It Fl c
+Forces an attempt to copy the old sector to the replacement,
+and may be useful when replacing an unreliable sector.
+.It Fl f
+For a RP06, RM03, RM05, Fujitsu Eagle,
+or
+.Tn SMD
+disk on a Massbus, the
+.Fl f
+option may be used to mark the new bad sectors as ``bad''
+by reformatting them as unusable sectors.
+This option is
+.Em required unless
+the sectors have already been marked bad,
+or the system will not be notified that it should use the replacement sector.
+This option may be used while running multiuser; it is no longer necessary
+to perform format operations while running single-user.
+.It Fl v
+The entire process is described as it happens in gory detail if
+.Fl v
+(verbose) is given.
+.El
+.Pp
+The format of
+the information is specified by
+.Tn DEC
+standard 144, as follows.
+The bad sector information is located in the first 5 even numbered sectors
+of the last track of the disk pack. There are five identical copies of
+the information, described by the
+.Ar dkbad
+structure.
+.Pp
+Replacement sectors are allocated starting with the first sector before
+the bad sector information and working backwards towards the beginning
+of the disk. A maximum of 126 bad sectors are supported. The position
+of the bad sector in the bad sector table determines the replacement
+sector to which it corresponds.
+The bad sectors must be listed in ascending order.
+.Pp
+The bad sector information and replacement sectors are conventionally
+only accessible through the ``c'' file system partition of the disk. If
+that partition is used for a file system, the user is responsible for
+making sure that it does not overlap the bad sector information or any
+replacement sectors.
+Thus, one track plus 126 sectors must be reserved to allow use
+of all of the possible bad sector replacements.
+.Pp
+The bad sector structure is as follows:
+.Bd -literal
+struct dkbad {
+ long bt_csn; /* cartridge serial number */
+ u_short bt_mbz; /* unused; should be 0 */
+ u_short bt_flag; /* -1 => alignment cartridge */
+ struct bt_bad {
+ u_short bt_cyl; /* bad sector cylinder number */
+ u_short bt_trksec; /* track and sector number */
+ } bt_bad[126];
+};
+.Ed
+.Pp
+Unused slots in the
+.Ar bt_bad
+array are filled with all bits set, a putatively
+illegal value.
+.Pp
+.Nm Bad144
+is invoked by giving a device name (e.g. hk0, hp1, etc.).
+With no optional arguments
+it reads the first sector of the last track
+of the corresponding disk and prints out the bad sector information.
+It issues a warning if the bad sectors are out of order.
+.Nm Bad144
+may also be invoked with a serial number for the pack and a list
+of bad sectors.
+It will write the supplied information into all copies
+of the bad-sector file, replacing any previous information.
+Note, however, that
+.Nm bad144
+does not arrange for the specified sectors to be marked bad in this case.
+This procedure should only be used to restore known bad sector information which
+was destroyed.
+.Pp
+It is no longer necessary to reboot to allow the kernel
+to reread the bad-sector table from the drive.
+.Sh SEE ALSO
+.Xr badsect 8 ,
+.Xr format 8
+.Sh BUGS
+It should be possible to format disks on-line under
+.Tn UNIX .
+.Pp
+It should be possible to mark bad sectors on drives of all type.
+.Pp
+On an 11/750,
+the standard bootstrap drivers used to boot the system do
+not understand bad sectors,
+handle
+.Tn ECC
+errors, or the special
+.Tn SSE
+(skip sector) errors of RM80-type disks.
+This means that none of these errors can occur when reading the file
+.Pa /netbsd
+to boot. Sectors 0-15 of the disk drive
+must also not have any of these errors.
+.Pp
+The drivers which write a system core image on disk after a crash do not
+handle errors; thus the crash dump area must be free of errors and bad
+sectors.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.1 .
diff --git a/usr.sbin/bad144/bad144.c b/usr.sbin/bad144/bad144.c
new file mode 100644
index 00000000000..cec3af46331
--- /dev/null
+++ b/usr.sbin/bad144/bad144.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 1980, 1986, 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) 1980, 1986, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)bad144.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: bad144.c,v 1.1.1.1 1995/10/18 08:47:25 deraadt Exp $";
+#endif not lint
+
+/*
+ * bad144
+ *
+ * This program prints and/or initializes a bad block record for a pack,
+ * in the format used by the DEC standard 144.
+ * It can also add bad sector(s) to the record, moving the sector
+ * replacements as necessary.
+ *
+ * It is preferable to write the bad information with a standard formatter,
+ * but this program will do.
+ *
+ * RP06 sectors are marked as bad by inverting the format bit in the
+ * header; on other drives the valid-sector bit is cleared.
+ */
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/disklabel.h>
+#include <ufs/ffs/fs.h>
+
+#include <stdio.h>
+#include <paths.h>
+
+#define RETRIES 10 /* number of retries on reading old sectors */
+#ifdef i386 /* XXX */
+#define RAWPART "d" /* disk partition containing badsector tables */
+#else
+#define RAWPART "c" /* disk partition containing badsector tables */
+#endif
+
+int fflag, add, copy, verbose, nflag;
+int compare();
+int dups;
+int badfile = -1; /* copy of badsector table to use, -1 if any */
+#define MAXSECSIZE 1024
+struct dkbad curbad, oldbad;
+#define DKBAD_MAGIC 0x4321
+
+char label[BBSIZE];
+daddr_t size, getold(), badsn();
+struct disklabel *dp;
+char name[BUFSIZ];
+char *malloc();
+off_t lseek();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct bt_bad *bt;
+ daddr_t sn, bn[126];
+ int i, f, nbad, new, bad, errs;
+
+ argc--, argv++;
+ while (argc > 0 && **argv == '-') {
+ (*argv)++;
+ while (**argv) {
+ switch (**argv) {
+#if vax
+ case 'f':
+ fflag++;
+ break;
+#endif
+ case 'a':
+ add++;
+ break;
+ case 'c':
+ copy++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'n':
+ nflag++;
+ verbose++;
+ break;
+ default:
+ if (**argv >= '0' && **argv <= '4') {
+ badfile = **argv - '0';
+ break;
+ }
+ goto usage;
+ }
+ (*argv)++;
+ }
+ argc--, argv++;
+ }
+ if (argc < 1) {
+usage:
+ fprintf(stderr,
+ "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n");
+ fprintf(stderr,
+ "to read or overwrite bad-sector table, e.g.: bad144 hp0\n");
+ fprintf(stderr,
+ "or bad144 -a [ -f ] [ -c ] disk bn ...\n");
+ fprintf(stderr, "where options are:\n");
+ fprintf(stderr, "\t-a add new bad sectors to the table\n");
+ fprintf(stderr, "\t-f reformat listed sectors as bad\n");
+ fprintf(stderr, "\t-c copy original sector to replacement\n");
+ exit(1);
+ }
+ if (argv[0][0] != '/')
+ (void)sprintf(name, "%sr%s%s", _PATH_DEV, argv[0], RAWPART);
+ else
+ strcpy(name, argv[0]);
+ f = open(name, argc == 1? O_RDONLY : O_RDWR);
+ if (f < 0)
+ Perror(name);
+#ifdef was
+ if (read(f, label, sizeof(label)) < 0)
+ Perror("read");
+ for (dp = (struct disklabel *)(label + LABELOFFSET);
+ dp < (struct disklabel *)
+ (label + sizeof(label) - sizeof(struct disklabel));
+ dp = (struct disklabel *)((char *)dp + 64))
+ if (dp->d_magic == DISKMAGIC && dp->d_magic2 == DISKMAGIC)
+ break;
+#else
+ /* obtain label and adjust to fit */
+ dp = (struct disklabel *)&label;
+ if (ioctl(f, DIOCGDINFO, dp) < 0)
+ Perror("ioctl DIOCGDINFO");
+#endif
+ if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC
+ /* dkcksum(lp) != 0 */ ) {
+ fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n");
+ exit(1);
+ }
+ if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) {
+ fprintf(stderr, "Disk sector size too large/small (%d)\n",
+ dp->d_secsize);
+ exit(7);
+ }
+#ifdef i386
+ if (dp->d_type == DTYPE_SCSI) {
+ fprintf(stderr, "SCSI disks don't use bad144!\n");
+ exit(1);
+ }
+ /* are we inside a DOS partition? */
+ if (dp->d_partitions[0].p_offset) {
+ /* yes, rules change. assume bad tables at end of partition C,
+ which maps all of DOS partition we are within -wfj */
+ size = dp->d_partitions[2].p_offset + dp->d_partitions[2].p_size;
+ } else
+#endif
+ size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders;
+ argc--;
+ argv++;
+ if (argc == 0) {
+ sn = getold(f, &oldbad);
+ printf("bad block information at sector %d in %s:\n",
+ sn, name);
+ printf("cartridge serial number: %d(10)\n", oldbad.bt_csn);
+ switch (oldbad.bt_flag) {
+
+ case (u_short)-1:
+ printf("alignment cartridge\n");
+ break;
+
+ case DKBAD_MAGIC:
+ break;
+
+ default:
+ printf("bt_flag=%x(16)?\n", oldbad.bt_flag);
+ break;
+ }
+ bt = oldbad.bt_bad;
+ for (i = 0; i < 126; i++) {
+ bad = (bt->bt_cyl<<16) + bt->bt_trksec;
+ if (bad < 0)
+ break;
+ printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt),
+ bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
+ bt++;
+ }
+ (void) checkold(&oldbad);
+ exit(0);
+ }
+ if (add) {
+ /*
+ * Read in the old badsector table.
+ * Verify that it makes sense, and the bad sectors
+ * are in order. Copy the old table to the new one.
+ */
+ (void) getold(f, &oldbad);
+ i = checkold(&oldbad);
+ if (verbose)
+ printf("Had %d bad sectors, adding %d\n", i, argc);
+ if (i + argc > 126) {
+ printf("bad144: not enough room for %d more sectors\n",
+ argc);
+ printf("limited to 126 by information format\n");
+ exit(1);
+ }
+ curbad = oldbad;
+ } else {
+ curbad.bt_csn = atoi(*argv++);
+ argc--;
+ curbad.bt_mbz = 0;
+ curbad.bt_flag = DKBAD_MAGIC;
+ if (argc > 126) {
+ printf("bad144: too many bad sectors specified\n");
+ printf("limited to 126 by information format\n");
+ exit(1);
+ }
+ i = 0;
+ }
+ errs = 0;
+ new = argc;
+ while (argc > 0) {
+ daddr_t sn = atoi(*argv++);
+ argc--;
+ if (sn < 0 || sn >= size) {
+ printf("%d: out of range [0,%d) for disk %s\n",
+ sn, size, dp->d_typename);
+ errs++;
+ continue;
+ }
+ bn[i] = sn;
+ curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
+ sn %= (dp->d_nsectors*dp->d_ntracks);
+ curbad.bt_bad[i].bt_trksec =
+ ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
+ i++;
+ }
+ if (errs)
+ exit(1);
+ nbad = i;
+ while (i < 126) {
+ curbad.bt_bad[i].bt_trksec = -1;
+ curbad.bt_bad[i].bt_cyl = -1;
+ i++;
+ }
+ if (add) {
+ /*
+ * Sort the new bad sectors into the list.
+ * Then shuffle the replacement sectors so that
+ * the previous bad sectors get the same replacement data.
+ */
+ qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad),
+ compare);
+ if (dups) {
+ fprintf(stderr,
+"bad144: bad sectors have been duplicated; can't add existing sectors\n");
+ exit(3);
+ }
+ shift(f, nbad, nbad-new);
+ }
+ if (badfile == -1)
+ i = 0;
+ else
+ i = badfile * 2;
+ for (; i < 10 && i < dp->d_nsectors; i += 2) {
+ if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i),
+ L_SET) < 0)
+ Perror("lseek");
+ if (verbose)
+ printf("write badsect file at %d\n",
+ size - dp->d_nsectors + i);
+ if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) !=
+ sizeof(curbad)) {
+ char msg[80];
+ (void)sprintf(msg, "bad144: write bad sector file %d",
+ i/2);
+ perror(msg);
+ }
+ if (badfile != -1)
+ break;
+ }
+#ifdef vax
+ if (nflag == 0 && fflag)
+ for (i = nbad - new; i < nbad; i++)
+ format(f, bn[i]);
+#endif
+#ifdef DIOCSBAD
+ if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0)
+ fprintf(stderr,
+ "Can't sync bad-sector file; reboot for changes to take effect\n");
+#endif
+ if ((dp->d_flags & D_BADSECT) == 0 && nflag == 0) {
+ dp->d_flags |= D_BADSECT;
+ if (ioctl(f, DIOCWDINFO, dp) < 0) {
+ perror("label");
+ fprintf(stderr, "Can't write label to enable bad sector handling\n");
+ exit(1);
+ }
+ }
+ exit(0);
+}
+
+daddr_t
+getold(f, bad)
+struct dkbad *bad;
+{
+ register int i;
+ daddr_t sn;
+ char msg[80];
+
+ if (badfile == -1)
+ i = 0;
+ else
+ i = badfile * 2;
+ for (; i < 10 && i < dp->d_nsectors; i += 2) {
+ sn = size - dp->d_nsectors + i;
+ if (lseek(f, sn * dp->d_secsize, L_SET) < 0)
+ Perror("lseek");
+ if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) {
+ if (i > 0)
+ printf("Using bad-sector file %d\n", i/2);
+ return(sn);
+ }
+ (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn);
+ perror(msg);
+ if (badfile != -1)
+ break;
+ }
+ fprintf(stderr, "bad144: %s: can't read bad block info\n", name);
+ exit(1);
+ /*NOTREACHED*/
+}
+
+checkold()
+{
+ register int i;
+ register struct bt_bad *bt;
+ daddr_t sn, lsn;
+ int errors = 0, warned = 0;
+
+ if (oldbad.bt_flag != DKBAD_MAGIC) {
+ fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n",
+ name);
+ errors++;
+ }
+ if (oldbad.bt_mbz != 0) {
+ fprintf(stderr, "bad144: %s: bad magic number\n", name);
+ errors++;
+ }
+ bt = oldbad.bt_bad;
+ for (i = 0; i < 126; i++, bt++) {
+ if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff)
+ break;
+ if ((bt->bt_cyl >= dp->d_ncylinders) ||
+ ((bt->bt_trksec >> 8) >= dp->d_ntracks) ||
+ ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) {
+ fprintf(stderr,
+ "bad144: cyl/trk/sect out of range in existing entry: ");
+ fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n",
+ badsn(bt), bt->bt_cyl, bt->bt_trksec>>8,
+ bt->bt_trksec & 0xff);
+ errors++;
+ }
+ sn = (bt->bt_cyl * dp->d_ntracks +
+ (bt->bt_trksec >> 8)) *
+ dp->d_nsectors + (bt->bt_trksec & 0xff);
+ if (i > 0 && sn < lsn && !warned) {
+ fprintf(stderr,
+ "bad144: bad sector file is out of order\n");
+ errors++;
+ warned++;
+ }
+ if (i > 0 && sn == lsn) {
+ fprintf(stderr,
+ "bad144: bad sector file contains duplicates (sn %d)\n",
+ sn);
+ errors++;
+ }
+ lsn = sn;
+ }
+ if (errors)
+ exit(1);
+ return (i);
+}
+
+/*
+ * Move the bad sector replacements
+ * to make room for the new bad sectors.
+ * new is the new number of bad sectors, old is the previous count.
+ */
+shift(f, new, old)
+{
+ daddr_t repl;
+
+ /*
+ * First replacement is last sector of second-to-last track.
+ */
+ repl = size - dp->d_nsectors - 1;
+ new--; old--;
+ while (new >= 0 && new != old) {
+ if (old < 0 ||
+ compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) {
+ /*
+ * Insert new replacement here-- copy original
+ * sector if requested and possible,
+ * otherwise write a zero block.
+ */
+ if (!copy ||
+ !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new))
+ blkzero(f, repl - new);
+ } else {
+ if (blkcopy(f, repl - old, repl - new) == 0)
+ fprintf(stderr,
+ "Can't copy replacement sector %d to %d\n",
+ repl-old, repl-new);
+ old--;
+ }
+ new--;
+ }
+}
+
+char *buf;
+
+/*
+ * Copy disk sector s1 to s2.
+ */
+blkcopy(f, s1, s2)
+daddr_t s1, s2;
+{
+ register tries, n;
+
+ if (buf == (char *)NULL) {
+ buf = malloc((unsigned)dp->d_secsize);
+ if (buf == (char *)NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit(20);
+ }
+ }
+ for (tries = 0; tries < RETRIES; tries++) {
+ if (lseek(f, dp->d_secsize * s1, L_SET) < 0)
+ Perror("lseek");
+ if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize)
+ break;
+ }
+ if (n != dp->d_secsize) {
+ fprintf(stderr, "bad144: can't read sector, %d: ", s1);
+ if (n < 0)
+ perror((char *)0);
+ return(0);
+ }
+ if (lseek(f, dp->d_secsize * s2, L_SET) < 0)
+ Perror("lseek");
+ if (verbose)
+ printf("copying %d to %d\n", s1, s2);
+ if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) {
+ fprintf(stderr,
+ "bad144: can't write replacement sector, %d: ", s2);
+ perror((char *)0);
+ return(0);
+ }
+ return(1);
+}
+
+char *zbuf;
+
+blkzero(f, sn)
+daddr_t sn;
+{
+
+ if (zbuf == (char *)NULL) {
+ zbuf = malloc((unsigned)dp->d_secsize);
+ if (zbuf == (char *)NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit(20);
+ }
+ }
+ if (lseek(f, dp->d_secsize * sn, L_SET) < 0)
+ Perror("lseek");
+ if (verbose)
+ printf("zeroing %d\n", sn);
+ if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) {
+ fprintf(stderr,
+ "bad144: can't write replacement sector, %d: ", sn);
+ perror((char *)0);
+ }
+}
+
+compare(b1, b2)
+register struct bt_bad *b1, *b2;
+{
+ if (b1->bt_cyl > b2->bt_cyl)
+ return(1);
+ if (b1->bt_cyl < b2->bt_cyl)
+ return(-1);
+ if (b1->bt_trksec == b2->bt_trksec)
+ dups++;
+ return (b1->bt_trksec - b2->bt_trksec);
+}
+
+daddr_t
+badsn(bt)
+register struct bt_bad *bt;
+{
+ return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors
+ + (bt->bt_trksec&0xff));
+}
+
+#ifdef vax
+
+struct rp06hdr {
+ short h_cyl;
+ short h_trksec;
+ short h_key1;
+ short h_key2;
+ char h_data[512];
+#define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */
+};
+
+/*
+ * Most massbus and unibus drives
+ * have headers of this form
+ */
+struct hpuphdr {
+ u_short hpup_cyl;
+ u_char hpup_sect;
+ u_char hpup_track;
+ char hpup_data[512];
+#define HPUP_OKSECT 0xc000 /* this normally means sector is good */
+#define HPUP_16BIT 0x1000 /* 1 == 16 bit format */
+};
+int rp06format(), hpupformat();
+
+struct formats {
+ char *f_name; /* disk name */
+ int f_bufsize; /* size of sector + header */
+ int f_bic; /* value to bic in hpup_cyl */
+ int (*f_routine)(); /* routine for special handling */
+} formats[] = {
+ { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format },
+ { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat },
+ { 0, 0, 0, 0 }
+};
+
+/*ARGSUSED*/
+hpupformat(fp, dp, blk, buf, count)
+ struct formats *fp;
+ struct disklabel *dp;
+ daddr_t blk;
+ char *buf;
+ int count;
+{
+ struct hpuphdr *hdr = (struct hpuphdr *)buf;
+ int sect;
+
+ if (count < sizeof(struct hpuphdr)) {
+ hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) |
+ (blk / (dp->d_nsectors * dp->d_ntracks));
+ sect = blk % (dp->d_nsectors * dp->d_ntracks);
+ hdr->hpup_track = (u_char)(sect / dp->d_nsectors);
+ hdr->hpup_sect = (u_char)(sect % dp->d_nsectors);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+rp06format(fp, dp, blk, buf, count)
+ struct formats *fp;
+ struct disklabel *dp;
+ daddr_t blk;
+ char *buf;
+ int count;
+{
+
+ if (count < sizeof(struct rp06hdr)) {
+ fprintf(stderr, "Can't read header on blk %d, can't reformat\n",
+ blk);
+ return (-1);
+ }
+ return (0);
+}
+
+format(fd, blk)
+ int fd;
+ daddr_t blk;
+{
+ register struct formats *fp;
+ static char *buf;
+ static char bufsize;
+ struct format_op fop;
+ int n;
+
+ for (fp = formats; fp->f_name; fp++)
+ if (strcmp(dp->d_typename, fp->f_name) == 0)
+ break;
+ if (fp->f_name == 0) {
+ fprintf(stderr, "bad144: don't know how to format %s disks\n",
+ dp->d_typename);
+ exit(2);
+ }
+ if (buf && bufsize < fp->f_bufsize) {
+ free(buf);
+ buf = NULL;
+ }
+ if (buf == NULL)
+ buf = malloc((unsigned)fp->f_bufsize);
+ if (buf == NULL) {
+ fprintf(stderr, "bad144: can't allocate sector buffer\n");
+ exit(3);
+ }
+ bufsize = fp->f_bufsize;
+ /*
+ * Here we do the actual formatting. All we really
+ * do is rewrite the sector header and flag the bad sector
+ * according to the format table description. If a special
+ * purpose format routine is specified, we allow it to
+ * process the sector as well.
+ */
+ if (verbose)
+ printf("format blk %d\n", blk);
+ bzero((char *)&fop, sizeof(fop));
+ fop.df_buf = buf;
+ fop.df_count = fp->f_bufsize;
+ fop.df_startblk = blk;
+ bzero(buf, fp->f_bufsize);
+ if (ioctl(fd, DIOCRFORMAT, &fop) < 0)
+ perror("bad144: read format");
+ if (fp->f_routine &&
+ (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0)
+ return;
+ if (fp->f_bic) {
+ struct hpuphdr *xp = (struct hpuphdr *)buf;
+
+ xp->hpup_cyl &= ~fp->f_bic;
+ }
+ if (nflag)
+ return;
+ bzero((char *)&fop, sizeof(fop));
+ fop.df_buf = buf;
+ fop.df_count = fp->f_bufsize;
+ fop.df_startblk = blk;
+ if (ioctl(fd, DIOCWFORMAT, &fop) < 0)
+ Perror("write format");
+ if (fop.df_count != fp->f_bufsize) {
+ char msg[80];
+ (void)sprintf(msg, "bad144: write format %d", blk);
+ perror(msg);
+ }
+}
+#endif
+
+Perror(op)
+ char *op;
+{
+
+ fprintf(stderr, "bad144: "); perror(op);
+ exit(4);
+}
diff --git a/usr.sbin/bootpd/Announce b/usr.sbin/bootpd/Announce
new file mode 100644
index 00000000000..e4ae04c20d8
--- /dev/null
+++ b/usr.sbin/bootpd/Announce
@@ -0,0 +1,63 @@
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges most of the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+New features in version 2.4 include:
+
+ Added a simple BOOTP gateway program: bootpgw
+ Allow host name anywhere IP address is expected.
+ Automatically lookup the IP address when the name of a
+ bootptab entry is a valid hostname.
+ (Dummy entries names should start with '.')
+ Merged changes from NetBSD and Columbia versions.
+ Merged changes for Solaris-2.X and SVR4 systems.
+ Combined bootptest into the bootp release.
+ Merged tag 18 support (:ef=...:) from Jason Zions.
+ Use :ef=extension_file_name: and make the
+ extension files for all clients using bootpef.
+ Merged HP compatibility (:ra=...:) from David R Linn.
+ Allows you to override the reply address.
+ (i.e. send the reply to a broadcast address)
+ Add /etc/ethers support for NetBSD.
+ More systems support getether (Ultrix, OSF, NetBSD)
+ Added RFC 1533 tags 40,41,42
+ :yd=<NIS domain>:ys=<NIS server>:nt=<NTP server>:
+ ConvOldTab.sh to convert old (1.1) bootptab to new format.
+ Permits extended-length replies with more option data.
+
+Problems fixed in this version:
+
+ Fixed references to free host structures.
+ (used to cause core dump on Solaris)
+ Remove change that added null terminator to string options.
+ (this annoyed some clients...)
+ Add missing symbols to dump routine, fix order.
+ Works (again) with no -DSYSLOGD defined.
+ Fixed several more NULL references in readfile.
+ Added proper length checks to option insertions.
+ Fixed bootptest IP address printing.
+ Cleaned-up signed/unsigned and byteorder bugs.
+ Added SVR4/Streams support to getif and getether
+ Removed extra newlines in syslog messages.
+ Specify facility code when calling syslog(3)
+ When lookup_hwa fails, assume numeric HW address.
+
+Systems on which I have seen this code work:
+ SunOS 4.X (Solaris 1.X)
+ SunOS 5.X (Solaris 2.X)
+ System V/386 Rel. 4.0
+
+Systems on which others say this code works:
+ CDC EP/IX (1.4.3, 2.1.1)
+ DEC Ultrix (4.2, 4.3)
+ NetBSD (Current-8/94)
+ OSF/1 (DEC Alpha CPU)
+
+Please direct questions, comments, and bug reports to:
+ <bootp@andrew.cmu.edu>
+
+Gordon W. Ross Mercury Computer Systems
+gwr@mc.com 199 Riverneck Road
+508-256-1300 Chelmsford, MA 01824-2820
diff --git a/usr.sbin/bootpd/Changes b/usr.sbin/bootpd/Changes
new file mode 100644
index 00000000000..06165486acc
--- /dev/null
+++ b/usr.sbin/bootpd/Changes
@@ -0,0 +1,245 @@
+Changes, most recent first
+Date, <email> Real Name
+ what...
+
+--> bootp-2.4.0
+
+08/20/94 gwr@mc.com (Gordon W. Ross)
+ Fix code to build bootfile name based on combination of
+ client requested name and bootfile specifications.
+ Behave similarly with or without CHECK_FILE_ACCESS.
+
+07/30/94 Dirk Koeppen <dirk@incom.de>
+ Add "min wait" option (mw) to cause bootpd to ignore
+ requests from clients that have not waited long enough.
+ Add code to honor client requests containing the DHCP
+ option "Maximum Message Size" and use its value to
+ determine the size of the reply message.
+
+--> bootp-2.3.8
+
+06/25/94 Christos Zoulas <christos@deshaw.com>
+ Add "-h" flag to override host name (affects default IP
+ address provided in reply messages. (Also minor bug fix)
+
+05/27/94 gwr@mc.com (Gordon W. Ross)
+ Add code to call "arp -s IPADDR HWADDR" on systems
+ that do not provide an SIOCSARP ioctl (i.e. NetBSD)
+
+--> bootp-2.3.7
+
+05/05/94 Walter Wong <wcw+@CMU.EDU>
+ Reduce noize at debug level one, where log messages
+ are generated only for hosts that are recognized
+ and replied to by bootpd. (At request of HP folks.)
+
+04/30/94 gwr@mc.com (Gordon W. Ross)
+ Use memxxx functions unless USE_BFUNCS is defined.
+ Added -f <file> option to bootptest (requested file).
+
+04/29/94 tpaquett@ita.lgc.com (Trevor Paquette)
+ Remove call to haddr_conv802() in sendreply().
+ The setarp should get the non-transformed address.
+
+04/27/94 gwr@mc.com
+ Improve logic for building bootfile pathname, so a path
+ will be put in the reply if either the client or bootpd
+ specifies a boot file. (Needed for NetBSD diskless boot)
+
+04/25/94 shamash@boxhill.com (Ari Shamash)
+ Fix prs_inetaddr() so it allows '_' in hostnames.
+
+04/16/94 gwr@mc.com (Gordon W. Ross)
+ Fix setarp for SVR4 (needs to use I_STR ioctl)
+ Thanks to several people: (all sent the same fix)
+ Barney Wolff <barney@databus.com>,
+ bear@upsys.se (Bj|rn Sj|holm),
+ Michael Kuschke <Michael.Kuschke@Materna.DE>,
+
+03/25/95 Ulrich Heuer </I=zhhi9/G=Ulrich/S=Heuer/@zhflur.ubs.ubs.ch>
+ Make option string lengths not include a null terminator.
+ The trailing null breaks some clients.
+
+03/15/94 "Edmund J. Sutcliffe" <ejs1@tower.york.ac.uk>
+ Add support for the "EX" option: Execute a program
+ before sending a BOOTREPLY to a client. Support for
+ this option is conditional on YORK_EX_OPTION.
+
+03/10/94 Nigel Metheringham <nigelm@ohm.york.ac.uk>
+ Make getether.c work on Linux.
+
+03/09/94 Koch@Math.Uni-Duisburg.DE (Peter Koch)
+ Add missing MANDIR definition to Makefile.
+
+03/08/94 Jeroen.Scheerder@let.ruu.nl
+ Fix args to report in getether code for Ultrix.
+ Run install individually for each program.
+
+--> bootp-2.3.6
+03/07/94 gwr@mc.com
+ Cleanup for release (run gnu indent, tab-size=4)
+
+02/24/94 Jeroen.Scheerder@let.ruu.nl
+ Allow underscore in host names - readfile.c:goodname()
+ Add ConvOldTab.sh - converts 1.1 bootptab to new format.
+
+02/20/94 gwr@mc.com (Gordon W. Ross)
+ Make readfile tolerant of hardware addresses that start
+ with a letter. (If lookup_hwa() fails, assume numeric.)
+ Fix whitespace skip before :vm= auto: and avoid lookup.
+
+02/12/94 walker@zk3.dec.com (Mary Walker)
+ Added support for 64-bit longs (for the DEC Alpha)
+ Allow ieee802 hardware address in bit-reversed oreder
+
+02/07/94 hl@tekla.fi (Harald Lundberg)
+ Fix conflict with DUMP_FILE in syslog.h on OSF1
+ Use int for (struct bootp).bp_xid (for DEC Alpha)
+ Added Ultrix support to bootptest (getether)
+
+02/06/94 brezak@ch.hp.com (John Brezak)
+ Add man-page and install targets to Makefile.NetBSD
+ Add getether support for NetBSD
+
+02/05/94 gwr@mc.com (Gordon W. Ross)
+ Added tags 40,41,42 (NIS domain, NIS server, NTP server)
+ Add stub to getether for machines not yet supported.
+
+--> bootp-2.3.5
+01/29/94 gwr@mc.com (Gordon W. Ross)
+ Make bootpgw put a correct address in "giaddr" when
+ the client request came via broadcast.
+
+01/22/94 gwr@mc.com (Gordon W. Ross)
+ Fix syslog call (missing "facility" code)
+ Add SVR4/Streams support to getif() and getether()
+ Fix getif bug (matched when it should not)
+ Macro-ize lots of similar cases in readfile.c
+
+12/27/93 brezak@ch.hp.com (John Brezak)
+ Remove all newlines passed to syslog(3)
+ Add /etc/ethers support for NetBSD.
+
+12/18/93 gwr@mc.com (Gordon W. Ross)
+ Fix bootptest IP address printing.
+ Fix byte-order bugs in bootpgw and bootptest.
+ Clean-up signed/unsigned mismatches.
+ Back out SLIP support changes for now
+ (code fragment saved in ToDo).
+
+--> bootp-2.3.4 (beta test release)
+12/12/93 gwr@mc.com (Gordon W. Ross)
+ Fixed several more NULL references in readfile.
+ Added proper length checks to option insertions.
+
+--> bootp-2.3.3 (beta test release)
+12/09/93 gwr@mc.com (Gordon W. Ross)
+ Added ASSERT checks to readfile.c:fill_defaults()
+
+12/08/93 brezak@ch.hp.com (John Brezak)
+ New Makefile.NetBSD
+ Added setsid() and #ifdef TIOCNOTTY
+ (bootpd.c, bootpgw.c)
+ Moved #include <net/if.h> out of #ifdef SUNOS
+ Fixed several multiple declaration problems
+
+12/04/93 gwr@mc.com (Gordon W. Ross)
+ Re-implemented Extension File support
+ based on work by Jason Zions <jazz@hal.com>
+ Added support for Reply-Address-Override to support
+ HP clients (need reply sent to broadcast address)
+ from David R. Linn <drl@vuse.vanderbilt.edu>
+
+--> bootp-2.3.2 (beta test release)
+11/27/93 gwr@mc.com (Gordon W. Ross)
+ Incorporated bootptest into the bootp release.
+ Added ANSI function prototypes everywhere.
+
+11/17/93 dpm@depend.com (David P. Maynard)
+ Added automatic SLIP address determination.
+ (This is NOT dynamic IP address assignment.)
+ Cleaned up some type warnings from gcc.
+
+11/11/93 gwr@mc.com (Gordon W. Ross)
+ Works (again) with no -DSYSLOGD defined.
+ Provide a default value for the subnet mask.
+ More #ifdef's for SunOS specific code (lookup_hwa)
+ Added a simple BOOTP gateway program: bootpgw
+ Reorganized for more code sharing (with bootpgw)
+
+--> bootp-2.3.1 (alpha test release)
+11/08/93 gwr@mc.com (Gordon W. Ross)
+ Back-out changes to honor option structure in request
+ (this needs to be a per-client option).
+ Merged changes from NetBSD and Columbia versions.
+ Allow host name anywhere IP address is expected.
+ Add null terminators to option strings.
+ Add missing symbols to dump routine, dump symbols
+ in alphabetical order, one tag per line.
+
+--> bootp-2.2.D (posted as patch 2)
+10/19/93 gwr@mc.com (Gordon W. Ross)
+ Fix references to free memory (leads to core dumps).
+
+--> bootp-2.2.C (posted as patch 1)
+10/14/93 gwr@mc.com (Gordon W. Ross)
+ Fix data access alignment problems on SPARC/Solaris.
+
+--> bootp-2.2.B (posted to usenet)
+10/11/93 gwr@mc.com (Gordon W. Ross)
+ Allow extended-length BOOTP packets (more vendor options)
+ Honor option format specified in client requests.
+ Added Solaris-2.X changes from db@sunbim.be (Danny Backx).
+
+All history before this point may be inaccurate. Please send
+changes if any of the credits are incorrect. -gwr
+
+--> bootp-2.2+NetBSD released
+08/27/93 brezak@ch.hp.com (John Brezak)
+ Added RFC 1396 support (tags 14-17)
+
+--> bootp-2.2+NetBSD (version?)
+??/??/93 mckim@lerc.nasa.gov (Jim McKim)
+ Ported to NetBSD (see Makefile.NetBSD)
+ Set server host name in responses.
+ Check all interfaces in address match routine.
+
+--> bootp-2.2+FdC released
+01/27/93 <fdc@watsun.cc.columbia.edu> Frank da Cruz
+ Added RFC 1395 information: Merit dump file,
+ client domain name, swap server address, root path.
+
+--> bootp-2.2alpha released
+11/14/91 <walt+@cmu.edu> Walter L. Wimer
+ Add "td" to TFTP directory for "secure" (chroot) TFTP.
+ Add "sa" tag to set explicit server address.
+ Automatically determine if child of inetd.
+ Use RFC 1048 format when request has magic number zero.
+ Fixed various bugs. Give bootptab a separate man page.
+
+--> bootp-2.1 released
+01/09/89 <walt+@cmu.edu> Walter L. Wimer
+ Check world read bit on TFTP boot file.
+ Add support for rfc1085 "bootfile size" tag.
+ Add generic tags. Fix byte order of rfc1048 data.
+ Fix various crashing bugs.
+
+--> bootp-2.0 released
+07/15/88 <walt+@cmu.edu> Walter L. Wimer
+ Added vendor information to conform to RFC1048.
+ Adopted termcap-like file format to support above.
+ Added hash table lookup instead of linear search.
+ Other cleanups.
+
+--> bootp-1.3(?) released
+07/24/87 <ddp@andrew.cmu.edu> Drew D. Perkins
+ Modified to use syslog instead of Kovar's
+ routines. Add debugging dumps. Many other fixups.
+
+--> bootp-1.2(?) released
+07/30/86 David Kovar at Carnegie Mellon University
+ Modified to work at CMU.
+
+--> bootp-1.1 released
+01/22/86 Bill Croft at Stanford University
+ Original created.
diff --git a/usr.sbin/bootpd/ConvOldTab.sh b/usr.sbin/bootpd/ConvOldTab.sh
new file mode 100644
index 00000000000..00683f0c049
--- /dev/null
+++ b/usr.sbin/bootpd/ConvOldTab.sh
@@ -0,0 +1,141 @@
+#!/bin/sh
+# convert_bootptab Jeroen.Scheerder@let.ruu.nl 02/25/94
+# This script can be used to convert bootptab files in old format
+# to new (termcap-like) bootptab files
+#
+# The old format - real entries are commented out by '###'
+#
+# Old-style bootp files consist of two sections.
+# The first section has two entries:
+# First, a line that specifies the home directory
+# (where boot file paths are relative to)
+
+###/tftpboot
+
+# The next non-empty non-comment line specifies the default bootfile
+
+###no-file
+
+# End of first section - indicated by '%%' at the start of the line
+
+###%%
+
+# The remainder of this file contains one line per client
+# interface with the information shown by the table headings
+# below. The host name is also tried as a suffix for the
+# bootfile when searching the home directory (that is,
+# bootfile.host)
+#
+# Note that htype is always 1, indicating the hardware type Ethernet.
+# Conversion therefore always yields ':ha=ether:'.
+#
+# host htype haddr iaddr bootfile
+#
+
+###somehost 1 00:0b:ad:01:de:ad 128.128.128.128 dummy
+
+# That's all for the description of the old format.
+# For the new-and-improved format, see bootptab(5).
+
+set -u$DX
+
+case $#
+in 2 ) OLDTAB=$1 ; NEWTAB=$2 ;;
+ * ) echo "Usage: `basename $0` <Input> <Output>"
+ exit 1
+esac
+
+if [ ! -r $OLDTAB ]
+then
+ echo "`basename $0`: $OLDTAB does not exist or is unreadable."
+ exit 1
+fi
+
+if touch $NEWTAB 2> /dev/null
+then
+ :
+else
+ echo "`basename $0`: cannot write to $NEWTAB."
+ exit 1
+fi
+
+
+cat << END_OF_HEADER >> $NEWTAB
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# This file was generated automagically
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: your.domain.name)
+
+END_OF_HEADER
+
+# Fix up HW addresses in aa:bb:cc:dd:ee:ff and aa-bb-cc-dd-ee-ff style first
+# Then awk our stuff together
+sed -e 's/[:-]//g' < $OLDTAB | \
+nawk 'BEGIN { PART = 0 ; FIELD=0 ; BOOTPATH="unset" ; BOOTFILE="unset" }
+ /^%%/ {
+ PART = 1
+ printf ".default:\\\n\t:ht=ether:\\\n\t:hn:\\\n\t:dn=your.domain.name:\\\n\t:ds=your,dns,servers:\\\n\t:sm=255.255.0.0:\\\n\t:hd=%s:\\\n\t:rp=%s:\\\n\t:td=%s:\\\n\t:bf=%s:\\\n\t:to=auto:\n\n", BOOTPATH, BOOTPATH, BOOTPATH, BOOTFILE
+ next
+ }
+ /^$/ { next }
+ /^#/ { next }
+ {
+ if ( PART == 0 && FIELD < 2 )
+ {
+ if ( FIELD == 0 ) BOOTPATH=$1
+ if ( FIELD == 1 ) BOOTFILE=$1
+ FIELD++
+ }
+ }
+ {
+ if ( PART == 1 )
+ {
+ HOST=$1
+ HA=$3
+ IP=$4
+ BF=$5
+ printf "%s:\\\n\t:tc=.default:\\\n\t:ha=0x%s:\\\n\t:ip=%s:\\\n\t:bf=%s:\n", HOST, HA, IP, BF
+ }
+ }' >> $NEWTAB
+
+exit 0
diff --git a/usr.sbin/bootpd/Installation b/usr.sbin/bootpd/Installation
new file mode 100644
index 00000000000..466cabce0cd
--- /dev/null
+++ b/usr.sbin/bootpd/Installation
@@ -0,0 +1,29 @@
+
+Installation instructions for SunOS
+
+Compile the executable:
+For SunOS 4.X:
+ make sunos4
+For SunOS 5.X: (Solaris)
+ make sunos5
+
+Install the executables:
+
+ make install
+
+Edit (or create) the bootptab:
+(See bootptab.sample and bootptab.5 manual entry)
+ edit /etc/bootptab
+
+Edit /etc/services to add these two lines:
+bootps 67/udp bootp # BOOTP Server
+bootpc 68/udp # BOOTP Client
+
+Edit /etc/inetd.conf to add the line:
+bootp dgram udp wait root /usr/etc/bootpd bootpd -i
+
+If you compiled report.c with LOG_LOCAL2 (defined in the Makefile)
+then you may want to capture syslog messages from BOOTP by changing
+your syslog.conf file. (See the sample syslog.conf file here).
+Test the change with: logger -t test -p local2.info "message"
+
diff --git a/usr.sbin/bootpd/Makefile b/usr.sbin/bootpd/Makefile
new file mode 100644
index 00000000000..fbd05538d5d
--- /dev/null
+++ b/usr.sbin/bootpd/Makefile
@@ -0,0 +1,13 @@
+# bootpd/Makefile
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:25 deraadt Exp $
+
+PROG= bootpd
+CFLAGS+= -DETC_ETHERS -DSYSLOG -DDEBUG -DVEND_CMU
+
+SRCS= bootpd.c dovend.c readfile.c hash.c dumptab.c \
+ lookup.c getif.c hwaddr.c report.c tzone.c
+
+MAN= bootpd.8 bootptab.5
+MLINKS= bootpd.8 bootpgw.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bootpd/Makefile.UNIX b/usr.sbin/bootpd/Makefile.UNIX
new file mode 100644
index 00000000000..e333ce5d2ca
--- /dev/null
+++ b/usr.sbin/bootpd/Makefile.UNIX
@@ -0,0 +1,184 @@
+#
+# Makefile for the BOOTP programs:
+# bootpd - BOOTP server daemon
+# bootpef - BOOTP extension file builder
+# bootpgw - BOOTP gateway daemon
+# bootptest - BOOTP tester (client)
+#
+
+# OPTion DEFinitions:
+# Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format"
+# in addition to the RFC1048 format. Leaving out DEBUG saves little.
+OPTDEFS= -DSYSLOG -DVEND_CMU -DDEBUG
+
+# Uncomment and edit this to choose the facility code used for syslog.
+# LOG_FACILITY= "-DLOG_BOOTP=LOG_LOCAL2"
+
+# SYStem DEFinitions:
+# Either uncomment some of the following, or do:
+# "make sunos4" (or "make sunos5", etc.)
+# SYSDEFS= -DSUNOS -DETC_ETHERS
+# SYSDEFS= -DSVR4
+# SYSLIBS= -lsocket -lnsl
+
+# Uncomment this if your system does not provide streror(3)
+# STRERROR=strerror.o
+
+# FILE DEFinitions:
+# The next few lines may be uncommented and changed to alter the default
+# filenames bootpd uses for its configuration and dump files.
+#CONFFILE= -DCONFIG_FILE=\"/usr/etc/bootptab\"
+#DUMPFILE= -DDUMPTAB_FILE=\"/usr/etc/bootpd.dump\"
+#FILEDEFS= $(CONFFILE) $(DUMPFILE)
+
+# MORE DEFinitions (whatever you might want to add)
+# One might define NDEBUG (to remove "assert()" checks).
+MOREDEFS=
+
+INSTALL=/usr/bin/install
+DESTDIR=
+BINDIR=/usr/etc
+MANDIR=/usr/local/man
+
+CFLAGS= $(OPTDEFS) $(SYSDEFS) $(FILEDEFS) $(MOREDEFS)
+PROGS= bootpd bootpef bootpgw bootptest
+TESTS= trylook trygetif trygetea
+
+all: $(PROGS)
+
+tests: $(TESTS)
+
+system: install
+
+install: $(PROGS)
+ -for f in $(PROGS) ;\
+ do \
+ $(INSTALL) -c -s $$f $(DESTDIR)$(BINDIR) ;\
+ done
+
+MAN5= bootptab.5
+MAN8= bootpd.8 bootpef.8 bootptest.8
+install.man: $(MAN5) $(MAN8)
+ -for f in $(MAN5) ;\
+ do \
+ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man5 ;\
+ done
+ -for f in $(MAN8) ;\
+ do \
+ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man8 ;\
+ done
+
+clean:
+ -rm -f core *.o
+ -rm -f $(PROGS) $(TESTS)
+
+distclean:
+ -rm -f *.BAK *.CKP *~ .emacs*
+
+#
+# Handy targets for individual systems:
+#
+
+# DEC/OSF1 on the Alpha
+alpha:
+ $(MAKE) SYSDEFS="-DETC_ETHERS -Dint32=int -D_SOCKADDR_LEN" \
+ STRERROR=strerror.o
+
+# Control Data EP/IX 1.4.3 system, BSD 4.3 mode
+epix143:
+ $(MAKE) CC="cc -systype bsd43" \
+ SYSDEFS="-Dconst= -D_SIZE_T -DNO_UNISTD -DUSE_BFUNCS" \
+ STRERROR=strerror.o
+
+# Control Data EP/IX 2.1.1 system, SVR4 mode
+epix211:
+ $(MAKE) CC="cc -systype svr4" \
+ SYSDEFS="-DSVR4" \
+ SYSLIBS="-lsocket -lnsl"
+
+# Silicon Graphics IRIX (no <sys/sockio.h>, so not SVR4)
+irix:
+ $(MAKE) SYSDEFS="-DSYSV -DIRIX"
+
+# SunOS 4.X
+sunos4:
+ $(MAKE) SYSDEFS="-DSUNOS -DETC_ETHERS" \
+ STRERROR=strerror.o
+
+# Solaris 2.X (i.e. SunOS 5.X)
+sunos5:
+ $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS" \
+ SYSLIBS="-lsocket -lnsl"
+
+# UNIX System V Rel. 4 (also: IRIX 5.X, others)
+svr4:
+ $(MAKE) SYSDEFS="-DSVR4" \
+ SYSLIBS="-lsocket -lnsl"
+
+#
+# How to build each program:
+#
+
+OBJ_D= bootpd.o dovend.o readfile.o hash.o dumptab.o \
+ lookup.o getif.o hwaddr.o tzone.o report.o $(STRERROR)
+bootpd: $(OBJ_D)
+ $(CC) -o $@ $(OBJ_D) $(SYSLIBS)
+
+OBJ_EF= bootpef.o dovend.o readfile.o hash.o dumptab.o \
+ lookup.o hwaddr.o tzone.o report.o $(STRERROR)
+bootpef: $(OBJ_EF)
+ $(CC) -o $@ $(OBJ_EF) $(SYSLIBS)
+
+OBJ_GW= bootpgw.o getif.o hwaddr.o report.o $(STRERROR)
+bootpgw: $(OBJ_GW)
+ $(CC) -o $@ $(OBJ_GW) $(SYSLIBS)
+
+OBJ_TEST= bootptest.o print-bootp.o getif.o getether.o \
+ report.o $(STRERROR)
+bootptest: $(OBJ_TEST)
+ $(CC) -o $@ $(OBJ_TEST) $(SYSLIBS)
+
+# This is just for testing the lookup functions.
+TRYLOOK= trylook.o lookup.o report.o $(STRERROR)
+trylook : $(TRYLOOK)
+ $(CC) -o $@ $(TRYLOOK) $(SYSLIBS)
+
+# This is just for testing getif.
+TRYGETIF= trygetif.o getif.o report.o $(STRERROR)
+trygetif : $(TRYGETIF)
+ $(CC) -o $@ $(TRYGETIF) $(SYSLIBS)
+
+# This is just for testing getether.
+TRYGETEA= trygetea.o getether.o report.o $(STRERROR)
+trygetea : $(TRYGETEA)
+ $(CC) -o $@ $(TRYGETEA) $(SYSLIBS)
+
+# This rule just keeps the LOG_BOOTP define localized.
+report.o : report.c
+ $(CC) $(CFLAGS) $(LOG_FACILITY) -c $<
+
+# Punt SunOS -target noise
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+#
+# Header file dependencies:
+#
+
+bootpd.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
+bootpd.o : readfile.h report.h tzone.h patchlevel.h getif.h
+bootpef.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
+bootpef.o : readfile.h report.h tzone.h patchlevel.h
+bootpgw.o : bootp.h bptypes.h getif.h hwaddr.h report.h patchlevel.h
+bootptest.o : bootp.h bptypes.h bootptest.h getif.h patchlevel.h
+dovend.o : bootp.h bptypes.h bootpd.h hash.h hwaddr.h report.h dovend.h
+dumptab.o : bootp.h bptypes.h hash.h hwaddr.h report.h patchlevel.h bootpd.h
+getif.o : getif.h report.h
+hash.o : hash.h
+hwaddr.o : bptypes.h hwaddr.h report.h
+lookup.o : bootp.h bptypes.h lookup.h report.h
+print-bootp.o : bootp.h bptypes.h bootptest.h
+readfile.o : bootp.h bptypes.h hash.h hwaddr.h lookup.h readfile.h
+readfile.o : report.h tzone.h bootpd.h
+report.o : report.h
+tzone.o : bptypes.h report.h tzone.h
diff --git a/usr.sbin/bootpd/Problems b/usr.sbin/bootpd/Problems
new file mode 100644
index 00000000000..9478676eca4
--- /dev/null
+++ b/usr.sbin/bootpd/Problems
@@ -0,0 +1,47 @@
+
+Common problems and ways to work around them:
+
+Bootpd complains that it "can not get IP addr for HOSTNAME"
+
+ If the entry is a "dummy" (not a real host) used only for
+ reference by other entries, put '.' in front of the name.
+
+ If the entry is for a real client and the IP address for
+ the client can not be found using gethostbyname(), specify
+ the IP address for the client using numeric form.
+
+Bootpd takes a long time to finish parsing the bootptab file:
+
+ Excessive startup time is usually caused by waiting for
+ timeouts on failed DNS lookup operations. If this is the
+ problem, find the client names for which DNS lookup fails
+ and change the bootptab to specify the IP addresses for
+ those clients using numeric form.
+
+ When bootptab entries do not specify an ip address, bootpd
+ attempts to lookup the tagname as a host name to find the
+ IP address. To suppress this default action, either make
+ the entry a "dummy" or specify its IP numeric address.
+
+ If your DNS lookups work but are just slow, consider either
+ running bootpd on the same machine as the DNS server or
+ running a caching DNS server on the host running bootpd.
+
+My huge bootptab file causes startup time to be so long that clients
+give up waiting for a reply.
+
+ Truly huge bootptab files make "inetd" mode impractical.
+ Start bootpd in "standalone" mode when the server boots.
+
+ Another possibility is to run one bootpd on each network
+ segment so each one can have a smaller bootptab. Only one
+ instance of bootpd may run on one server, so you would need
+ to use a different server for each network segment.
+
+My bootp clients are given responses with a boot file name that is
+not a fully specified path.
+
+ Make sure the TFTP directory or home directory tags are set:
+ :td=/tftpboot: (or)
+ :hd=/usr/boot: (for example)
+
diff --git a/usr.sbin/bootpd/README b/usr.sbin/bootpd/README
new file mode 100644
index 00000000000..c7755b786dd
--- /dev/null
+++ b/usr.sbin/bootpd/README
@@ -0,0 +1,133 @@
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges all the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+Please direct questions, comments, and bug reports to the list:
+ <bootp@andrew.cmu.edu>
+
+You can subscribe to this mailing list by sending mail to:
+ bootp-request@andrew.cmu.edu
+(The body of the message should contain: "Add <your-address>")
+
+[ From the NetBSD README file: ]
+
+BOOTPD is a useful adjunct to the nfs diskless boot EPROM code.
+
+The alternatives for initiating a boot of a kernel across a network
+are to use RARP protocol, or BOOTP protocol. BOOTP is more flexible;
+it allows additional items of information to be returned to the
+booting client; it also supports booting across gateways.
+
+[ From the CMU README file: ]
+
+Notes:
+1) BOOTP was originally designed and implemented by Bill Croft at Stanford.
+ Much of the credit for the ideas and the code goes to him. We've added
+ code to support the vendor specific area of the packet as specified in
+ RFC1048. We've also improved the host lookup algorithm and added some
+ extra logging.
+
+2) The server now uses syslog to do logging. Specifically it uses the 4.3bsd
+ version. I've #ifdef'd all of these calls. If you are running 4.2 you
+ should compile without the -DSYSLOG switch.
+
+3) You must update your /etc/services file to contain the following two lines:
+ bootps 67/udp bootp # BOOTP Server
+ bootpc 68/udp # BOOTP Client
+
+4) Edit the bootptab. It has some explanitory comments, and there
+ is a manual entry describing its format (bootptab.5)
+ If you have any questions, just let us know.
+
+Construction:
+ [ See the file Installation which is more up-to-date. -gwr ]
+
+ Make sure all of the files exist first. If anything is missing,
+ please contact either Walt Wimer or Drew Perkins by E-mail or phone.
+ Addresses and phone numbers are listed below.
+
+ Type 'make'. The options at present are: -DSYSLOG which enables logging
+ code, -DDEBUG which enables table dumping via signals, and -DVEND_CMU
+ which enables the CMU extensions for CMU PC/IP.
+
+ Edit the bootptab. The man page and the comments in the file should
+ explain how to go about doing so. If you have any problems, let me know.
+
+ Type 'make install'. This should put all of the files in the right place.
+
+ Edit your /etc/rc.local or /etc/inetd.conf file to start up bootpd upon
+ reboot. The following is a sample /etc/inetd.conf entry:
+ # BOOTP server
+ bootps dgram udp wait root /usr/etc/bootpd bootpd -i
+
+Care and feeding:
+ If you change the interface cards on your host or add new hosts you will
+ need to update /etc/bootptab. Just edit it as before. Once you write
+ it back out, bootpd will notice that there is a new copy and will
+ reread it the next time it gets a request.
+
+ If your bootp clients don't get a response then several things might be
+ wrong. Most often, the entry for that host is not in the database.
+ Check the hardware address and then check the entry and make sure
+ everything is right. Other problems include the server machine crashing,
+ bad cables, and the like. If your network is very congested you should
+ try making your bootp clients send additional requests before giving up.
+
+
+November 7, 1988
+
+
+Walter L. Wimer Drew D. Perkins
+ww0n@andrew.cmu.edu ddp@andrew.cmu.edu
+(412) 268-6252 (412) 268-8576
+
+4910 Forbes Ave
+Pittsburgh, PA 15213
+
+[ Contents description by file: ]
+
+Announce* Text of release announcements
+Changes Change history, reverse chronological
+Installation Instructions for building and installing
+Makefile* for "make"
+README This file
+ToDo Things not yet done
+bootp.h The protocol header file
+bootpd.8 Manual page for bootpd, boopgw
+bootpd.c BOOTP server main module
+bootpd.h header for above (and others)
+bootpef.8 Manual page for bootpef
+bootpef.c BOOTP extension file compiler
+bootpgw.c BOOTP gateway main module
+bootptab.5 A manual describing the bootptab format
+bootptab.cmu A sample database file for the server
+bootptab.mcs Another sample from <gwr@mc.com>
+bootptest.8 Manual page for bootptest
+bootptest.c BOOTP test program (fake client)
+bootptest.h header for above
+dovend.c Vendor Option builder (for bootpd, bootpef)
+dovend.h header for above
+dumptab.c Implements debugging dump for bootpd
+getether.c For bootptest (not used yet)
+getif.c Get network interface info.
+getif.h header for above
+hash.c The hash table module
+hash.h header for above
+hwaddr.c Hardware address support
+hwaddr.h header for above
+lookup.c Internet Protocol address lookup
+lookup.h header for above
+patchlevel.h Holds version numbers
+print-bootp.c Prints BOOTP packets (taken from BSD tcpdump)
+readfile.c The configuration file-reading routines
+readfile.h header for above
+report.c Does syslog-style messages
+report.h header for above
+strerror.c Library errno-to-string (for systems lacking it)
+syslog.conf Sample config file for syslogd(8)
+syslog.h For systems that lack syslog(3)
+try*.c Test programs (for debugging)
+tzone.c Get timezone offset
+tzone.h header for above
diff --git a/usr.sbin/bootpd/bootp.h b/usr.sbin/bootpd/bootp.h
new file mode 100644
index 00000000000..60d43359f63
--- /dev/null
+++ b/usr.sbin/bootpd/bootp.h
@@ -0,0 +1,147 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1395.
+ *
+ * $Id: bootp.h,v 1.1.1.1 1995/10/18 08:47:25 deraadt Exp $
+ *
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ */
+
+#include "bptypes.h" /* for int32, u_int32 */
+
+#define BP_CHADDR_LEN 16
+#define BP_SNAME_LEN 64
+#define BP_FILE_LEN 128
+#define BP_VEND_LEN 64
+#define BP_MINPKTSZ 300 /* to check sizeof(struct bootp) */
+
+struct bootp {
+ unsigned char bp_op; /* packet opcode type */
+ unsigned char bp_htype; /* hardware addr type */
+ unsigned char bp_hlen; /* hardware addr length */
+ unsigned char bp_hops; /* gateway hops */
+ u_int32 bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_flags; /* RFC1532 broadcast, etc. */
+ struct in_addr bp_ciaddr; /* client IP address */
+ struct in_addr bp_yiaddr; /* 'your' IP address */
+ struct in_addr bp_siaddr; /* server IP address */
+ struct in_addr bp_giaddr; /* gateway IP address */
+ unsigned char bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */
+ char bp_sname[BP_SNAME_LEN]; /* server host name */
+ char bp_file[BP_FILE_LEN]; /* boot file name */
+ unsigned char bp_vend[BP_VEND_LEN]; /* vendor-specific area */
+ /* note that bp_vend can be longer, extending to end of packet. */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define IPPORT_BOOTPS 67
+#define IPPORT_BOOTPC 68
+
+#define BOOTREPLY 2
+#define BOOTREQUEST 1
+
+/*
+ * Hardware types from Assigned Numbers RFC.
+ */
+#define HTYPE_ETHERNET 1
+#define HTYPE_EXP_ETHERNET 2
+#define HTYPE_AX25 3
+#define HTYPE_PRONET 4
+#define HTYPE_CHAOS 5
+#define HTYPE_IEEE802 6
+#define HTYPE_ARCNET 7
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048 { 99, 130, 83, 99 }
+
+
+
+/*
+ * Tag values used to specify what information is being supplied in
+ * the vendor (options) data area of the packet.
+ */
+/* RFC 1048 */
+#define TAG_END ((unsigned char) 255)
+#define TAG_PAD ((unsigned char) 0)
+#define TAG_SUBNET_MASK ((unsigned char) 1)
+#define TAG_TIME_OFFSET ((unsigned char) 2)
+#define TAG_GATEWAY ((unsigned char) 3)
+#define TAG_TIME_SERVER ((unsigned char) 4)
+#define TAG_NAME_SERVER ((unsigned char) 5)
+#define TAG_DOMAIN_SERVER ((unsigned char) 6)
+#define TAG_LOG_SERVER ((unsigned char) 7)
+#define TAG_COOKIE_SERVER ((unsigned char) 8)
+#define TAG_LPR_SERVER ((unsigned char) 9)
+#define TAG_IMPRESS_SERVER ((unsigned char) 10)
+#define TAG_RLP_SERVER ((unsigned char) 11)
+#define TAG_HOST_NAME ((unsigned char) 12)
+#define TAG_BOOT_SIZE ((unsigned char) 13)
+/* RFC 1395 */
+#define TAG_DUMP_FILE ((unsigned char) 14)
+#define TAG_DOMAIN_NAME ((unsigned char) 15)
+#define TAG_SWAP_SERVER ((unsigned char) 16)
+#define TAG_ROOT_PATH ((unsigned char) 17)
+/* RFC 1497 */
+#define TAG_EXTEN_FILE ((unsigned char) 18)
+/* RFC 1533 */
+#define TAG_NIS_DOMAIN ((unsigned char) 40)
+#define TAG_NIS_SERVER ((unsigned char) 41)
+#define TAG_NTP_SERVER ((unsigned char) 42)
+/* DHCP maximum message size. */
+#define TAG_MAX_MSGSZ ((unsigned char) 57)
+
+/* XXX - Add new tags here */
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ char v_magic[4]; /* magic number */
+ u_int32 v_flags; /* flags/opcodes, etc. */
+ struct in_addr v_smask; /* Subnet mask */
+ struct in_addr v_dgate; /* Default gateway */
+ struct in_addr v_dns1, v_dns2; /* Domain name servers */
+ struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
+ struct in_addr v_ts1, v_ts2; /* Time servers */
+ int32 v_unused[6]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/usr.sbin/bootpd/bootpd.8 b/usr.sbin/bootpd/bootpd.8
new file mode 100644
index 00000000000..ece114614a2
--- /dev/null
+++ b/usr.sbin/bootpd/bootpd.8
@@ -0,0 +1,305 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /home/cvs/src/usr.sbin/bootpd/Attic/bootpd.8,v 1.1.1.1 1995/10/18 08:47:25 deraadt Exp $
+.\"
+.TH BOOTPD 8 "November 06, 1993" "Carnegie Mellon University"
+.SH NAME
+bootpd, bootpgw \- Internet Boot Protocol server/gateway
+.SH SYNOPSIS
+.B bootpd
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+.B \-c
+chdir\-path
+]
+[
+.I bootptab
+[
+.I dumpfile
+] ]
+.br
+.B bootpgw
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+] server
+.SH DESCRIPTION
+.I Bootpd
+implements an Internet Bootstrap Protocol (BOOTP) server as defined in
+RFC951, RFC1532, and RFC1533.
+.I Bootpgw
+implements a simple BOOTP gateway which can be used to forward
+requests and responses between clients on one subnet and a
+BOOTP server (i.e.
+.IR bootpd )
+on another subnet. While either
+.I bootpd
+or
+.I bootpgw
+will forward BOOTREPLY packets, only
+.I bootpgw
+will forward BOOTREQUEST packets.
+.PP
+One host on each network segment is normally configured to run either
+.I bootpd
+or
+.I bootpgw
+from
+.I inetd
+by including one of the following lines in the file
+.IR /etc/inetd.conf :
+.IP
+bootps dgram udp wait root /etc/bootpd bootpd bootptab
+.br
+bootps dgram udp wait root /etc/bootpgw bootpgw server
+.PP
+This mode of operation is referred to as "inetd mode" and causes
+.I bootpd
+(or
+.IR bootpgw )
+to be started only when a boot request arrives. If it does not
+receive another packet within fifteen minutes of the last one
+it received, it will exit to conserve system resources. The
+.B \-t
+option controls this timeout (see OPTIONS).
+.PP
+It is also possible to run
+.I bootpd
+(or
+.IR bootpgw )
+in "standalone mode" (without
+.IR inetd )
+by simply invoking it from a shell like any other regular command.
+Standalone mode is particularly useful when
+.I bootpd
+is used with a large configuration database, where the start up
+delay might otherwise prevent timely response to client requests.
+(Automatic start up in standalone mode can be done by invoking
+.I bootpd
+from within
+.IR /etc/rc.local ,
+for example.)
+Standalone mode is less useful for
+.I bootgw
+which
+has very little start up delay because
+it does not read a configuration file.
+.PP
+Either program automatically detects whether it was invoked from inetd
+or from a shell and automatically selects the appropriate mode.
+The
+.B \-s
+or
+.B \-i
+option may be used to force standalone or inetd mode respectively
+(see OPTIONS).
+.SH OPTIONS
+.TP
+.BI \-t \ timeout
+Specifies the
+.I timeout
+value (in minutes) that a
+.I bootpd
+or
+.I bootpgw
+process will wait for a BOOTP packet before exiting.
+If no packets are recieved for
+.I timeout
+seconds, then the program will exit.
+A timeout value of zero means "run forever".
+In standalone mode, this option is forced to zero.
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
+For example, -d4 or -d 4 will set the debugging level to 4.
+For compatibility with older versions of
+.IR bootpd ,
+omitting the numeric parameter (i.e. just -d) will
+simply increment the debug level by one.
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpd
+while checking the existence and size of client boot files. This is
+useful when client boot files are specified as relative pathnames, and
+.I bootpd
+needs to use the same current directory as the TFTP server
+(typically /tftpboot). This option is not recoginzed by
+.IR bootpgw .
+.TP
+.B \-i
+Force inetd mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.B \-s
+Force standalone mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.I bootptab
+Specifies the name of the configuration file from which
+.I bootpd
+loads its database of known clients and client options
+.RI ( bootpd
+only).
+.TP
+.I dumpfile
+Specifies the name of the file that
+.I bootpd
+will dump its internal database into when it receives a
+SIGUSR1 signal
+.RI ( bootpd
+only). This option is only recognized if
+.I bootpd
+was compiled with the -DDEBUG flag.
+.TP
+.I server
+Specifies the name of a BOOTP server to which
+.I bootpgw
+will forward all BOOTREQUEST packets it receives
+.RI ( bootpgw
+only).
+.SH OPERATION
+.PP
+Both
+.I bootpd
+and
+.I bootpgw
+operate similarly in that both listen for any packets sent to the
+.I bootps
+port, and both simply forward any BOOTREPLY packets.
+They differ in their handling of BOOTREQUEST packets.
+.PP
+When
+.I bootpgw
+is started, it determines the address of a BOOTP server
+whose name is provided as a command line parameter. When
+.I bootpgw
+receives a BOOTREQUEST packet, it sets the "gateway address"
+and "hop count" fields in the packet and forwards the packet
+to the BOOTP server at the address determined earlier.
+Requests are forwarded only if they indicate that
+the client has been waiting for at least three seconds.
+.PP
+When
+.I bootpd
+is started it reads a configuration file, (normally
+.IR /etc/bootptab )
+that initializes the internal database of known clients and client
+options. This internal database is reloaded
+from the configuration file when
+.I bootpd
+receives a hangup signal (SIGHUP) or when it discovers that the
+configuration file has changed.
+.PP
+When
+.I bootpd
+receives a BOOTREQUEST packet, it
+.\" checks the modification time of the
+.\" configuration file and reloads the database if necessary. Then it
+looks for a database entry matching the client request.
+If the client is known,
+.I bootpd
+composes a BOOTREPLY packet using the database entry found above,
+and sends the reply to the client (possibly using a gateway).
+If the client is unknown, the request is discarded
+(with a notice if debug > 0).
+.PP
+If
+.I bootpd
+is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes
+it to dump its internal database to the file
+.I /etc/bootpd.dump
+or the dumpfile specified as a command line parameter.
+.PP
+During initialization, both programs
+determine the UDP port numbers to be used by calling
+.I getservbyname
+(which nomally uses
+.IR /etc/services).
+Two service names (and port numbers) are used:
+.IP
+bootps \- BOOTP Server listening port
+.br
+bootpc \- BOOTP Client destination port
+.LP
+If the port numbers cannot
+be determined using
+.I getservbyname
+then the values default to boopts=67 and bootpc=68.
+.SH FILES
+.TP 20
+/etc/bootptab
+Database file read by
+.IR bootpd .
+.TP
+/etc/bootpd.dump
+Debugging dump file created by
+.IR bootpd .
+.TP
+/etc/services
+Internet service numbers.
+.TP
+/tftpboot
+Current directory typically used by the TFTP server and
+.IR bootpd .
+
+.SH BUGS
+Individual host entries must not exceed 1024 characters.
+
+.SH CREDITS
+.PP
+This distribution is currently maintained by
+Walter L. Wimer <walt+@cmu.edu>.
+.PP
+The original BOOTP server was created by
+Bill Croft at Stanford University in January 1986.
+.PP
+The current version of
+.I bootpd
+is primarily the work of David Kovar,
+Drew D. Perkins, and Walter L. Wimer,
+at Carnegie Mellon University.
+.TP
+Enhancements and bug\-fixes have been contributed by:
+(in alphabetical order)
+.br
+Danny Backx <db@sunbim.be>
+.br
+John Brezak <brezak@ch.hp.com>
+.br
+Frank da Cruz <fdc@cc.columbia.edu>
+.br
+David R. Linn <drl@vuse.vanderbilt.edu>
+.br
+Jim McKim <mckim@lerc.nasa.gov>
+.br
+Gordon W. Ross <gwr@mc.com>
+.br
+Jason Zions <jazz@hal.com>
+.SH "SEE ALSO"
+.LP
+bootptab(5), inetd(8), tftpd(8)
+.LP
+DARPA Internet Request For Comments:
+.TP 10
+RFC951
+Bootstrap Protocol
+.TP 10
+RFC1532
+Clarifications and Extensions for the Bootstrap Protocol
+.TP 10
+RFC1533
+DHCP Options and BOOTP Vendor Extensions
diff --git a/usr.sbin/bootpd/bootpd.c b/usr.sbin/bootpd/bootpd.c
new file mode 100644
index 00000000000..483a6a1b067
--- /dev/null
+++ b/usr.sbin/bootpd/bootpd.c
@@ -0,0 +1,1380 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Id: bootpd.c,v 1.1.1.1 1995/10/18 08:47:25 deraadt Exp $";
+#endif
+
+/*
+ * BOOTP (bootstrap protocol) server daemon.
+ *
+ * Answers BOOTP request packets from booting client machines.
+ * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
+ * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
+ * See RFC 1395 for option tags 14-17.
+ * See accompanying man page -- bootpd.8
+ *
+ * HISTORY
+ * See ./Changes
+ *
+ * BUGS
+ * See ./ToDo
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifdef SVR4
+/* Using sigset() avoids the need to re-arm each time. */
+#define signal sigset
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "bootpd.h"
+#include "dovend.h"
+#include "getif.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+#ifndef DUMPTAB_FILE
+#define DUMPTAB_FILE "/tmp/bootpd.dump"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void dumptab P((char *));
+
+PRIVATE void catcher P((int));
+PRIVATE int chk_access P((char *, int32 *));
+#ifdef VEND_CMU
+PRIVATE void dovend_cmu P((struct bootp *, struct host *));
+#endif
+PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
+PRIVATE void handle_reply P((void));
+PRIVATE void handle_request P((void));
+PRIVATE void sendreply P((int forward, int32 dest_override));
+PRIVATE void usage P((void));
+
+#undef P
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in bind_addr; /* Listening */
+struct sockaddr_in recv_addr; /* Packet source */
+struct sockaddr_in send_addr; /* destination */
+
+
+/*
+ * option defaults
+ */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
+
+/*
+ * General
+ */
+
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *chdir_path;
+char hostname[MAXHOSTNAMELEN]; /* System host name */
+struct in_addr my_ip_addr;
+
+/* Flags set by signal catcher. */
+PRIVATE int do_readtab = 0;
+PRIVATE int do_dumptab = 0;
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = CONFIG_FILE;
+char *bootpd_dump = DUMPTAB_FILE;
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAX_MSG_SIZE);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
+
+ /*
+ * Check to see if a socket was passed to us from inetd.
+ *
+ * Use getsockname() to determine if descriptor 0 is indeed a socket
+ * (and thus we are probably a child of inetd) or if it is instead
+ * something else and we are running standalone.
+ */
+ s = 0;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_ERR, "getsockname: not an INET socket");
+ }
+ }
+
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ fprintf(stderr,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug level */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'h': /* override hostname */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp) {
+ fprintf(stderr,
+ "bootpd: missing hostname\n");
+ break;
+ }
+ strncpy(hostname, stmp, sizeof(hostname)-1);
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
+ break;
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (60 * n);
+ /*
+ * If the actual timeout is zero, pass a NULL pointer
+ * to select so it blocks indefinitely, otherwise,
+ * point to the actual timeout value.
+ */
+ timeout = (n > 0) ? &actualtimeout : NULL;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+
+ } /* switch */
+ } /* for args */
+
+ /*
+ * Override default file names if specified on the command line.
+ */
+ if (argc > 0)
+ bootptab = argv[0];
+
+ if (argc > 1)
+ bootpd_dump = argv[1];
+
+ /*
+ * Get my hostname and IP address.
+ */
+ if (hostname[0] == '\0') {
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ fprintf(stderr, "bootpd: can't get hostname\n");
+ exit(1);
+ }
+ }
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ fprintf(stderr, "Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
+
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+
+ } /* if standalone (1st) */
+
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
+
+ /* Get the timezone. */
+ tzone_init();
+
+ /* Allocate hash tables. */
+ rdtab_init();
+
+ /*
+ * Read the bootptab file.
+ */
+ readtab(1); /* force read */
+
+ if (standalone) {
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", get_network_errmsg());
+ exit(1);
+ }
+
+ /*
+ * Get server's listening port number
+ */
+ servp = getservbyname("bootps", "udp");
+ if (servp) {
+ bootps_port = ntohs((u_short) servp->s_port);
+ } else {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bind_addr.sin_port = htons(bootps_port);
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone (2nd)*/
+
+ /*
+ * Get destination port number so we can reply to client
+ */
+ servp = getservbyname("bootpc", "udp");
+ if (servp) {
+ bootpc_port = ntohs(servp->s_port);
+ } else {
+ report(LOG_ERR,
+ "udp/bootpc: unknown service -- assuming port %d",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /*
+ * Set up signals to read or dump the table.
+ */
+ if ((long) signal(SIGHUP, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
+ }
+ if ((long) signal(SIGUSR1, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
+ }
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ readfds = 1 << s;
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ /*
+ * Call readtab() or dumptab() here to avoid the
+ * dangers of doing I/O from a signal handler.
+ */
+ if (do_readtab) {
+ do_readtab = 0;
+ readtab(1); /* force read */
+ }
+ if (do_dumptab) {
+ do_dumptab = 0;
+ dumptab(bootpd_dump);
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ if (debug > 1)
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(recv_addr);
+ n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 1) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
+
+ readtab(0); /* maybe re-read bootptab */
+
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+PRIVATE void
+usage()
+{
+ fprintf(stderr,
+ "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
+ fprintf(stderr, "\t -c n\tset current directory\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
+ fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
+ fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
+ exit(1);
+}
+
+/* Signal catchers */
+PRIVATE void
+catcher(sig)
+ int sig;
+{
+ if (sig == SIGHUP)
+ do_readtab = 1;
+ if (sig == SIGUSR1)
+ do_dumptab = 1;
+#ifdef SYSV
+ /* For older "System V" derivatives with no sigset(). */
+ /* XXX - Should just do it the POSIX way (sigaction). */
+ signal(sig, catcher);
+#endif
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * Note: This version of the bootpd.c server never forwards
+ * a request to another server. That is the job of a gateway
+ * program such as the "bootpgw" program included here.
+ *
+ * (Also this version does not interpret the hostname field of
+ * the request packet; it COULD do a name->address lookup and
+ * forward the request there.)
+ */
+PRIVATE void
+handle_request()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct host *hp = NULL;
+ struct host dummyhost;
+ int32 bootsize = 0;
+ unsigned hlen, hashcode;
+ int32 dest;
+ char realpath[1024];
+ char *clntpath;
+ char *homedir, *bootfile;
+ int n;
+
+ /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
+
+ /*
+ * If the servername field is set, compare it against us.
+ * If we're not being addressed, ignore this request.
+ * If the server name field is null, throw in our name.
+ */
+ if (strlen(bp->bp_sname)) {
+ if (strcmp(bp->bp_sname, hostname)) {
+ if (debug)
+ report(LOG_INFO, "\
+ignoring request for server %s from client at %s address %s",
+ bp->bp_sname, netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ /* XXX - Is it correct to ignore such a request? -gwr */
+ return;
+ }
+ } else {
+ strcpy(bp->bp_sname, hostname);
+ }
+
+ /* Convert the request into a reply. */
+ bp->bp_op = BOOTREPLY;
+ if (bp->bp_ciaddr.s_addr == 0) {
+ /*
+ * client doesnt know his IP address,
+ * search by hardware address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ }
+ hlen = haddrlength(bp->bp_htype);
+ if (hlen != bp->bp_hlen) {
+ report(LOG_NOTICE, "bad addr len from from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, hlen));
+ }
+ dummyhost.htype = bp->bp_htype;
+ bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
+ hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
+ &dummyhost);
+ if (hp == NULL &&
+ bp->bp_htype == HTYPE_IEEE802)
+ {
+ /* Try again with address in "canonical" form. */
+ haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
+ if (debug > 1) {
+ report(LOG_INFO, "\
+HW addr type is IEEE 802. convert to %s and check again\n",
+ haddrtoa(dummyhost.haddr, bp->bp_hlen));
+ }
+ hashcode = hash_HashFunction(dummyhost.haddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
+ hwlookcmp, &dummyhost);
+ }
+ if (hp == NULL) {
+ /*
+ * XXX - Add dynamic IP address assignment?
+ */
+ if (debug > 1)
+ report(LOG_INFO, "unknown client %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ return; /* not found */
+ }
+ (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
+
+ } else {
+
+ /*
+ * search by IP address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from IP addr %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
+ hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
+ hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
+ &dummyhost);
+ if (hp == NULL) {
+ if (debug > 1) {
+ report(LOG_NOTICE, "IP address not found: %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ return;
+ }
+ }
+
+ if (debug) {
+ report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
+ hp->hostname->string);
+ }
+
+ /*
+ * If there is a response delay threshold, ignore requests
+ * with a timestamp lower than the threshold.
+ */
+ if (hp->flags.min_wait) {
+ u_int32 t = (u_int32) ntohs(bp->bp_secs);
+ if (t < hp->min_wait) {
+ if (debug > 1)
+ report(LOG_INFO,
+ "ignoring request due to timestamp (%d < %d)",
+ t, hp->min_wait);
+ return;
+ }
+ }
+
+#ifdef YORK_EX_OPTION
+ /*
+ * The need for the "ex" tag arose out of the need to empty
+ * shared networked drives on diskless PCs. This solution is
+ * not very clean but it does work fairly well.
+ * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
+ *
+ * XXX - This could compromise security if a non-trusted user
+ * managed to write an entry in the bootptab with :ex=trojan:
+ * so I would leave this turned off unless you need it. -gwr
+ */
+ /* Run a program, passing the client name as a parameter. */
+ if (hp->flags.exec_file) {
+ char tst[100];
+ /* XXX - Check string lengths? -gwr */
+ strcpy (tst, hp->exec_file->string);
+ strcat (tst, " ");
+ strcat (tst, hp->hostname->string);
+ strcat (tst, " &");
+ if (debug)
+ report(LOG_INFO, "executing %s", tst);
+ system(tst); /* Hope this finishes soon... */
+ }
+#endif /* YORK_EX_OPTION */
+
+ /*
+ * If a specific TFTP server address was specified in the bootptab file,
+ * fill it in, otherwise zero it.
+ * XXX - Rather than zero it, should it be the bootpd address? -gwr
+ */
+ (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
+ hp->bootserver.s_addr : 0L;
+
+#ifdef STANFORD_PROM_COMPAT
+ /*
+ * Stanford bootp PROMs (for a Sun?) have no way to leave
+ * the boot file name field blank (because the boot file
+ * name is automatically generated from some index).
+ * As a work-around, this little hack allows those PROMs to
+ * specify "sunboot14" with the same effect as a NULL name.
+ * (The user specifies boot device 14 or some such magic.)
+ */
+ if (strcmp(bp->bp_file, "sunboot14") == 0)
+ bp->bp_file[0] = '\0'; /* treat it as unspecified */
+#endif
+
+ /*
+ * Fill in the client's proper bootfile.
+ *
+ * If the client specifies an absolute path, try that file with a
+ * ".host" suffix and then without. If the file cannot be found, no
+ * reply is made at all.
+ *
+ * If the client specifies a null or relative file, use the following
+ * table to determine the appropriate action:
+ *
+ * Homedir Bootfile Client's file
+ * specified? specified? specification Action
+ * -------------------------------------------------------------------
+ * No No Null Send null filename
+ * No No Relative Discard request
+ * No Yes Null Send if absolute else null
+ * No Yes Relative Discard request *XXX
+ * Yes No Null Send null filename
+ * Yes No Relative Lookup with ".host"
+ * Yes Yes Null Send home/boot or bootfile
+ * Yes Yes Relative Lookup with ".host" *XXX
+ *
+ */
+
+ /*
+ * XXX - I don't like the policy of ignoring a client when the
+ * boot file is not accessible. The TFTP server might not be
+ * running on the same machine as the BOOTP server, in which
+ * case checking accessibility of the boot file is pointless.
+ *
+ * Therefore, file accessibility is now demanded ONLY if you
+ * define CHECK_FILE_ACCESS in the Makefile options. -gwr
+ */
+
+ /*
+ * The "real" path is as seen by the BOOTP daemon on this
+ * machine, while the client path is relative to the TFTP
+ * daemon chroot directory (i.e. /tftpboot).
+ */
+ if (hp->flags.tftpdir) {
+ strcpy(realpath, hp->tftpdir->string);
+ clntpath = &realpath[strlen(realpath)];
+ } else {
+ realpath[0] = '\0';
+ clntpath = realpath;
+ }
+
+ /*
+ * Determine client's requested homedir and bootfile.
+ */
+ homedir = NULL;
+ bootfile = NULL;
+ if (bp->bp_file[0]) {
+ homedir = bp->bp_file;
+ bootfile = strrchr(homedir, '/');
+ if (bootfile) {
+ if (homedir == bootfile)
+ homedir = NULL;
+ *bootfile++ = '\0';
+ } else {
+ /* no "/" in the string */
+ bootfile = homedir;
+ homedir = NULL;
+ }
+ if (debug > 2) {
+ report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
+ (homedir) ? homedir : "",
+ (bootfile) ? bootfile : "");
+ }
+ }
+
+ /*
+ * Specifications in bootptab override client requested values.
+ */
+ if (hp->flags.homedir)
+ homedir = hp->homedir->string;
+ if (hp->flags.bootfile)
+ bootfile = hp->bootfile->string;
+
+ /*
+ * Construct bootfile path.
+ */
+ if (homedir) {
+ if (homedir[0] != '/')
+ strcat(clntpath, "/");
+ strcat(clntpath, homedir);
+ homedir = NULL;
+ }
+ if (bootfile) {
+ if (bootfile[0] != '/')
+ strcat(clntpath, "/");
+ strcat(clntpath, bootfile);
+ bootfile = NULL;
+ }
+
+ /*
+ * First try to find the file with a ".host" suffix
+ */
+ n = strlen(clntpath);
+ strcat(clntpath, ".");
+ strcat(clntpath, hp->hostname->string);
+ if (chk_access(realpath, &bootsize) < 0) {
+ clntpath[n] = 0; /* Try it without the suffix */
+ if (chk_access(realpath, &bootsize) < 0) {
+ /* neither "file.host" nor "file" was found */
+#ifdef CHECK_FILE_ACCESS
+
+ if (bp->bp_file[0]) {
+ /*
+ * Client wanted specific file
+ * and we didn't have it.
+ */
+ report(LOG_NOTICE,
+ "requested file not found: \"%s\"", clntpath);
+ return;
+ }
+ /*
+ * Client didn't ask for a specific file and we couldn't
+ * access the default file, so just zero-out the bootfile
+ * field in the packet and continue processing the reply.
+ */
+ bzero(bp->bp_file, sizeof(bp->bp_file));
+ goto null_file_name;
+
+#else /* CHECK_FILE_ACCESS */
+
+ /* Complain only if boot file size was needed. */
+ if (hp->flags.bootsize_auto) {
+ report(LOG_ERR, "can not determine size of file \"%s\"",
+ clntpath);
+ }
+
+#endif /* CHECK_FILE_ACCESS */
+ }
+ }
+ strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
+ if (debug > 2)
+ report(LOG_INFO, "bootfile=\"%s\"", clntpath);
+
+null_file_name:
+
+
+ /*
+ * Handle vendor options based on magic number.
+ */
+
+ if (debug > 1) {
+ report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
+ (int) ((bp->bp_vend)[0]),
+ (int) ((bp->bp_vend)[1]),
+ (int) ((bp->bp_vend)[2]),
+ (int) ((bp->bp_vend)[3]));
+ }
+ /*
+ * If this host isn't set for automatic vendor info then copy the
+ * specific cookie into the bootp packet, thus forcing a certain
+ * reply format. Only force reply format if user specified it.
+ */
+ if (hp->flags.vm_cookie) {
+ /* Slam in the user specified magic number. */
+ bcopy(hp->vm_cookie, bp->bp_vend, 4);
+ }
+ /*
+ * Figure out the format for the vendor-specific info.
+ * Note that bp->bp_vend may have been set above.
+ */
+ if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
+ /* RFC1048 conformant bootp client */
+ dovend_rfc1048(bp, hp, bootsize);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with RFC1048 options)");
+ }
+ }
+#ifdef VEND_CMU
+ else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
+ dovend_cmu(bp, hp);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with CMU options)");
+ }
+ }
+#endif
+ else {
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with no options)");
+ }
+ }
+
+ dest = (hp->flags.reply_addr) ?
+ hp->reply_addr.s_addr : 0L;
+
+ /* not forwarded */
+ sendreply(0, dest);
+}
+
+
+/*
+ * Process BOOTREPLY packet.
+ */
+PRIVATE void
+handle_reply()
+{
+ if (debug) {
+ report(LOG_INFO, "processing boot reply");
+ }
+ /* forwarded, no destination override */
+ sendreply(1, 0);
+}
+
+
+/*
+ * Send a reply packet to the client. 'forward' flag is set if we are
+ * not the originator of this reply packet.
+ */
+PRIVATE void
+sendreply(forward, dst_override)
+ int forward;
+ int32 dst_override;
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct in_addr dst;
+ u_short port = bootpc_port;
+ unsigned char *ha;
+ int len;
+
+ /*
+ * XXX - Should honor bp_flags "broadcast" bit here.
+ * Temporary workaround: use the :ra=ADDR: option to
+ * set the reply address to the broadcast address.
+ */
+
+ /*
+ * If the destination address was specified explicitly
+ * (i.e. the broadcast address for HP compatiblity)
+ * then send the response to that address. Otherwise,
+ * act in accordance with RFC951:
+ * If the client IP address is specified, use that
+ * else if gateway IP address is specified, use that
+ * else make a temporary arp cache entry for the client's
+ * NEW IP/hardware address and use that.
+ */
+ if (dst_override) {
+ dst.s_addr = dst_override;
+ if (debug > 1) {
+ report(LOG_INFO, "reply address override: %s",
+ inet_ntoa(dst));
+ }
+ } else if (bp->bp_ciaddr.s_addr) {
+ dst = bp->bp_ciaddr;
+ } else if (bp->bp_giaddr.s_addr && forward == 0) {
+ dst = bp->bp_giaddr;
+ port = bootps_port;
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply to gateway %s",
+ inet_ntoa(dst));
+ }
+ } else {
+ dst = bp->bp_yiaddr;
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(dst), haddrtoa(ha, len));
+ setarp(s, &dst, ha, len);
+ }
+
+ if ((forward == 0) &&
+ (bp->bp_siaddr.s_addr == 0))
+ {
+ struct ifreq *ifr;
+ struct in_addr siaddr;
+ /*
+ * If we are originating this reply, we
+ * need to find our own interface address to
+ * put in the bp_siaddr field of the reply.
+ * If this server is multi-homed, pick the
+ * 'best' interface (the one on the same net
+ * as the client). Of course, the client may
+ * be on the other side of a BOOTP gateway...
+ */
+ ifr = getif(s, &dst);
+ if (ifr) {
+ struct sockaddr_in *sip;
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ siaddr = sip->sin_addr;
+ } else {
+ /* Just use my "official" IP address. */
+ siaddr = my_ip_addr;
+ }
+
+ /* XXX - No need to set bp_giaddr here. */
+
+ /* Finally, set the server address field. */
+ bp->bp_siaddr = siaddr;
+ }
+ /* Set up socket address for send. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(port);
+ send_addr.sin_addr = dst;
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+} /* sendreply */
+
+
+/* nmatch() - now in getif.c */
+/* setarp() - now in hwaddr.c */
+
+
+/*
+ * This call checks read access to a file. It returns 0 if the file given
+ * by "path" exists and is publically readable. A value of -1 is returned if
+ * access is not permitted or an error occurs. Successful calls also
+ * return the file size in bytes using the long pointer "filesize".
+ *
+ * The read permission bit for "other" users is checked. This bit must be
+ * set for tftpd(8) to allow clients to read the file.
+ */
+
+PRIVATE int
+chk_access(path, filesize)
+ char *path;
+ int32 *filesize;
+{
+ struct stat st;
+
+ if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
+ *filesize = (int32) st.st_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+/*
+ * Now in dumptab.c :
+ * dumptab()
+ * dump_host()
+ * list_ipaddresses()
+ */
+
+#ifdef VEND_CMU
+
+/*
+ * Insert the CMU "vendor" data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+
+PRIVATE void
+dovend_cmu(bp, hp)
+ struct bootp *bp;
+ struct host *hp;
+{
+ struct cmu_vend *vendp;
+ struct in_addr_list *taddr;
+
+ /*
+ * Initialize the entire vendor field to zeroes.
+ */
+ bzero(bp->bp_vend, sizeof(bp->bp_vend));
+
+ /*
+ * Fill in vendor information. Subnet mask, default gateway,
+ * domain name server, ien name server, time server
+ */
+ vendp = (struct cmu_vend *) bp->bp_vend;
+ strcpy(vendp->v_magic, (char *)vm_cmu);
+ if (hp->flags.subnet_mask) {
+ (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
+ (vendp->v_flags) |= VF_SMASK;
+ if (hp->flags.gateway) {
+ (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
+ }
+ }
+ if (hp->flags.domain_server) {
+ taddr = hp->domain_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ if (hp->flags.name_server) {
+ taddr = hp->name_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ if (hp->flags.time_server) {
+ taddr = hp->time_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ /* Log message now done by caller. */
+} /* dovend_cmu */
+
+#endif /* VEND_CMU */
+
+
+
+/*
+ * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return; \
+ } while (0)
+PRIVATE void
+dovend_rfc1048(bp, hp, bootsize)
+ struct bootp *bp;
+ struct host *hp;
+ int32 bootsize;
+{
+ int bytesleft, len;
+ byte *vp;
+ char *tmpstr;
+
+ static char noroom[] = "%s: No room for \"%s\" option";
+
+ vp = bp->bp_vend;
+
+ if (hp->flags.msg_size) {
+ pktlen = hp->msg_size;
+ } else {
+ /*
+ * If the request was longer than the official length, build
+ * a response of that same length where the additional length
+ * is assumed to be part of the bp_vend (options) area.
+ */
+ if (pktlen > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "request message length=%d", pktlen);
+ }
+ /*
+ * Check whether the request contains the option:
+ * Maximum DHCP Message Size (RFC1533 sec. 9.8)
+ * and if so, override the response length with its value.
+ * This request must lie within the first BP_VEND_LEN
+ * bytes of the option space.
+ */
+ {
+ byte *p, *ep;
+ byte tag, len;
+ short msgsz = 0;
+
+ p = vp + 4;
+ ep = p + BP_VEND_LEN - 4;
+ while (p < ep) {
+ tag = *p++;
+ /* Check for tags with no data first. */
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ break;
+ /* Now scan the length byte. */
+ len = *p++;
+ switch (tag) {
+ case TAG_MAX_MSGSZ:
+ if (len == 2) {
+ bcopy(p, (char*)&msgsz, 2);
+ msgsz = ntohs(msgsz);
+ }
+ break;
+ case TAG_SUBNET_MASK:
+ /* XXX - Should preserve this if given... */
+ break;
+ } /* swtich */
+ p += len;
+ }
+
+ if (msgsz > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
+ pktlen = msgsz;
+ }
+ }
+ }
+
+ if (pktlen < sizeof(*bp)) {
+ report(LOG_ERR, "invalid response length=%d", pktlen);
+ pktlen = sizeof(*bp);
+ }
+ bytesleft = ((byte*)bp + pktlen) - vp;
+ if (pktlen > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "extended reply, length=%d, options=%d",
+ pktlen, bytesleft);
+ }
+
+ /* Copy in the magic cookie */
+ bcopy(vm_rfc1048, vp, 4);
+ vp += 4;
+ bytesleft -= 4;
+
+ if (hp->flags.subnet_mask) {
+ /* always enough room here. */
+ *vp++ = TAG_SUBNET_MASK;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ if (hp->flags.gateway) {
+ (void) insert_ip(TAG_GATEWAY,
+ hp->gateway,
+ &vp, &bytesleft);
+ }
+ }
+ if (hp->flags.bootsize) {
+ /* always enough room here */
+ bootsize = (hp->flags.bootsize_auto) ?
+ ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
+ *vp++ = TAG_BOOT_SIZE;
+ *vp++ = 2;
+ *vp++ = (byte) ((bootsize >> 8) & 0xFF);
+ *vp++ = (byte) (bootsize & 0xFF);
+ bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
+ }
+ /*
+ * This one is special: Remaining options go in the ext file.
+ * Only the subnet_mask, bootsize, and gateway should precede.
+ */
+ if (hp->flags.exten_file) {
+ /*
+ * Check for room for exten_file. Add 3 to account for
+ * TAG_EXTEN_FILE, length, and TAG_END.
+ */
+ len = strlen(hp->exten_file->string);
+ NEED((len + 3), "ef");
+ *vp++ = TAG_EXTEN_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->exten_file->string, vp, len);
+ vp += len;
+ *vp++ = TAG_END;
+ bytesleft -= len + 3;
+ return; /* no more options here. */
+ }
+ /*
+ * The remaining options are inserted by the following
+ * function (which is shared with bootpef.c).
+ * Keep back one byte for the TAG_END.
+ */
+ len = dovend_rfc1497(hp, vp, bytesleft - 1);
+ vp += len;
+ bytesleft -= len;
+
+ /* There should be at least one byte left. */
+ NEED(1, "(end)");
+ *vp++ = TAG_END;
+ bytesleft--;
+
+ /* Log message done by caller. */
+ if (bytesleft > 0) {
+ /*
+ * Zero out any remaining part of the vendor area.
+ */
+ bzero(vp, bytesleft);
+ }
+} /* dovend_rfc1048 */
+#undef NEED
+
+
+/*
+ * Now in readfile.c:
+ * hwlookcmp()
+ * iplookcmp()
+ */
+
+/* haddrtoa() - now in hwaddr.c */
+/*
+ * Now in dovend.c:
+ * insert_ip()
+ * insert_generic()
+ * insert_u_long()
+ */
+
+/* get_errmsg() - now in report.c */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/bootpd.h b/usr.sbin/bootpd/bootpd.h
new file mode 100644
index 00000000000..11c4a8b41d6
--- /dev/null
+++ b/usr.sbin/bootpd/bootpd.h
@@ -0,0 +1,211 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+
+/*
+ * bootpd.h -- common header file for all the modules of the bootpd program.
+ */
+
+#include "bptypes.h"
+#include "hash.h"
+#include "hwaddr.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+#ifndef SIGUSR1
+#define SIGUSR1 30 /* From 4.3 <signal.h> */
+#endif
+
+#define MAXSTRINGLEN 80 /* Max string length */
+
+/* Local definitions: */
+#define MAX_MSG_SIZE (3*512) /* Maximum packet size */
+
+
+/*
+ * Return pointer to static string which gives full network error message.
+ */
+#define get_network_errmsg get_errmsg
+
+
+/*
+ * Data structure used to hold an arbitrary-lengthed list of IP addresses.
+ * The list may be shared among multiple hosts by setting the linkcount
+ * appropriately.
+ */
+
+struct in_addr_list {
+ unsigned int linkcount, addrcount;
+ struct in_addr addr[1]; /* Dynamically extended */
+};
+
+
+/*
+ * Data structures used to hold shared strings and shared binary data.
+ * The linkcount must be set appropriately.
+ */
+
+struct shared_string {
+ unsigned int linkcount;
+ char string[1]; /* Dynamically extended */
+};
+
+struct shared_bindata {
+ unsigned int linkcount, length;
+ byte data[1]; /* Dynamically extended */
+};
+
+
+/*
+ * Flag structure which indicates which symbols have been defined for a
+ * given host. This information is used to determine which data should or
+ * should not be reported in the bootp packet vendor info field.
+ */
+
+struct flag {
+ unsigned bootfile :1,
+ bootserver :1,
+ bootsize :1,
+ bootsize_auto :1,
+ cookie_server :1,
+ domain_server :1,
+ gateway :1,
+ generic :1,
+ haddr :1,
+ homedir :1,
+ htype :1,
+ impress_server :1,
+ iaddr :1,
+ log_server :1,
+ lpr_server :1,
+ name_server :1,
+ name_switch :1,
+ rlp_server :1,
+ send_name :1,
+ subnet_mask :1,
+ tftpdir :1,
+ time_offset :1,
+ time_server :1,
+ dump_file :1,
+ domain_name :1,
+ swap_server :1,
+ root_path :1,
+ exten_file :1,
+ reply_addr :1,
+ nis_domain :1,
+ nis_server :1,
+ ntp_server :1,
+ exec_file :1,
+ msg_size :1,
+ min_wait :1,
+ /* XXX - Add new tags here */
+ vm_cookie :1;
+};
+
+
+
+/*
+ * The flags structure contains TRUE flags for all the fields which
+ * are considered valid, regardless of whether they were explicitly
+ * specified or indirectly inferred from another entry.
+ *
+ * The gateway and the various server fields all point to a shared list of
+ * IP addresses.
+ *
+ * The hostname, home directory, and bootfile are all shared strings.
+ *
+ * The generic data field is a shared binary data structure. It is used to
+ * hold future RFC1048 vendor data until bootpd is updated to understand it.
+ *
+ * The vm_cookie field specifies the four-octet vendor magic cookie to use
+ * if it is desired to always send the same response to a given host.
+ *
+ * Hopefully, the rest is self-explanatory.
+ */
+
+struct host {
+ unsigned linkcount; /* hash list inserts */
+ struct flag flags; /* ALL valid fields */
+ struct in_addr_list *cookie_server,
+ *domain_server,
+ *gateway,
+ *impress_server,
+ *log_server,
+ *lpr_server,
+ *name_server,
+ *rlp_server,
+ *time_server,
+ *nis_server,
+ *ntp_server;
+ struct shared_string *bootfile,
+ *hostname,
+ *domain_name,
+ *homedir,
+ *tftpdir,
+ *dump_file,
+ *exten_file,
+ *root_path,
+ *nis_domain,
+ *exec_file;
+ struct shared_bindata *generic;
+ byte vm_cookie[4],
+ htype, /* RFC826 says this should be 16-bits but
+ RFC951 only allocates 1 byte. . . */
+ haddr[MAXHADDRLEN];
+ int32 time_offset;
+ u_int32 bootsize,
+ msg_size,
+ min_wait;
+ struct in_addr bootserver,
+ iaddr,
+ swap_server,
+ reply_addr,
+ subnet_mask;
+ /* XXX - Add new tags here (or above as appropriate) */
+};
+
+
+
+/*
+ * Variables shared among modules.
+ */
+
+extern int debug;
+extern char *bootptab;
+extern char *progname;
+
+extern u_char vm_cmu[4];
+extern u_char vm_rfc1048[4];
+
+extern hash_tbl *hwhashtable;
+extern hash_tbl *iphashtable;
+extern hash_tbl *nmhashtable;
+
diff --git a/usr.sbin/bootpd/bootpef.8 b/usr.sbin/bootpd/bootpef.8
new file mode 100644
index 00000000000..0f0b1fc7b43
--- /dev/null
+++ b/usr.sbin/bootpd/bootpef.8
@@ -0,0 +1,52 @@
+.\" bootpef.8
+.TH BOOTPEF 8 "4 Dec 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootpef \- BOOTP Extension File compiler
+.SH SYNOPSIS
+.LP
+.B bootpef
+.RI [ "-c chdir" ]
+.RI [ "-d debug-level" ]
+.RI [ "-f config-file" ]
+.RI [ client-name " [...]]"
+.SH DESCRIPTION
+.B bootpef
+builds the
+.I Extension Path
+files described by RFC 1497 (tag 18).
+If any
+.I client-name
+arguments are specified, then
+.I bootpef
+compiles the extension files for only those clients.
+.SH OPTIONS
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpef
+while creating extension files. This is useful when the
+extension file names are specified as relative pathnames, and
+.I bootpef
+needs to use the same current directory as the TFTP server
+(typically /tftpboot).
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
+For example, -d4 or -d 4 will set the debugging level to 4.
+.TP
+.BI \-f \ config\-file
+Set the name of the config file that specifies the option
+data to be sent to each client.
+.SH "SEE ALSO"
+bootpd(8), tftpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1497
+BOOTP Vendor Information Extensions
+
+
diff --git a/usr.sbin/bootpd/bootpef.c b/usr.sbin/bootpd/bootpef.c
new file mode 100644
index 00000000000..489c4972b97
--- /dev/null
+++ b/usr.sbin/bootpd/bootpef.c
@@ -0,0 +1,347 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Id: bootpef.c,v 1.1.1.1 1995/10/18 08:47:26 deraadt Exp $";
+#endif
+
+
+/*
+ * bootpef - BOOTP Extension File generator
+ * Makes an "Extension File" for each host entry that
+ * defines an and Extension File. (See RFC1497, tag 18.)
+ *
+ * HISTORY
+ * See ./Changes
+ *
+ * BUGS
+ * See ./ToDo
+ */
+
+
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "bootpd.h"
+#include "dovend.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
+
+#define BUFFERSIZE 0x4000
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void dovend_rfc1048 P((struct bootp *, struct host *, int32));
+static void mktagfile P((struct host *));
+static void usage P((void));
+
+#undef P
+
+
+/*
+ * General
+ */
+
+char *progname;
+char *chdir_path;
+int debug = 0; /* Debugging flag (level) */
+byte *buffer;
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = CONFIG_FILE;
+
+
+/*
+ * Print "usage" message and exit
+ */
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
+ fprintf(stderr, "\t -c n\tset current directory\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -f n\tconfig file name\n");
+ exit(1);
+}
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct host *hp;
+ char *stmp;
+ int n;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /* Get work space for making tag 18 files. */
+ buffer = (byte *) malloc(BUFFERSIZE);
+ if (!buffer) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ fprintf(stderr,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "bootpd: invalid debug level\n");
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'f': /* config file */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ bootptab = stmp;
+ break;
+
+ default:
+ fprintf(stderr, "bootpd: unknown switch: -%c\n",
+ argv[0][1]);
+ usage();
+ break;
+ }
+ }
+
+ /* Get the timezone. */
+ tzone_init();
+
+ /* Allocate hash tables. */
+ rdtab_init();
+
+ /*
+ * Read the bootptab file.
+ */
+ readtab(1); /* force read */
+
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
+ /* If there are host names on the command line, do only those. */
+ if (argc > 0) {
+ unsigned int tlen, hashcode;
+
+ while (argc) {
+ tlen = strlen(argv[0]);
+ hashcode = hash_HashFunction((u_char *)argv[0], tlen);
+ hp = (struct host *) hash_Lookup(nmhashtable,
+ hashcode,
+ nmcmp, argv[0]);
+ if (!hp) {
+ printf("%s: no matching entry\n", argv[0]);
+ exit(1);
+ }
+ if (!hp->flags.exten_file) {
+ printf("%s: no extension file\n", argv[0]);
+ exit(1);
+ }
+ mktagfile(hp);
+ argv++;
+ argc--;
+ }
+ exit(0);
+ }
+ /* No host names specified. Do them all. */
+ hp = (struct host *) hash_FirstEntry(nmhashtable);
+ while (hp != NULL) {
+ mktagfile(hp);
+ hp = (struct host *) hash_NextEntry(nmhashtable);
+ }
+}
+
+
+
+/*
+ * Make a "TAG 18" file for this host.
+ * (Insert the RFC1497 options.)
+ */
+
+static void
+mktagfile(hp)
+ struct host *hp;
+{
+ FILE *fp;
+ int bytesleft, len;
+ byte *vp;
+ char *tmpstr;
+
+ if (!hp->flags.exten_file)
+ return;
+
+ vp = buffer;
+ bytesleft = BUFFERSIZE;
+ bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
+ vp += 4;
+ bytesleft -= 4;
+
+ /*
+ * The "extension file" options are appended by the following
+ * function (which is shared with bootpd.c).
+ */
+ len = dovend_rfc1497(hp, vp, bytesleft);
+ vp += len;
+ bytesleft -= len;
+
+ if (bytesleft < 1) {
+ report(LOG_ERR, "%s: too much option data",
+ hp->exten_file->string);
+ return;
+ }
+ *vp++ = TAG_END;
+ bytesleft--;
+
+ /* Write the buffer to the extension file. */
+ printf("Updating \"%s\"\n", hp->exten_file->string);
+ if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ hp->exten_file->string, get_errmsg());
+ return;
+ }
+ len = vp - buffer;
+ if (len != fwrite(buffer, 1, len, fp)) {
+ report(LOG_ERR, "write failed on \"%s\" : %s",
+ hp->exten_file->string, get_errmsg());
+ }
+ fclose(fp);
+
+} /* dovend_rfc1048 */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/bootpgw.c b/usr.sbin/bootpd/bootpgw.c
new file mode 100644
index 00000000000..527550c3dcd
--- /dev/null
+++ b/usr.sbin/bootpd/bootpgw.c
@@ -0,0 +1,672 @@
+/*
+ * bootpgw.c - BOOTP GateWay
+ * This program forwards BOOTP Request packets to a BOOTP server.
+ */
+
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Id: bootpgw.c,v 1.1.1.1 1995/10/18 08:47:26 deraadt Exp $";
+#endif
+
+/*
+ * BOOTPGW is typically used to forward BOOTP client requests from
+ * one subnet to a BOOTP server on a different subnet.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "getif.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+
+/* Local definitions: */
+#define MAX_MSG_SIZE (3*512) /* Maximum packet size */
+#define TRUE 1
+#define FALSE 0
+#define get_network_errmsg get_errmsg
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void usage P((void));
+static void handle_reply P((void));
+static void handle_request P((void));
+
+#undef P
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in bind_addr; /* Listening */
+struct sockaddr_in clnt_addr; /* client address */
+struct sockaddr_in serv_addr; /* server address */
+
+
+/*
+ * option defaults
+ */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
+u_int maxhops = 4; /* Number of hops allowed for requests. */
+u_int minwait = 3; /* Number of seconds client must wait before
+ its bootrequest packets are forwarded. */
+
+/*
+ * General
+ */
+
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *servername;
+
+char myhostname[64];
+struct in_addr my_ip_addr;
+
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAX_MSG_SIZE);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
+
+ /*
+ * Check to see if a socket was passed to us from inetd.
+ *
+ * Use getsockname() to determine if descriptor 0 is indeed a socket
+ * (and thus we are probably a child of inetd) or if it is instead
+ * something else and we are running standalone.
+ */
+ s = 0;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_INFO, "getsockname: not an INET socket");
+ }
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
+ gethostname(myhostname, sizeof(myhostname));
+ hep = gethostbyname(myhostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'd': /* debug level */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'h': /* hop count limit */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 16))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid hop count limit\n");
+ break;
+ }
+ maxhops = (u_int)n;
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
+ break;
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (60 * n);
+ /*
+ * If the actual timeout is zero, pass a NULL pointer
+ * to select so it blocks indefinitely, otherwise,
+ * point to the actual timeout value.
+ */
+ timeout = (n > 0) ? &actualtimeout : NULL;
+ break;
+
+ case 'w': /* wait time */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 60))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid wait time\n");
+ break;
+ }
+ minwait = (u_int)n;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+
+ } /* switch */
+ } /* for args */
+
+ /* Make sure server name argument is suplied. */
+ servername = argv[0];
+ if (!servername) {
+ fprintf(stderr, "bootpgw: missing server name\n");
+ usage();
+ }
+ /*
+ * Get address of real bootp server.
+ */
+ if (inet_aton(servername, &serv_addr.sin_addr) == 0) {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "bootpgw: can't get addr for %s\n", servername);
+ exit(1);
+ }
+ memcpy(&serv_addr.sin_addr, hep->h_addr,
+ sizeof(serv_addr.sin_addr));
+ }
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ * XXX - This is not the POSIX way (Should use setsid). -gwr
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+
+ /*
+ * Here, bootpd would do:
+ * chdir
+ * tzone_init
+ * rdtab_init
+ * readtab
+ */
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", get_network_errmsg());
+ exit(1);
+ }
+ /*
+ * Get server's listening port number
+ */
+ servp = getservbyname("bootps", "udp");
+ if (servp) {
+ bootps_port = ntohs((u_short) servp->s_port);
+ } else {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_port = htons(bootps_port);
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone */
+ /*
+ * Get destination port number so we can reply to client
+ */
+ servp = getservbyname("bootpc", "udp");
+ if (servp) {
+ bootpc_port = ntohs(servp->s_port);
+ } else {
+ report(LOG_ERR,
+ "udp/bootpc: unknown service -- assuming port %d",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /* no signal catchers */
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ readfds = 1 << s;
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(clnt_addr);
+ n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
+ (struct sockaddr *) &clnt_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 3) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(clnt_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
+
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: bootpgw [-d level] [-i] [-s] [-t timeout] server\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -h n\tset max hop count\n");
+ fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
+ fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
+ fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
+ fprintf(stderr, "\t -w n\tset min wait time (secs)\n");
+ exit(1);
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * Note, this just forwards the request to a real server.
+ */
+static void
+handle_request()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct ifreq *ifr;
+ u_short secs, hops;
+
+ /* XXX - SLIP init: Set bp_ciaddr = clnt_addr here? */
+
+ if (debug) {
+ report(LOG_INFO, "request from %s",
+ inet_ntoa(clnt_addr.sin_addr));
+ }
+ /* Has the client been waiting long enough? */
+ secs = ntohs(bp->bp_secs);
+ if (secs < minwait)
+ return;
+
+ /* Has this packet hopped too many times? */
+ hops = ntohs(bp->bp_hops);
+ if (++hops > maxhops) {
+ report(LOG_NOTICE, "request from %s reached hop limit",
+ inet_ntoa(clnt_addr.sin_addr));
+ return;
+ }
+ bp->bp_hops = htons(hops);
+
+ /*
+ * Here one might discard a request from the same subnet as the
+ * real server, but we can assume that the real server will send
+ * a reply to the client before it waits for minwait seconds.
+ */
+
+ /* If gateway address is not set, put in local interface addr. */
+ if (bp->bp_giaddr.s_addr == 0) {
+#if 0 /* BUG */
+ struct sockaddr_in *sip;
+ /*
+ * XXX - This picks the wrong interface when the receive addr
+ * is the broadcast address. There is no portable way to
+ * find out which interface a broadcast was received on. -gwr
+ * (Thanks to <walker@zk3.dec.com> for finding this bug!)
+ */
+ ifr = getif(s, &clnt_addr.sin_addr);
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for request from %s",
+ inet_ntoa(clnt_addr.sin_addr));
+ return;
+ }
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#else /* BUG */
+ /*
+ * XXX - Just set "giaddr" to our "official" IP address.
+ * RFC 1532 says giaddr MUST be set to the address of the
+ * interface on which the request was received. Setting
+ * it to our "default" IP address is not strictly correct,
+ * but is good enough to allow the real BOOTP server to
+ * get the reply back here. Then, before we forward the
+ * reply to the client, the giaddr field is corrected.
+ * (In case the client uses giaddr, which it should not.)
+ * See handle_reply()
+ */
+ bp->bp_giaddr = my_ip_addr;
+#endif /* BUG */
+
+ /*
+ * XXX - DHCP says to insert a subnet mask option into the
+ * options area of the request (if vendor magic == std).
+ */
+ }
+ /* Set up socket address for send. */
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(bootps_port);
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &serv_addr,
+ sizeof(serv_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+
+
+/*
+ * Process BOOTREPLY packet.
+ */
+static void
+handle_reply()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct ifreq *ifr;
+ struct sockaddr_in *sip;
+ u_char canon_haddr[MAXHADDRLEN];
+ unsigned char *ha;
+ int len;
+
+ if (debug) {
+ report(LOG_INFO, " reply for %s",
+ inet_ntoa(bp->bp_yiaddr));
+ }
+ /* Make sure client is directly accessible. */
+ ifr = getif(s, &(bp->bp_yiaddr));
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for reply to %s",
+ inet_ntoa(bp->bp_yiaddr));
+ return;
+ }
+#if 1 /* Experimental (see BUG above) */
+/* #ifdef CATER_TO_OLD_CLIENTS ? */
+ /*
+ * The giaddr field has been set to our "default" IP address
+ * which might not be on the same interface as the client.
+ * In case the client looks at giaddr, (which it should not)
+ * giaddr is now set to the address of the correct interface.
+ */
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#endif
+
+ /* Set up socket address for send to client. */
+ clnt_addr.sin_family = AF_INET;
+ clnt_addr.sin_addr = bp->bp_yiaddr;
+ clnt_addr.sin_port = htons(bootpc_port);
+
+ /* Create an ARP cache entry for the client. */
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+ if (bp->bp_htype == HTYPE_IEEE802) {
+ haddr_conv802(ha, canon_haddr, len);
+ ha = canon_haddr;
+ }
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(bp->bp_yiaddr), haddrtoa(ha, len));
+ setarp(s, &bp->bp_yiaddr, ha, len);
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &clnt_addr,
+ sizeof(clnt_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/bootptab.5 b/usr.sbin/bootpd/bootptab.5
new file mode 100644
index 00000000000..99b4646c3e2
--- /dev/null
+++ b/usr.sbin/bootpd/bootptab.5
@@ -0,0 +1,395 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /home/cvs/src/usr.sbin/bootpd/Attic/bootptab.5,v 1.1.1.1 1995/10/18 08:47:26 deraadt Exp $
+.\"
+.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
+.UC 6
+
+.SH NAME
+bootptab \- Internet Bootstrap Protocol server database
+.SH DESCRIPTION
+The
+.I bootptab
+file is the configuration database file for
+.IR bootpd ,
+the Internet Bootstrap Protocol server.
+It's format is similar to that of
+.IR termcap (5)
+in which two-character case-sensitive tag symbols are used to
+represent host parameters. These parameter declarations are separated by
+colons (:), with a general format of:
+.PP
+.I " hostname:tg=value. . . :tg=value. . . :tg=value. . . ."
+.PP
+where
+.I hostname
+is the actual name of a bootp client (or a "dummy entry"), and
+.I tg
+is a two-character tag symbol. Dummy entries have an invalid hostname
+(one with a "." as the first character) and are used to provide
+default values used by other entries via the
+.B tc=.dummy-entry
+mechanism. Most tags must be followed by an equals-sign
+and a value as above. Some may also appear in a boolean form with no
+value (i.e.
+.RI : tg :).
+The currently recognized tags are:
+.PP
+.br
+ bf Bootfile
+.br
+ bs Bootfile size in 512-octet blocks
+.br
+ cs Cookie server address list
+.br
+ df Merit dump file
+.br
+ dn Domain name
+.br
+ ds Domain name server address list
+.br
+ ef Extension file
+.br
+ gw Gateway address list
+.br
+ ha Host hardware address
+.br
+ hd Bootfile home directory
+.br
+ hn Send client's hostname to client
+.br
+ ht Host hardware type (see Assigned Numbers RFC)
+.br
+ im Impress server address list
+.br
+ ip Host IP address
+.br
+ lg Log server address list
+.br
+ lp LPR server address list
+.br
+ ns IEN-116 name server address list
+.br
+ nt NTP (time) Server (RFC 1129)
+.br
+ ra Reply address override
+.br
+ rl Resource location protocol server address list
+.br
+ rp Root path to mount as root
+.br
+ sa TFTP server address client should use
+.br
+ sm Host subnet mask
+.br
+ sw Swap server address
+.br
+ tc Table continuation (points to similar "template" host entry)
+.br
+ td TFTP root directory used by "secure" TFTP servers
+.br
+ to Time offset in seconds from UTC
+.br
+ ts Time server address list
+.br
+ vm Vendor magic cookie selector
+.br
+ yd YP (NIS) domain name
+.br
+ ys YP (NIS) server address
+
+.PP
+There is also a generic tag,
+.RI T n ,
+where
+.I n
+is an RFC1084 vendor field tag number. Thus it is possible to immediately
+take advantage of future extensions to RFC1084 without being forced to modify
+.I bootpd
+first. Generic data may be represented as either a stream of hexadecimal
+numbers or as a quoted string of ASCII characters. The length of the generic
+data is automatically determined and inserted into the proper field(s) of the
+RFC1084-style bootp reply.
+.PP
+The following tags take a whitespace-separated list of IP addresses:
+.BR cs ,
+.BR ds ,
+.BR gw ,
+.BR im ,
+.BR lg ,
+.BR lp ,
+.BR ns ,
+.BR nt ,
+.BR ra ,
+.BR rl ,
+and
+.BR ts .
+The
+.BR ip ,
+.BR sa ,
+.BR sw ,
+.BR sm ,
+and
+.B ys
+tags each take a single IP address.
+All IP addresses are specified in standard Internet "dot" notation
+and may use decimal, octal, or hexadecimal numbers
+(octal numbers begin with 0, hexadecimal numbers begin with '0x' or '0X').
+Any IP addresses may alternatively be specified as a hostname, causing
+.I bootpd
+to lookup the IP address for that host name using gethostbyname(3).
+If the
+.B ip
+tag is not specified,
+.I bootpd
+will determine the IP address using the entry name as the host name.
+(Dummy entries use an invalid host name to avoid automatic IP lookup.)
+.PP
+The
+.B ht
+tag specifies the hardware type code as either an unsigned decimal, octal, or
+hexadecimal integer or one of the following symbolic names:
+.B ethernet
+or
+.B ether
+for 10Mb Ethernet,
+.B ethernet3
+or
+.B ether3
+for 3Mb experimental Ethernet,
+.BR ieee802 ,
+.BR tr ,
+or
+.B token-ring
+for IEEE 802 networks,
+.B pronet
+for Proteon ProNET Token Ring, or
+.BR chaos ,
+.BR arcnet ,
+or
+.B ax.25
+for Chaos, ARCNET, and AX.25 Amateur Radio networks, respectively.
+The
+.B ha
+tag takes a hardware address which may be specified as a host name
+or in numeric form. Note that the numeric form
+.I must
+be specified in hexadecimal; optional periods and/or a leading '0x' may be
+included for readability. The
+.B ha
+tag must be preceded by the
+.B ht
+tag (either explicitly or implicitly; see
+.B tc
+below).
+If the hardware address is not specified and the type is specified
+as either "ethernet" or "ieee802", then
+.I bootpd
+will try to determine the hardware address using ether_hton(3).
+.PP
+The hostname, home directory, and bootfile are ASCII strings which may be
+optionally surrounded by double quotes ("). The client's request and the
+values of the
+.B hd
+and
+.B bf
+symbols determine how the server fills in the bootfile field of the bootp
+reply packet.
+.PP
+If the client provides a file name it is left as is.
+Otherwise, if the
+.B bf
+option is specified its value is copied into the reply packet.
+If the
+.B hd
+option is specified as well, its value is prepended to the
+boot file copied into the reply packet.
+The existence of the boot file is checked only if the
+.BR bs =auto
+option is used (to determine the boot file size).
+A reply may be sent whether or not the boot file exists.
+.PP
+Some newer versions of
+.I tftpd
+provide a security feature to change their root directory using
+the
+.IR chroot (2)
+system call.
+The
+.B td
+tag may be used to inform
+.I bootpd
+of this special root directory used by
+.IR tftpd .
+(One may alternatively use the
+.I bootpd
+"-c chdir" option.)
+The
+.B hd
+tag is actually relative to the root directory specified by the
+.B td
+tag.
+For example, if the real absolute path to your BOOTP client bootfile is
+/tftpboot/bootfiles/bootimage, and
+.IR tftpd
+uses /tftpboot as its "secure" directory, then specify the following in
+.IR bootptab :
+.PP
+.br
+ :td=/tftpboot:hd=/bootfiles:bf=bootimage:
+.PP
+If your bootfiles are located directly in /tftpboot, use:
+.PP
+.br
+ :td=/tftpboot:hd=/:bf=bootimage:
+.PP
+The
+.B sa
+tag may be used to specify the IP address of the particular TFTP server
+you wish the client to use. In the absence of this tag,
+.I bootpd
+will tell the client to perform TFTP to the same machine
+.I bootpd
+is running on.
+.PP
+The time offset
+.B to
+may be either a signed decimal integer specifying the client's
+time zone offset in seconds from UTC, or the keyword
+.B auto
+which uses the server's time zone offset. Specifying the
+.B to
+symbol as a boolean has the same effect as specifying
+.B auto
+as its value.
+.PP
+The bootfile size
+.B bs
+may be either a decimal, octal, or hexadecimal integer specifying the size of
+the bootfile in 512-octet blocks, or the keyword
+.B auto
+which causes the server to automatically calculate the bootfile size at each
+request. As with the time offset, specifying the
+.B bs
+symbol as a boolean has the same effect as specifying
+.B auto
+as its value.
+.PP
+The vendor magic cookie selector (the
+.B vm
+tag) may take one of the following keywords:
+.B auto
+(indicating that vendor information is determined by the client's request),
+.B rfc1048
+or
+.B rfc1084
+(which always forces an RFC1084-style reply), or
+.B cmu
+(which always forces a CMU-style reply).
+.PP
+The
+.B hn
+tag is strictly a boolean tag; it does not take the usual equals-sign and
+value. It's presence indicates that the hostname should be sent to RFC1084
+clients.
+.I Bootpd
+attempts to send the entire hostname as it is specified in the configuration
+file; if this will not fit into the reply packet, the name is shortened to
+just the host field (up to the first period, if present) and then tried.
+In no case is an arbitrarily-truncated hostname sent (if nothing reasonable
+will fit, nothing is sent).
+.PP
+Often, many host entries share common values for certain tags (such as name
+servers, etc.). Rather than repeatedly specifying these tags, a full
+specification can be listed for one host entry and shared by others via the
+.B tc
+(table continuation) mechanism.
+Often, the template entry is a dummy host which doesn't actually exist and
+never sends bootp requests. This feature is similar to the
+.B tc
+feature of
+.IR termcap (5)
+for similar terminals. Note that
+.I bootpd
+allows the
+.B tc
+tag symbol to appear anywhere in the host entry, unlike
+.I termcap
+which requires it to be the last tag. Information explicitly specified for a
+host always overrides information implied by a
+.B tc
+tag symbol, regardless of its location within the entry. The
+value of the
+.B tc
+tag may be the hostname or IP address of any host entry
+previously listed in the configuration file.
+.PP
+Sometimes it is necessary to delete a specific tag after it has been inferred
+via
+.BR tc .
+This can be done using the construction
+.IB tag @
+which removes the effect of
+.I tag
+as in
+.IR termcap (5).
+For example, to completely undo an IEN-116 name server specification, use
+":ns@:" at an appropriate place in the configuration entry. After removal
+with
+.BR @ ,
+a tag is eligible to be set again through the
+.B tc
+mechanism.
+.PP
+Blank lines and lines beginning with "#" are ignored in the configuration
+file. Host entries are separated from one another by newlines; a single host
+entry may be extended over multiple lines if the lines end with a backslash
+(\\). It is also acceptable for lines to be longer than 80 characters. Tags
+may appear in any order, with the following exceptions: the hostname must be
+the very first field in an entry, and the hardware type must precede the
+hardware address.
+.PP
+An example
+.I /etc/bootptab
+file follows:
+.PP
+.nf
+ # Sample bootptab file (domain=andrew.cmu.edu)
+
+ .default:\\
+ :hd=/usr/boot:bf=null:\\
+ :ds=netserver, lancaster:\\
+ :ns=pcs2, pcs1:\\
+ :ts=pcs2, pcs1:\\
+ :sm=255.255.255.0:\\
+ :gw=gw.cs.cmu.edu:\\
+ :hn:to=-18000:
+
+ carnegie:ht=6:ha=7FF8100000AF:tc=.default:
+ baldwin:ht=1:ha=0800200159C3:tc=.default:
+ wylie:ht=1:ha=00DD00CADF00:tc=.default:
+ arnold:ht=1:ha=0800200102AD:tc=.default:
+ bairdford:ht=1:ha=08002B02A2F9:tc=.default:
+ bakerstown:ht=1:ha=08002B0287C8:tc=.default:
+
+ # Special domain name server and option tags for next host
+ butlerjct:ha=08002001560D:ds=128.2.13.42:\\
+ :T37=0x12345927AD3BCF:\\
+ :T99="Special ASCII string":\\
+ :tc=.default:
+
+ gastonville:ht=6:ha=7FFF81000A47:tc=.default:
+ hahntown:ht=6:ha=7FFF81000434:tc=.default:
+ hickman:ht=6:ha=7FFF810001BA:tc=.default:
+ lowber:ht=1:ha=00DD00CAF000:tc=.default:
+ mtoliver:ht=1:ha=00DD00FE1600:tc=.default:
+
+.fi
+.SH FILES
+/etc/bootptab
+
+.SH "SEE ALSO"
+.br
+bootpd(8), tftpd(8),
+.br
+DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers
diff --git a/usr.sbin/bootpd/bootptab.cmu b/usr.sbin/bootpd/bootptab.cmu
new file mode 100644
index 00000000000..66212d421a2
--- /dev/null
+++ b/usr.sbin/bootpd/bootptab.cmu
@@ -0,0 +1,124 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# (I've hacked on this but can't test it... -gwr)
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: andrew.cmu.edu)
+.default:\
+ :hn:dn=cmu.edu:\
+ :hd=/usr/boot:\
+ :ds=netserver, lancaster:\
+ :ns=pcs2, pcs1:\
+ :ts=pcs2, pcs1:\
+ :sm=255.255.0.0:\
+ :gw=gw.cs.cmu.edu:\
+ to=auto:
+
+
+# Next, we can define different master entries for each subnet. . .
+.subnet13 :sm=255.255.255.0:gw=128.2.13.1 :tc=.default:
+.subnet19 :sm=255.255.255.0:gw=128.2.19.1 :tc=.default:
+.subnet232 :sm=255.255.255.0:gw=128.2.232.1 :tc=.default:
+
+#
+# We should be able to use as many levels of indirection as desired. Use
+# your imagination. . .
+#
+
+
+# Individual entries (could also have different servers for some/all of these
+# hosts, but we don't really use this feature at CMU):
+
+carnegie:tc=.subnet13:ht=ieee802:ha=7FF8100000AF:
+baldwin:tc=.subnet19:ha=0800200159C3:
+wylie:tc=.subnet232:ha=00DD00CADF00:
+arnold:tc=.subnet19:ha=0800200102AD:
+bairdford:tc=.subnet19:ha=08002B02A2F9:
+bakerstown:tc=.subnet19:ha=08002B0287C8:
+butlerjct:tc=.subnet232:ha=08002001560D:
+gastonville:tc=.subnet232:ht=ieee802:ha=7FFF81000A47:
+hahntown:tc=.subnet13:ht=ieee802:ha=7FFF81000434:
+hickman:tc=.subnet19:ht=ieee802:ha=7FFF810001BA:
+lowber:tc=.subnet13:ha=00DD00CAF000:
+mtoliver:tc=.subnet19:ha=00DD00FE1600:
+osborne:tc=.subnet232:ha=00DD00CAD600:
+russelton:tc=.subnet232:ha=080020017FC3:
+thornburg:tc=.subnet13:ha=080020012A33:
+
+
+# Hmmm. . . Let's throw in some whitespace for readability. . . .
+
+andrew: tc=.subnet19:ha=00DD00C88900:
+birdville: tc=.subnet19:ha=00DD00FE2D00:
+coudersport: tc=.subnet13:ha=00DD00CB1E00:
+bridgeville: tc=.subnet232:ha=080020011394:
+franklin: tc=.subnet19:ha=08002B02A5D5:
+hollidaysburg: tc=.subnet19:ht=ieee802:ha=7FFF810002C8:
+honesdale: tc=.subnet19:ha=08002B02F83F:
+huntingdon: tc=.subnet19:ha=08002B02E410:
+indiana: tc=.subnet13:ha=08002B029BEC:
+jimthorpe: tc=.subnet232:ha=08002B02FBBA:
+kittanning: tc=.subnet232:ha=08002B0273FC:
+lebanon: tc=.subnet232:ha=08002B037F67:
+lewisburg: tc=.subnet19:ha=50005A1A0DE4:
+middleburg: tc=.subnet232:ha=00DD00FE1200:
+aspinwall: tc=.subnet13:ha=08002B03C163:
+berlin: tc=.subnet13:ha=00DD000A4400:
+norristown: tc=.subnet13:ha=08002001455B:
+pottsville: tc=.subnet13:ha=00DD000A3700:
+ridgway: tc=.subnet19:ha=08002B029425:
+scranton: tc=.subnet232:ha=0800200113A1:
+chalfont: tc=.subnet13:ha=08002001124B:
+washington: tc=.subnet19:ha=00DD00656E00:
+wellsboro: tc=.subnet13:ha=00DD00CB1C00:
+bb1: tc=.subnet19:ha=00DD000A1F00:
+adamstown: tc=.subnet13:ha=08002B02D0E6:
+beta: tc=.subnet19:ha=02070100B197:
+carbondale: tc=.subnet232:ha=08002B022A73:
+clairton: tc=.subnet19:ha=080020010FD1:
+egypt: tc=.subnet13:ha=00DD00847B00:
+fairchance: tc=.subnet232:ha=00DD000AB100:
+fairhope: tc=.subnet232:ha=00DD00CB0800:
+galeton: tc=.subnet232:ha=08002001138C:
+imperial: tc=.subnet232:ha=08002001130C:
+kingston: tc=.subnet232:ha=080020011382:
+knox: tc=.subnet232:ha=50005A1A0D2A:
+lakecity: tc=.subnet13:ha=080020011380:
diff --git a/usr.sbin/bootpd/bootptab.mcs b/usr.sbin/bootpd/bootptab.mcs
new file mode 100644
index 00000000000..6fa04d1347e
--- /dev/null
+++ b/usr.sbin/bootpd/bootptab.mcs
@@ -0,0 +1,92 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# Last update: gwr, Sun Dec 12 19:00:00 EDT 1993
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+
+# If you leave "td" empty, run bootpd with the "-c /tftpboot" switch
+# so path names (boot files) will be interpreted relative to the same
+# directory as tftpd will use when opening files.
+.default:\
+ :hn:dn="mc.com":\
+ :td=/tftpboot:\
+ :ds=merlin, jericho:\
+ :to=auto:
+
+# Next, we can define different master entries for each subnet. . .
+
+.subnet16:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin:\
+ :sa=merlin:
+
+.subnet17:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin-gw:\
+ :sa=merlin-gw:
+
+#
+# We should be able to use as many levels of indirection as desired. Use
+# your imagination. . .
+#
+
+# Individual entries (could also have different servers for some/all of these
+# hosts, but we don't really use this feature at CMU):
+
+# Emulex terminal server
+emulex: tc=.subnet16:ha=00.00.C9.00.42.E0:bf=P4KTL0E:
+
+# Lantronix eps1
+eps1: tc=.subnet16:ha=00.80.A3.04.1D.78:
+
+# Tadpole 885 board.
+tp885: tc=.subnet17:ha=08.00.4C.00.2F.74:bf=tp885sys2.cfe:
+
+# MVME147 VxWorks board.
+#mvme147:tc=.subnet17:ha=08.00.3e.20.da.47:bf=mv147vxw.st:
+
+# These are just for testing
+
+walnut:tc=.subnet16:ha=walnut:
+banana:tc=.subnet17:ha=banana:
+thor:tc=.subnet17:ha=thor:
+classic:tc=.subnet16:ha=classic:
diff --git a/usr.sbin/bootpd/bootptest.8 b/usr.sbin/bootpd/bootptest.8
new file mode 100644
index 00000000000..d076c8bc25b
--- /dev/null
+++ b/usr.sbin/bootpd/bootptest.8
@@ -0,0 +1,74 @@
+.\" bootptest.8
+.TH BOOTPTEST 8 "10 June 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootptest \- send BOOTP queries and print responses
+.SH SYNOPSIS
+.LP
+.B bootptest
+[
+.B \-f
+.I bootfile
+]
+[
+.B \-h
+]
+[
+.B \-m
+.I magic_number
+]
+.I server\-name
+.RI [ template-file ]
+.SH DESCRIPTION
+.B bootptest
+sends BOOTP requests to the host specified as
+.I server\-name
+at one\-second intervals until either a response is received,
+or until ten requests have gone unanswered.
+After a response is received,
+.B bootptest
+will wait one more second listening for additional responses.
+.SH OPTIONS
+.TP
+.B \-f
+.I bootfile
+Fill in the boot file field of the request with
+.IR bootfile .
+.TP
+.B \-h
+Use the hardware (Ethernet) address to identify the client.
+By default, the IP address is copied into the request
+indicating that this client already knows its IP address.
+.TP
+.B \-m
+.I magic_number
+Initialize the first word of the vendor options field with
+.IR magic_number .
+.LP
+A
+.I template-file
+may be specified, in which case
+.B bootptest
+uses the (binary) contents of this file to initialize the
+.I options
+area of the request packet.
+.SH CREDITS
+.LP
+The bootptest program is a combination of original and derived works.
+The main program module (bootptest.c) is original work by
+Gordon W. Ross <gwr@mc.com>.
+The packet printing module (print-bootp.c) is a slightly modified
+version of a file from the BSD tcpdump program.
+.LP
+This program includes software developed by the University of
+California, Lawrence Berkeley Laboratory and its contributors.
+(See the copyright notice in print-bootp.c)
+.SH "SEE ALSO"
+.LP
+bootpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1048
+BOOTP Vendor Information Extensions
diff --git a/usr.sbin/bootpd/bootptest.c b/usr.sbin/bootpd/bootptest.c
new file mode 100644
index 00000000000..d1cbcab92f4
--- /dev/null
+++ b/usr.sbin/bootpd/bootptest.c
@@ -0,0 +1,497 @@
+/*
+ * bootptest.c - Test out a bootp server.
+ *
+ * This simple program was put together from pieces taken from
+ * various places, including the CMU BOOTP client and server.
+ * The packet printing routine is from the Berkeley "tcpdump"
+ * program with some enhancements I added. The print-bootp.c
+ * file was shared with my copy of "tcpdump" and therefore uses
+ * some unusual utility routines that would normally be provided
+ * by various parts of the tcpdump program. Gordon W. Ross
+ *
+ * Boilerplate:
+ *
+ * This program includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory and its contributors.
+ * (See the copyright notice in print-bootp.c)
+ *
+ * The remainder of this program is public domain. You may do
+ * whatever you like with it except claim that you wrote it.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * HISTORY:
+ *
+ * 12/02/93 Released version 1.4 (with bootp-2.3.2)
+ * 11/05/93 Released version 1.3
+ * 10/14/93 Released version 1.2
+ * 10/11/93 Released version 1.1
+ * 09/28/93 Released version 1.0
+ * 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
+ */
+
+char *usage = "bootptest [-h] server-name [vendor-data-template-file]";
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <assert.h>
+
+#include "bootp.h"
+#include "bootptest.h"
+#include "getif.h"
+#include "patchlevel.h"
+
+#define LOG_ERR 1
+#define BUFLEN 1024
+#define WAITSECS 1
+#define MAXWAIT 10
+
+int vflag = 1;
+int tflag = 0;
+int thiszone;
+char *progname;
+unsigned char *packetp;
+unsigned char *snapend;
+int snaplen;
+
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in sin_server; /* where to send requests */
+struct sockaddr_in sin_client; /* for bind and listen */
+struct sockaddr_in sin_from; /* Packet source */
+u_char eaddr[16]; /* Ethernet address */
+
+/*
+ * General
+ */
+
+int debug = 1; /* Debugging flag (level) */
+char hostname[64];
+char *sndbuf; /* Send packet buffer */
+char *rcvbuf; /* Receive packet buffer */
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+
+unsigned char vm_cmu[4] = VM_CMU;
+unsigned char vm_rfc1048[4] = VM_RFC1048;
+short secs; /* How long client has waited */
+
+char *get_errmsg();
+extern void bootp_print();
+
+/*
+ * Initialization such as command-line processing is done, then
+ * the receiver loop is started. Die when interrupted.
+ */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct bootp *bp;
+ struct servent *sep;
+ struct hostent *hep;
+
+ char *servername = NULL;
+ char *vendor_file = NULL;
+ char *bp_file = NULL;
+ int s; /* Socket file descriptor */
+ int n, tolen, fromlen, recvcnt;
+ int use_hwa = 0;
+ int32 vend_magic;
+ int32 xid;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+ argc--;
+ argv++;
+
+ if (debug)
+ printf("%s: version %s.%d\n", progname, VERSION, PATCHLEVEL);
+
+ /*
+ * Verify that "struct bootp" has the correct official size.
+ * (Catch evil compilers that do struct padding.)
+ */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ sndbuf = malloc(BUFLEN);
+ rcvbuf = malloc(BUFLEN);
+ if (!sndbuf || !rcvbuf) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+
+ /* default magic number */
+ bcopy(vm_rfc1048, (char*)&vend_magic, 4);
+
+ /* Handle option switches. */
+ while (argc > 0) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'f': /* File name to reqest. */
+ if (argc < 2)
+ goto error;
+ argc--; argv++;
+ bp_file = *argv;
+ break;
+
+ case 'h': /* Use hardware address. */
+ use_hwa = 1;
+ break;
+
+ case 'm': /* Magic number value. */
+ if (argc < 2)
+ goto error;
+ argc--; argv++;
+ vend_magic = inet_addr(*argv);
+ break;
+
+ error:
+ default:
+ puts(usage);
+ exit(1);
+
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Get server name (or address) for query. */
+ if (argc > 0) {
+ servername = *argv;
+ argc--;
+ argv++;
+ }
+ /* Get optional vendor-data-template-file. */
+ if (argc > 0) {
+ vendor_file = *argv;
+ argc--;
+ argv++;
+ }
+ if (!servername) {
+ printf("missing server name.\n");
+ puts(usage);
+ exit(1);
+ }
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ /*
+ * Get server's listening port number
+ */
+ sep = getservbyname("bootps", "udp");
+ if (sep) {
+ bootps_port = ntohs((u_short) sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootps: unknown service -- using port %d\n",
+ IPPORT_BOOTPS);
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ }
+
+ /*
+ * Set up server socket address (for send)
+ */
+ if (servername) {
+ if (inet_aton(servername, &sin_server.sin_addr) == 0) {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "%s: unknown host\n", servername);
+ exit(1);
+ }
+ memcpy(&sin_server.sin_addr, hep->h_addr,
+ sizeof(sin_server.sin_addr));
+ }
+ } else {
+ /* Get broadcast address */
+ /* XXX - not yet */
+ sin_server.sin_addr.s_addr = INADDR_ANY;
+ }
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_port = htons(bootps_port);
+
+ /*
+ * Get client's listening port number
+ */
+ sep = getservbyname("bootpc", "udp");
+ if (sep) {
+ bootpc_port = ntohs(sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootpc: unknown service -- using port %d\n",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /*
+ * Set up client socket address (for listen)
+ */
+ sin_client.sin_family = AF_INET;
+ sin_client.sin_port = htons(bootpc_port);
+ sin_client.sin_addr.s_addr = INADDR_ANY;
+
+ /*
+ * Bind client socket to BOOTPC port.
+ */
+ if (bind(s, (struct sockaddr *) &sin_client, sizeof(sin_client)) < 0) {
+ perror("bind BOOTPC port");
+ if (errno == EACCES)
+ fprintf(stderr, "You need to run this as root\n");
+ exit(1);
+ }
+ /*
+ * Build a request.
+ */
+ bp = (struct bootp *) sndbuf;
+ bzero(bp, sizeof(*bp));
+ bp->bp_op = BOOTREQUEST;
+ xid = (int32) getpid();
+ bp->bp_xid = (u_int32) htonl(xid);
+ if (bp_file)
+ strncpy(bp->bp_file, bp_file, BP_FILE_LEN);
+
+ /*
+ * Fill in the hardware address (or client IP address)
+ */
+ if (use_hwa) {
+ struct ifreq *ifr;
+
+ ifr = getif(s, &sin_server.sin_addr);
+ if (!ifr) {
+ printf("No interface for %s\n", servername);
+ exit(1);
+ }
+ if (getether(ifr->ifr_name, eaddr)) {
+ printf("Can not get ether addr for %s\n", ifr->ifr_name);
+ exit(1);
+ }
+ /* Copy Ethernet address into request packet. */
+ bp->bp_htype = 1;
+ bp->bp_hlen = 6;
+ bcopy(eaddr, bp->bp_chaddr, bp->bp_hlen);
+ } else {
+ /* Fill in the client IP address. */
+ gethostname(hostname, sizeof(hostname));
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, &bp->bp_ciaddr, hep->h_length);
+ }
+
+ /*
+ * Copy in the default vendor data.
+ */
+ bcopy((char*)&vend_magic, bp->bp_vend, 4);
+ if (vend_magic)
+ bp->bp_vend[4] = TAG_END;
+
+ /*
+ * Read in the "options" part of the request.
+ * This also determines the size of the packet.
+ */
+ snaplen = sizeof(*bp);
+ if (vendor_file) {
+ int fd = open(vendor_file, 0);
+ if (fd < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ /* Compute actual space for options. */
+ n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
+ n = read(fd, bp->bp_vend, n);
+ close(fd);
+ if (n < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ printf("read %d bytes of vendor template\n", n);
+ if (n > BP_VEND_LEN) {
+ printf("warning: extended options in use (len > %d)\n",
+ BP_VEND_LEN);
+ snaplen += (n - BP_VEND_LEN);
+ }
+ }
+ /*
+ * Set globals needed by print_bootp
+ * (called by send_request)
+ */
+ packetp = (unsigned char *) eaddr;
+ snapend = (unsigned char *) sndbuf + snaplen;
+
+ /* Send a request once per second while waiting for replies. */
+ recvcnt = 0;
+ bp->bp_secs = secs = 0;
+ send_request(s);
+ while (1) {
+ struct timeval tv;
+ int readfds;
+
+ tv.tv_sec = WAITSECS;
+ tv.tv_usec = 0L;
+ readfds = (1 << s);
+ n = select(s + 1, (fd_set *) & readfds, NULL, NULL, &tv);
+ if (n < 0) {
+ perror("select");
+ break;
+ }
+ if (n == 0) {
+ /*
+ * We have not received a response in the last second.
+ * If we have ever received any responses, exit now.
+ * Otherwise, bump the "wait time" field and re-send.
+ */
+ if (recvcnt > 0)
+ exit(0);
+ secs += WAITSECS;
+ if (secs > MAXWAIT)
+ break;
+ bp->bp_secs = htons(secs);
+ send_request(s);
+ continue;
+ }
+ fromlen = sizeof(sin_from);
+ n = recvfrom(s, rcvbuf, BUFLEN, 0,
+ (struct sockaddr *) &sin_from, &fromlen);
+ if (n <= 0) {
+ continue;
+ }
+ if (n < sizeof(struct bootp)) {
+ printf("received short packet\n");
+ continue;
+ }
+ recvcnt++;
+
+ /* Print the received packet. */
+ printf("Recvd from %s", inet_ntoa(sin_from.sin_addr));
+ /* set globals needed by bootp_print() */
+ snaplen = n;
+ snapend = (unsigned char *) rcvbuf + snaplen;
+ bootp_print(rcvbuf, n, sin_from.sin_port, 0);
+ putchar('\n');
+ /*
+ * This no longer exits immediately after receiving
+ * one response because it is useful to know if the
+ * client might get multiple responses. This code
+ * will now listen for one second after a response.
+ */
+ }
+ fprintf(stderr, "no response from %s\n", servername);
+ exit(1);
+}
+
+send_request(s)
+ int s;
+{
+ /* Print the request packet. */
+ printf("Sending to %s", inet_ntoa(sin_server.sin_addr));
+ bootp_print(sndbuf, snaplen, sin_from.sin_port, 0);
+ putchar('\n');
+
+ /* Send the request packet. */
+ if (sendto(s, sndbuf, snaplen, 0,
+ (struct sockaddr *) &sin_server,
+ sizeof(sin_server)) < 0)
+ {
+ perror("sendto server");
+ exit(1);
+ }
+}
+
+/*
+ * Print out a filename (or other ascii string).
+ * Return true if truncated.
+ */
+int
+printfn(s, ep)
+ register u_char *s, *ep;
+{
+ register u_char c;
+
+ putchar('"');
+ while (c = *s++) {
+ if (s > ep) {
+ putchar('"');
+ return (1);
+ }
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+ return (0);
+}
+
+/*
+ * Convert an IP addr to a string.
+ * (like inet_ntoa, but ina is a pointer)
+ */
+char *
+ipaddr_string(ina)
+ struct in_addr *ina;
+{
+ static char b[24];
+ u_char *p;
+
+ p = (u_char *) ina;
+ sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ return (b);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/bootptest.h b/usr.sbin/bootpd/bootptest.h
new file mode 100644
index 00000000000..27f78ba963b
--- /dev/null
+++ b/usr.sbin/bootpd/bootptest.h
@@ -0,0 +1,30 @@
+/* bootptest.h */
+/*
+ * Hacks for sharing print-bootp.c between tcpdump and bootptest.
+ */
+#define ESRC(p) (p)
+#define EDST(p) (p)
+
+#ifndef USE_BFUNCS
+/* Use mem/str functions */
+/* There are no overlapped copies, so memcpy is OK. */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+extern int vflag; /* verbose flag */
+
+/* global pointers to beginning and end of current packet (during printing) */
+extern unsigned char *packetp;
+extern unsigned char *snapend;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern char *ipaddr_string P((struct in_addr *));
+
+#undef P
diff --git a/usr.sbin/bootpd/bptypes.h b/usr.sbin/bootpd/bptypes.h
new file mode 100644
index 00000000000..9fe00a8216c
--- /dev/null
+++ b/usr.sbin/bootpd/bptypes.h
@@ -0,0 +1,25 @@
+/* bptypes.h */
+
+#ifndef BPTYPES_H
+#define BPTYPES_H
+
+/*
+ * 32 bit integers are different types on various architectures
+ * XXX THE CORRECT WAY TO DO THIS IS:
+ * XXX (1) convert to _t form for all uses,
+ * XXX (2) define the _t's here (or somewhere)
+ * XXX if !defined(__BIT_TYPES_DEFINED__)
+ */
+
+typedef int32_t int32;
+typedef u_int32_t u_int32;
+
+/*
+ * Nice typedefs. . .
+ */
+
+typedef int boolean;
+typedef unsigned char byte;
+
+
+#endif /* BPTYPES_H */
diff --git a/usr.sbin/bootpd/dovend.c b/usr.sbin/bootpd/dovend.c
new file mode 100644
index 00000000000..ba6ab288b8b
--- /dev/null
+++ b/usr.sbin/bootpd/dovend.c
@@ -0,0 +1,413 @@
+/*
+ * dovend.c : Inserts all but the first few vendor options.
+ */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# define index strchr
+#endif
+
+#include "bootp.h"
+#include "bootpd.h"
+#include "report.h"
+#include "dovend.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE int insert_generic P((struct shared_bindata *, byte **, int *));
+
+/*
+ * Insert the 2nd part of the options into an option buffer.
+ * Return amount of space used.
+ *
+ * This inserts everything EXCEPT:
+ * magic cookie, subnet mask, gateway, bootsize, extension file
+ * Those are handled separately (in bootpd.c) to allow this function
+ * to be shared between bootpd and bootpef.
+ *
+ * When an "extension file" is in use, the options inserted by
+ * this function go into the exten_file, not the bootp response.
+ */
+
+int
+dovend_rfc1497(hp, buf, len)
+ struct host *hp;
+ byte *buf;
+ int len;
+{
+ int bytesleft = len;
+ byte *vp = buf;
+ char *tmpstr;
+
+ static char noroom[] = "%s: No room for \"%s\" option";
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return (vp - buf); \
+ } while (0)
+
+ /*
+ * Note that the following have already been inserted:
+ * magic_cookie, subnet_mask, gateway, bootsize
+ *
+ * The remaining options are inserted in order of importance.
+ * (Of course the importance of each is a matter of opinion.)
+ * The option insertion order should probably be configurable.
+ *
+ * This is the order used in the NetBSD version. Can anyone
+ * explain why the time_offset and swap_server are first?
+ * Also, why is the hostname so far down the list? -gwr
+ */
+
+ if (hp->flags.time_offset) {
+ NEED(6, "to");
+ *vp++ = TAG_TIME_OFFSET;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
+ bytesleft -= 6;
+ }
+ /*
+ * swap server, root path, dump path
+ */
+ if (hp->flags.swap_server) {
+ NEED(6, "sw");
+ /* There is just one SWAP_SERVER, so it is not an iplist. */
+ *vp++ = TAG_SWAP_SERVER;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->swap_server.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ }
+ if (hp->flags.root_path) {
+ /*
+ * Check for room for root_path. Add 2 to account for
+ * TAG_ROOT_PATH and length.
+ */
+ len = strlen(hp->root_path->string);
+ NEED((len + 2), "rp");
+ *vp++ = TAG_ROOT_PATH;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->root_path->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ if (hp->flags.dump_file) {
+ /*
+ * Check for room for dump_file. Add 2 to account for
+ * TAG_DUMP_FILE and length.
+ */
+ len = strlen(hp->dump_file->string);
+ NEED((len + 2), "df");
+ *vp++ = TAG_DUMP_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->dump_file->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * DNS server and domain
+ */
+ if (hp->flags.domain_server) {
+ if (insert_ip(TAG_DOMAIN_SERVER,
+ hp->domain_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.domain_name) {
+ /*
+ * Check for room for domain_name. Add 2 to account for
+ * TAG_DOMAIN_NAME and length.
+ */
+ len = strlen(hp->domain_name->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_DOMAIN_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->domain_name->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * NIS (YP) server and domain
+ */
+ if (hp->flags.nis_server) {
+ if (insert_ip(TAG_NIS_SERVER,
+ hp->nis_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.nis_domain) {
+ /*
+ * Check for room for nis_domain. Add 2 to account for
+ * TAG_NIS_DOMAIN and length.
+ */
+ len = strlen(hp->nis_domain->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_NIS_DOMAIN;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->nis_domain->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /* IEN 116 name server */
+ if (hp->flags.name_server) {
+ if (insert_ip(TAG_NAME_SERVER,
+ hp->name_server,
+ &vp, &bytesleft))
+ NEED(8, "ns");
+ }
+ if (hp->flags.rlp_server) {
+ if (insert_ip(TAG_RLP_SERVER,
+ hp->rlp_server,
+ &vp, &bytesleft))
+ NEED(8, "rl");
+ }
+ /* Time server (RFC 868) */
+ if (hp->flags.time_server) {
+ if (insert_ip(TAG_TIME_SERVER,
+ hp->time_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /* NTP (time) Server (RFC 1129) */
+ if (hp->flags.ntp_server) {
+ if (insert_ip(TAG_NTP_SERVER,
+ hp->ntp_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /*
+ * I wonder: If the hostname were "promoted" into the BOOTP
+ * response part, might these "extension" files possibly be
+ * shared between several clients?
+ *
+ * Also, why not just use longer BOOTP packets with all the
+ * additional length used as option data. This bootpd version
+ * already supports that feature by replying with the same
+ * packet length as the client request packet. -gwr
+ */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ /*
+ * Check for room for hostname. Add 2 to account for
+ * TAG_HOST_NAME and length.
+ */
+ len = strlen(hp->hostname->string);
+#if 0
+ /*
+ * XXX - Too much magic. The user can always set the hostname
+ * to the short version in the bootptab file. -gwr
+ */
+ if ((len + 2) > bytesleft) {
+ /*
+ * Not enough room for full (domain-qualified) hostname, try
+ * stripping it down to just the first field (host).
+ */
+ tmpstr = hp->hostname->string;
+ len = 0;
+ while (*tmpstr && (*tmpstr != '.')) {
+ tmpstr++;
+ len++;
+ }
+ }
+#endif
+ NEED((len + 2), "hn");
+ *vp++ = TAG_HOST_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->hostname->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * The rest of these are less important, so they go last.
+ */
+ if (hp->flags.lpr_server) {
+ if (insert_ip(TAG_LPR_SERVER,
+ hp->lpr_server,
+ &vp, &bytesleft))
+ NEED(8, "lp");
+ }
+ if (hp->flags.cookie_server) {
+ if (insert_ip(TAG_COOKIE_SERVER,
+ hp->cookie_server,
+ &vp, &bytesleft))
+ NEED(8, "cs");
+ }
+ if (hp->flags.log_server) {
+ if (insert_ip(TAG_LOG_SERVER,
+ hp->log_server,
+ &vp, &bytesleft))
+ NEED(8, "lg");
+ }
+ /*
+ * XXX - Add new tags here (to insert options)
+ */
+ if (hp->flags.generic) {
+ if (insert_generic(hp->generic, &vp, &bytesleft))
+ NEED(64, "(generic)");
+ }
+ /*
+ * The end marker is inserted by the caller.
+ */
+ return (vp - buf);
+#undef NEED
+} /* dovend_rfc1497 */
+
+
+
+/*
+ * Insert a tag value, a length value, and a list of IP addresses into the
+ * memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
+ * number to use, "iplist" is a pointer to a list of IP addresses
+ * (struct in_addr_list), and "bytesleft" points to an integer which
+ * indicates the size of the "dest" buffer.
+ *
+ * Return zero if everything fits.
+ *
+ * This is used to fill the vendor-specific area of a bootp packet in
+ * conformance to RFC1048.
+ */
+
+int
+insert_ip(tag, iplist, dest, bytesleft)
+ byte tag;
+ struct in_addr_list *iplist;
+ byte **dest;
+ int *bytesleft;
+{
+ struct in_addr *addrptr;
+ unsigned addrcount = 1;
+ byte *d;
+
+ if (iplist == NULL)
+ return (0);
+
+ if (*bytesleft >= 6) {
+ d = *dest; /* Save pointer for later */
+ **dest = tag;
+ (*dest) += 2;
+ (*bytesleft) -= 2; /* Account for tag and length */
+ addrptr = iplist->addr;
+ addrcount = iplist->addrcount;
+ while ((*bytesleft >= 4) && (addrcount > 0)) {
+ insert_u_long(addrptr->s_addr, dest);
+ addrptr++;
+ addrcount--;
+ (*bytesleft) -= 4; /* Four bytes per address */
+ }
+ d[1] = (byte) ((*dest - d - 2) & 0xFF);
+ }
+ return (addrcount);
+}
+
+
+
+/*
+ * Insert generic data into a bootp packet. The data is assumed to already
+ * be in RFC1048 format. It is inserted using a first-fit algorithm which
+ * attempts to insert as many tags as possible. Tags and data which are
+ * too large to fit are skipped; any remaining tags are tried until they
+ * have all been exhausted.
+ * Return zero if everything fits.
+ */
+
+static int
+insert_generic(gendata, buff, bytesleft)
+ struct shared_bindata *gendata;
+ byte **buff;
+ int *bytesleft;
+{
+ byte *srcptr;
+ int length, numbytes;
+ int skipped = 0;
+
+ if (gendata == NULL)
+ return (0);
+
+ srcptr = gendata->data;
+ length = gendata->length;
+ while ((length > 0) && (*bytesleft > 0)) {
+ switch (*srcptr) {
+ case TAG_END:
+ length = 0; /* Force an exit on next iteration */
+ break;
+ case TAG_PAD:
+ *(*buff)++ = *srcptr++;
+ (*bytesleft)--;
+ length--;
+ break;
+ default:
+ numbytes = srcptr[1] + 2;
+ if (*bytesleft < numbytes)
+ skipped += numbytes;
+ else {
+ bcopy(srcptr, *buff, numbytes);
+ (*buff) += numbytes;
+ (*bytesleft) -= numbytes;
+ }
+ srcptr += numbytes;
+ length -= numbytes;
+ break;
+ }
+ } /* while */
+ return (skipped);
+}
+
+/*
+ * Insert the unsigned long "value" into memory starting at the byte
+ * pointed to by the byte pointer (*dest). (*dest) is updated to
+ * point to the next available byte.
+ *
+ * Since it is desirable to internally store network addresses in network
+ * byte order (in struct in_addr's), this routine expects longs to be
+ * passed in network byte order.
+ *
+ * However, due to the nature of the main algorithm, the long must be in
+ * host byte order, thus necessitating the use of ntohl() first.
+ */
+
+void
+insert_u_long(value, dest)
+ u_int32 value;
+ byte **dest;
+{
+ byte *temp;
+ int n;
+
+ value = ntohl(value); /* Must use host byte order here */
+ temp = (*dest += 4);
+ for (n = 4; n > 0; n--) {
+ *--temp = (byte) (value & 0xFF);
+ value >>= 8;
+ }
+ /* Final result is network byte order */
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/dovend.h b/usr.sbin/bootpd/dovend.h
new file mode 100644
index 00000000000..b30c982d8e2
--- /dev/null
+++ b/usr.sbin/bootpd/dovend.h
@@ -0,0 +1,13 @@
+/* dovend.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern int dovend_rfc1497 P((struct host *hp, u_char *buf, int len));
+extern int insert_ip P((int, struct in_addr_list *, u_char **, int *));
+extern void insert_u_long P((u_int32, u_char **));
+
+#undef P
diff --git a/usr.sbin/bootpd/dumptab.c b/usr.sbin/bootpd/dumptab.c
new file mode 100644
index 00000000000..5893f6c4a23
--- /dev/null
+++ b/usr.sbin/bootpd/dumptab.c
@@ -0,0 +1,382 @@
+/*
+ * dumptab.c - handles dumping the database
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <time.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+#include "bootpd.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void dump_generic P((FILE *, struct shared_bindata *));
+static void dump_host P((FILE *, struct host *));
+static void list_ipaddresses P((FILE *, struct in_addr_list *));
+
+#undef P
+
+#ifndef DEBUG
+void
+dumptab(filename)
+ char *filename;
+{
+ report(LOG_INFO, "No dumptab support!");
+}
+
+#else /* DEBUG */
+
+/*
+ * Dump the internal memory database to bootpd_dump.
+ */
+
+void
+dumptab(filename)
+ char *filename;
+{
+ int n;
+ struct host *hp;
+ FILE *fp;
+ time_t t;
+ /* Print symbols in alphabetical order for reader's convenience. */
+ static char legend[] = "#\n# Legend:\t(see bootptab.5)\n\
+#\tfirst field -- hostname (not indented)\n\
+#\tbf -- bootfile\n\
+#\tbs -- bootfile size in 512-octet blocks\n\
+#\tcs -- cookie servers\n\
+#\tdf -- dump file name\n\
+#\tdn -- domain name\n\
+#\tds -- domain name servers\n\
+#\tef -- extension file\n\
+#\tex -- exec file (YORK_EX_OPTION)\n\
+#\tgw -- gateways\n\
+#\tha -- hardware address\n\
+#\thd -- home directory for bootfiles\n\
+#\thn -- host name set for client\n\
+#\tht -- hardware type\n\
+#\tim -- impress servers\n\
+#\tip -- host IP address\n\
+#\tlg -- log servers\n\
+#\tlp -- LPR servers\n\
+#\tms -- message size\n\
+#\tmw -- min wait (secs)\n\
+#\tns -- IEN-116 name servers\n\
+#\tnt -- NTP servers (RFC 1129)\n\
+#\tra -- reply address override\n\
+#\trl -- resource location protocol servers\n\
+#\trp -- root path\n\
+#\tsa -- boot server address\n\
+#\tsm -- subnet mask\n\
+#\tsw -- swap server\n\
+#\ttc -- template host (points to similar host entry)\n\
+#\ttd -- TFTP directory\n\
+#\tto -- time offset (seconds)\n\
+#\tts -- time servers\n\
+#\tvm -- vendor magic number\n\
+#\tyd -- YP (NIS) domain\n\
+#\tys -- YP (NIS) servers\n\
+#\tTn -- generic option tag n\n\
+\n";
+
+ /*
+ * Open bootpd.dump file.
+ */
+ if ((fp = fopen(filename, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ filename, get_errmsg());
+ exit(1);
+ }
+ t = time(NULL);
+ fprintf(fp, "\n# %s %s.%d\n", progname, VERSION, PATCHLEVEL);
+ fprintf(fp, "# %s: dump of bootp server database.\n", filename);
+ fprintf(fp, "# Dump taken %s", ctime(&t));
+ fwrite(legend, 1, sizeof(legend) - 1, fp);
+
+ n = 0;
+ for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
+ hp = (struct host *) hash_NextEntry(nmhashtable)) {
+ dump_host(fp, hp);
+ fprintf(fp, "\n");
+ n++;
+ }
+ fclose(fp);
+
+ report(LOG_INFO, "dumped %d entries to \"%s\".", n, filename);
+}
+
+
+
+/*
+ * Dump all the available information on the host pointed to by "hp".
+ * The output is sent to the file pointed to by "fp".
+ */
+
+static void
+dump_host(fp, hp)
+ FILE *fp;
+ struct host *hp;
+{
+ /* Print symbols in alphabetical order for reader's convenience. */
+ if (hp) {
+ fprintf(fp, "%s:", (hp->hostname ?
+ hp->hostname->string : "?"));
+ if (hp->flags.bootfile) {
+ fprintf(fp, "\\\n\t:bf=%s:", hp->bootfile->string);
+ }
+ if (hp->flags.bootsize) {
+ fprintf(fp, "\\\n\t:bs=");
+ if (hp->flags.bootsize_auto) {
+ fprintf(fp, "auto:");
+ } else {
+ fprintf(fp, "%d:", hp->bootsize);
+ }
+ }
+ if (hp->flags.cookie_server) {
+ fprintf(fp, "\\\n\t:cs=");
+ list_ipaddresses(fp, hp->cookie_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.dump_file) {
+ fprintf(fp, "\\\n\t:df=%s:", hp->dump_file->string);
+ }
+ if (hp->flags.domain_name) {
+ fprintf(fp, "\\\n\t:dn=%s:", hp->domain_name->string);
+ }
+ if (hp->flags.domain_server) {
+ fprintf(fp, "\\\n\t:ds=");
+ list_ipaddresses(fp, hp->domain_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.exten_file) {
+ fprintf(fp, "\\\n\t:ef=%s:", hp->exten_file->string);
+ }
+ if (hp->flags.exec_file) {
+ fprintf(fp, "\\\n\t:ex=%s:", hp->exec_file->string);
+ }
+ if (hp->flags.gateway) {
+ fprintf(fp, "\\\n\t:gw=");
+ list_ipaddresses(fp, hp->gateway);
+ fprintf(fp, ":");
+ }
+ /* FdC: swap_server (see below) */
+ if (hp->flags.homedir) {
+ fprintf(fp, "\\\n\t:hd=%s:", hp->homedir->string);
+ }
+ /* FdC: dump_file (see above) */
+ /* FdC: domain_name (see above) */
+ /* FdC: root_path (see below) */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ fprintf(fp, "\\\n\t:hn:");
+ }
+ if (hp->flags.htype) {
+ int hlen = haddrlength(hp->htype);
+ fprintf(fp, "\\\n\t:ht=%u:", (unsigned) hp->htype);
+ if (hp->flags.haddr) {
+ fprintf(fp, "ha=\"%s\":",
+ haddrtoa(hp->haddr, hlen));
+ }
+ }
+ if (hp->flags.impress_server) {
+ fprintf(fp, "\\\n\t:im=");
+ list_ipaddresses(fp, hp->impress_server);
+ fprintf(fp, ":");
+ }
+ /* NetBSD: swap_server (see below) */
+ if (hp->flags.iaddr) {
+ fprintf(fp, "\\\n\t:ip=%s:", inet_ntoa(hp->iaddr));
+ }
+ if (hp->flags.log_server) {
+ fprintf(fp, "\\\n\t:lg=");
+ list_ipaddresses(fp, hp->log_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.lpr_server) {
+ fprintf(fp, "\\\n\t:lp=");
+ list_ipaddresses(fp, hp->lpr_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.msg_size) {
+ fprintf(fp, "\\\n\t:ms=%d:", hp->msg_size);
+ }
+ if (hp->flags.min_wait) {
+ fprintf(fp, "\\\n\t:mw=%d:", hp->min_wait);
+ }
+ if (hp->flags.name_server) {
+ fprintf(fp, "\\\n\t:ns=");
+ list_ipaddresses(fp, hp->name_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.ntp_server) {
+ fprintf(fp, "\\\n\t:nt=");
+ list_ipaddresses(fp, hp->ntp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.reply_addr) {
+ fprintf(fp, "\\\n\t:ra=%s:", inet_ntoa(hp->reply_addr));
+ }
+ if (hp->flags.rlp_server) {
+ fprintf(fp, "\\\n\t:rl=");
+ list_ipaddresses(fp, hp->rlp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.root_path) {
+ fprintf(fp, "\\\n\t:rp=%s:", hp->root_path->string);
+ }
+ if (hp->flags.bootserver) {
+ fprintf(fp, "\\\n\t:sa=%s:", inet_ntoa(hp->bootserver));
+ }
+ if (hp->flags.subnet_mask) {
+ fprintf(fp, "\\\n\t:sm=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.swap_server) {
+ fprintf(fp, "\\\n\t:sw=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.tftpdir) {
+ fprintf(fp, "\\\n\t:td=%s:", hp->tftpdir->string);
+ }
+ /* NetBSD: rootpath (see above) */
+ /* NetBSD: domainname (see above) */
+ /* NetBSD: dumpfile (see above) */
+ if (hp->flags.time_offset) {
+ fprintf(fp, "\\\n\t:to=%ld:", hp->time_offset);
+ }
+ if (hp->flags.time_server) {
+ fprintf(fp, "\\\n\t:ts=");
+ list_ipaddresses(fp, hp->time_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.vm_cookie) {
+ fprintf(fp, "\\\n\t:vm=");
+ if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
+ fprintf(fp, "rfc1048:");
+ } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
+ fprintf(fp, "cmu:");
+ } else {
+ fprintf(fp, "%d.%d.%d.%d:",
+ (int) ((hp->vm_cookie)[0]),
+ (int) ((hp->vm_cookie)[1]),
+ (int) ((hp->vm_cookie)[2]),
+ (int) ((hp->vm_cookie)[3]));
+ }
+ }
+ if (hp->flags.nis_domain) {
+ fprintf(fp, "\\\n\t:yd=%s:",
+ hp->nis_domain->string);
+ }
+ if (hp->flags.nis_server) {
+ fprintf(fp, "\\\n\t:ys=");
+ list_ipaddresses(fp, hp->nis_server);
+ fprintf(fp, ":");
+ }
+ /*
+ * XXX - Add new tags here (or above,
+ * so they print in alphabetical order).
+ */
+
+ if (hp->flags.generic) {
+ dump_generic(fp, hp->generic);
+ }
+ }
+}
+
+
+static void
+dump_generic(fp, generic)
+ FILE *fp;
+ struct shared_bindata *generic;
+{
+ u_char *bp = generic->data;
+ u_char *ep = bp + generic->length;
+ u_char tag;
+ int len;
+
+ while (bp < ep) {
+ tag = *bp++;
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ len = *bp++;
+ if (bp + len > ep) {
+ fprintf(fp, " #junk in generic! :");
+ return;
+ }
+ fprintf(fp, "\\\n\t:T%d=", tag);
+ while (len) {
+ fprintf(fp, "%02X", *bp);
+ bp++;
+ len--;
+ if (len)
+ fprintf(fp, ".");
+ }
+ fprintf(fp, ":");
+ }
+}
+
+
+
+/*
+ * Dump an entire struct in_addr_list of IP addresses to the indicated file.
+ *
+ * The addresses are printed in standard ASCII "dot" notation and separated
+ * from one another by a single space. A single leading space is also
+ * printed before the first adddress.
+ *
+ * Null lists produce no output (and no error).
+ */
+
+static void
+list_ipaddresses(fp, ipptr)
+ FILE *fp;
+ struct in_addr_list *ipptr;
+{
+ unsigned count;
+ struct in_addr *addrptr;
+
+ if (ipptr) {
+ count = ipptr->addrcount;
+ addrptr = ipptr->addr;
+ while (count > 0) {
+ fprintf(fp, "%s", inet_ntoa(*addrptr++));
+ count--;
+ if (count)
+ fprintf(fp, ", ");
+ }
+ }
+}
+
+#endif /* DEBUG */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/getether.c b/usr.sbin/bootpd/getether.c
new file mode 100644
index 00000000000..d131b50f7f8
--- /dev/null
+++ b/usr.sbin/bootpd/getether.c
@@ -0,0 +1,374 @@
+/*
+ * getether.c : get the ethernet address of an interface
+ *
+ * All of this code is quite system-specific. As you may well
+ * guess, it took a good bit of detective work to figure out!
+ *
+ * If you figure out how to do this on another system,
+ * please let me know. <gwr@mc.com>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <syslog.h>
+
+#include "report.h"
+#define EALEN 6
+
+#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
+/*
+ * This is really easy on Ultrix! Thanks to
+ * Harald Lundberg <hl@tekla.fi> for this code.
+ *
+ * The code here is not specific to the Alpha, but that was the
+ * only symbol we could find to identify DEC's version of OSF.
+ * (Perhaps we should just define DEC in the Makefile... -gwr)
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifdevea */
+
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifdevea phys;
+ bzero(&phys, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed");
+ } else {
+ bcopy(&phys.current_pa[0], eap, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* ultrix|osf1 */
+
+
+#ifdef SUNOS
+
+#include <sys/sockio.h>
+#include <sys/time.h> /* needed by net_if.h */
+#include <net/nit_if.h> /* for NIOCBIND */
+#include <net/if.h> /* for struct ifreq */
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+
+ struct ifreq ifrnit;
+ int nit;
+
+ bzero((char *) &ifrnit, sizeof(ifrnit));
+ strncpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ);
+
+ nit = open("/dev/nit", 0);
+ if (nit < 0) {
+ report(LOG_ERR, "getether: open /dev/nit: %s",
+ get_errmsg());
+ return rc;
+ }
+ do {
+ if (ioctl(nit, NIOCBIND, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: NIOCBIND on nit");
+ break;
+ }
+ if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: SIOCGIFADDR on nit");
+ break;
+ }
+ bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN);
+ rc = 0;
+ } while (0);
+ close(nit);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SUNOS */
+
+
+#if defined(__386BSD__) || defined(__NetBSD__)
+/* Thanks to John Brezak <brezak@ch.hp.com> for this code. */
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int fd, rc = -1;
+ register int n;
+ struct ifreq ibuf[16], ifr;
+ struct ifconf ifc;
+ register struct ifreq *ifrp, *ifend;
+
+ /* Fetch the interface configuration */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg());
+ return (fd);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t) ibuf;
+ if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg);
+ goto out;
+ }
+ /* Search interface configuration list for link layer address. */
+ ifrp = ibuf;
+ ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
+ while (ifrp < ifend) {
+ /* Look for interface */
+ if (strcmp(ifname, ifrp->ifr_name) == 0 &&
+ ifrp->ifr_addr.sa_family == AF_LINK &&
+ ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
+ bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN);
+ rc = 0;
+ break;
+ }
+ /* Bump interface config pointer */
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+ ifrp = (struct ifreq *) ((char *) ifrp + n);
+ }
+
+ out:
+ close(fd);
+ return (rc);
+}
+
+#define GETETHER
+#endif /* __NetBSD__ */
+
+
+#ifdef SVR4
+/*
+ * This is for "Streams TCP/IP" by Lachman Associates.
+ * They sure made this cumbersome! -gwr
+ */
+
+#include <sys/sockio.h>
+#include <sys/dlpi.h>
+#include <stropts.h>
+#ifndef NULL
+#define NULL 0
+#endif
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+ char devname[32];
+ char tmpbuf[sizeof(union DL_primitives) + 16];
+ struct strbuf cbuf;
+ int fd, flags;
+ union DL_primitives *dlp;
+ char *enaddr;
+ int unit = -1; /* which unit to attach */
+
+ sprintf(devname, "/dev/%s", ifname);
+ fd = open(devname, 2);
+ if (fd < 0) {
+ /* Try without the trailing digit. */
+ char *p = devname + 5;
+ while (isalpha(*p))
+ p++;
+ if (isdigit(*p)) {
+ unit = *p - '0';
+ *p = '\0';
+ }
+ fd = open(devname, 2);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: open %s: %s",
+ devname, get_errmsg());
+ return rc;
+ }
+ }
+#ifdef DL_ATTACH_REQ
+ /*
+ * If this is a "Style 2" DLPI, then we must "attach" first
+ * to tell the driver which unit (board, port) we want.
+ * For now, decide this based on the device name.
+ * (Should do "info_req" and check dl_provider_style ...)
+ */
+ if (unit >= 0) {
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_ATTACH_REQ;
+ dlp->attach_req.dl_ppa = unit;
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_ATTACH_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_OK_ACK) {
+ report(LOG_ERR, "getether: attach: not OK or ERROR");
+ goto out;
+ }
+ } /* unit >= 0 */
+#endif /* DL_ATTACH_REQ */
+
+ /*
+ * Get the Ethernet address the same way the ARP module
+ * does when it is pushed onto a new stream (bind).
+ * One should instead be able just do an dl_info_req
+ * but many drivers do not supply the hardware address
+ * in the response to dl_info_req (they MUST supply it
+ * for dl_bind_ack because the ARP module requires it).
+ */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_BIND_REQ;
+ dlp->bind_req.dl_sap = 0x8FF; /* XXX - Unused SAP */
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_BIND_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_BIND_ACK) {
+ report(LOG_ERR, "getether: bind: not OK or ERROR");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_offset == 0) {
+ report(LOG_ERR, "getether: bind: ack has no address");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_length < EALEN) {
+ report(LOG_ERR, "getether: bind: ack address truncated");
+ goto out;
+ }
+ /*
+ * Copy the Ethernet address out of the message.
+ */
+ enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset;
+ memcpy(eap, enaddr, EALEN);
+ rc = 0;
+
+ out:
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SVR4 */
+
+
+#ifdef linux
+/*
+ * This is really easy on Linux! This version (for linux)
+ * written by Nigel Metheringham <nigelm@ohm.york.ac.uk>
+ *
+ * The code is almost identical to the Ultrix code - however
+ * the names are different to confuse the innocent :-)
+ * Most of this code was stolen from the Ultrix bit above.
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifreq */
+
+/* In a properly configured system this should be either sys/socketio.h
+ or sys/sockios.h, but on my distribution these don't line up correctly */
+#include <linux/sockios.h> /* Needed for IOCTL defs */
+
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifreq phys;
+ bzero(&phys, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed");
+ } else {
+ bcopy(phys.ifr_hwaddr, eap, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* linux */
+
+
+/* If we don't know how on this system, just return an error. */
+#ifndef GETETHER
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ return -1;
+}
+
+#endif /* !GETETHER */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/getif.c b/usr.sbin/bootpd/getif.c
new file mode 100644
index 00000000000..ba0a00bdd0f
--- /dev/null
+++ b/usr.sbin/bootpd/getif.c
@@ -0,0 +1,146 @@
+/*
+ * getif.c : get an interface structure
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stropts.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "getif.h"
+#include "report.h"
+
+#ifdef __bsdi__
+#define BSD 43
+#endif
+
+static struct ifreq ifreq[10]; /* Holds interface configuration */
+static struct ifconf ifconf; /* points to ifreq */
+
+static int nmatch();
+
+/* Return a pointer to the interface struct for the passed address. */
+struct ifreq *
+getif(s, addrp)
+ int s; /* socket file descriptor */
+ struct in_addr *addrp; /* destination address on interface */
+{
+ int maxmatch;
+ int len, m, incr;
+ struct ifreq *ifrq, *ifrmax;
+ struct sockaddr_in *sip;
+ char *p;
+
+ /* If no address was supplied, just return NULL. */
+ if (!addrp)
+ return (struct ifreq *) 0;
+
+ /* Get the interface config if not done already. */
+ if (ifconf.ifc_len == 0) {
+#ifdef SVR4
+ /*
+ * SysVr4 returns garbage if you do this the obvious way!
+ * This one took a while to figure out... -gwr
+ */
+ struct strioctl ioc;
+ ioc.ic_cmd = SIOCGIFCONF;
+ ioc.ic_timout = 0;
+ ioc.ic_len = sizeof(ifreq);
+ ioc.ic_dp = (char *) ifreq;
+ m = ioctl(s, I_STR, (char *) &ioc);
+ ifconf.ifc_len = ioc.ic_len;
+ ifconf.ifc_req = ifreq;
+#else /* SVR4 */
+ ifconf.ifc_len = sizeof(ifreq);
+ ifconf.ifc_req = ifreq;
+ m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
+#endif /* SVR4 */
+ if ((m < 0) || (ifconf.ifc_len <= 0)) {
+ report(LOG_ERR, "ioctl SIOCGIFCONF");
+ return (struct ifreq *) 0;
+ }
+ }
+ maxmatch = 7; /* this many bits or less... */
+ ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
+ p = (char *) ifreq;
+ len = ifconf.ifc_len;
+ while (len > 0) {
+ ifrq = (struct ifreq *) p;
+ sip = (struct sockaddr_in *) &ifrq->ifr_addr;
+ m = nmatch(addrp, &(sip->sin_addr));
+ if (m > maxmatch) {
+ maxmatch = m;
+ ifrmax = ifrq;
+ }
+ /* XXX - Could this be just #ifndef IFNAMSIZ instead? -gwr */
+#if (BSD - 0) < 43
+ /* BSD not defined or earlier than 4.3 */
+ incr = sizeof(*ifrq);
+#else /* NetBSD */
+ incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
+#endif /* NetBSD */
+
+ p += incr;
+ len -= incr;
+ }
+
+ return ifrmax;
+}
+
+/*
+ * Return the number of leading bits matching in the
+ * internet addresses supplied.
+ */
+static int
+nmatch(ca, cb)
+ u_char *ca, *cb; /* ptrs to IP address, network order */
+{
+ u_int m = 0; /* count of matching bits */
+ u_int n = 4; /* bytes left, then bitmask */
+
+ /* Count matching bytes. */
+ while (n && (*ca == *cb)) {
+ ca++;
+ cb++;
+ m += 8;
+ n--;
+ }
+ /* Now count matching bits. */
+ if (n) {
+ n = 0x80;
+ while (n && ((*ca & n) == (*cb & n))) {
+ m++;
+ n >>= 1;
+ }
+ }
+ return (m);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/getif.h b/usr.sbin/bootpd/getif.h
new file mode 100644
index 00000000000..c51dafd2095
--- /dev/null
+++ b/usr.sbin/bootpd/getif.h
@@ -0,0 +1,7 @@
+/* getif.h */
+
+#ifdef __STDC__
+extern struct ifreq *getif(int, struct in_addr *);
+#else
+extern struct ifreq *getif();
+#endif
diff --git a/usr.sbin/bootpd/hash.c b/usr.sbin/bootpd/hash.c
new file mode 100644
index 00000000000..1dba833889b
--- /dev/null
+++ b/usr.sbin/bootpd/hash.c
@@ -0,0 +1,425 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Id: hash.c,v 1.1.1.1 1995/10/18 08:47:27 deraadt Exp $";
+#endif
+
+
+/*
+ * Generalized hash table ADT
+ *
+ * Provides multiple, dynamically-allocated, variable-sized hash tables on
+ * various data and keys.
+ *
+ * This package attempts to follow some of the coding conventions suggested
+ * by Bob Sidebotham and the AFS Clean Code Committee of the
+ * Information Technology Center at Carnegie Mellon.
+ */
+
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "hash.h"
+
+#define TRUE 1
+#define FALSE 0
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * This can be changed to make internal routines visible to debuggers, etc.
+ */
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE void hashi_FreeMembers P((hash_member *, hash_freefp));
+
+#undef P
+
+
+
+/*
+ * Hash table initialization routine.
+ *
+ * This routine creates and intializes a hash table of size "tablesize"
+ * entries. Successful calls return a pointer to the hash table (which must
+ * be passed to other hash routines to identify the hash table). Failed
+ * calls return NULL.
+ */
+
+hash_tbl *
+hash_Init(tablesize)
+ unsigned tablesize;
+{
+ register hash_tbl *hashtblptr;
+ register unsigned totalsize;
+
+ if (tablesize > 0) {
+ totalsize = sizeof(hash_tbl)
+ + sizeof(hash_member *) * (tablesize - 1);
+ hashtblptr = (hash_tbl *) malloc(totalsize);
+ if (hashtblptr) {
+ bzero((char *) hashtblptr, totalsize);
+ hashtblptr->size = tablesize; /* Success! */
+ hashtblptr->bucketnum = 0;
+ hashtblptr->member = (hashtblptr->table)[0];
+ }
+ } else {
+ hashtblptr = NULL; /* Disallow zero-length tables */
+ }
+ return hashtblptr; /* NULL if failure */
+}
+
+
+
+/*
+ * Frees an entire linked list of bucket members (used in the open
+ * hashing scheme). Does nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void
+hashi_FreeMembers(bucketptr, free_data)
+ hash_member *bucketptr;
+ hash_freefp free_data;
+{
+ hash_member *nextbucket;
+ while (bucketptr) {
+ nextbucket = bucketptr->next;
+ (*free_data) (bucketptr->data);
+ free((char *) bucketptr);
+ bucketptr = nextbucket;
+ }
+}
+
+
+
+
+/*
+ * This routine re-initializes the hash table. It frees all the allocated
+ * memory and resets all bucket pointers to NULL.
+ */
+
+void
+hash_Reset(hashtable, free_data)
+ hash_tbl *hashtable;
+ hash_freefp free_data;
+{
+ hash_member **bucketptr;
+ unsigned i;
+
+ bucketptr = hashtable->table;
+ for (i = 0; i < hashtable->size; i++) {
+ hashi_FreeMembers(*bucketptr, free_data);
+ *bucketptr++ = NULL;
+ }
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+}
+
+
+
+/*
+ * Generic hash function to calculate a hash code from the given string.
+ *
+ * For each byte of the string, this function left-shifts the value in an
+ * accumulator and then adds the byte into the accumulator. The contents of
+ * the accumulator is returned after the entire string has been processed.
+ * It is assumed that this result will be used as the "hashcode" parameter in
+ * calls to other functions in this package. These functions automatically
+ * adjust the hashcode for the size of each hashtable.
+ *
+ * This algorithm probably works best when the hash table size is a prime
+ * number.
+ *
+ * Hopefully, this function is better than the previous one which returned
+ * the sum of the squares of all the bytes. I'm still open to other
+ * suggestions for a default hash function. The programmer is more than
+ * welcome to supply his/her own hash function as that is one of the design
+ * features of this package.
+ */
+
+unsigned
+hash_HashFunction(string, len)
+ unsigned char *string;
+ register unsigned len;
+{
+ register unsigned accum;
+
+ accum = 0;
+ for (; len > 0; len--) {
+ accum <<= 1;
+ accum += (unsigned) (*string++ & 0xFF);
+ }
+ return accum;
+}
+
+
+
+/*
+ * Returns TRUE if at least one entry for the given key exists; FALSE
+ * otherwise.
+ */
+
+int
+hash_Exists(hashtable, hashcode, compare, key)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
+{
+ register hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ return TRUE; /* Entry does exist */
+ }
+ memberptr = memberptr->next;
+ }
+ return FALSE; /* Entry does not exist */
+}
+
+
+
+/*
+ * Insert the data item "element" into the hash table using "hashcode"
+ * to determine the bucket number, and "compare" and "key" to determine
+ * its uniqueness.
+ *
+ * If the insertion is successful 0 is returned. If a matching entry
+ * already exists in the given bucket of the hash table, or some other error
+ * occurs, -1 is returned and the insertion is not done.
+ */
+
+int
+hash_Insert(hashtable, hashcode, compare, key, element)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key, *element;
+{
+ hash_member *temp;
+
+ hashcode %= hashtable->size;
+ if (hash_Exists(hashtable, hashcode, compare, key)) {
+ return -1; /* At least one entry already exists */
+ }
+ temp = (hash_member *) malloc(sizeof(hash_member));
+ if (!temp)
+ return -1; /* malloc failed! */
+
+ temp->data = element;
+ temp->next = (hashtable->table)[hashcode];
+ (hashtable->table)[hashcode] = temp;
+ return 0; /* Success */
+}
+
+
+
+/*
+ * Delete all data elements which match the given key. If at least one
+ * element is found and the deletion is successful, 0 is returned.
+ * If no matching elements can be found in the hash table, -1 is returned.
+ */
+
+int
+hash_Delete(hashtable, hashcode, compare, key, free_data)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
+ hash_freefp free_data;
+{
+ hash_member *memberptr, *tempptr;
+ hash_member *previous = NULL;
+ int retval;
+
+ retval = -1;
+ hashcode %= hashtable->size;
+
+ /*
+ * Delete the first member of the list if it matches. Since this moves
+ * the second member into the first position we have to keep doing this
+ * over and over until it no longer matches.
+ */
+ memberptr = (hashtable->table)[hashcode];
+ while (memberptr && (*compare) (key, memberptr->data)) {
+ (hashtable->table)[hashcode] = memberptr->next;
+ /*
+ * Stop hashi_FreeMembers() from deleting the whole list!
+ */
+ memberptr->next = NULL;
+ hashi_FreeMembers(memberptr, free_data);
+ memberptr = (hashtable->table)[hashcode];
+ retval = 0;
+ }
+
+ /*
+ * Now traverse the rest of the list
+ */
+ if (memberptr) {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ tempptr = memberptr;
+ previous->next = memberptr = memberptr->next;
+ /*
+ * Put the brakes on hashi_FreeMembers(). . . .
+ */
+ tempptr->next = NULL;
+ hashi_FreeMembers(tempptr, free_data);
+ retval = 0;
+ } else {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ }
+ return retval;
+}
+
+
+
+/*
+ * Locate and return the data entry associated with the given key.
+ *
+ * If the data entry is found, a pointer to it is returned. Otherwise,
+ * NULL is returned.
+ */
+
+hash_datum *
+hash_Lookup(hashtable, hashcode, compare, key)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
+{
+ hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ return (memberptr->data);
+ }
+ memberptr = memberptr->next;
+ }
+ return NULL;
+}
+
+
+
+/*
+ * Return the next available entry in the hashtable for a linear search
+ */
+
+hash_datum *
+hash_NextEntry(hashtable)
+ hash_tbl *hashtable;
+{
+ register unsigned bucket;
+ register hash_member *memberptr;
+
+ /*
+ * First try to pick up where we left off.
+ */
+ memberptr = hashtable->member;
+ if (memberptr) {
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+ }
+ /*
+ * We hit the end of a chain, so look through the array of buckets
+ * until we find a new chain (non-empty bucket) or run out of buckets.
+ */
+ bucket = hashtable->bucketnum + 1;
+ while ((bucket < hashtable->size) &&
+ !(memberptr = (hashtable->table)[bucket])) {
+ bucket++;
+ }
+
+ /*
+ * Check to see if we ran out of buckets.
+ */
+ if (bucket >= hashtable->size) {
+ /*
+ * Reset to top of table for next call.
+ */
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ /*
+ * But return end-of-table indication to the caller this time.
+ */
+ return NULL;
+ }
+ /*
+ * Must have found a non-empty bucket.
+ */
+ hashtable->bucketnum = bucket;
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+}
+
+
+
+/*
+ * Return the first entry in a hash table for a linear search
+ */
+
+hash_datum *
+hash_FirstEntry(hashtable)
+ hash_tbl *hashtable;
+{
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ return hash_NextEntry(hashtable);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/hash.h b/usr.sbin/bootpd/hash.h
new file mode 100644
index 00000000000..51d0a5ebd33
--- /dev/null
+++ b/usr.sbin/bootpd/hash.h
@@ -0,0 +1,158 @@
+#ifndef HASH_H
+#define HASH_H
+/* hash.h */
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+/*
+ * Generalized hash table ADT
+ *
+ * Provides multiple, dynamically-allocated, variable-sized hash tables on
+ * various data and keys.
+ *
+ * This package attempts to follow some of the coding conventions suggested
+ * by Bob Sidebotham and the AFS Clean Code Committee.
+ */
+
+
+/*
+ * The user must supply the following:
+ *
+ * 1. A comparison function which is declared as:
+ *
+ * int compare(data1, data2)
+ * hash_datum *data1, *data2;
+ *
+ * This function must compare the desired fields of data1 and
+ * data2 and return TRUE (1) if the data should be considered
+ * equivalent (i.e. have the same key value) or FALSE (0)
+ * otherwise. This function is called through a pointer passed to
+ * the various hashtable functions (thus pointers to different
+ * functions may be passed to effect different tests on different
+ * hash tables).
+ *
+ * Internally, all the functions of this package always call the
+ * compare function with the "key" parameter as the first parameter,
+ * and a full data element as the second parameter. Thus, the key
+ * and element arguments to functions such as hash_Lookup() may
+ * actually be of different types and the programmer may provide a
+ * compare function which compares the two different object types
+ * as desired.
+ *
+ * Example:
+ *
+ * int compare(key, element)
+ * char *key;
+ * struct some_complex_structure *element;
+ * {
+ * return !strcmp(key, element->name);
+ * }
+ *
+ * key = "John C. Doe"
+ * element = &some_complex_structure
+ * hash_Lookup(table, hashcode, compare, key);
+ *
+ * 2. A hash function yielding an unsigned integer value to be used
+ * as the hashcode (index into the hashtable). Thus, the user
+ * may hash on whatever data is desired and may use several
+ * different hash functions for various different hash tables.
+ * The actual hash table index will be the passed hashcode modulo
+ * the hash table size.
+ *
+ * A generalized hash function, hash_HashFunction(), is included
+ * with this package to make things a little easier. It is not
+ * guarenteed to use the best hash algorithm in existence. . . .
+ */
+
+
+
+/*
+ * Various hash table definitions
+ */
+
+
+/*
+ * Define "hash_datum" as a universal data type
+ */
+#ifdef __STDC__
+typedef void hash_datum;
+#else
+typedef char hash_datum;
+#endif
+
+typedef struct hash_memberstruct hash_member;
+typedef struct hash_tblstruct hash_tbl;
+typedef struct hash_tblstruct_hdr hash_tblhdr;
+
+struct hash_memberstruct {
+ hash_member *next;
+ hash_datum *data;
+};
+
+struct hash_tblstruct_hdr {
+ unsigned size, bucketnum;
+ hash_member *member;
+};
+
+struct hash_tblstruct {
+ unsigned size, bucketnum;
+ hash_member *member; /* Used for linear dump */
+ hash_member *table[1]; /* Dynamically extended */
+};
+
+/* ANSI function prototypes or empty arg list? */
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+typedef int (*hash_cmpfp) P((hash_datum *, hash_datum *));
+typedef void (*hash_freefp) P((hash_datum *));
+
+extern hash_tbl *hash_Init P((u_int tablesize));
+
+extern void hash_Reset P((hash_tbl *tbl, hash_freefp));
+
+extern unsigned hash_HashFunction P((u_char *str, u_int len));
+
+extern int hash_Exists P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern int hash_Insert P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_datum *element));
+
+extern int hash_Delete P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_freefp));
+
+extern hash_datum *hash_Lookup P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern hash_datum *hash_FirstEntry P((hash_tbl *));
+
+extern hash_datum *hash_NextEntry P((hash_tbl *));
+
+#undef P
+
+#endif /* HASH_H */
diff --git a/usr.sbin/bootpd/hwaddr.c b/usr.sbin/bootpd/hwaddr.c
new file mode 100644
index 00000000000..10a6a0518d8
--- /dev/null
+++ b/usr.sbin/bootpd/hwaddr.c
@@ -0,0 +1,286 @@
+/*
+ * hwaddr.c - routines that deal with hardware addresses.
+ * (i.e. Ethernet)
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stream.h>
+#include <stropts.h>
+#include <fcntl.h>
+#endif
+
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+/* Yes, memcpy is OK here (no overlapped copies). */
+#include <memory.h>
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bptypes.h"
+#include "hwaddr.h"
+#include "report.h"
+
+extern int debug;
+
+/*
+ * Hardware address lengths (in bytes) and network name based on hardware
+ * type code. List in order specified by Assigned Numbers RFC; Array index
+ * is hardware type code. Entries marked as zero are unknown to the author
+ * at this time. . . .
+ */
+
+struct hwinfo hwinfolist[] =
+{
+ {0, "Reserved"}, /* Type 0: Reserved (don't use this) */
+ {6, "Ethernet"}, /* Type 1: 10Mb Ethernet (48 bits) */
+ {1, "3Mb Ethernet"}, /* Type 2: 3Mb Ethernet (8 bits) */
+ {0, "AX.25"}, /* Type 3: Amateur Radio AX.25 */
+ {1, "ProNET"}, /* Type 4: Proteon ProNET Token Ring */
+ {0, "Chaos"}, /* Type 5: Chaos */
+ {6, "IEEE 802"}, /* Type 6: IEEE 802 Networks */
+ {0, "ARCNET"} /* Type 7: ARCNET */
+};
+int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
+
+
+/*
+ * Setup the arp cache so that IP address 'ia' will be temporarily
+ * bound to hardware address 'ha' of length 'len'.
+ */
+void
+setarp(s, ia, ha, len)
+ int s; /* socket fd */
+ struct in_addr *ia;
+ u_char *ha;
+ int len;
+{
+#ifdef SIOCSARP
+ struct arpreq arpreq; /* Arp request ioctl block */
+ struct sockaddr_in *si;
+#ifdef SVR4
+ int fd;
+ struct strioctl iocb;
+#endif /* SVR4 */
+
+ bzero((caddr_t) & arpreq, sizeof(arpreq));
+ arpreq.arp_flags = ATF_INUSE | ATF_COM;
+
+ /* Set up the protocol address. */
+ arpreq.arp_pa.sa_family = AF_INET;
+ si = (struct sockaddr_in *) &arpreq.arp_pa;
+ si->sin_addr = *ia;
+
+ /* Set up the hardware address. */
+ bcopy(ha, arpreq.arp_ha.sa_data, len);
+
+#ifdef SVR4
+ /*
+ * And now the stuff for System V Rel 4.x which does not
+ * appear to allow SIOCxxx ioctls on a socket descriptor.
+ * Thanks to several people: (all sent the same fix)
+ * Barney Wolff <barney@databus.com>,
+ * bear@upsys.se (Bj|rn Sj|holm),
+ * Michael Kuschke <Michael.Kuschke@Materna.DE>,
+ */
+ if ((fd=open("/dev/arp", O_RDWR)) < 0) {
+ report(LOG_ERR, "open /dev/arp: %s\n", get_errmsg());
+ }
+ iocb.ic_cmd = SIOCSARP;
+ iocb.ic_timout = 0;
+ iocb.ic_dp = (char *)&arpreq;
+ iocb.ic_len = sizeof(arpreq);
+ if (ioctl(fd, I_STR, (caddr_t)&iocb) < 0) {
+ report(LOG_ERR, "ioctl I_STR: %s\n", get_errmsg());
+ }
+ close (fd);
+
+#else /* SVR4 */
+ /*
+ * On SunOS, the ioctl sometimes returns ENXIO, and it
+ * appears to happen when the ARP cache entry you tried
+ * to add is already in the cache. (Sigh...)
+ * XXX - Should this error simply be ignored? -gwr
+ */
+ if (ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) {
+ report(LOG_ERR, "ioctl SIOCSARP: %s", get_errmsg());
+ }
+#endif /* SVR4 */
+#else /* SIOCSARP */
+ /*
+ * Oh well, SIOCSARP is not defined. Just run arp(8).
+ * XXX - Gag!
+ */
+ int status;
+ char buf[256];
+ char *a;
+ extern char *inet_ntoa();
+
+ a = inet_ntoa(*ia);
+ sprintf(buf, "arp -d %s; arp -s %s %s temp",
+ a, a, haddrtoa(ha, len));
+ if (debug > 2)
+ report(LOG_INFO, buf);
+ status = system(buf);
+ if (status)
+ report(LOG_ERR, "arp failed, exit code=0x%x", status);
+ return;
+#endif /* SIOCSARP */
+}
+
+
+/*
+ * Convert a hardware address to an ASCII string.
+ */
+char *
+haddrtoa(haddr, hlen)
+ u_char *haddr;
+ int hlen;
+{
+ static char haddrbuf[3 * MAXHADDRLEN + 1];
+ char *bufptr;
+
+ if (hlen > MAXHADDRLEN)
+ hlen = MAXHADDRLEN;
+
+ bufptr = haddrbuf;
+ while (hlen > 0) {
+ sprintf(bufptr, "%02X:", (unsigned) (*haddr++ & 0xFF));
+ bufptr += 3;
+ hlen--;
+ }
+ bufptr[-1] = 0;
+ return (haddrbuf);
+}
+
+
+/*
+ * haddr_conv802()
+ * --------------
+ *
+ * Converts a backwards address to a canonical address and a canonical address
+ * to a backwards address.
+ *
+ * INPUTS:
+ * adr_in - pointer to six byte string to convert (unsigned char *)
+ * addr_len - how many bytes to convert
+ *
+ * OUTPUTS:
+ * addr_out - The string is updated to contain the converted address.
+ *
+ * CALLER:
+ * many
+ *
+ * DATA:
+ * Uses conv802table to bit-reverse the address bytes.
+ */
+
+static u_char conv802table[256] =
+{
+ /* 0x00 */ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ /* 0x08 */ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ /* 0x10 */ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ /* 0x18 */ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ /* 0x20 */ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ /* 0x28 */ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ /* 0x30 */ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ /* 0x38 */ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ /* 0x40 */ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ /* 0x48 */ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ /* 0x50 */ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ /* 0x58 */ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ /* 0x60 */ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ /* 0x68 */ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ /* 0x70 */ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ /* 0x78 */ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ /* 0x80 */ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ /* 0x88 */ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ /* 0x90 */ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ /* 0x98 */ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ /* 0xA0 */ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ /* 0xA8 */ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ /* 0xB0 */ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ /* 0xB8 */ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ /* 0xC0 */ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ /* 0xC8 */ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ /* 0xD0 */ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ /* 0xD8 */ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ /* 0xE0 */ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ /* 0xE8 */ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ /* 0xF0 */ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ /* 0xF8 */ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
+};
+
+void
+haddr_conv802(addr_in, addr_out, len)
+ register u_char *addr_in, *addr_out;
+ int len;
+{
+ u_char *lim;
+
+ lim = addr_out + len;
+ while (addr_out < lim)
+ *addr_out++ = conv802table[*addr_in++];
+}
+
+#if 0
+/*
+ * For the record, here is a program to generate the
+ * bit-reverse table above.
+ */
+static int
+bitrev(n)
+ int n;
+{
+ int i, r;
+
+ r = 0;
+ for (i = 0; i < 8; i++) {
+ r <<= 1;
+ r |= (n & 1);
+ n >>= 1;
+ }
+ return r;
+}
+
+main()
+{
+ int i;
+ for (i = 0; i <= 0xFF; i++) {
+ if ((i & 7) == 0)
+ printf("/* 0x%02X */", i);
+ printf(" 0x%02X,", bitrev(i));
+ if ((i & 7) == 7)
+ printf("\n");
+ }
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/hwaddr.h b/usr.sbin/bootpd/hwaddr.h
new file mode 100644
index 00000000000..dea7158be8c
--- /dev/null
+++ b/usr.sbin/bootpd/hwaddr.h
@@ -0,0 +1,39 @@
+/* hwaddr.h */
+#ifndef HWADDR_H
+#define HWADDR_H
+
+#define MAXHADDRLEN 8 /* Max hw address length in bytes */
+
+/*
+ * This structure holds information about a specific network type. The
+ * length of the network hardware address is stored in "hlen".
+ * The string pointed to by "name" is the cononical name of the network.
+ */
+struct hwinfo {
+ unsigned int hlen;
+ char *name;
+};
+
+extern struct hwinfo hwinfolist[];
+extern int hwinfocnt;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void setarp P((int, struct in_addr *, u_char *, int));
+extern char *haddrtoa P((u_char *, int));
+extern void haddr_conv802 P((u_char *, u_char *, int));
+
+#undef P
+
+/*
+ * Return the length in bytes of a hardware address of the given type.
+ * Return the canonical name of the network of the given type.
+ */
+#define haddrlength(type) ((hwinfolist[(int) (type)]).hlen)
+#define netname(type) ((hwinfolist[(int) (type)]).name)
+
+#endif /* HWADDR_H */
diff --git a/usr.sbin/bootpd/lookup.c b/usr.sbin/bootpd/lookup.c
new file mode 100644
index 00000000000..2a30a59b2c3
--- /dev/null
+++ b/usr.sbin/bootpd/lookup.c
@@ -0,0 +1,126 @@
+/*
+ * lookup.c - Lookup IP address, HW address, netmask
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#ifdef ETC_ETHERS
+#include <netinet/if_ether.h>
+extern int ether_hostton();
+#endif
+
+#include <netdb.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#endif
+
+#include "bootp.h"
+#include "lookup.h"
+#include "report.h"
+
+/*
+ * Lookup an Ethernet address and return it.
+ * Return NULL if addr not found.
+ */
+u_char *
+lookup_hwa(hostname, htype)
+ char *hostname;
+ int htype;
+{
+ switch (htype) {
+
+ /* XXX - How is this done on other systems? -gwr */
+#ifdef ETC_ETHERS
+ case HTYPE_ETHERNET:
+ case HTYPE_IEEE802:
+ {
+ static struct ether_addr ea;
+ /* This does a lookup in /etc/ethers */
+ if (ether_hostton(hostname, &ea)) {
+ report(LOG_ERR, "no HW addr for host \"%s\"",
+ hostname);
+ return (u_char *) 0;
+ }
+ return (u_char *) & ea;
+ }
+#endif /* ETC_ETHERS */
+
+ default:
+ report(LOG_ERR, "no lookup for HW addr type %d", htype);
+ } /* switch */
+
+ /* If the system can't do it, just return an error. */
+ return (u_char *) 0;
+}
+
+
+/*
+ * Lookup an IP address.
+ * Return non-zero on failure.
+ */
+int
+lookup_ipa(hostname, result)
+ char *hostname;
+ u_int32 *result;
+{
+ struct hostent *hp;
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return -1;
+ bcopy(hp->h_addr, result, sizeof(*result));
+ return 0;
+}
+
+
+/*
+ * Lookup a netmask
+ * Return non-zero on failure.
+ *
+ * XXX - This is OK as a default, but to really make this automatic,
+ * we would need to get the subnet mask from the ether interface.
+ * If this is wrong, specify the correct value in the bootptab.
+ */
+int
+lookup_netmask(addr, result)
+ u_int32 addr; /* both in network order */
+ u_int32 *result;
+{
+ int32 m, a;
+
+ a = ntohl(addr);
+ m = 0;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+
+ if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+
+ if (IN_CLASSC(a))
+ m = IN_CLASSC_NET;
+
+ if (!m)
+ return -1;
+ *result = htonl(m);
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/lookup.h b/usr.sbin/bootpd/lookup.h
new file mode 100644
index 00000000000..04805d8915c
--- /dev/null
+++ b/usr.sbin/bootpd/lookup.h
@@ -0,0 +1,15 @@
+/* lookup.h */
+
+#include "bptypes.h" /* for int32, u_int32 */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern u_char *lookup_hwa P((char *hostname, int htype));
+extern int lookup_ipa P((char *hostname, u_int32 *addr));
+extern int lookup_netmask P((u_int32 addr, u_int32 *mask));
+
+#undef P
diff --git a/usr.sbin/bootpd/patchlevel.h b/usr.sbin/bootpd/patchlevel.h
new file mode 100644
index 00000000000..782959e3c75
--- /dev/null
+++ b/usr.sbin/bootpd/patchlevel.h
@@ -0,0 +1,3 @@
+/* patchlevel.h */
+#define VERSION "2.4"
+#define PATCHLEVEL 1
diff --git a/usr.sbin/bootpd/print-bootp.c b/usr.sbin/bootpd/print-bootp.c
new file mode 100644
index 00000000000..abc451a4dc3
--- /dev/null
+++ b/usr.sbin/bootpd/print-bootp.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print bootp packets.
+ *
+ * This file was copied from tcpdump-2.1.1 and modified.
+ * There is an e-mail list for tcpdump: <tcpdump@ee.lbl.gov>
+ */
+#ifndef lint
+static char rcsid[] = "$Id: print-bootp.c,v 1.1.1.1 1995/10/18 08:47:27 deraadt Exp $";
+/* 93/10/10 <gwr@mc.com> New data-driven option print routine. */
+#endif
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "bootp.h"
+#include "bootptest.h"
+
+/* These decode the vendor data. */
+static void rfc1048_print();
+static void cmu_print();
+static void other_print();
+static void dump_hex();
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(bp, length, sport, dport)
+ struct bootp *bp;
+ int length;
+ u_short sport, dport;
+{
+ static char tstr[] = " [|bootp]";
+ static unsigned char vm_cmu[4] = VM_CMU;
+ static unsigned char vm_rfc1048[4] = VM_RFC1048;
+ u_char *ep;
+ int vdlen;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ /* Note funny sized packets */
+ if (length != sizeof(struct bootp))
+ (void) printf(" [len=%d]", length);
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *) snapend;
+
+ switch (bp->bp_op) {
+
+ case BOOTREQUEST:
+ /* Usually, a request goes from a client to a server */
+ if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
+ printf(" (request)");
+ break;
+
+ case BOOTREPLY:
+ /* Usually, a reply goes from a server to a client */
+ if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
+ printf(" (reply)");
+ break;
+
+ default:
+ printf(" bootp-#%d", bp->bp_op);
+ }
+
+ /* The usual hardware address type is 1 (10Mb Ethernet) */
+ if (bp->bp_htype != 1)
+ printf(" htype:%d", bp->bp_htype);
+
+ /* The usual length for 10Mb Ethernet address is 6 bytes */
+ if (bp->bp_hlen != 6)
+ printf(" hlen:%d", bp->bp_hlen);
+
+ /* Client's Hardware address */
+ if (bp->bp_hlen) {
+ register struct ether_header *eh;
+ register char *e;
+
+ TCHECK(bp->bp_chaddr[0], 6);
+ eh = (struct ether_header *) packetp;
+ if (bp->bp_op == BOOTREQUEST)
+ e = (char *) ESRC(eh);
+ else if (bp->bp_op == BOOTREPLY)
+ e = (char *) EDST(eh);
+ else
+ e = 0;
+ if (e == 0 || bcmp((char *) bp->bp_chaddr, e, 6))
+ dump_hex(bp->bp_chaddr, bp->bp_hlen);
+ }
+ /* Only print interesting fields */
+ if (bp->bp_hops)
+ printf(" hops:%d", bp->bp_hops);
+
+ if (bp->bp_xid)
+ printf(" xid:%d", ntohl(bp->bp_xid));
+
+ if (bp->bp_secs)
+ printf(" secs:%d", ntohs(bp->bp_secs));
+
+ /* Client's ip address */
+ TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
+ if (bp->bp_ciaddr.s_addr)
+ printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
+
+ /* 'your' ip address (bootp client) */
+ TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
+ if (bp->bp_yiaddr.s_addr)
+ printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
+
+ /* Server's ip address */
+ TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
+ if (bp->bp_siaddr.s_addr)
+ printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
+
+ /* Gateway's ip address */
+ TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
+ if (bp->bp_giaddr.s_addr)
+ printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
+
+ TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname));
+ if (*bp->bp_sname) {
+ printf(" sname:");
+ if (printfn(bp->bp_sname, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ TCHECK(bp->bp_file[0], sizeof(bp->bp_file));
+ if (*bp->bp_file) {
+ printf(" file:");
+ if (printfn(bp->bp_file, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ /* Don't try to decode the vendor buffer unless we're verbose */
+ if (vflag <= 0)
+ return;
+
+ vdlen = sizeof(bp->bp_vend);
+ /* Vendor data can extend to the end of the packet. */
+ if (vdlen < (ep - bp->bp_vend))
+ vdlen = (ep - bp->bp_vend);
+
+ TCHECK(bp->bp_vend[0], vdlen);
+ printf(" vend");
+ if (!bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_int32)))
+ rfc1048_print(bp->bp_vend, vdlen);
+ else if (!bcmp(bp->bp_vend, vm_cmu, sizeof(u_int32)))
+ cmu_print(bp->bp_vend, vdlen);
+ else
+ other_print(bp->bp_vend, vdlen);
+
+ return;
+ trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
+
+/*
+ * Option description data follows.
+ * These are decribed in: RFC-1048, RFC-1395, RFC-1497, RFC-1533
+ *
+ * The first char of each option string encodes the data format:
+ * ?: unknown
+ * a: ASCII
+ * b: byte (8-bit)
+ * i: inet address
+ * l: int32
+ * s: short (16-bit)
+ */
+char *
+rfc1048_opts[] = {
+ /* Originally from RFC-1048: */
+ "?PAD", /* 0: Padding - special, no data. */
+ "iSM", /* 1: subnet mask (RFC950)*/
+ "lTZ", /* 2: time offset, seconds from UTC */
+ "iGW", /* 3: gateways (or routers) */
+ "iTS", /* 4: time servers (RFC868) */
+ "iINS", /* 5: IEN name servers (IEN116) */
+ "iDNS", /* 6: domain name servers (RFC1035)(1034?) */
+ "iLOG", /* 7: MIT log servers */
+ "iCS", /* 8: cookie servers (RFC865) */
+ "iLPR", /* 9: lpr server (RFC1179) */
+ "iIPS", /* 10: impress servers (Imagen) */
+ "iRLP", /* 11: resource location servers (RFC887) */
+ "aHN", /* 12: host name (ASCII) */
+ "sBFS", /* 13: boot file size (in 512 byte blocks) */
+
+ /* Added by RFC-1395: */
+ "aDUMP", /* 14: Merit Dump File */
+ "aDNAM", /* 15: Domain Name (for DNS) */
+ "iSWAP", /* 16: Swap Server */
+ "aROOT", /* 17: Root Path */
+
+ /* Added by RFC-1497: */
+ "aEXTF", /* 18: Extensions Path (more options) */
+
+ /* Added by RFC-1533: (many, many options...) */
+#if 1 /* These might not be worth recognizing by name. */
+
+ /* IP Layer Parameters, per-host (RFC-1533, sect. 4) */
+ "bIP-forward", /* 19: IP Forwarding flag */
+ "bIP-srcroute", /* 20: IP Source Routing Enable flag */
+ "iIP-filters", /* 21: IP Policy Filter (addr pairs) */
+ "sIP-maxudp", /* 22: IP Max-UDP reassembly size */
+ "bIP-ttlive", /* 23: IP Time to Live */
+ "lIP-pmtuage", /* 24: IP Path MTU aging timeout */
+ "sIP-pmtutab", /* 25: IP Path MTU plateau table */
+
+ /* IP parameters, per-interface (RFC-1533, sect. 5) */
+ "sIP-mtu-sz", /* 26: IP MTU size */
+ "bIP-mtu-sl", /* 27: IP MTU all subnets local */
+ "bIP-bcast1", /* 28: IP Broadcast Addr ones flag */
+ "bIP-mask-d", /* 29: IP do mask discovery */
+ "bIP-mask-s", /* 30: IP do mask supplier */
+ "bIP-rt-dsc", /* 31: IP do router discovery */
+ "iIP-rt-sa", /* 32: IP router solicitation addr */
+ "iIP-routes", /* 33: IP static routes (dst,router) */
+
+ /* Link Layer parameters, per-interface (RFC-1533, sect. 6) */
+ "bLL-trailer", /* 34: do tralier encapsulation */
+ "lLL-arp-tmo", /* 35: ARP cache timeout */
+ "bLL-ether2", /* 36: Ethernet version 2 (IEEE 802.3) */
+
+ /* TCP parameters (RFC-1533, sect. 7) */
+ "bTCP-def-ttl", /* 37: default time to live */
+ "lTCP-KA-tmo", /* 38: keepalive time interval */
+ "bTCP-KA-junk", /* 39: keepalive sends extra junk */
+
+ /* Application and Service Parameters (RFC-1533, sect. 8) */
+ "aNISDOM", /* 40: NIS Domain (Sun YP) */
+ "iNISSRV", /* 41: NIS Servers */
+ "iNTPSRV", /* 42: NTP (time) Servers (RFC 1129) */
+ "?VSINFO", /* 43: Vendor Specific Info (encapsulated) */
+ "iNBiosNS", /* 44: NetBIOS Name Server (RFC-1001,1..2) */
+ "iNBiosDD", /* 45: NetBIOS Datagram Dist. Server. */
+ "bNBiosNT", /* 46: NetBIOS Note Type */
+ "?NBiosS", /* 47: NetBIOS Scope */
+ "iXW-FS", /* 48: X Window System Font Servers */
+ "iXW-DM", /* 49: X Window System Display Managers */
+
+ /* DHCP extensions (RFC-1533, sect. 9) */
+#endif
+};
+#define KNOWN_OPTIONS (sizeof(rfc1048_opts) / sizeof(rfc1048_opts[0]))
+
+static void print_string();
+
+static void
+rfc1048_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char tag;
+ u_char *ep;
+ register int len, j;
+ u_int32 ul;
+ u_short us;
+ struct in_addr ia;
+ char *optstr;
+
+ printf("-rfc1395");
+
+ /* Step over magic cookie */
+ bp += sizeof(int32);
+ /* Setup end pointer */
+ ep = bp + length;
+ while (bp < ep) {
+ tag = *bp++;
+ /* Check for tags with no data first. */
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ if (tag < KNOWN_OPTIONS) {
+ optstr = rfc1048_opts[tag];
+ printf(" %s:", optstr + 1);
+ } else {
+ printf(" T%d:", tag);
+ optstr = "?";
+ }
+ /* Now scan the length byte. */
+ len = *bp++;
+ if (bp + len > ep) {
+ /* truncated option */
+ printf(" |(%d>%d)", len, ep - bp);
+ return;
+ }
+ /* Print the option value(s). */
+ switch (optstr[0]) {
+
+ case 'a': /* ASCII string */
+ printfn(bp, bp + len);
+ bp += len;
+ len = 0;
+ break;
+
+ case 's': /* Word formats */
+ while (len >= 2) {
+ bcopy((char *) bp, (char *) &us, 2);
+ printf("%d", ntohs(us));
+ bp += 2;
+ len -= 2;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'l': /* Long words */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ul, 4);
+ printf("%d", ntohl(ul));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'i': /* INET addresses */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ia, 4);
+ printf("%s", ipaddr_string(&ia));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'b':
+ default:
+ break;
+
+ } /* switch */
+
+ /* Print as characters, if appropriate. */
+ if (len) {
+ dump_hex(bp, len);
+ if (isascii(*bp) && isprint(*bp)) {
+ printf("(");
+ printfn(bp, bp + len);
+ printf(")");
+ }
+ bp += len;
+ len = 0;
+ }
+ } /* while bp < ep */
+}
+
+static void
+cmu_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ struct cmu_vend *v;
+ u_char *ep;
+
+ printf("-cmu");
+
+ v = (struct cmu_vend *) bp;
+ if (length < sizeof(*v)) {
+ printf(" |L=%d", length);
+ return;
+ }
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Subnet mask */
+ if (v->v_flags & VF_SMASK) {
+ printf(" SM:%s", ipaddr_string(&v->v_smask));
+ }
+ /* Default gateway */
+ if (v->v_dgate.s_addr)
+ printf(" GW:%s", ipaddr_string(&v->v_dgate));
+
+ /* Domain name servers */
+ if (v->v_dns1.s_addr)
+ printf(" DNS1:%s", ipaddr_string(&v->v_dns1));
+ if (v->v_dns2.s_addr)
+ printf(" DNS2:%s", ipaddr_string(&v->v_dns2));
+
+ /* IEN-116 name servers */
+ if (v->v_ins1.s_addr)
+ printf(" INS1:%s", ipaddr_string(&v->v_ins1));
+ if (v->v_ins2.s_addr)
+ printf(" INS2:%s", ipaddr_string(&v->v_ins2));
+
+ /* Time servers */
+ if (v->v_ts1.s_addr)
+ printf(" TS1:%s", ipaddr_string(&v->v_ts1));
+ if (v->v_ts2.s_addr)
+ printf(" TS2:%s", ipaddr_string(&v->v_ts2));
+
+}
+
+
+/*
+ * Print out arbitrary, unknown vendor data.
+ */
+
+static void
+other_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char *ep; /* end pointer */
+ u_char *zp; /* points one past last non-zero byte */
+ register int i, j;
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Find the last non-zero byte. */
+ for (zp = ep; zp > bp; zp--) {
+ if (zp[-1] != 0)
+ break;
+ }
+
+ /* Print the all-zero case in a compact representation. */
+ if (zp == bp) {
+ printf("-all-zero");
+ return;
+ }
+ printf("-unknown");
+
+ /* Are there enough trailing zeros to make "00..." worthwhile? */
+ if (zp + 2 > ep)
+ zp = ep; /* print them all normally */
+
+ /* Now just print all the non-zero data. */
+ while (bp < zp) {
+ printf(".%02X", *bp);
+ bp++;
+ }
+
+ if (zp < ep)
+ printf(".00...");
+
+ return;
+}
+
+static void
+dump_hex(bp, len)
+ u_char *bp;
+ int len;
+{
+ while (len > 0) {
+ printf("%02X", *bp);
+ bp++;
+ len--;
+ if (len) printf(".");
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/readfile.c b/usr.sbin/bootpd/readfile.c
new file mode 100644
index 00000000000..1d44b43c73b
--- /dev/null
+++ b/usr.sbin/bootpd/readfile.c
@@ -0,0 +1,2097 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Id: readfile.c,v 1.1.1.1 1995/10/18 08:47:27 deraadt Exp $";
+#endif
+
+
+/*
+ * bootpd configuration file reading code.
+ *
+ * The routines in this file deal with reading, interpreting, and storing
+ * the information found in the bootpd configuration file (usually
+ * /etc/bootptab).
+ */
+
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "lookup.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "bootpd.h"
+
+#define HASHTABLESIZE 257 /* Hash table size (prime) */
+
+/* Non-standard hardware address type (see bootp.h) */
+#define HTYPE_DIRECT 0
+
+/* Error codes returned by eval_symbol: */
+#define SUCCESS 0
+#define E_END_OF_ENTRY (-1)
+#define E_SYNTAX_ERROR (-2)
+#define E_UNKNOWN_SYMBOL (-3)
+#define E_BAD_IPADDR (-4)
+#define E_BAD_HWADDR (-5)
+#define E_BAD_LONGWORD (-6)
+#define E_BAD_HWATYPE (-7)
+#define E_BAD_PATHNAME (-8)
+#define E_BAD_VALUE (-9)
+
+/* Tag idendities. */
+#define SYM_NULL 0
+#define SYM_BOOTFILE 1
+#define SYM_COOKIE_SERVER 2
+#define SYM_DOMAIN_SERVER 3
+#define SYM_GATEWAY 4
+#define SYM_HWADDR 5
+#define SYM_HOMEDIR 6
+#define SYM_HTYPE 7
+#define SYM_IMPRESS_SERVER 8
+#define SYM_IPADDR 9
+#define SYM_LOG_SERVER 10
+#define SYM_LPR_SERVER 11
+#define SYM_NAME_SERVER 12
+#define SYM_RLP_SERVER 13
+#define SYM_SUBNET_MASK 14
+#define SYM_TIME_OFFSET 15
+#define SYM_TIME_SERVER 16
+#define SYM_VENDOR_MAGIC 17
+#define SYM_SIMILAR_ENTRY 18
+#define SYM_NAME_SWITCH 19
+#define SYM_BOOTSIZE 20
+#define SYM_BOOT_SERVER 22
+#define SYM_TFTPDIR 23
+#define SYM_DUMP_FILE 24
+#define SYM_DOMAIN_NAME 25
+#define SYM_SWAP_SERVER 26
+#define SYM_ROOT_PATH 27
+#define SYM_EXTEN_FILE 28
+#define SYM_REPLY_ADDR 29
+#define SYM_NIS_DOMAIN 30 /* RFC 1533 */
+#define SYM_NIS_SERVER 31 /* RFC 1533 */
+#define SYM_NTP_SERVER 32 /* RFC 1533 */
+#define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */
+#define SYM_MSG_SIZE 34
+#define SYM_MIN_WAIT 35
+/* XXX - Add new tags here */
+
+#define OP_ADDITION 1 /* Operations on tags */
+#define OP_DELETION 2
+#define OP_BOOLEAN 3
+
+#define MAXINADDRS 16 /* Max size of an IP address list */
+#define MAXBUFLEN 256 /* Max temp buffer space */
+#define MAXENTRYLEN 2048 /* Max size of an entire entry */
+
+
+
+/*
+ * Structure used to map a configuration-file symbol (such as "ds") to a
+ * unique integer.
+ */
+
+struct symbolmap {
+ char *symbol;
+ int symbolcode;
+};
+
+
+struct htypename {
+ char *name;
+ byte htype;
+};
+
+
+PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
+PRIVATE int nentries; /* Total number of entries */
+PRIVATE int32 modtime = 0; /* Last modification time of bootptab */
+PRIVATE char *current_hostname; /* Name of the current entry. */
+PRIVATE char current_tagname[8];
+
+/*
+ * List of symbolic names used in the bootptab file. The order and actual
+ * values of the symbol codes (SYM_. . .) are unimportant, but they must
+ * all be unique.
+ */
+
+PRIVATE struct symbolmap symbol_list[] = {
+ {"bf", SYM_BOOTFILE},
+ {"bs", SYM_BOOTSIZE},
+ {"cs", SYM_COOKIE_SERVER},
+ {"df", SYM_DUMP_FILE},
+ {"dn", SYM_DOMAIN_NAME},
+ {"ds", SYM_DOMAIN_SERVER},
+ {"ef", SYM_EXTEN_FILE},
+ {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */
+ {"gw", SYM_GATEWAY},
+ {"ha", SYM_HWADDR},
+ {"hd", SYM_HOMEDIR},
+ {"hn", SYM_NAME_SWITCH},
+ {"ht", SYM_HTYPE},
+ {"im", SYM_IMPRESS_SERVER},
+ {"ip", SYM_IPADDR},
+ {"lg", SYM_LOG_SERVER},
+ {"lp", SYM_LPR_SERVER},
+ {"ms", SYM_MSG_SIZE},
+ {"mw", SYM_MIN_WAIT},
+ {"ns", SYM_NAME_SERVER},
+ {"nt", SYM_NTP_SERVER},
+ {"ra", SYM_REPLY_ADDR},
+ {"rl", SYM_RLP_SERVER},
+ {"rp", SYM_ROOT_PATH},
+ {"sa", SYM_BOOT_SERVER},
+ {"sm", SYM_SUBNET_MASK},
+ {"sw", SYM_SWAP_SERVER},
+ {"tc", SYM_SIMILAR_ENTRY},
+ {"td", SYM_TFTPDIR},
+ {"to", SYM_TIME_OFFSET},
+ {"ts", SYM_TIME_SERVER},
+ {"vm", SYM_VENDOR_MAGIC},
+ {"yd", SYM_NIS_DOMAIN},
+ {"ys", SYM_NIS_SERVER},
+ /* XXX - Add new tags here */
+};
+
+
+/*
+ * List of symbolic names for hardware types. Name translates into
+ * hardware type code listed with it. Names must begin with a letter
+ * and must be all lowercase. This is searched linearly, so put
+ * commonly-used entries near the beginning.
+ */
+
+PRIVATE struct htypename htnamemap[] = {
+ {"ethernet", HTYPE_ETHERNET},
+ {"ethernet3", HTYPE_EXP_ETHERNET},
+ {"ether", HTYPE_ETHERNET},
+ {"ether3", HTYPE_EXP_ETHERNET},
+ {"ieee802", HTYPE_IEEE802},
+ {"tr", HTYPE_IEEE802},
+ {"token-ring", HTYPE_IEEE802},
+ {"pronet", HTYPE_PRONET},
+ {"chaos", HTYPE_CHAOS},
+ {"arcnet", HTYPE_ARCNET},
+ {"ax.25", HTYPE_AX25},
+ {"direct", HTYPE_DIRECT},
+ {"serial", HTYPE_DIRECT},
+ {"slip", HTYPE_DIRECT},
+ {"ppp", HTYPE_DIRECT}
+};
+
+
+
+/*
+ * Externals and forward declarations.
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern boolean iplookcmp();
+boolean nmcmp P((hash_datum *, hash_datum *));
+
+PRIVATE void
+ adjust P((char **));
+PRIVATE void
+ del_string P((struct shared_string *));
+PRIVATE void
+ del_bindata P((struct shared_bindata *));
+PRIVATE void
+ del_iplist P((struct in_addr_list *));
+PRIVATE void
+ eat_whitespace P((char **));
+PRIVATE int
+ eval_symbol P((char **, struct host *));
+PRIVATE void
+ fill_defaults P((struct host *, char **));
+PRIVATE void
+ free_host P((hash_datum *));
+PRIVATE struct in_addr_list *
+ get_addresses P((char **));
+PRIVATE struct shared_string *
+ get_shared_string P((char **));
+PRIVATE char *
+ get_string P((char **, char *, u_int *));
+PRIVATE u_int32
+ get_u_long P((char **));
+PRIVATE boolean
+ goodname P((char *));
+PRIVATE boolean
+ hwinscmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ interp_byte P((char **, byte *));
+PRIVATE void
+ makelower P((char *));
+PRIVATE boolean
+ nullcmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ process_entry P((struct host *, char *));
+PRIVATE int
+ process_generic P((char **, struct shared_bindata **, u_int));
+PRIVATE byte *
+ prs_haddr P((char **, u_int));
+PRIVATE int
+ prs_inetaddr P((char **, u_int32 *));
+PRIVATE void
+ read_entry P((FILE *, char *, u_int *));
+PRIVATE char *
+ smalloc P((u_int));
+
+#undef P
+
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+u_char vm_cmu[4] = VM_CMU;
+u_char vm_rfc1048[4] = VM_RFC1048;
+
+/*
+ * Main hash tables
+ */
+hash_tbl *hwhashtable;
+hash_tbl *iphashtable;
+hash_tbl *nmhashtable;
+
+/*
+ * Allocate hash tables for hardware address, ip address, and hostname
+ * (shared by bootpd and bootpef)
+ */
+void
+rdtab_init()
+{
+ hwhashtable = hash_Init(HASHTABLESIZE);
+ iphashtable = hash_Init(HASHTABLESIZE);
+ nmhashtable = hash_Init(HASHTABLESIZE);
+ if (!(hwhashtable && iphashtable && nmhashtable)) {
+ report(LOG_ERR, "Unable to allocate hash tables.");
+ exit(1);
+ }
+}
+
+
+/*
+ * Read bootptab database file. Avoid rereading the file if the
+ * write date hasn't changed since the last time we read it.
+ */
+
+void
+readtab(force)
+ int force;
+{
+ struct host *hp;
+ FILE *fp;
+ struct stat st;
+ unsigned hashcode, buflen;
+ static char buffer[MAXENTRYLEN];
+
+ /*
+ * Check the last modification time.
+ */
+ if (stat(bootptab, &st) < 0) {
+ report(LOG_ERR, "stat on \"%s\": %s",
+ bootptab, get_errmsg());
+ return;
+ }
+#ifdef DEBUG
+ if (debug > 3) {
+ char timestr[28];
+ strcpy(timestr, ctime(&(st.st_mtime)));
+ /* zap the newline */
+ timestr[24] = '\0';
+ report(LOG_INFO, "bootptab mtime: %s",
+ timestr);
+ }
+#endif
+ if ((force == 0) &&
+ (st.st_mtime == modtime) &&
+ st.st_nlink) {
+ /*
+ * hasn't been modified or deleted yet.
+ */
+ return;
+ }
+ if (debug)
+ report(LOG_INFO, "reading %s\"%s\"",
+ (modtime != 0L) ? "new " : "",
+ bootptab);
+
+ /*
+ * Open bootptab file.
+ */
+ if ((fp = fopen(bootptab, "r")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
+ return;
+ }
+ /*
+ * Record file modification time.
+ */
+ if (fstat(fileno(fp), &st) < 0) {
+ report(LOG_ERR, "fstat: %s", get_errmsg());
+ fclose(fp);
+ return;
+ }
+ modtime = st.st_mtime;
+
+ /*
+ * Entirely erase all hash tables.
+ */
+ hash_Reset(hwhashtable, free_host);
+ hash_Reset(iphashtable, free_host);
+ hash_Reset(nmhashtable, free_host);
+
+ nhosts = 0;
+ nentries = 0;
+ while (TRUE) {
+ buflen = sizeof(buffer);
+ read_entry(fp, buffer, &buflen);
+ if (buflen == 0) { /* More entries? */
+ break;
+ }
+ hp = (struct host *) smalloc(sizeof(struct host));
+ bzero((char *) hp, sizeof(*hp));
+ /* the link count it zero */
+
+ /*
+ * Get individual info
+ */
+ if (process_entry(hp, buffer) < 0) {
+ hp->linkcount = 1;
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ /*
+ * If this is not a dummy entry, and the IP or HW
+ * address is not yet set, try to get them here.
+ * Dummy entries have . as first char of name.
+ */
+ if (goodname(hp->hostname->string)) {
+ char *hn = hp->hostname->string;
+ u_int32 value;
+ if (hp->flags.iaddr == 0) {
+ if (lookup_ipa(hn, &value)) {
+ report(LOG_ERR, "can not get IP addr for %s", hn);
+ report(LOG_ERR, "(dummy names should start with '.')");
+ } else {
+ hp->iaddr.s_addr = value;
+ hp->flags.iaddr = TRUE;
+ }
+ }
+ /* Set default subnet mask. */
+ if (hp->flags.subnet_mask == 0) {
+ if (lookup_netmask(hp->iaddr.s_addr, &value)) {
+ report(LOG_ERR, "can not get netmask for %s", hn);
+ } else {
+ hp->subnet_mask.s_addr = value;
+ hp->flags.subnet_mask = TRUE;
+ }
+ }
+ }
+ if (hp->flags.iaddr) {
+ nhosts++;
+ }
+ /* Register by HW addr if known. */
+ if (hp->flags.htype && hp->flags.haddr) {
+ /* We will either insert it or free it. */
+ hp->linkcount++;
+ hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
+ if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
+ report(LOG_NOTICE, "duplicate %s address: %s",
+ netname(hp->htype),
+ haddrtoa(hp->haddr, hp->htype));
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ }
+ /* Register by IP addr if known. */
+ if (hp->flags.iaddr) {
+ hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
+ if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on IP address insertion");
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
+ }
+ /* Register by Name (always known) */
+ hashcode = hash_HashFunction((u_char *) hp->hostname->string,
+ strlen(hp->hostname->string));
+ if (hash_Insert(nmhashtable, hashcode, nullcmp,
+ hp->hostname->string, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on insertion of hostname: \"%s\"",
+ hp->hostname->string);
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
+
+ nentries++;
+ }
+
+ fclose(fp);
+ if (debug)
+ report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
+ nentries, nhosts, bootptab);
+ return;
+}
+
+
+
+/*
+ * Read an entire host entry from the file pointed to by "fp" and insert it
+ * into the memory pointed to by "buffer". Leading whitespace and comments
+ * starting with "#" are ignored (removed). Backslashes (\) always quote
+ * the next character except that newlines preceeded by a backslash cause
+ * line-continuation onto the next line. The entry is terminated by a
+ * newline character which is not preceeded by a backslash. Sequences
+ * surrounded by double quotes are taken literally (including newlines, but
+ * not backslashes).
+ *
+ * The "bufsiz" parameter points to an unsigned int which specifies the
+ * maximum permitted buffer size. Upon return, this value will be replaced
+ * with the actual length of the entry (not including the null terminator).
+ *
+ * This code is a little scary. . . . I don't like using gotos in C
+ * either, but I first wrote this as an FSM diagram and gotos seemed like
+ * the easiest way to implement it. Maybe later I'll clean it up.
+ */
+
+PRIVATE void
+read_entry(fp, buffer, bufsiz)
+ FILE *fp;
+ char *buffer;
+ unsigned *bufsiz;
+{
+ int c, length;
+
+ length = 0;
+
+ /*
+ * Eat whitespace, blank lines, and comment lines.
+ */
+ top:
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (isspace(c)) {
+ goto top; /* Skip over whitespace */
+ }
+ if (c == '#') {
+ while (TRUE) { /* Eat comments after # */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (c == '\n') {
+ goto top; /* Try to read the next line */
+ }
+ }
+ }
+ ungetc(c, fp); /* Other character, push it back to reprocess it */
+
+
+ /*
+ * Now we're actually reading a data entry. Get each character and
+ * assemble it into the data buffer, processing special characters like
+ * double quotes (") and backslashes (\).
+ */
+
+ mainloop:
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
+ case '\n':
+ goto done; /* Exit on EOF or newline */
+ case '\\':
+ c = fgetc(fp); /* Backslash, read a new character */
+ if (c < 0) {
+ goto done; /* Exit on EOF */
+ }
+ *buffer++ = c; /* Store the literal character */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop;
+ } else {
+ goto done;
+ }
+ case '"':
+ *buffer++ = '"'; /* Store double-quote */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ while (TRUE) { /* Special quote processing loop */
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
+ goto done; /* Exit on EOF . . . */
+ case '"':
+ *buffer++ = '"';/* Store matching quote */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop; /* And continue main loop */
+ } else {
+ goto done;
+ }
+ case '\\':
+ if ((c = fgetc(fp)) < 0) { /* Backslash */
+ goto done; /* EOF. . . .*/
+ } /* else fall through */
+ default:
+ *buffer++ = c; /* Other character, store it */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ }
+ }
+ case ':':
+ *buffer++ = c; /* Store colons */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ do { /* But remove whitespace after them */
+ c = fgetc(fp);
+ if ((c < 0) || (c == '\n')) {
+ goto done;
+ }
+ } while (isspace(c)); /* Skip whitespace */
+
+ if (c == '\\') { /* Backslash quotes next character */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done;
+ }
+ if (c == '\n') {
+ goto top; /* Backslash-newline continuation */
+ }
+ }
+ /* fall through if "other" character */
+ default:
+ *buffer++ = c; /* Store other characters */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ }
+ goto mainloop; /* Keep going */
+
+ done:
+ *buffer = '\0'; /* Terminate string */
+ *bufsiz = length; /* Tell the caller its length */
+}
+
+
+
+/*
+ * Parse out all the various tags and parameters in the host entry pointed
+ * to by "src". Stuff all the data into the appropriate fields of the
+ * host structure pointed to by "host". If there is any problem with the
+ * entry, an error message is reported via report(), no further processing
+ * is done, and -1 is returned. Successful calls return 0.
+ *
+ * (Some errors probably shouldn't be so completely fatal. . . .)
+ */
+
+PRIVATE int
+process_entry(host, src)
+ struct host *host;
+ char *src;
+{
+ int retval;
+ char *msg;
+
+ if (!host || *src == '\0') {
+ return -1;
+ }
+ host->hostname = get_shared_string(&src);
+#if 0
+ /* Be more liberal for the benefit of dummy tag names. */
+ if (!goodname(host->hostname->string)) {
+ report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
+ del_string(host->hostname);
+ return -1;
+ }
+#endif
+ current_hostname = host->hostname->string;
+ adjust(&src);
+ while (TRUE) {
+ retval = eval_symbol(&src, host);
+ if (retval == SUCCESS) {
+ adjust(&src);
+ continue;
+ }
+ if (retval == E_END_OF_ENTRY) {
+ /* The default subnet mask is set in readtab() */
+ return 0;
+ }
+ /* Some kind of error. */
+ switch (retval) {
+ case E_SYNTAX_ERROR:
+ msg = "bad syntax";
+ break;
+ case E_UNKNOWN_SYMBOL:
+ msg = "unknown symbol";
+ break;
+ case E_BAD_IPADDR:
+ msg = "bad INET address";
+ break;
+ case E_BAD_HWADDR:
+ msg = "bad hardware address";
+ break;
+ case E_BAD_LONGWORD:
+ msg = "bad longword value";
+ break;
+ case E_BAD_HWATYPE:
+ msg = "bad HW address type";
+ break;
+ case E_BAD_PATHNAME:
+ msg = "bad pathname (need leading '/')";
+ case E_BAD_VALUE:
+ msg = "bad value";
+ default:
+ msg = "unkown error";
+ break;
+ } /* switch */
+ report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
+ current_hostname, current_tagname, msg);
+ return -1;
+ }
+}
+
+
+/*
+ * Macros for use in the function below:
+ */
+
+/* Parse one INET address stored directly in MEMBER. */
+#define PARSE_IA1(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = FALSE; \
+ if (optype == OP_ADDITION) { \
+ if (prs_inetaddr(symbol, &value) < 0) \
+ return E_BAD_IPADDR; \
+ hp->MEMBER.s_addr = value; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a list of INET addresses pointed to by MEMBER */
+#define PARSE_IAL(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_iplist(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_addresses(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a shared string pointed to by MEMBER */
+#define PARSE_STR(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_string(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_shared_string(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse an integer value for MEMBER */
+#define PARSE_INT(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = FALSE; \
+ if (optype == OP_ADDITION) { \
+ value = get_u_long(symbol); \
+ hp->MEMBER = value; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/*
+ * Evaluate the two-character tag symbol pointed to by "symbol" and place
+ * the data in the structure pointed to by "hp". The pointer pointed to
+ * by "symbol" is updated to point past the source string (but may not
+ * point to the next tag entry).
+ *
+ * Obviously, this need a few more comments. . . .
+ */
+PRIVATE int
+eval_symbol(symbol, hp)
+ char **symbol;
+ struct host *hp;
+{
+ char tmpstr[MAXSTRINGLEN];
+ byte *tmphaddr;
+ struct shared_string *ss;
+ struct symbolmap *symbolptr;
+ u_int32 value;
+ int32 timeoff;
+ int i, numsymbols;
+ unsigned len;
+ int optype; /* Indicates boolean, addition, or deletion */
+
+ eat_whitespace(symbol);
+
+ /* Make sure this is set before returning. */
+ current_tagname[0] = (*symbol)[0];
+ current_tagname[1] = (*symbol)[1];
+ current_tagname[2] = 0;
+
+ if ((*symbol)[0] == '\0') {
+ return E_END_OF_ENTRY;
+ }
+ if ((*symbol)[0] == ':') {
+ return SUCCESS;
+ }
+ if ((*symbol)[0] == 'T') { /* generic symbol */
+ (*symbol)++;
+ value = get_u_long(symbol);
+ sprintf(current_tagname, "T%d", value);
+ eat_whitespace(symbol);
+ if ((*symbol)[0] != '=') {
+ return E_SYNTAX_ERROR;
+ }
+ (*symbol)++;
+ if (!(hp->generic)) {
+ hp->generic = (struct shared_bindata *)
+ smalloc(sizeof(struct shared_bindata));
+ }
+ if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
+ return E_SYNTAX_ERROR;
+ hp->flags.generic = TRUE;
+ return SUCCESS;
+ }
+ /*
+ * Determine the type of operation to be done on this symbol
+ */
+ switch ((*symbol)[2]) {
+ case '=':
+ optype = OP_ADDITION;
+ break;
+ case '@':
+ optype = OP_DELETION;
+ break;
+ case ':':
+ case '\0':
+ optype = OP_BOOLEAN;
+ break;
+ default:
+ return E_SYNTAX_ERROR;
+ }
+
+ symbolptr = symbol_list;
+ numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
+ for (i = 0; i < numsymbols; i++) {
+ if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
+ ((symbolptr->symbol)[1] == (*symbol)[1])) {
+ break;
+ }
+ symbolptr++;
+ }
+ if (i >= numsymbols) {
+ return E_UNKNOWN_SYMBOL;
+ }
+ /*
+ * Skip past the = or @ character (to point to the data) if this
+ * isn't a boolean operation. For boolean operations, just skip
+ * over the two-character tag symbol (and nothing else. . . .).
+ */
+ (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
+
+ eat_whitespace(symbol);
+
+ /* The cases below are in order by symbolcode value. */
+ switch (symbolptr->symbolcode) {
+
+ case SYM_BOOTFILE:
+ PARSE_STR(bootfile);
+ break;
+
+ case SYM_COOKIE_SERVER:
+ PARSE_IAL(cookie_server);
+ break;
+
+ case SYM_DOMAIN_SERVER:
+ PARSE_IAL(domain_server);
+ break;
+
+ case SYM_GATEWAY:
+ PARSE_IAL(gateway);
+ break;
+
+ case SYM_HWADDR:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.haddr = FALSE;
+ if (optype == OP_ADDITION) {
+ /* Default the HW type to Ethernet */
+ if (hp->flags.htype == 0) {
+ hp->flags.htype = TRUE;
+ hp->htype = HTYPE_ETHERNET;
+ }
+ tmphaddr = prs_haddr(symbol, hp->htype);
+ if (!tmphaddr)
+ return E_BAD_HWADDR;
+ bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
+ hp->flags.haddr = TRUE;
+ }
+ break;
+
+ case SYM_HOMEDIR:
+ PARSE_STR(homedir);
+ break;
+
+ case SYM_HTYPE:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.htype = FALSE;
+ if (optype == OP_ADDITION) {
+ value = 0L; /* Assume an illegal value */
+ eat_whitespace(symbol);
+ if (isdigit(**symbol)) {
+ value = get_u_long(symbol);
+ } else {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ makelower(tmpstr);
+ numsymbols = sizeof(htnamemap) /
+ sizeof(struct htypename);
+ for (i = 0; i < numsymbols; i++) {
+ if (!strcmp(htnamemap[i].name, tmpstr)) {
+ break;
+ }
+ }
+ if (i < numsymbols) {
+ value = htnamemap[i].htype;
+ }
+ }
+ if (value >= hwinfocnt) {
+ return E_BAD_HWATYPE;
+ }
+ hp->htype = (byte) (value & 0xFF);
+ hp->flags.htype = TRUE;
+ }
+ break;
+
+ case SYM_IMPRESS_SERVER:
+ PARSE_IAL(impress_server);
+ break;
+
+ case SYM_IPADDR:
+ PARSE_IA1(iaddr);
+ break;
+
+ case SYM_LOG_SERVER:
+ PARSE_IAL(log_server);
+ break;
+
+ case SYM_LPR_SERVER:
+ PARSE_IAL(lpr_server);
+ break;
+
+ case SYM_NAME_SERVER:
+ PARSE_IAL(name_server);
+ break;
+
+ case SYM_RLP_SERVER:
+ PARSE_IAL(rlp_server);
+ break;
+
+ case SYM_SUBNET_MASK:
+ PARSE_IA1(subnet_mask);
+ break;
+
+ case SYM_TIME_OFFSET:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.time_offset = FALSE;
+ if (optype == OP_ADDITION) {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ if (!strncmp(tmpstr, "auto", 4)) {
+ hp->time_offset = secondswest;
+ } else {
+ if (sscanf(tmpstr, "%d", &timeoff) != 1)
+ return E_BAD_LONGWORD;
+ hp->time_offset = timeoff;
+ }
+ hp->flags.time_offset = TRUE;
+ }
+ break;
+
+ case SYM_TIME_SERVER:
+ PARSE_IAL(time_server);
+ break;
+
+ case SYM_VENDOR_MAGIC:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.vm_cookie = FALSE;
+ if (optype == OP_ADDITION) {
+ if (strncmp(*symbol, "auto", 4)) {
+ /* The string is not "auto" */
+ if (!strncmp(*symbol, "rfc", 3)) {
+ bcopy(vm_rfc1048, hp->vm_cookie, 4);
+ } else if (!strncmp(*symbol, "cmu", 3)) {
+ bcopy(vm_cmu, hp->vm_cookie, 4);
+ } else {
+ if (!isdigit(**symbol))
+ return E_BAD_IPADDR;
+ if (prs_inetaddr(symbol, &value) < 0)
+ return E_BAD_IPADDR;
+ bcopy(&value, hp->vm_cookie, 4);
+ }
+ hp->flags.vm_cookie = TRUE;
+ }
+ }
+ break;
+
+ case SYM_SIMILAR_ENTRY:
+ switch (optype) {
+ case OP_ADDITION:
+ fill_defaults(hp, symbol);
+ break;
+ default:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_NAME_SWITCH:
+ switch (optype) {
+ case OP_ADDITION:
+ return E_SYNTAX_ERROR;
+ case OP_DELETION:
+ hp->flags.send_name = FALSE;
+ hp->flags.name_switch = FALSE;
+ break;
+ case OP_BOOLEAN:
+ hp->flags.send_name = TRUE;
+ hp->flags.name_switch = TRUE;
+ break;
+ }
+ break;
+
+ case SYM_BOOTSIZE:
+ switch (optype) {
+ case OP_ADDITION:
+ if (!strncmp(*symbol, "auto", 4)) {
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ } else {
+ hp->bootsize = (unsigned int) get_u_long(symbol);
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = FALSE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.bootsize = FALSE;
+ break;
+ case OP_BOOLEAN:
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ break;
+ }
+ break;
+
+ case SYM_BOOT_SERVER:
+ PARSE_IA1(bootserver);
+ break;
+
+ case SYM_TFTPDIR:
+ PARSE_STR(tftpdir);
+ if ((hp->tftpdir != NULL) &&
+ (hp->tftpdir->string[0] != '/'))
+ return E_BAD_PATHNAME;
+ break;
+
+ case SYM_DUMP_FILE:
+ PARSE_STR(dump_file);
+ break;
+
+ case SYM_DOMAIN_NAME:
+ PARSE_STR(domain_name);
+ break;
+
+ case SYM_SWAP_SERVER:
+ PARSE_IA1(swap_server);
+ break;
+
+ case SYM_ROOT_PATH:
+ PARSE_STR(root_path);
+ break;
+
+ case SYM_EXTEN_FILE:
+ PARSE_STR(exten_file);
+ break;
+
+ case SYM_REPLY_ADDR:
+ PARSE_IA1(reply_addr);
+ break;
+
+ case SYM_NIS_DOMAIN:
+ PARSE_STR(nis_domain);
+ break;
+
+ case SYM_NIS_SERVER:
+ PARSE_IAL(nis_server);
+ break;
+
+ case SYM_NTP_SERVER:
+ PARSE_IAL(ntp_server);
+ break;
+
+#ifdef YORK_EX_OPTION
+ case SYM_EXEC_FILE:
+ PARSE_STR(exec_file);
+ break;
+#endif
+
+ case SYM_MSG_SIZE:
+ PARSE_INT(msg_size);
+ if (hp->msg_size < BP_MINPKTSZ ||
+ hp->msg_size > MAX_MSG_SIZE)
+ return E_BAD_VALUE;
+ break;
+
+ case SYM_MIN_WAIT:
+ PARSE_INT(min_wait);
+ if (hp->min_wait < 0)
+ return E_BAD_VALUE;
+ break;
+
+ /* XXX - Add new tags here */
+
+ default:
+ return E_UNKNOWN_SYMBOL;
+
+ } /* switch symbolcode */
+
+ return SUCCESS;
+}
+#undef PARSE_IA1
+#undef PARSE_IAL
+#undef PARSE_STR
+
+
+
+
+/*
+ * Read a string from the buffer indirectly pointed to through "src" and
+ * move it into the buffer pointed to by "dest". A pointer to the maximum
+ * allowable length of the string (including null-terminator) is passed as
+ * "length". The actual length of the string which was read is returned in
+ * the unsigned integer pointed to by "length". This value is the same as
+ * that which would be returned by applying the strlen() function on the
+ * destination string (i.e the terminating null is not counted as a
+ * character). Trailing whitespace is removed from the string. For
+ * convenience, the function returns the new value of "dest".
+ *
+ * The string is read until the maximum number of characters, an unquoted
+ * colon (:), or a null character is read. The return string in "dest" is
+ * null-terminated.
+ */
+
+PRIVATE char *
+get_string(src, dest, length)
+ char **src, *dest;
+ unsigned *length;
+{
+ int n, len, quoteflag;
+
+ quoteflag = FALSE;
+ n = 0;
+ len = *length - 1;
+ while ((n < len) && (**src)) {
+ if (!quoteflag && (**src == ':')) {
+ break;
+ }
+ if (**src == '"') {
+ (*src)++;
+ quoteflag = !quoteflag;
+ continue;
+ }
+ if (**src == '\\') {
+ (*src)++;
+ if (!**src) {
+ break;
+ }
+ }
+ *dest++ = *(*src)++;
+ n++;
+ }
+
+ /*
+ * Remove that troublesome trailing whitespace. . .
+ */
+ while ((n > 0) && isspace(dest[-1])) {
+ dest--;
+ n--;
+ }
+
+ *dest = '\0';
+ *length = n;
+ return dest;
+}
+
+
+
+/*
+ * Read the string indirectly pointed to by "src", update the caller's
+ * pointer, and return a pointer to a malloc'ed shared_string structure
+ * containing the string.
+ *
+ * The string is read using the same rules as get_string() above.
+ */
+
+PRIVATE struct shared_string *
+get_shared_string(src)
+ char **src;
+{
+ char retstring[MAXSTRINGLEN];
+ struct shared_string *s;
+ unsigned length;
+
+ length = sizeof(retstring);
+ (void) get_string(src, retstring, &length);
+
+ s = (struct shared_string *) smalloc(sizeof(struct shared_string)
+ + length);
+ s->linkcount = 1;
+ strcpy(s->string, retstring);
+
+ return s;
+}
+
+
+
+/*
+ * Load RFC1048 generic information directly into a memory buffer.
+ *
+ * "src" indirectly points to the ASCII representation of the generic data.
+ * "dest" points to a string structure which is updated to point to a new
+ * string with the new data appended to the old string. The old string is
+ * freed.
+ *
+ * The given tag value is inserted with the new data.
+ *
+ * The data may be represented as either a stream of hexadecimal numbers
+ * representing bytes (any or all bytes may optionally start with '0x' and
+ * be separated with periods ".") or as a quoted string of ASCII
+ * characters (the quotes are required).
+ */
+
+PRIVATE int
+process_generic(src, dest, tagvalue)
+ char **src;
+ struct shared_bindata **dest;
+ u_int tagvalue;
+{
+ byte tmpbuf[MAXBUFLEN];
+ byte *str;
+ struct shared_bindata *bdata;
+ u_int newlength, oldlength;
+
+ str = tmpbuf;
+ *str++ = (tagvalue & 0xFF); /* Store tag value */
+ str++; /* Skip over length field */
+ if ((*src)[0] == '"') { /* ASCII data */
+ newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
+ (void) get_string(src, (char *) str, &newlength);
+ newlength++; /* null terminator */
+ } else { /* Numeric data */
+ newlength = 0;
+ while (newlength < sizeof(tmpbuf) - 2) {
+ if (interp_byte(src, str++) < 0)
+ break;
+ newlength++;
+ if (**src == '.') {
+ (*src)++;
+ }
+ }
+ }
+ if ((*src)[0] != ':')
+ return -1;
+
+ tmpbuf[1] = (newlength & 0xFF);
+ oldlength = ((*dest)->length);
+ bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
+ + oldlength + newlength + 1);
+ if (oldlength > 0) {
+ bcopy((*dest)->data, bdata->data, oldlength);
+ }
+ bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
+ bdata->length = oldlength + newlength + 2;
+ bdata->linkcount = 1;
+ if (*dest) {
+ del_bindata(*dest);
+ }
+ *dest = bdata;
+ return 0;
+}
+
+
+
+/*
+ * Verify that the given string makes sense as a hostname (according to
+ * Appendix 1, page 29 of RFC882).
+ *
+ * Return TRUE for good names, FALSE otherwise.
+ */
+
+PRIVATE boolean
+goodname(hostname)
+ register char *hostname;
+{
+ do {
+ if (!isalpha(*hostname++)) { /* First character must be a letter */
+ return FALSE;
+ }
+ while (isalnum(*hostname) ||
+ (*hostname == '-') ||
+ (*hostname == '_') )
+ {
+ hostname++; /* Alphanumeric or a hyphen */
+ }
+ if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
+ return FALSE;
+ }
+ if (*hostname == '\0') {/* Done? */
+ return TRUE;
+ }
+ } while (*hostname++ == '.'); /* Dot, loop for next label */
+
+ return FALSE; /* If it's not a dot, lose */
+}
+
+
+
+/*
+ * Null compare function -- always returns FALSE so an element is always
+ * inserted into a hash table (i.e. there is never a collision with an
+ * existing element).
+ */
+
+PRIVATE boolean
+nullcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ return FALSE;
+}
+
+
+/*
+ * Function for comparing a string with the hostname field of a host
+ * structure.
+ */
+
+boolean
+nmcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ char *name = (char *) d1; /* XXX - OK? */
+ struct host *hp = (struct host *) d2;
+
+ return !strcmp(name, hp->hostname->string);
+}
+
+
+/*
+ * Compare function to determine whether two hardware addresses are
+ * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
+ * otherwise.
+ *
+ * If the hardware addresses of "host1" and "host2" are identical, but
+ * they are on different IP subnets, this function returns FALSE.
+ *
+ * This function is used when inserting elements into the hardware address
+ * hash table.
+ */
+
+PRIVATE boolean
+hwinscmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ /* XXX - Is the subnet_mask field set yet? */
+ if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
+ if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
+ ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ * Macros for use in the function below:
+ */
+
+#define DUP_COPY(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ hp->MEMBER = hp2->MEMBER; \
+ } \
+ } \
+} while (0)
+
+#define DUP_LINK(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ assert(hp2->MEMBER); \
+ hp->MEMBER = hp2->MEMBER; \
+ (hp->MEMBER->linkcount)++; \
+ } \
+ } \
+} while (0)
+
+/*
+ * Process the "similar entry" symbol.
+ *
+ * The host specified as the value of the "tc" symbol is used as a template
+ * for the current host entry. Symbol values not explicitly set in the
+ * current host entry are inferred from the template entry.
+ */
+PRIVATE void
+fill_defaults(hp, src)
+ struct host *hp;
+ char **src;
+{
+ unsigned int tlen, hashcode;
+ struct host *hp2;
+ char tstring[MAXSTRINGLEN];
+
+ tlen = sizeof(tstring);
+ (void) get_string(src, tstring, &tlen);
+ hashcode = hash_HashFunction((u_char *) tstring, tlen);
+ hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
+
+ if (hp2 == NULL) {
+ report(LOG_ERR, "can't find tc=\"%s\"", tstring);
+ return;
+ }
+ DUP_LINK(bootfile);
+ DUP_LINK(cookie_server);
+ DUP_LINK(domain_server);
+ DUP_LINK(gateway);
+ /* haddr not copied */
+ DUP_LINK(homedir);
+ DUP_COPY(htype);
+
+ DUP_LINK(impress_server);
+ /* iaddr not copied */
+ DUP_LINK(log_server);
+ DUP_LINK(lpr_server);
+ DUP_LINK(name_server);
+ DUP_LINK(rlp_server);
+
+ DUP_COPY(subnet_mask);
+ DUP_COPY(time_offset);
+ DUP_LINK(time_server);
+
+ if (!hp->flags.vm_cookie) {
+ if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
+ bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
+ }
+ }
+ if (!hp->flags.name_switch) {
+ if ((hp->flags.name_switch = hp2->flags.name_switch)) {
+ hp->flags.send_name = hp2->flags.send_name;
+ }
+ }
+ if (!hp->flags.bootsize) {
+ if ((hp->flags.bootsize = hp2->flags.bootsize)) {
+ hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
+ hp->bootsize = hp2->bootsize;
+ }
+ }
+ DUP_COPY(bootserver);
+
+ DUP_LINK(tftpdir);
+ DUP_LINK(dump_file);
+ DUP_LINK(domain_name);
+
+ DUP_COPY(swap_server);
+ DUP_LINK(root_path);
+ DUP_LINK(exten_file);
+
+ DUP_COPY(reply_addr);
+
+ DUP_LINK(nis_domain);
+ DUP_LINK(nis_server);
+ DUP_LINK(ntp_server);
+
+#ifdef YORK_EX_OPTION
+ DUP_LINK(exec_file);
+#endif
+
+ DUP_COPY(msg_size);
+ DUP_COPY(min_wait);
+
+ /* XXX - Add new tags here */
+
+ DUP_LINK(generic);
+
+}
+#undef DUP_COPY
+#undef DUP_LINK
+
+
+
+/*
+ * This function adjusts the caller's pointer to point just past the
+ * first-encountered colon. If it runs into a null character, it leaves
+ * the pointer pointing to it.
+ */
+
+PRIVATE void
+adjust(s)
+ char **s;
+{
+ register char *t;
+
+ t = *s;
+ while (*t && (*t != ':')) {
+ t++;
+ }
+ if (*t) {
+ t++;
+ }
+ *s = t;
+}
+
+
+
+
+/*
+ * This function adjusts the caller's pointer to point to the first
+ * non-whitespace character. If it runs into a null character, it leaves
+ * the pointer pointing to it.
+ */
+
+PRIVATE void
+eat_whitespace(s)
+ char **s;
+{
+ register char *t;
+
+ t = *s;
+ while (*t && isspace(*t)) {
+ t++;
+ }
+ *s = t;
+}
+
+
+
+/*
+ * This function converts the given string to all lowercase.
+ */
+
+PRIVATE void
+makelower(s)
+ char *s;
+{
+ while (*s) {
+ if (isupper(*s)) {
+ *s = tolower(*s);
+ }
+ s++;
+ }
+}
+
+
+
+/*
+ *
+ * N O T E :
+ *
+ * In many of the functions which follow, a parameter such as "src" or
+ * "symbol" is passed as a pointer to a pointer to something. This is
+ * done for the purpose of letting the called function update the
+ * caller's copy of the parameter (i.e. to effect call-by-reference
+ * parameter passing). The value of the actual parameter is only used
+ * to locate the real parameter of interest and then update this indirect
+ * parameter.
+ *
+ * I'm sure somebody out there won't like this. . . .
+ * (Yea, because it usually makes code slower... -gwr)
+ *
+ */
+
+
+
+/*
+ * "src" points to a character pointer which points to an ASCII string of
+ * whitespace-separated IP addresses. A pointer to an in_addr_list
+ * structure containing the list of addresses is returned. NULL is
+ * returned if no addresses were found at all. The pointer pointed to by
+ * "src" is updated to point to the first non-address (illegal) character.
+ */
+
+PRIVATE struct in_addr_list *
+get_addresses(src)
+ char **src;
+{
+ struct in_addr tmpaddrlist[MAXINADDRS];
+ struct in_addr *address1, *address2;
+ struct in_addr_list *result;
+ unsigned addrcount, totalsize;
+
+ address1 = tmpaddrlist;
+ for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
+ while (isspace(**src) || (**src == ',')) {
+ (*src)++;
+ }
+ if (!**src) { /* Quit if nothing more */
+ break;
+ }
+ if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
+ break;
+ }
+ address1++; /* Point to next address slot */
+ }
+ if (addrcount < 1) {
+ result = NULL;
+ } else {
+ totalsize = sizeof(struct in_addr_list)
+ + (addrcount - 1) * sizeof(struct in_addr);
+ result = (struct in_addr_list *) smalloc(totalsize);
+ result->linkcount = 1;
+ result->addrcount = addrcount;
+ address1 = tmpaddrlist;
+ address2 = result->addr;
+ for (; addrcount > 0; addrcount--) {
+ address2->s_addr = address1->s_addr;
+ address1++;
+ address2++;
+ }
+ }
+ return result;
+}
+
+
+
+/*
+ * prs_inetaddr(src, result)
+ *
+ * "src" is a value-result parameter; the pointer it points to is updated
+ * to point to the next data position. "result" points to an unsigned long
+ * in which an address is returned.
+ *
+ * This function parses the IP address string in ASCII "dot notation" pointed
+ * to by (*src) and places the result (in network byte order) in the unsigned
+ * long pointed to by "result". For malformed addresses, -1 is returned,
+ * (*src) points to the first illegal character, and the unsigned long pointed
+ * to by "result" is unchanged. Successful calls return 0.
+ */
+
+PRIVATE int
+prs_inetaddr(src, result)
+ char **src;
+ u_int32 *result;
+{
+ char tmpstr[MAXSTRINGLEN];
+ register u_int32 value;
+ u_int32 parts[4], *pp;
+ int n;
+ char *s, *t;
+
+#if 1 /* XXX - experimental */
+ /* Leading alpha char causes IP addr lookup. */
+ if (isalpha(**src)) {
+ /* Lookup IP address. */
+ s = *src;
+ t = tmpstr;
+ while ((isalnum(*s) || (*s == '.') ||
+ (*s == '-') || (*s == '_') ) &&
+ (t < &tmpstr[MAXSTRINGLEN - 1]) )
+ *t++ = *s++;
+ *t = '\0';
+ *src = s;
+
+ n = lookup_ipa(tmpstr, result);
+ if (n < 0)
+ report(LOG_ERR, "can not get IP addr for %s", tmpstr);
+ return n;
+ }
+#endif
+
+ /*
+ * Parse an address in Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ pp = parts;
+ loop:
+ /* If it's not a digit, return error. */
+ if (!isdigit(**src))
+ return -1;
+ *pp++ = get_u_long(src);
+ if (**src == '.') {
+ if (pp < (parts + 4)) {
+ (*src)++;
+ goto loop;
+ }
+ return (-1);
+ }
+#if 0
+ /* This is handled by the caller. */
+ if (**src && !(isspace(**src) || (**src == ':'))) {
+ return (-1);
+ }
+#endif
+
+ /*
+ * Construct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts;
+ switch (n) {
+ case 1: /* a -- 32 bits */
+ value = parts[0];
+ break;
+ case 2: /* a.b -- 8.24 bits */
+ value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
+ break;
+ case 3: /* a.b.c -- 8.8.16 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ (parts[2] & 0xFFFF);
+ break;
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
+ break;
+ default:
+ return (-1);
+ }
+ *result = htonl(value);
+ return (0);
+}
+
+
+
+/*
+ * "src" points to a pointer which in turn points to a hexadecimal ASCII
+ * string. This string is interpreted as a hardware address and returned
+ * as a pointer to the actual hardware address, represented as an array of
+ * bytes.
+ *
+ * The ASCII string must have the proper number of digits for the specified
+ * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
+ * Two-digit sequences (bytes) may be separated with periods (.) and/or
+ * prefixed with '0x' for readability, but this is not required.
+ *
+ * For bad addresses, the pointer which "src" points to is updated to point
+ * to the start of the first two-digit sequence which was bad, and the
+ * function returns a NULL pointer.
+ */
+
+PRIVATE byte *
+prs_haddr(src, htype)
+ char **src;
+ u_int htype;
+{
+ static byte haddr[MAXHADDRLEN];
+ byte *hap;
+ char tmpstr[MAXSTRINGLEN];
+ u_int tmplen;
+ unsigned hal;
+ char *p;
+
+ hal = haddrlength(htype); /* Get length of this address type */
+ if (hal <= 0) {
+ report(LOG_ERR, "Invalid addr type for HW addr parse");
+ return NULL;
+ }
+ tmplen = sizeof(tmpstr);
+ get_string(src, tmpstr, &tmplen);
+ p = tmpstr;
+
+#if 1 /* XXX - experimental */
+ /* If it's a valid host name, try to lookup the HW address. */
+ if (goodname(p)) {
+ /* Lookup Hardware Address for hostname. */
+ if ((hap = lookup_hwa(p, htype)) != NULL)
+ return hap; /* success */
+ report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
+ /* OK, assume it must be numeric. */
+ }
+#endif
+
+ hap = haddr;
+ while (hap < haddr + hal) {
+ if (*p == '.')
+ p++;
+ if (interp_byte(&p, hap++) < 0) {
+ return NULL;
+ }
+ }
+ return haddr;
+}
+
+
+
+/*
+ * "src" is a pointer to a character pointer which in turn points to a
+ * hexadecimal ASCII representation of a byte. This byte is read, the
+ * character pointer is updated, and the result is deposited into the
+ * byte pointed to by "retbyte".
+ *
+ * The usual '0x' notation is allowed but not required. The number must be
+ * a two digit hexadecimal number. If the number is invalid, "src" and
+ * "retbyte" are left untouched and -1 is returned as the function value.
+ * Successful calls return 0.
+ */
+
+PRIVATE int
+interp_byte(src, retbyte)
+ char **src;
+ byte *retbyte;
+{
+ int v;
+
+ if ((*src)[0] == '0' &&
+ ((*src)[1] == 'x' ||
+ (*src)[1] == 'X')) {
+ (*src) += 2; /* allow 0x for hex, but don't require it */
+ }
+ if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
+ return -1;
+ }
+ if (sscanf(*src, "%2x", &v) != 1) {
+ return -1;
+ }
+ (*src) += 2;
+ *retbyte = (byte) (v & 0xFF);
+ return 0;
+}
+
+
+
+/*
+ * The parameter "src" points to a character pointer which points to an
+ * ASCII string representation of an unsigned number. The number is
+ * returned as an unsigned long and the character pointer is updated to
+ * point to the first illegal character.
+ */
+
+PRIVATE u_int32
+get_u_long(src)
+ char **src;
+{
+ register u_int32 value, base;
+ char c;
+
+ /*
+ * Collect number up to first illegal character. Values are specified
+ * as for C: 0x=hex, 0=octal, other=decimal.
+ */
+ value = 0;
+ base = 10;
+ if (**src == '0') {
+ base = 8;
+ (*src)++;
+ }
+ if (**src == 'x' || **src == 'X') {
+ base = 16;
+ (*src)++;
+ }
+ while ((c = **src)) {
+ if (isdigit(c)) {
+ value = (value * base) + (c - '0');
+ (*src)++;
+ continue;
+ }
+ if (base == 16 && isxdigit(c)) {
+ value = (value << 4) + ((c & ~32) + 10 - 'A');
+ (*src)++;
+ continue;
+ }
+ break;
+ }
+ return value;
+}
+
+
+
+/*
+ * Routines for deletion of data associated with the main data structure.
+ */
+
+
+/*
+ * Frees the entire host data structure given. Does nothing if the passed
+ * pointer is NULL.
+ */
+
+PRIVATE void
+free_host(hmp)
+ hash_datum *hmp;
+{
+ struct host *hostptr = (struct host *) hmp;
+ if (hostptr == NULL)
+ return;
+ assert(hostptr->linkcount > 0);
+ if (--(hostptr->linkcount))
+ return; /* Still has references */
+ del_iplist(hostptr->cookie_server);
+ del_iplist(hostptr->domain_server);
+ del_iplist(hostptr->gateway);
+ del_iplist(hostptr->impress_server);
+ del_iplist(hostptr->log_server);
+ del_iplist(hostptr->lpr_server);
+ del_iplist(hostptr->name_server);
+ del_iplist(hostptr->rlp_server);
+ del_iplist(hostptr->time_server);
+ del_iplist(hostptr->nis_server);
+ del_iplist(hostptr->ntp_server);
+
+ /*
+ * XXX - Add new tags here
+ * (if the value is an IP list)
+ */
+
+ del_string(hostptr->hostname);
+ del_string(hostptr->homedir);
+ del_string(hostptr->bootfile);
+ del_string(hostptr->tftpdir);
+ del_string(hostptr->root_path);
+ del_string(hostptr->domain_name);
+ del_string(hostptr->dump_file);
+ del_string(hostptr->exten_file);
+ del_string(hostptr->nis_domain);
+
+#ifdef YORK_EX_OPTION
+ del_string(hostptr->exec_file);
+#endif
+
+ /*
+ * XXX - Add new tags here
+ * (if it is a shared string)
+ */
+
+ del_bindata(hostptr->generic);
+ free((char *) hostptr);
+}
+
+
+
+/*
+ * Decrements the linkcount on the given IP address data structure. If the
+ * linkcount goes to zero, the memory associated with the data is freed.
+ */
+
+PRIVATE void
+del_iplist(iplist)
+ struct in_addr_list *iplist;
+{
+ if (iplist) {
+ if (!(--(iplist->linkcount))) {
+ free((char *) iplist);
+ }
+ }
+}
+
+
+
+/*
+ * Decrements the linkcount on a string data structure. If the count
+ * goes to zero, the memory associated with the string is freed. Does
+ * nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void
+del_string(stringptr)
+ struct shared_string *stringptr;
+{
+ if (stringptr) {
+ if (!(--(stringptr->linkcount))) {
+ free((char *) stringptr);
+ }
+ }
+}
+
+
+
+/*
+ * Decrements the linkcount on a shared_bindata data structure. If the
+ * count goes to zero, the memory associated with the data is freed. Does
+ * nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void
+del_bindata(dataptr)
+ struct shared_bindata *dataptr;
+{
+ if (dataptr) {
+ if (!(--(dataptr->linkcount))) {
+ free((char *) dataptr);
+ }
+ }
+}
+
+
+
+
+/* smalloc() -- safe malloc()
+ *
+ * Always returns a valid pointer (if it returns at all). The allocated
+ * memory is initialized to all zeros. If malloc() returns an error, a
+ * message is printed using the report() function and the program aborts
+ * with a status of 1.
+ */
+
+PRIVATE char *
+smalloc(nbytes)
+ unsigned nbytes;
+{
+ char *retvalue;
+
+ retvalue = malloc(nbytes);
+ if (!retvalue) {
+ report(LOG_ERR, "malloc() failure -- exiting");
+ exit(1);
+ }
+ bzero(retvalue, nbytes);
+ return retvalue;
+}
+
+
+/*
+ * Compare function to determine whether two hardware addresses are
+ * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
+ * otherwise.
+ *
+ * This function is used when retrieving elements from the hardware address
+ * hash table.
+ */
+
+boolean
+hwlookcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*
+ * Compare function for doing IP address hash table lookup.
+ */
+
+boolean
+iplookcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ return (host1->iaddr.s_addr == host2->iaddr.s_addr);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/readfile.h b/usr.sbin/bootpd/readfile.h
new file mode 100644
index 00000000000..3913455857c
--- /dev/null
+++ b/usr.sbin/bootpd/readfile.h
@@ -0,0 +1,19 @@
+/* readfile.h */
+
+#include "bptypes.h"
+#include "hash.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern boolean hwlookcmp P((hash_datum *, hash_datum *));
+extern boolean iplookcmp P((hash_datum *, hash_datum *));
+extern boolean nmcmp P((hash_datum *, hash_datum *));
+extern void readtab P((int));
+extern void rdtab_init P((void));
+
+#undef P
+
diff --git a/usr.sbin/bootpd/report.c b/usr.sbin/bootpd/report.c
new file mode 100644
index 00000000000..4f7f03616a2
--- /dev/null
+++ b/usr.sbin/bootpd/report.c
@@ -0,0 +1,154 @@
+/*
+ * report() - calls syslog
+ */
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "report.h"
+
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_BOOTP
+#define LOG_BOOTP LOG_DAEMON
+#endif
+
+extern int debug;
+extern char *progname;
+
+/*
+ * This is initialized so you get stderr until you call
+ * report_init()
+ */
+static int stderr_only = 1;
+
+void
+report_init(nolog)
+ int nolog;
+{
+ stderr_only = nolog;
+#ifdef SYSLOG
+ if (!stderr_only) {
+ openlog(progname, LOG_PID | LOG_NDELAY, LOG_BOOTP);
+ }
+#endif
+}
+
+/*
+ * This routine reports errors and such via stderr and syslog() if
+ * appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
+ * from being scattered throughout the code.
+ *
+ * The syntax is identical to syslog(3), but %m is not considered special
+ * for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
+ * control strings should normally end with \n since newlines aren't
+ * automatically generated for stderr output (whereas syslog strips out all
+ * newlines and adds its own at the end).
+ */
+
+static char *levelnames[] = {
+#ifdef LOG_SALERT
+ "level(0): ",
+ "alert(1): ",
+ "alert(2): ",
+ "emerg(3): ",
+ "error(4): ",
+ "crit(5): ",
+ "warn(6): ",
+ "note(7): ",
+ "info(8): ",
+ "debug(9): ",
+ "level(?): "
+#else
+ "emerg(0): ",
+ "alert(1): ",
+ "crit(2): ",
+ "error(3): ",
+ "warn(4): ",
+ "note(5): ",
+ "info(6): ",
+ "debug(7): ",
+ "level(?): "
+#endif
+};
+static int numlevels = sizeof(levelnames) / sizeof(levelnames[0]);
+
+
+/*
+ * Print a log message using syslog(3) and/or stderr.
+ * The message passed in should not include a newline.
+ */
+#ifdef __STDC__
+void
+report(int priority, char *fmt,...)
+#else
+/*VARARGS2*/
+void
+report(priority, fmt, va_alist)
+ int priority;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ static char buf[128];
+
+ if ((priority < 0) || (priority >= numlevels)) {
+ priority = numlevels - 1;
+ }
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /*
+ * Print the message
+ */
+ if (stderr_only || (debug > 2)) {
+ fprintf(stderr, "%s: %s %s\n",
+ progname, levelnames[priority], buf);
+ }
+#ifdef SYSLOG
+ if (!stderr_only)
+ syslog((priority | LOG_BOOTP), "%s", buf);
+#endif
+}
+
+
+
+/*
+ * Return pointer to static string which gives full filesystem error message.
+ */
+char *
+get_errmsg()
+{
+ extern int errno;
+ extern char *strerror();
+
+ return strerror(errno);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/bootpd/report.h b/usr.sbin/bootpd/report.h
new file mode 100644
index 00000000000..0bf63d60fbb
--- /dev/null
+++ b/usr.sbin/bootpd/report.h
@@ -0,0 +1,13 @@
+/* report.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void report_init P((int nolog));
+extern void report P((int, char *, ...));
+extern char *get_errmsg P((void));
+
+#undef P
diff --git a/usr.sbin/bootpd/syslog.conf b/usr.sbin/bootpd/syslog.conf
new file mode 100644
index 00000000000..2c135af4974
--- /dev/null
+++ b/usr.sbin/bootpd/syslog.conf
@@ -0,0 +1,63 @@
+#
+# syslog configuration file for SunOS 4.X
+# (modified to do local2 separately)
+#
+# This file is processed by m4 so be careful to quote (`') names
+# that match m4 reserved words. Also, within ifdef's, arguments
+# containing commas must be quoted.
+#
+# Note: Have to exclude user from most lines so that user.alert
+# and user.emerg are not included, because old sendmails
+# will generate them for debugging information. If you
+# have no 4.2BSD based systems doing network logging, you
+# can remove all the special cases for "user" logging.
+
+#*.err;kern.debug;auth.notice;user.none /dev/console
+kern.debug;user,mail.crit;auth.notice /dev/console
+daemon,syslog,lpr,news,uucp,cron.err /dev/console
+
+#*.err;kern.debug;daemon,auth.notice;mail.crit;user.none /var/adm/messages
+kern.debug;user,mail.crit;auth.notice /var/adm/messages
+daemon.notice;syslog,news,uucp,cron.err /var/adm/messages
+
+lpr.debug /var/adm/lpd-errs
+
+*.alert;kern.err;daemon.err;user.none operator
+*.alert;user.none root
+
+*.emerg;user.none *
+
+# for loghost machines, to have authentication messages (su, login, etc.)
+# logged to a file, un-comment out the following line and adjust the file name
+# as appropriate.
+#
+# if a non-loghost machine chooses to have such messages
+# sent to the loghost machine, un-comment out the following line.
+#
+#auth.notice ifdef(`LOGHOST', /var/log/authlog, @loghost)
+
+mail.debug ifdef(`LOGHOST', /var/log/syslog, @loghost)
+
+# following line for compatibility with old sendmails. they will send
+# messages with no facility code, which will be turned into "user" messages
+# by the local syslog daemon. only the "loghost" machine needs the following
+# line, to cause these old sendmail log messages to be logged in the
+# mail syslog file.
+#
+ifdef(`LOGHOST',
+user.alert /var/log/syslog
+)
+#
+# non-loghost machines will use the following lines to cause "user"
+# log messages to be logged locally.
+#
+ifdef(`LOGHOST', ,
+user.err /dev/console
+user.err /var/adm/messages
+user.alert `root, operator'
+user.emerg *
+)
+
+# Local2: (bootpd, pppd)
+local2.debug /dev/console
+#local2.debug /var/log/local2
diff --git a/usr.sbin/bootpd/trygetea.c b/usr.sbin/bootpd/trygetea.c
new file mode 100644
index 00000000000..e9314aede96
--- /dev/null
+++ b/usr.sbin/bootpd/trygetea.c
@@ -0,0 +1,46 @@
+/*
+ * trygetea.c - test program for getether.c
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ u_char ea[16]; /* Ethernet address */
+ int i;
+
+ progname = argv[0]; /* for report */
+
+ if (argc < 2) {
+ printf("need interface name\n");
+ exit(1);
+ }
+ if ((i = getether(argv[1], ea)) < 0) {
+ printf("Could not get Ethernet address (rc=%d)\n", i);
+ exit(1);
+ }
+ printf("Ether-addr");
+ for (i = 0; i < 6; i++)
+ printf(":%x", ea[i] & 0xFF);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/usr.sbin/bootpd/trygetif.c b/usr.sbin/bootpd/trygetif.c
new file mode 100644
index 00000000000..894f17b6e91
--- /dev/null
+++ b/usr.sbin/bootpd/trygetif.c
@@ -0,0 +1,66 @@
+/*
+ * trygetif.c - test program for getif.c
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "getif.h"
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ struct hostent *hep;
+ struct sockaddr ea; /* Ethernet address */
+ struct sockaddr_in *sip; /* Interface address */
+ struct ifreq *ifr;
+ struct in_addr dst_addr;
+ struct in_addr *dap;
+ int i, s;
+
+ progname = argv[0]; /* for report */
+
+ dap = NULL;
+ if (argc > 1) {
+ dap = &dst_addr;
+ if (inet_aton(argv[1], &dst_addr) == 0) {
+ hep = gethostbyname(argv[1]);
+ if (!hep) {
+ printf("gethostbyname(%s)\n", argv[1]);
+ exit(1);
+ }
+ memcpy(&dst_addr, hep->h_addr, sizeof(dst_addr));
+ }
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket open");
+ exit(1);
+ }
+ ifr = getif(s, dap);
+ if (!ifr) {
+ printf("no interface for address\n");
+ exit(1);
+ }
+ printf("Intf-name:%s\n", ifr->ifr_name);
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ printf("Intf-addr:%s\n", inet_ntoa(sip->sin_addr));
+
+ exit(0);
+}
diff --git a/usr.sbin/bootpd/trylook.c b/usr.sbin/bootpd/trylook.c
new file mode 100644
index 00000000000..40652a21159
--- /dev/null
+++ b/usr.sbin/bootpd/trylook.c
@@ -0,0 +1,50 @@
+/*
+ * trylook.c - test program for lookup.c
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#include "report.h"
+#include "lookup.h"
+
+extern char *ether_ntoa();
+extern char *inet_ntoa();
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ int i;
+ struct in_addr in;
+ char *a;
+ u_char *hwa;
+
+ progname = argv[0]; /* for report */
+
+ for (i = 1; i < argc; i++) {
+
+ /* Host name */
+ printf("%s:", argv[i]);
+
+ /* IP addr */
+ if (lookup_ipa(argv[i], &in.s_addr))
+ a = "?";
+ else
+ a = inet_ntoa(in);
+ printf(" ipa=%s", a);
+
+ /* Ether addr */
+ hwa = lookup_hwa(argv[i], 1);
+ if (!hwa)
+ a = "?";
+ else
+ a = ether_ntoa(hwa);
+ printf(" hwa=%s\n", a);
+
+ }
+ exit(0);
+}
diff --git a/usr.sbin/bootpd/tzone.c b/usr.sbin/bootpd/tzone.c
new file mode 100644
index 00000000000..526764e5bae
--- /dev/null
+++ b/usr.sbin/bootpd/tzone.c
@@ -0,0 +1,46 @@
+/*
+ * tzone.c - get the timezone
+ *
+ * This is shared by bootpd and bootpef
+ */
+
+#include <sys/types.h>
+
+#ifdef SVR4
+/* XXX - Is this really SunOS specific? -gwr */
+/* This is in <time.h> but only visible if (__STDC__ == 1). */
+extern long timezone;
+#else /* SVR4 */
+/* BSD or SunOS */
+# include <sys/time.h>
+# include <syslog.h>
+#endif /* SVR4 */
+
+#include "bptypes.h"
+#include "report.h"
+#include "tzone.h"
+
+/* This is what other modules use. */
+int32 secondswest;
+
+/*
+ * Get our timezone offset so we can give it to clients if the
+ * configuration file doesn't specify one.
+ */
+void
+tzone_init()
+{
+#ifdef SVR4
+ /* XXX - Is this really SunOS specific? -gwr */
+ secondswest = timezone;
+#else /* SVR4 */
+ struct timezone tzp; /* Time zone offset for clients */
+ struct timeval tp; /* Time (extra baggage) */
+ if (gettimeofday(&tp, &tzp) < 0) {
+ secondswest = 0; /* Assume GMT for lack of anything better */
+ report(LOG_ERR, "gettimeofday: %s", get_errmsg());
+ } else {
+ secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
+ }
+#endif /* SVR4 */
+}
diff --git a/usr.sbin/bootpd/tzone.h b/usr.sbin/bootpd/tzone.h
new file mode 100644
index 00000000000..ddd67c4b625
--- /dev/null
+++ b/usr.sbin/bootpd/tzone.h
@@ -0,0 +1,3 @@
+/* tzone.h */
+extern int32 secondswest;
+extern void tzone_init();
diff --git a/usr.sbin/bootpef/Makefile b/usr.sbin/bootpef/Makefile
new file mode 100644
index 00000000000..4034af7e21b
--- /dev/null
+++ b/usr.sbin/bootpef/Makefile
@@ -0,0 +1,15 @@
+# bootpef/Makefile
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:28 deraadt Exp $
+
+PROG= bootpef
+SRCDIR= ${.CURDIR}/../bootpd
+CFLAGS+= -DETC_ETHERS -DDEBUG -I${SRCDIR}
+.PATH: ${SRCDIR}
+
+SRCS= bootpef.c dovend.c readfile.c hash.c dumptab.c \
+ lookup.c hwaddr.c report.c tzone.c
+
+MAN= bootpef.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/bootpgw/Makefile b/usr.sbin/bootpgw/Makefile
new file mode 100644
index 00000000000..4e800062db6
--- /dev/null
+++ b/usr.sbin/bootpgw/Makefile
@@ -0,0 +1,14 @@
+# bootpgw/Makefile
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:28 deraadt Exp $
+
+PROG= bootpgw
+SRCDIR= ${.CURDIR}/../bootpd
+CFLAGS+= -DSYSLOG -DDEBUG -I${SRCDIR}
+.PATH: ${SRCDIR}
+
+SRCS= bootpgw.c getif.c hwaddr.c report.c
+
+NOMAN=
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/bootptest/Makefile b/usr.sbin/bootptest/Makefile
new file mode 100644
index 00000000000..2d086c64a2d
--- /dev/null
+++ b/usr.sbin/bootptest/Makefile
@@ -0,0 +1,14 @@
+# bootptest/Makefile
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:28 deraadt Exp $
+
+PROG= bootptest
+SRCDIR= ${.CURDIR}/../bootpd
+CFLAGS+= -I${SRCDIR}
+.PATH: ${SRCDIR}
+
+SRCS= bootptest.c print-bootp.c getif.c getether.c report.c
+
+MAN= bootptest.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/catman/Makefile b/usr.sbin/catman/Makefile
new file mode 100644
index 00000000000..5ac20d4d709
--- /dev/null
+++ b/usr.sbin/catman/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:28 deraadt Exp $
+
+BINDIR= /usr/sbin
+PROG= catman
+MAN= catman.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/catman/TODO b/usr.sbin/catman/TODO
new file mode 100644
index 00000000000..3b498a27c5d
--- /dev/null
+++ b/usr.sbin/catman/TODO
@@ -0,0 +1,2 @@
+Use man.conf
+Handle hard-linked manpages.
diff --git a/usr.sbin/catman/catman.8 b/usr.sbin/catman/catman.8
new file mode 100644
index 00000000000..b11679e752e
--- /dev/null
+++ b/usr.sbin/catman/catman.8
@@ -0,0 +1,100 @@
+.\"
+.\" Copyright (c) 1993 Winning Strategies, Inc.
+.\" 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 Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: catman.8,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+.\"
+.Dd July 30, 1993
+.Dt CATMAN 8
+.Os
+.Sh NAME
+.Nm catman
+.Nd format cat pages from man pages
+.Sh SYNOPSIS
+.Nm catman
+.Op Fl knpsw
+.Op Fl M Ar directory
+.Op Ar sections
+.Sh DESCRIPTION
+.Nm Catman
+creates formatted versions of the on-line manual pages from their
+.Xr nroff 1
+source.
+Manual pages whose formatted versions are missing or out of date are
+regenerated.
+If manual pages are regenerated,
+.Nm catman
+also regenerates the
+.Nm whatis
+database.
+.Pp
+The optional
+.Ar sections
+argument is one word, and contains the section numbers of all the
+sections to be checked. For example, if
+.Ar sections
+is ``138'', the
+manual pages in sections 1, 3, and 8 will be checked and regenerated.
+If no
+.Ar sections
+argument is provided,
+.Nm catman
+will try to operate on all of the known manual sections.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl k
+Ignore errors from nroff when building manpages.
+.It Fl n
+Do not create the
+.Nm whatis
+database.
+.It Fl p
+Display the commands that would have been executed, but do not actually
+execute them.
+.It Fl s
+Perform work silently; do not echo commands as they are executed. This
+flag is ignored if
+.Fl p
+is specified.
+.It Fl w
+Only create the
+.Nm whatis
+database.
+.It Fl M Ar directory
+Update manual pages in
+.Ar directory.
+.El
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr man 1 ,
+.Xr whatis 1
+.Sh BUGS
+Currently knows nothing about
+.Pa /etc/man.conf
+and machine specific man pages.
diff --git a/usr.sbin/catman/catman.c b/usr.sbin/catman/catman.c
new file mode 100644
index 00000000000..cbcdb99e482
--- /dev/null
+++ b/usr.sbin/catman/catman.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: catman.c,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+
+#include "pathnames.h"
+
+int f_nowhatis;
+int f_noaction;
+int f_noformat;
+int f_ignerr;
+int f_noprint;
+
+int dowhatis;
+
+char *mp = _PATH_MAN;
+char *sp = _MAN_SECTIONS;
+
+void usage __P((void));
+void catman __P((const char *, char *));
+void makewhatis __P((const char *));
+void dosystem __P((const char *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "knpswM:")) != EOF) {
+ switch (c) {
+ case 'k':
+ f_ignerr = 1;
+ break;
+ case 'n':
+ f_nowhatis = 1;
+ break;
+ case 'p':
+ f_noaction = 1;
+ break;
+ case 's':
+ f_noprint = 1;
+ break;
+ case 'w':
+ f_noformat = 1;
+ break;
+ case 'M':
+ mp = optarg;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (f_noprint && f_noaction)
+ f_noprint = 0;
+
+ if (argc > 1)
+ usage();
+ if (argc == 1)
+ sp = *argv;
+
+ if (f_noformat == 0 || f_nowhatis == 0)
+ catman(mp, sp);
+ if (f_nowhatis == 0 && dowhatis)
+ makewhatis(mp);
+
+ exit(0);
+}
+
+
+void
+catman(path, section)
+ const char *path;
+ char *section;
+{
+ char mandir[PATH_MAX];
+ char catdir[PATH_MAX];
+ char manpage[PATH_MAX];
+ char catpage[PATH_MAX];
+ char sysbuf[1024];
+ struct stat manstat;
+ struct stat catstat;
+ struct dirent *dp;
+ DIR *dirp;
+ char *s, *tmp;
+ int sectlen, error;
+
+ for (s = section; *s; s += sectlen) {
+#ifdef notdef
+ tmp = s;
+ sectlen = 0;
+ if (isdigit(*tmp)) {
+ sectlen++;
+ tmp++;
+ while (*tmp && isdigit(*tmp) == 0) {
+ sectlen++;
+ tmp++;
+ }
+ }
+#else
+ sectlen = 1;
+#endif
+ if (sectlen == 0)
+ errx(1, "malformed section string");
+
+ sprintf(mandir, "%s/%s%.*s", path, _PATH_MANPAGES, sectlen, s);
+ sprintf(catdir, "%s/%s%.*s", path, _PATH_CATPAGES, sectlen, s);
+
+ if ((dirp = opendir(mandir)) == 0) {
+ warn("can't open %s", mandir);
+ continue;
+ }
+
+ if (stat(catdir, &catstat) < 0) {
+ if (errno != ENOENT) {
+ warn("can't stat %s", catdir);
+ closedir(dirp);
+ continue;
+ }
+ if (f_noprint == 0)
+ printf("mkdir %s\n", catdir);
+ if (f_noaction == 0 && mkdir(catdir, 0755) < 0) {
+ warn("can't create %s", catdir);
+ closedir(dirp);
+ return;
+ }
+
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ sprintf(manpage, "%s/%s", mandir, dp->d_name);
+ sprintf(catpage, "%s/%s", catdir, dp->d_name);
+ if ((tmp = strrchr(catpage, '.')) != NULL)
+ strcpy(tmp, ".0");
+ else
+ continue;
+
+ if (stat(manpage, &manstat) < 0) {
+ warn("can't stat %s", manpage);
+ continue;
+ }
+
+ if (!S_ISREG(manstat.st_mode)) {
+ warnx("not a regular file %s", manpage);
+ continue;
+ }
+ if ((error = stat(catpage, &catstat)) &&
+ errno != ENOENT) {
+ warn("can't stat %s", catpage);
+ continue;
+ }
+
+ if ((error && errno == ENOENT) ||
+ manstat.st_mtime >= catstat.st_mtime) {
+ if (f_noformat)
+ dowhatis = 1;
+ else {
+ /*
+ * manpage is out of date,
+ * reformat
+ */
+ sprintf(sysbuf, "nroff -mandoc %s > %s",
+ manpage, catpage);
+ if (f_noprint == 0)
+ printf("%s\n", sysbuf);
+ if (f_noaction == 0)
+ dosystem(sysbuf);
+ dowhatis = 1;
+ }
+ }
+ }
+ closedir(dirp);
+ }
+}
+
+void
+makewhatis(path)
+ const char *path;
+{
+ char sysbuf[1024];
+
+ sprintf(sysbuf, "%s %s", _PATH_MAKEWHATIS, path);
+ if (f_noprint == 0)
+ printf("%s\n", sysbuf);
+ if (f_noaction == 0)
+ dosystem(sysbuf);
+}
+
+void
+dosystem(cmd)
+ const char *cmd;
+{
+ int status;
+
+ if ((status = system(cmd)) == 0)
+ return;
+
+ if (status == -1)
+ err(1, "cannot execute action");
+ if (WIFSIGNALED(status))
+ errx(1, "child was signaled to quit. aborting");
+ if (WIFSTOPPED(status))
+ errx(1, "child was stopped. aborting");
+ if (f_ignerr == 0)
+ errx(1,"*** Exited %d");
+ warnx("*** Exited %d (continuing)");
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: catman [-knpsw] [-M manpath] [sections]\n");
+ exit(1);
+}
diff --git a/usr.sbin/catman/pathnames.h b/usr.sbin/catman/pathnames.h
new file mode 100644
index 00000000000..be7e352b4ce
--- /dev/null
+++ b/usr.sbin/catman/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+ */
+
+#define _MAN_SECTIONS "12345678" /* l, n, o, and p, too? */
+#define _PATH_MAKEWHATIS "/usr/libexec/makewhatis"
+#define _PATH_MANPAGES "man"
+#define _PATH_CATPAGES "cat"
diff --git a/usr.sbin/chown/Makefile b/usr.sbin/chown/Makefile
new file mode 100644
index 00000000000..24f28db8b21
--- /dev/null
+++ b/usr.sbin/chown/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+
+PROG= chown
+CFLAGS+=-DSUPPORT_DOT
+MAN= chgrp.1 chown.8
+LINKS= ${BINDIR}/chown /usr/bin/chgrp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/chown/chgrp.1 b/usr.sbin/chown/chgrp.1
new file mode 100644
index 00000000000..0090e26e319
--- /dev/null
+++ b/usr.sbin/chown/chgrp.1
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1983, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)chgrp.1 8.3 (Berkeley) 3/31/94
+.\" $Id: chgrp.1,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHGRP 1
+.Os BSD 4.2
+.Sh NAME
+.Nm chgrp
+.Nd change group
+.Sh SYNOPSIS
+.Nm chgrp
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl f
+.Ar group
+.Ar files ...
+.Sh DESCRIPTION
+The chgrp utility sets the group ID of the file named by each
+.Ar file
+operand to the
+.Ar group
+ID specified by the group operand.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl f
+The force option ignores errors, except for usage errors and doesn't
+query about strange modes (unless the user does not have proper permissions).
+.El
+.Pp
+Symbolic links don't have groups, so unless the
+.Fl H
+or
+.Fl L
+option is set,
+.Nm chgrp
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Ar group
+operand can be either a group name from the group database,
+or a numeric group ID.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+The user invoking
+.Nm chgrp
+must belong to the specified group and be the owner of the file,
+or be the super-user.
+.Pp
+The
+.Nm chgrp
+utility exits 0 on success, and >0 if an error occurs.
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm chgrp
+utility changed the group of symbolic links specified on the command
+line.
+In this system, symbolic links do not have groups.
+.Sh FILES
+.Bl -tag -width /etc/group -compact
+.It Pa /etc/group
+Group ID file
+.El
+.Sh SEE ALSO
+.Xr chown 2 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr fts 3 ,
+.Xr symlink 7 ,
+.Xr chown 8
+.Sh STANDARDS
+The
+.Nm chgrp
+utility is expected to be POSIX 1003.2 compatible.
diff --git a/usr.sbin/chown/chown.8 b/usr.sbin/chown/chown.8
new file mode 100644
index 00000000000..5c499166599
--- /dev/null
+++ b/usr.sbin/chown/chown.8
@@ -0,0 +1,150 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 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.
+.\"
+.\" from: @(#)chown.8 8.3 (Berkeley) 3/31/94
+.\" $Id: chown.8,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHOWN 8
+.Os BSD 4
+.Sh NAME
+.Nm chown
+.Nd change file owner and group
+.Sh SYNOPSIS
+.Nm chown
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl f
+.Ar owner Op Ar :group
+.Ar file ...
+.Nm chown
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl f
+.Ar :group
+.Ar file ...
+.Sh DESCRIPTION
+.Nm Chown
+sets the user ID and/or the group ID of the specified files.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the user ID and/or the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl f
+Don't report any failure to change file owner or group, nor modify
+the exit status to reflect such failures.
+.El
+.Pp
+Symbolic links don't have owners, so unless the
+.Fl H
+or
+.Fl L
+option is set,
+.Nm chown
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Ar owner
+and
+.Ar group
+operands are both optional, however, one must be specified.
+If the
+.Ar group
+operand is specified, it must be preceded by a colon (``:'') character.
+.Pp
+The
+.Ar owner
+may be either a numeric user ID or a user name.
+If a user name is also a numeric user ID, the operand is used as a
+user name.
+The
+.Ar group
+may be either a numeric group ID or a group name.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+The ownership of a file may only be altered by a super-user for
+obvious security reasons.
+.Pp
+The
+.Nm chown
+utility exits 0 on success, and >0 if an error occurs.
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm chown
+utility used the dot (``.'') character to distinguish the group name.
+This has been changed to be a colon (``:'') character so that user and
+group names may contain the dot character.
+.Pp
+Previous versions of the
+.Nm chown
+utility changed the owner of symbolic links specified on the command
+line.
+In this system, symbolic links do not have owners.
+.Sh SEE ALSO
+.Xr chgrp 1 ,
+.Xr find 1 ,
+.Xr chown 2 ,
+.Xr fts 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm chown
+command is expected to be POSIX 1003.2 compliant.
diff --git a/usr.sbin/chown/chown.c b/usr.sbin/chown/chown.c
new file mode 100644
index 00000000000..09209ab5162
--- /dev/null
+++ b/usr.sbin/chown/chown.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1988, 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 copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/* from: static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94"; */
+static char *rcsid = "$Id: chown.c,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void a_gid __P((char *));
+void a_uid __P((char *));
+void chownerr __P((char *));
+u_long id __P((char *, char *));
+void usage __P((void));
+
+uid_t uid;
+gid_t gid;
+int Rflag, ischown, fflag;
+char *gname, *myname;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ FTS *ftsp;
+ FTSENT *p;
+ int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval;
+ char *cp;
+
+ myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
+ ischown = myname[2] == 'o';
+
+ Hflag = Lflag = Pflag = hflag = 0;
+ while ((ch = getopt(argc, argv, "HLPRfh")) != EOF)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ /*
+ * In System V (and probably POSIX.2) the -h option
+ * causes chown/chgrp to change the owner/group of
+ * the symbolic link. 4.4BSD's symbolic links don't
+ * have owners/groups, so it's an undocumented noop.
+ * Do syntax checking, though.
+ */
+ hflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 2)
+ usage();
+
+ fts_options = FTS_PHYSICAL;
+ if (Rflag) {
+ if (hflag)
+ errx(1,
+ "the -R and -h options may not be specified together.");
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ }
+
+ uid = gid = -1;
+ if (ischown) {
+#ifdef SUPPORT_DOT
+ if ((cp = strchr(*argv, '.')) != NULL) {
+ *cp++ = '\0';
+ a_gid(cp);
+ } else
+#endif
+ if ((cp = strchr(*argv, ':')) != NULL) {
+ *cp++ = '\0';
+ a_gid(cp);
+ }
+ a_uid(*argv);
+ } else
+ a_gid(*argv);
+
+ if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
+ err(1, NULL);
+
+ for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (!Rflag) /* Change it at FTS_DP. */
+ fts_set(ftsp, p, FTS_SKIP);
+ continue;
+ case FTS_DNR: /* Warn, chown, continue. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_ERR: /* Warn, continue. */
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ continue;
+ case FTS_SL: /* Ignore. */
+ case FTS_SLNONE:
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything and ones that we found
+ * doing a physical walk.
+ */
+ continue;
+ default:
+ break;
+ }
+
+ if (chown(p->fts_accpath, uid, gid) && !fflag) {
+ warn("%s", p->fts_path);
+ rval = 1;
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ exit(rval);
+}
+
+void
+a_gid(s)
+ char *s;
+{
+ struct group *gr;
+
+ if (*s == '\0') /* Argument was "uid[:.]". */
+ return;
+ gname = s;
+ gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid;
+}
+
+void
+a_uid(s)
+ char *s;
+{
+ struct passwd *pw;
+
+ if (*s == '\0') /* Argument was "[:.]gid". */
+ return;
+ uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid;
+}
+
+u_long
+id(name, type)
+ char *name, *type;
+{
+ u_long val;
+ char *ep;
+
+ /*
+ * XXX
+ * We know that uid_t's and gid_t's are unsigned longs.
+ */
+ errno = 0;
+ val = strtoul(name, &ep, 10);
+ if (errno)
+ err(1, "%s", name);
+ if (*ep != '\0')
+ errx(1, "%s: illegal %s name", name, type);
+ return (val);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-R [-H | -L | -P]] [-f] %s file ...\n",
+ myname, ischown ? "[owner][:group]" : "group");
+ exit(1);
+}
diff --git a/usr.sbin/chroot/Makefile b/usr.sbin/chroot/Makefile
new file mode 100644
index 00000000000..8861b09ddb6
--- /dev/null
+++ b/usr.sbin/chroot/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+
+PROG= chroot
+MAN= chroot.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/chroot/chroot.8 b/usr.sbin/chroot/chroot.8
new file mode 100644
index 00000000000..32548c58c5a
--- /dev/null
+++ b/usr.sbin/chroot/chroot.8
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1988, 1991 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.
+.\"
+.\" from: @(#)chroot.8 5.3 (Berkeley) 3/16/91
+.\" $Id: chroot.8,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt CHROOT 8
+.Os BSD 4.3
+.Sh NAME
+.Nm chroot
+.Nd change root directory
+.Sh SYNOPSIS
+.Nm chroot
+.Ar newroot
+.Op Ar command
+.Sh DESCRIPTION
+The
+.Nm chroot
+command changes its root directory to the supplied directory
+.Ar newroot
+and exec's
+.Ar command ,
+if supplied, or an interactive copy of your shell.
+.Pp
+Note,
+.Ar command
+or the shell are run as your real-user-id.
+.Sh ENVIRONMENT
+The following environment variable is referenced by
+.Nm chroot :
+.Bl -tag -width SHELL
+.It Ev SHELL
+If set,
+the string specified by
+.Ev SHELL
+is interpreted as the name of
+the shell to exec.
+If the variable
+.Ev SHELL
+is not set,
+.Pa /bin/sh
+is used.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr chroot 2 ,
+.Xr environ 7
+.Sh HISTORY
+The
+.Nm
+command
+.Ud
diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c
new file mode 100644
index 00000000000..579ce0e1384
--- /dev/null
+++ b/usr.sbin/chroot/chroot.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1988 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
+char copyright[] =
+"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)chroot.c 5.8 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: chroot.c,v 1.1.1.1 1995/10/18 08:47:29 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <err.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *shell;
+
+ if (argc < 2) {
+ (void)fprintf(stderr, "usage: chroot newroot [command]\n");
+ exit(1);
+ }
+ if (chdir(argv[1]) || chroot("."))
+ err(1, "%s", argv[1]);
+ if (argv[2]) {
+ execvp(argv[2], &argv[2]);
+ err(1, "%s", argv[2]);
+ } else {
+ if (!(shell = getenv("SHELL")))
+ shell = _PATH_BSHELL;
+ execlp(shell, shell, "-i", (char *)NULL);
+ err(1, "%s", shell);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/config/Makefile b/usr.sbin/config/Makefile
new file mode 100644
index 00000000000..0a643a86dfc
--- /dev/null
+++ b/usr.sbin/config/Makefile
@@ -0,0 +1,16 @@
+# from: @(#)Makefile 8.2 (Berkeley) 4/19/94
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+
+PROG= config
+BINDIR= /usr/sbin
+SRCS= files.c gram.y hash.c main.c mkheaders.c mkioconf.c mkmakefile.c \
+ mkswap.c pack.c scan.l sem.c util.c
+CFLAGS+=-I${.CURDIR} -I.
+LDADD+= -ll
+DPADD+= ${LIBL}
+CLEANFILES=gram.c scan.c y.tab.h
+MAN= config.8
+
+.include <bsd.prog.mk>
+
+.depend: gram.c scan.c
diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8
new file mode 100644
index 00000000000..a4bec2e1f90
--- /dev/null
+++ b/usr.sbin/config/config.8
@@ -0,0 +1,168 @@
+.\" 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.
+.\"
+.\" from: @(#)config.8 8.2 (Berkeley) 4/19/94
+.\" $Id: config.8,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+.\"
+.Dd April 19, 1994
+.Dt CONFIG 8
+.Os BSD 4
+.Sh NAME
+.Nm config
+.Nd build kernel compilation directories
+.Sh SYNOPSIS
+.Nm config
+.Op Fl p
+.Ar system-name
+.Sh DESCRIPTION
+.Pp
+This is the new version of the
+.Nm config
+program.
+.\"It understands the more modern autoconfiguration scheme
+.\"used on the SPARC and i386 platforms.
+.\"The old version of config is still used with the
+.\"HP300, DECstation, and derivative platforms.
+.\"Only the version of
+.\".Nm config
+.\"applicable to the architecture that you are running
+.\"will be installed on your machine.
+.Pp
+.Nm Config
+builds a set of configuration files from the file
+.Ar system-name ,
+which describes
+the system to configure.
+.Pp
+.Nm Config
+should run from the
+.Pa conf
+subdirectory of the top-level machine-specific directory
+of the system source (usually
+.Pa /sys/arch/MACHINE/conf ,
+where
+.Pa MACHINE
+is one of
+.Pa vax ,
+.Pa tahoe ,
+.Pa hp300 ,
+and so forth).
+.Nm Config
+assumes the directory
+.Pa ../compile
+exists; it places all output files in a subdirectory there,
+creating the subdirectory if necessary.
+The subdirectory name is taken from the
+.Ar system-name ;
+thus, configuring with
+.Dq Li config PICKLE
+will use the directory
+.Pa ../compile/PICKLE .
+.Pp
+If the
+.Fl p
+option is supplied,
+.Pa .PROF
+is appended to the compilation directory name, and
+.Nm config
+acts as if the lines
+.Dq Li makeoptions PROF="-pg"
+and
+.Dq Li options GPROF
+appeared in the configuration file.
+This will build a system that includes profiling code; see
+.Xr kgmon 8
+and
+.Xr gprof 1 .
+The
+.Fl p
+flag is expected to be used for
+.Dq one-shot
+profiles of existing systems;
+for regular profiling,
+it is probably wiser to make a separate configuration
+containing the
+.Li makeoptions
+line.
+.Pp
+The old undocumented
+.Fl g
+flag is no longer supported.
+Instead, use
+.Dq Li makeoptions DEBUG="-g"
+and (typically)
+.Dq Li options KGDB .
+.Pp
+The output of
+.Nm config
+consists of a number of files, principally
+.Pa ioconf.c ,
+a description of I/O devices that may be attached to the system; and a
+.Pa Makefile ,
+used by
+.Xr make 1
+in building the kernel.
+.Pp
+After running
+.Nm config ,
+it is wise to run
+.Dq Li make depend
+in the directory where the new makefile
+was created.
+.Nm Config
+prints a reminder of this when it completes.
+.Pp
+If
+.Nm config
+stops due to errors, the problems reported should be corrected and
+.Nm config
+should be run again.
+.Nm Config
+attempts to avoid changing the compilation directory
+if there are configuration errors,
+but this code is not well-tested,
+and some problems (such as running out of disk space)
+are unrecoverable.
+.Sh SEE ALSO
+The SYNOPSIS portion of each device in section 4.
+.Rs
+.%T "Building 4.4 BSD Systems with Config"
+.\" .%T "Device Support in 4.4BSD"
+.Re
+.sp
+.Xr config 8
+.Sh HISTORY
+The
+.Nm config
+command appeared in
+.Bx 4.1 .
+It was completely revised in
+.Bx 4.4 .
diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h
new file mode 100644
index 00000000000..745e34a179f
--- /dev/null
+++ b/usr.sbin/config/config.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)config.h 8.1 (Berkeley) 6/6/93
+ * $Id: config.h,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+/*
+ * Name/value lists. Values can be strings or pointers and/or can carry
+ * integers. The names can be NULL, resulting in simple value lists.
+ */
+struct nvlist {
+ struct nvlist *nv_next;
+ const char *nv_name;
+ union {
+ const char *un_str;
+ void *un_ptr;
+ } nv_un;
+#define nv_str nv_un.un_str
+#define nv_ptr nv_un.un_ptr
+ int nv_int;
+};
+
+/*
+ * Kernel configurations.
+ */
+struct config {
+ struct config *cf_next; /* linked list */
+ const char *cf_name; /* "vmunix" */
+ int cf_lineno; /* source line */
+ struct nvlist *cf_root; /* "root on ra0a" */
+ struct nvlist *cf_swap; /* "swap on ra0b and ra1b" */
+ struct nvlist *cf_dump; /* "dumps on ra0b" */
+};
+
+/*
+ * Attributes. These come in two flavors: "plain" and "interface".
+ * Plain attributes (e.g., "ether") simply serve to pull in files.
+ * Interface attributes (e.g., "scsi") carry three lists: locators,
+ * child devices, and references. The locators are those things
+ * that must be specified in order to configure a device instance
+ * using this attribute (e.g., "tg0 at scsi0"). The a_devs field
+ * lists child devices that can connect here (e.g., "tg"s), while
+ * the a_refs are parents that carry the attribute (e.g., actual
+ * SCSI host adapter drivers such as the SPARC "esp").
+ */
+struct attr {
+ const char *a_name; /* name of this attribute */
+ int a_iattr; /* true => allows children */
+ struct nvlist *a_locs; /* locators required */
+ int a_loclen; /* length of above list */
+ struct nvlist *a_devs; /* children */
+ struct nvlist *a_refs; /* parents */
+};
+
+/*
+ * The "base" part of a device ("uba", "sd"; but not "uba2" or
+ * "sd0"). It may be found "at" one or more attributes, including
+ * "at root" (this is represented by a NULL attribute).
+ *
+ * Each device may also export attributes. If any provide an output
+ * interface (e.g., "esp" provides "scsi"), other devices (e.g.,
+ * "tg"s) can be found at instances of this one (e.g., "esp"s).
+ * Such a connection must provide locators as specified by that
+ * interface attribute (e.g., "target").
+ *
+ * Each base carries a list of instances (via d_ihead). Note that this
+ * list "skips over" aliases; those must be found through the instances
+ * themselves.
+ */
+struct devbase {
+ const char *d_name; /* e.g., "sd" */
+ struct devbase *d_next; /* linked list */
+ int d_isdef; /* set once properly defined */
+ int d_ispseudo; /* is a pseudo-device */
+ int d_major; /* used for "root on sd0", e.g. */
+ struct nvlist *d_atlist; /* e.g., "at tg" (attr list) */
+ struct nvlist *d_vectors; /* interrupt vectors, if any */
+ struct nvlist *d_attrs; /* attributes, if any */
+ struct devi *d_ihead; /* first instance, if any */
+ struct devi **d_ipp; /* used for tacking on more instances */
+ int d_umax; /* highest unit number + 1 */
+};
+
+/*
+ * An "instance" of a device. The same instance may be listed more
+ * than once, e.g., "xx0 at isa? port FOO" + "xx0 at isa? port BAR".
+ *
+ * After everything has been read in and verified, the devi's are
+ * "packed" to collect all the information needed to generate ioconf.c.
+ * In particular, we try to collapse multiple aliases into a single entry.
+ * We then assign each "primary" (non-collapsed) instance a cfdata index.
+ * Note that there may still be aliases among these.
+ */
+struct devi {
+ /* created while parsing config file */
+ const char *i_name; /* e.g., "sd0" */
+ int i_unit; /* unit from name, e.g., 0 */
+ struct devbase *i_base;/* e.g., pointer to "sd" base */
+ struct devi *i_next; /* list of all instances */
+ struct devi *i_bsame; /* list on same base */
+ struct devi *i_alias; /* other aliases of this instance */
+ const char *i_at; /* where this is "at" (NULL if at root) */
+ struct attr *i_atattr; /* attr that allowed attach */
+ struct devbase *i_atdev;/* dev if "at <devname><unit>", else NULL */
+ const char **i_locs; /* locators (as given by i_atattr) */
+ int i_atunit; /* unit from "at" */
+ int i_cfflags; /* flags from config line */
+ int i_lineno; /* line # in config, for later errors */
+
+ /* created during packing or ioconf.c generation */
+/* i_loclen via i_atattr->a_loclen */
+ short i_collapsed; /* set => this alias no longer needed */
+ short i_cfindex; /* our index in cfdata */
+ short i_pvlen; /* number of parents */
+ short i_pvoff; /* offset in parents.vec */
+ short i_locoff; /* offset in locators.vec */
+ short i_ivoff; /* offset in interrupt vectors, if any */
+ struct devi **i_parents;/* the parents themselves */
+
+};
+/* special units */
+#define STAR (-1) /* unit number for, e.g., "sd*" */
+#define WILD (-2) /* unit number for, e.g., "sd?" */
+
+/*
+ * Files. Each file is either standard (always included) or optional,
+ * depending on whether it has names on which to *be* optional.
+ */
+struct files {
+ struct files *fi_next; /* linked list */
+ const char *fi_srcfile; /* the name of the "files" file that got us */
+ u_short fi_srcline; /* and the line number */
+ u_char fi_flags; /* as below */
+ char fi_lastc; /* last char from path */
+ const char *fi_path; /* full file path */
+ const char *fi_tail; /* name, i.e., rindex(fi_path, '/') + 1 */
+ const char *fi_base; /* tail minus ".c" (or whatever) */
+ struct nvlist *fi_opt; /* optional on ... */
+ const char *fi_mkrule; /* special make rule, if any */
+};
+
+/* flags */
+#define FI_SEL 0x01 /* selected */
+#define FI_CONFIGDEP 0x02 /* config-dependent */
+#define FI_DRIVER 0x04 /* device-driver */
+#define FI_NEEDSCOUNT 0x08 /* needs-count */
+#define FI_NEEDSFLAG 0x10 /* needs-flag */
+#define FI_HIDDEN 0x20 /* obscured by other(s), base names overlap */
+
+/*
+ * Hash tables look up name=value pairs. The pointer value of the name
+ * is assumed to be constant forever; this can be arranged by interning
+ * the name. (This is fairly convenient since our lexer does this for
+ * all identifier-like strings---it has to save them anyway, lest yacc's
+ * look-ahead wipe out the current one.)
+ */
+struct hashtab;
+
+const char *conffile; /* source file, e.g., "GENERIC.sparc" */
+const char *confdirbase; /* basename of compile directory, usu. same */
+const char *machine; /* machine type, e.g., "sparc" or "sun3" */
+const char *machinearch; /* machine arch, e.g., "sparc" or "m68k" */
+int errors; /* counts calls to error() */
+int minmaxusers; /* minimum "maxusers" parameter */
+int defmaxusers; /* default "maxusers" parameter */
+int maxmaxusers; /* default "maxusers" parameter */
+int maxusers; /* configuration's "maxusers" parameter */
+int maxpartitions; /* configuration's "maxpartitions" parameter */
+struct nvlist *options; /* options */
+struct nvlist *mkoptions; /* makeoptions */
+struct hashtab *devbasetab; /* devbase lookup */
+struct hashtab *selecttab; /* selects things that are "optional foo" */
+struct hashtab *needcnttab; /* retains names marked "needs-count" */
+
+struct devbase *allbases; /* list of all devbase structures */
+struct config *allcf; /* list of configured kernels */
+struct devi *alldevi; /* list of all instances */
+struct devi *allpseudo; /* list of all pseudo-devices */
+int ndevi; /* number of devi's (before packing) */
+int npseudo; /* number of pseudo's */
+
+struct files *allfiles; /* list of all kernel source files */
+
+struct devi **packed; /* arrayified table for packed devi's */
+int npacked; /* size of packed table, <= ndevi */
+
+struct { /* pv[] table for config */
+ short *vec;
+ int used;
+} parents;
+struct { /* loc[] table for config */
+ const char **vec;
+ int used;
+} locators;
+
+/* files.c */
+void initfiles __P((void));
+void checkfiles __P((void));
+int fixfiles __P((void)); /* finalize */
+void addfile __P((const char *, struct nvlist *, int, const char *));
+
+/* hash.c */
+struct hashtab *ht_new __P((void));
+int ht_insrep __P((struct hashtab *, const char *, void *, int));
+#define ht_insert(ht, nam, val) ht_insrep(ht, nam, val, 0)
+#define ht_replace(ht, nam, val) ht_insrep(ht, nam, val, 1)
+void *ht_lookup __P((struct hashtab *, const char *));
+void initintern __P((void));
+const char *intern __P((const char *));
+
+/* main.c */
+void addoption __P((const char *name, const char *value));
+void addmkoption __P((const char *name, const char *value));
+
+/* mkheaders.c */
+int mkheaders __P((void));
+
+/* mkioconf.c */
+int mkioconf __P((void));
+
+/* mkmakefile.c */
+int mkmakefile __P((void));
+
+/* mkswap.c */
+int mkswap __P((void));
+
+/* pack.c */
+void pack __P((void));
+
+/* scan.l */
+int currentline __P((void));
+
+/* sem.c, other than for yacc actions */
+void initsem __P((void));
+
+/* util.c */
+void *emalloc __P((size_t));
+void *erealloc __P((void *, size_t));
+char *path __P((const char *));
+void error __P((const char *, ...)); /* immediate errs */
+void xerror __P((const char *, int, const char *, ...)); /* delayed errs */
+__dead void panic __P((const char *, ...));
+struct nvlist *newnv __P((const char *, const char *, void *, int));
+void nvfree __P((struct nvlist *));
+void nvfreel __P((struct nvlist *));
diff --git a/usr.sbin/config/files.c b/usr.sbin/config/files.c
new file mode 100644
index 00000000000..fbadd79760c
--- /dev/null
+++ b/usr.sbin/config/files.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)files.c 8.1 (Berkeley) 6/6/93
+ * $Id: files.c,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+extern const char *yyfile;
+
+/*
+ * We check that each full path name is unique. File base names
+ * should generally also be unique, e.g., having both a net/xx.c and
+ * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
+ * wrong, but is permitted under some conditions.
+ */
+static struct hashtab *basetab; /* file base names */
+static struct hashtab *pathtab; /* full path names */
+
+static struct files **nextfile;
+static struct files **unchecked;
+
+void
+initfiles()
+{
+
+ basetab = ht_new();
+ pathtab = ht_new();
+ nextfile = &allfiles;
+ unchecked = &allfiles;
+}
+
+static void
+showprev(pref, fi)
+ const char *pref;
+ register struct files *fi;
+{
+
+ xerror(fi->fi_srcfile, fi->fi_srcline,
+ "%sfile %s ...", pref, fi->fi_path);
+ errors--;
+}
+
+void
+addfile(path, opts, flags, rule)
+ const char *path;
+ struct nvlist *opts;
+ int flags;
+ const char *rule;
+{
+ struct files *fi;
+ const char *base, *dotp, *tail;
+ size_t baselen;
+ int needc, needf;
+ char buf[200];
+
+ /* check various errors */
+ needc = flags & FI_NEEDSCOUNT;
+ needf = flags & FI_NEEDSFLAG;
+ if (needc && needf) {
+ error("cannot mix needs-count and needs-flag");
+ goto bad;
+ }
+ if (opts == NULL && (needc || needf)) {
+ error("nothing to %s for %s", needc ? "count" : "flag", path);
+ goto bad;
+ }
+ if ((fi = ht_lookup(pathtab, path)) != NULL) {
+ showprev("", fi);
+ error("file %s listed again", path);
+ goto bad;
+ }
+
+ /* find last part of pathname, and same without trailing suffix */
+ tail = rindex(path, '/');
+ if (tail == NULL)
+ tail = path;
+ else
+ tail++;
+ dotp = rindex(tail, '.');
+ if (dotp == NULL || dotp[1] == 0 ||
+ (baselen = dotp - tail) >= sizeof(buf)) {
+ error("invalid pathname `%s'", path);
+ goto bad;
+ }
+
+ /*
+ * Make a copy of the path without the .c/.s/whatever suffix.
+ * This must be unique per "files" file (e.g., a specific
+ * file can override a standard file, but no standard file
+ * can override another standard file). This is not perfect
+ * but should catch any major errors.
+ */
+ bcopy(tail, buf, baselen);
+ buf[baselen] = 0;
+ base = intern(buf);
+ if ((fi = ht_lookup(basetab, base)) != NULL) {
+ if (fi->fi_srcfile != yyfile) {
+ showprev("note: ", fi);
+ error("is overriden by %s", path);
+ errors--; /* take it away */
+ fi->fi_flags |= FI_HIDDEN;
+ } else {
+ showprev("", fi);
+ error("collides with %s (both make %s.o)",
+ path, base);
+ goto bad;
+ }
+ }
+
+ /*
+ * Commit this file to memory.
+ */
+ fi = emalloc(sizeof *fi);
+ fi->fi_next = NULL;
+ fi->fi_srcfile = yyfile;
+ fi->fi_srcline = currentline();
+ fi->fi_flags = flags;
+ fi->fi_lastc = dotp[strlen(dotp) - 1];
+ fi->fi_path = path;
+ fi->fi_tail = tail;
+ fi->fi_base = base;
+ fi->fi_opt = opts;
+ fi->fi_mkrule = rule;
+ if (ht_insert(pathtab, path, fi))
+ panic("addfile: ht_insert(%s)", path);
+ (void)ht_replace(basetab, base, fi);
+ *nextfile = fi;
+ nextfile = &fi->fi_next;
+ return;
+bad:
+ nvfreel(opts);
+}
+
+/*
+ * We have finished reading some "files" file, either ../../conf/files
+ * or ./files.$machine. Make sure that everything that is flagged as
+ * needing a count is reasonable. (This prevents ../../conf/files from
+ * depending on some machine-specific device.)
+ */
+void
+checkfiles()
+{
+ register struct files *fi, *last;
+ register struct nvlist *nv;
+
+ last = NULL;
+ for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) {
+ if ((fi->fi_flags & FI_NEEDSCOUNT) == 0)
+ continue;
+ for (nv = fi->fi_opt; nv != NULL; nv = nv->nv_next)
+ if (ht_lookup(devbasetab, nv->nv_name) == NULL) {
+ xerror(fi->fi_srcfile, fi->fi_srcline,
+ "`%s' is not a countable device",
+ nv->nv_name);
+ /* keep fixfiles() from complaining again */
+ fi->fi_flags |= FI_HIDDEN;
+ }
+ }
+ if (last != NULL)
+ unchecked = &last->fi_next;
+}
+
+/*
+ * We have finished reading everything. Tack the files down: calculate
+ * selection and counts as needed.
+ */
+int
+fixfiles()
+{
+ register struct files *fi;
+ register struct nvlist *nv;
+ register struct devbase *dev;
+ int sel, err;
+
+ err = 0;
+ for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
+ if (fi->fi_flags & FI_HIDDEN)
+ continue;
+ if ((nv = fi->fi_opt) == NULL) { /* standard */
+ fi->fi_flags |= FI_SEL;
+ continue;
+ }
+ /* figure out whether it is selected */
+ sel = 0;
+ if (fi->fi_flags & FI_NEEDSCOUNT) {
+ /* ... and compute counts too */
+ do {
+ dev = ht_lookup(devbasetab, nv->nv_name);
+ if (dev == NULL) {
+ xerror(fi->fi_srcfile, fi->fi_srcline,
+ "`%s' is not a countable device",
+ nv->nv_name);
+ err = 1;
+ } else {
+ if (dev->d_umax)
+ sel = 1;
+ nv->nv_int = dev->d_umax;
+ (void)ht_insert(needcnttab,
+ nv->nv_name, nv);
+ }
+ } while ((nv = nv->nv_next) != NULL);
+ } else {
+ do {
+ if (ht_lookup(selecttab, nv->nv_name)) {
+ sel = 1;
+ break;
+ }
+ } while ((nv = nv->nv_next) != NULL);
+ if (fi->fi_flags & FI_NEEDSFLAG)
+ for (nv = fi->fi_opt; nv; nv = nv->nv_next)
+ nv->nv_int = sel;
+ }
+ /* if selected, we are go */
+ if (sel)
+ fi->fi_flags |= FI_SEL;
+ }
+ return (err);
+}
diff --git a/usr.sbin/config/gram.y b/usr.sbin/config/gram.y
new file mode 100644
index 00000000000..d7d030b53ad
--- /dev/null
+++ b/usr.sbin/config/gram.y
@@ -0,0 +1,421 @@
+%{
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)gram.y 8.1 (Berkeley) 6/6/93
+ * $Id: gram.y,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "sem.h"
+
+#define FORMAT(n) ((n) > -10 && (n) < 10 ? "%d" : "0x%x")
+
+#define stop(s) error(s), exit(1)
+
+int include __P((const char *, int));
+void yyerror __P((const char *));
+int yylex __P((void));
+extern const char *lastfile;
+
+static struct config conf; /* at most one active at a time */
+
+/* the following is used to recover nvlist space after errors */
+static struct nvlist *alloc[1000];
+static int adepth;
+#define new0(n,s,p,i) (alloc[adepth++] = newnv(n, s, p, i))
+#define new_n(n) new0(n, NULL, NULL, 0)
+#define new_ns(n, s) new0(n, s, NULL, 0)
+#define new_si(s, i) new0(NULL, s, NULL, i)
+#define new_nsi(n,s,i) new0(n, s, NULL, i)
+#define new_np(n, p) new0(n, NULL, p, 0)
+#define new_s(s) new0(NULL, s, NULL, 0)
+#define new_p(p) new0(NULL, NULL, p, 0)
+
+static void cleanup __P((void));
+static void setmachine __P((const char *, const char *));
+static void setmaxpartitions __P((int));
+
+%}
+
+%union {
+ struct attr *attr;
+ struct devbase *devb;
+ struct nvlist *list;
+ const char *str;
+ int val;
+}
+
+%token AND AT COMPILE_WITH CONFIG DEFINE DEVICE DUMPS ENDFILE
+%token XFILE FLAGS INCLUDE XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS
+%token MINOR ON OPTIONS PSEUDO_DEVICE ROOT SWAP VECTOR
+%token <val> FFLAG NUMBER
+%token <str> PATHNAME WORD
+
+%type <list> fopts
+%type <val> fflgs
+%type <str> rule
+%type <attr> attr
+%type <devb> devbase
+%type <list> atlist interface_opt
+%type <str> atname
+%type <list> loclist_opt loclist locdef
+%type <str> locdefault
+%type <list> veclist_opt veclist
+%type <list> attrs_opt attrs
+%type <list> locators locator
+%type <list> swapdev_list dev_spec
+%type <str> device_instance
+%type <str> attachment
+%type <str> value
+%type <val> major_minor signed_number npseudo
+%type <val> flags_opt
+
+%%
+
+/*
+ * A configuration consists of a machine type, followed by the machine
+ * definition files (via the include() mechanism), followed by the
+ * configuration specification(s) proper. In effect, this is two
+ * separate grammars, with some shared terminals and nonterminals.
+ */
+Configuration:
+ hdrs machine_spec /* "machine foo" from machine descr. */
+ dev_defs dev_eof /* ../../conf/devices */
+ dev_defs dev_eof /* devices.foo */
+ maxpart_spec dev_defs dev_eof /* ../../conf/devices */
+ specs; /* rest of machine description */
+
+hdrs:
+ hdrs hdr |
+ /* empty */;
+
+hdr:
+ include |
+ '\n';
+
+machine_spec:
+ XMACHINE WORD = { setmachine($2,NULL); } |
+ XMACHINE WORD WORD = { setmachine($2,$3); } |
+ error = { stop("cannot proceed without machine specifier"); };
+
+dev_eof:
+ ENDFILE = { enddefs(lastfile); checkfiles(); };
+
+maxpart_blanks:
+ maxpart_blanks '\n' |
+ /* empty */;
+
+maxpart_spec:
+ maxpart_blanks MAXPARTITIONS NUMBER = { setmaxpartitions($3); } |
+ error = { stop("cannot proceed without maxpartitions specifier"); };
+
+/*
+ * Various nonterminals shared between the grammars.
+ */
+file:
+ XFILE PATHNAME fopts fflgs rule = { addfile($2, $3, $4, $5); };
+
+/* order of options is important, must use right recursion */
+fopts:
+ WORD fopts = { ($$ = new_n($1))->nv_next = $2; } |
+ /* empty */ = { $$ = NULL; };
+
+fflgs:
+ fflgs FFLAG = { $$ = $1 | $2; } |
+ /* empty */ = { $$ = 0; };
+
+rule:
+ COMPILE_WITH WORD = { $$ = $2; } |
+ /* empty */ = { $$ = NULL; };
+
+include:
+ INCLUDE WORD = { (void)include($2, '\n'); };
+
+/*
+ * The machine definitions grammar.
+ */
+dev_defs:
+ dev_defs dev_def |
+ /* empty */;
+
+dev_def:
+ one_def '\n' = { adepth = 0; } |
+ '\n' |
+ error '\n' = { cleanup(); };
+
+one_def:
+ file |
+ include |
+ DEFINE WORD interface_opt = { (void)defattr($2, $3); } |
+ DEVICE devbase AT atlist veclist_opt interface_opt attrs_opt
+ = { defdev($2, 0, $4, $5, $6, $7); } |
+ MAXUSERS NUMBER NUMBER NUMBER = { setdefmaxusers($2, $3, $4); } |
+ PSEUDO_DEVICE devbase attrs_opt = { defdev($2,1,NULL,NULL,NULL,$3); } |
+ MAJOR '{' majorlist '}';
+
+atlist:
+ atlist ',' atname = { ($$ = new_n($3))->nv_next = $1; } |
+ atname = { $$ = new_n($1); };
+
+atname:
+ WORD = { $$ = $1; } |
+ ROOT = { $$ = NULL; };
+
+veclist_opt:
+ VECTOR veclist = { $$ = $2; } |
+ /* empty */ = { $$ = NULL; };
+
+/* veclist order matters, must use right recursion */
+veclist:
+ WORD veclist = { ($$ = new_n($1))->nv_next = $2; } |
+ WORD = { $$ = new_n($1); };
+
+devbase:
+ WORD = { $$ = getdevbase($1); };
+
+interface_opt:
+ '{' loclist_opt '}' = { ($$ = new_n(""))->nv_next = $2; } |
+ /* empty */ = { $$ = NULL; };
+
+loclist_opt:
+ loclist = { $$ = $1; } |
+ /* empty */ = { $$ = NULL; };
+
+/* loclist order matters, must use right recursion */
+loclist:
+ locdef ',' loclist = { ($$ = $1)->nv_next = $3; } |
+ locdef = { $$ = $1; };
+
+/* "[ WORD locdefault ]" syntax may be unnecessary... */
+locdef:
+ WORD locdefault = { $$ = new_nsi($1, $2, 0); } |
+ WORD = { $$ = new_nsi($1, NULL, 0); } |
+ '[' WORD locdefault ']' = { $$ = new_nsi($2, $3, 1); };
+
+locdefault:
+ '=' value = { $$ = $2; };
+
+value:
+ WORD = { $$ = $1; } |
+ signed_number = { char bf[40];
+ (void)sprintf(bf, FORMAT($1), $1);
+ $$ = intern(bf); };
+
+signed_number:
+ NUMBER = { $$ = $1; } |
+ '-' NUMBER = { $$ = -$2; };
+
+attrs_opt:
+ ':' attrs = { $$ = $2; } |
+ /* empty */ = { $$ = NULL; };
+
+attrs:
+ attrs ',' attr = { ($$ = new_p($3))->nv_next = $1; } |
+ attr = { $$ = new_p($1); };
+
+attr:
+ WORD = { $$ = getattr($1); };
+
+majorlist:
+ majorlist ',' majordef |
+ majordef;
+
+majordef:
+ devbase '=' NUMBER = { setmajor($1, $3); };
+
+
+
+/*
+ * The configuration grammar.
+ */
+specs:
+ specs spec |
+ /* empty */;
+
+spec:
+ config_spec '\n' = { adepth = 0; } |
+ '\n' |
+ error '\n' = { cleanup(); };
+
+config_spec:
+ file |
+ include |
+ OPTIONS opt_list |
+ MAKEOPTIONS mkopt_list |
+ MAXUSERS NUMBER = { setmaxusers($2); } |
+ CONFIG conf sysparam_list = { addconf(&conf); } |
+ PSEUDO_DEVICE WORD npseudo = { addpseudo($2, $3); } |
+ device_instance AT attachment locators flags_opt
+ = { adddev($1, $3, $4, $5); };
+
+mkopt_list:
+ mkopt_list ',' mkoption |
+ mkoption;
+
+mkoption:
+ WORD '=' value = { addmkoption($1, $3); }
+
+opt_list:
+ opt_list ',' option |
+ option;
+
+option:
+ WORD = { addoption($1, NULL); } |
+ WORD '=' value = { addoption($1, $3); };
+
+conf:
+ WORD = { conf.cf_name = $1;
+ conf.cf_lineno = currentline();
+ conf.cf_root = NULL;
+ conf.cf_swap = NULL;
+ conf.cf_dump = NULL; };
+
+sysparam_list:
+ sysparam_list sysparam |
+ sysparam;
+
+sysparam:
+ ROOT on_opt dev_spec = { setconf(&conf.cf_root, "root", $3); } |
+ SWAP on_opt swapdev_list = { setconf(&conf.cf_swap, "swap", $3); } |
+ DUMPS on_opt dev_spec = { setconf(&conf.cf_dump, "dumps", $3); };
+
+swapdev_list:
+ dev_spec AND swapdev_list = { ($$ = $1)->nv_next = $3; } |
+ dev_spec = { $$ = $1; };
+
+dev_spec:
+ WORD = { $$ = new_si($1, NODEV); } |
+ major_minor = { $$ = new_si(NULL, $1); };
+
+major_minor:
+ MAJOR NUMBER MINOR NUMBER = { $$ = makedev($2, $4); };
+
+on_opt:
+ ON | /* empty */;
+
+npseudo:
+ NUMBER = { $$ = $1; } |
+ /* empty */ = { $$ = 1; };
+
+device_instance:
+ WORD '*' = { $$ = starref($1); } |
+ WORD = { $$ = $1; };
+
+attachment:
+ ROOT = { $$ = NULL; } |
+ WORD '?' = { $$ = wildref($1); } |
+ WORD '*' = { $$ = starref($1); } |
+ WORD = { $$ = $1; };
+
+locators:
+ locators locator = { ($$ = $2)->nv_next = $1; } |
+ /* empty */ = { $$ = NULL; };
+
+locator:
+ WORD value = { $$ = new_ns($1, $2); } |
+ WORD '?' = { $$ = new_ns($1, NULL); };
+
+flags_opt:
+ FLAGS NUMBER = { $$ = $2; } |
+ /* empty */ = { $$ = 0; };
+
+%%
+
+void
+yyerror(s)
+ const char *s;
+{
+
+ error("%s", s);
+}
+
+/*
+ * Cleanup procedure after syntax error: release any nvlists
+ * allocated during parsing the current line.
+ */
+static void
+cleanup()
+{
+ register struct nvlist **np;
+ register int i;
+
+ for (np = alloc, i = adepth; --i >= 0; np++)
+ nvfree(*np);
+ adepth = 0;
+}
+
+static void
+setmachine(mch, mcharch)
+ const char *mch;
+ const char *mcharch;
+{
+ char buf[MAXPATHLEN], archbuf[MAXPATHLEN];
+
+ machine = mch;
+ machinearch = mcharch;
+ if (machinearch != NULL)
+ (void)sprintf(archbuf, "../../%s/conf/files.%s",
+ machinearch, machinearch);
+ else
+ strncpy(archbuf, _PATH_DEVNULL, MAXPATHLEN);
+ (void)sprintf(buf, "files.%s", machine);
+
+ if (include(buf, ENDFILE) ||
+ include(archbuf, ENDFILE) ||
+ include("../../../conf/files", ENDFILE))
+ exit(1);
+}
+
+static void
+setmaxpartitions(n)
+ int n;
+{
+
+ maxpartitions = n;
+}
diff --git a/usr.sbin/config/hash.c b/usr.sbin/config/hash.c
new file mode 100644
index 00000000000..86df34a776b
--- /dev/null
+++ b/usr.sbin/config/hash.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)hash.c 8.1 (Berkeley) 6/6/93
+ * $Id: hash.c,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+/*
+ * Interned strings are kept in a hash table. By making each string
+ * unique, the program can compare strings by comparing pointers.
+ */
+struct hashent {
+ struct hashent *h_next; /* hash buckets are chained */
+ const char *h_name; /* the string */
+ u_int h_hash; /* its hash value */
+ void *h_value; /* other values (for name=value) */
+};
+struct hashtab {
+ size_t ht_size; /* size (power of 2) */
+ u_int ht_mask; /* == ht_size - 1 */
+ u_int ht_used; /* number of entries used */
+ u_int ht_lim; /* when to expand */
+ struct hashent **ht_tab; /* base of table */
+};
+static struct hashtab strings;
+
+/*
+ * HASHFRACTION controls ht_lim, which in turn controls the average chain
+ * length. We allow a few entries, on average, as comparing them is usually
+ * cheap (the h_hash values prevent a strcmp).
+ */
+#define HASHFRACTION(sz) ((sz) * 3 / 2)
+
+/* round up to next multiple of y, where y is a power of 2 */
+#define ROUND(x, y) (((x) + (y) - 1) & ~((y) - 1))
+
+/*
+ * Allocate space that will never be freed.
+ */
+static void *
+poolalloc(size)
+ size_t size;
+{
+ register char *p;
+ register size_t alloc;
+ static char *pool;
+ static size_t nleft;
+
+ if (nleft < size) {
+ /*
+ * Compute a `good' size to allocate via malloc.
+ * 16384 is a guess at a good page size for malloc;
+ * 32 is a guess at malloc's overhead.
+ */
+ alloc = ROUND(size + 32, 16384) - 32;
+ p = emalloc(alloc);
+ nleft = alloc - size;
+ } else {
+ p = pool;
+ nleft -= size;
+ }
+ pool = p + size;
+ return (p);
+}
+
+/*
+ * Initialize a new hash table. The size must be a power of 2.
+ */
+static void
+ht_init(ht, sz)
+ register struct hashtab *ht;
+ size_t sz;
+{
+ register struct hashent **h;
+ register u_int n;
+
+ h = emalloc(sz * sizeof *h);
+ ht->ht_tab = h;
+ ht->ht_size = sz;
+ ht->ht_mask = sz - 1;
+ for (n = 0; n < sz; n++)
+ *h++ = NULL;
+ ht->ht_used = 0;
+ ht->ht_lim = HASHFRACTION(sz);
+}
+
+/*
+ * Expand an existing hash table.
+ */
+static void
+ht_expand(ht)
+ register struct hashtab *ht;
+{
+ register struct hashent *p, **h, **oldh, *q;
+ register u_int n, i;
+
+ n = ht->ht_size * 2;
+ h = emalloc(n * sizeof *h);
+ for (i = 0; i < n; i++)
+ h[i] = NULL;
+ oldh = ht->ht_tab;
+ n--;
+ for (i = ht->ht_size; i != 0; i--) {
+ for (p = *oldh++; p != NULL; p = q) {
+ q = p->h_next;
+ p->h_next = h[p->h_hash & n];
+ h[p->h_hash & n] = p;
+ }
+ }
+ free(ht->ht_tab);
+ ht->ht_tab = h;
+ ht->ht_mask = n;
+ ht->ht_size = ++n;
+ ht->ht_lim = HASHFRACTION(n);
+}
+
+/*
+ * Make a new hash entry, setting its h_next to NULL.
+ */
+static inline struct hashent *
+newhashent(name, h)
+ const char *name;
+ u_int h;
+{
+ register struct hashent *hp;
+ register char *m;
+
+ m = poolalloc(sizeof(*hp) + ALIGNBYTES);
+ hp = (struct hashent *)ALIGN(m);
+ hp->h_name = name;
+ hp->h_hash = h;
+ hp->h_next = NULL;
+ return (hp);
+}
+
+/*
+ * Hash a string.
+ */
+static inline u_int
+hash(str)
+ register const char *str;
+{
+ register u_int h;
+
+ for (h = 0; *str;)
+ h = (h << 5) + h + *str++;
+ return (h);
+}
+
+void
+initintern()
+{
+
+ ht_init(&strings, 128);
+}
+
+/*
+ * Generate a single unique copy of the given string. We expect this
+ * function to be used frequently, so it should be fast.
+ */
+const char *
+intern(s)
+ register const char *s;
+{
+ register struct hashtab *ht;
+ register struct hashent *hp, **hpp;
+ register u_int h;
+ register char *p;
+ register size_t l;
+
+ ht = &strings;
+ h = hash(s);
+ hpp = &ht->ht_tab[h & ht->ht_mask];
+ for (; (hp = *hpp) != NULL; hpp = &hp->h_next)
+ if (hp->h_hash == h && strcmp(hp->h_name, s) == 0)
+ return (hp->h_name);
+ l = strlen(s) + 1;
+ p = poolalloc(l);
+ bcopy(s, p, l);
+ *hpp = newhashent(p, h);
+ if (++ht->ht_used > ht->ht_lim)
+ ht_expand(ht);
+ return (p);
+}
+
+struct hashtab *
+ht_new()
+{
+ register struct hashtab *ht;
+
+ ht = emalloc(sizeof *ht);
+ ht_init(ht, 8);
+ return (ht);
+}
+
+/*
+ * Insert and/or replace.
+ */
+int
+ht_insrep(ht, nam, val, replace)
+ register struct hashtab *ht;
+ register const char *nam;
+ void *val;
+ int replace;
+{
+ register struct hashent *hp, **hpp;
+ register u_int h;
+
+ h = hash(nam);
+ hpp = &ht->ht_tab[h & ht->ht_mask];
+ for (; (hp = *hpp) != NULL; hpp = &hp->h_next) {
+ if (hp->h_name == nam) {
+ if (replace)
+ hp->h_value = val;
+ return (1);
+ }
+ }
+ *hpp = hp = newhashent(nam, h);
+ hp->h_value = val;
+ return (0);
+}
+
+void *
+ht_lookup(ht, nam)
+ register struct hashtab *ht;
+ register const char *nam;
+{
+ register struct hashent *hp, **hpp;
+ register u_int h;
+
+ h = hash(nam);
+ hpp = &ht->ht_tab[h & ht->ht_mask];
+ for (; (hp = *hpp) != NULL; hpp = &hp->h_next)
+ if (hp->h_name == nam)
+ return (hp->h_value);
+ return (NULL);
+}
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c
new file mode 100644
index 00000000000..f457fd8edcc
--- /dev/null
+++ b/usr.sbin/config/main.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)main.c 8.1 (Berkeley) 6/6/93
+ * $Id: main.c,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "config.h"
+
+int firstfile __P((const char *));
+int yyparse __P((void));
+
+extern char *optarg;
+extern int optind;
+
+static struct hashtab *opttab;
+static struct hashtab *mkopttab;
+static struct nvlist **nextopt;
+static struct nvlist **nextmkopt;
+
+static __dead void stop __P((void));
+static int do_option __P((struct hashtab *, struct nvlist ***,
+ const char *, const char *, const char *));
+static int crosscheck __P((void));
+static int badstar __P((void));
+static int mksymlinks __P((void));
+static int has_instances __P((struct devbase *, int));
+static int hasparent __P((struct devi *));
+static int cfcrosscheck __P((struct config *, const char *, struct nvlist *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register char *p;
+ int pflag, ch;
+ struct stat st;
+
+ pflag = 0;
+ while ((ch = getopt(argc, argv, "gp")) != EOF) {
+ switch (ch) {
+
+ case 'g':
+ /*
+ * In addition to DEBUG, you probably wanted to
+ * set "options KGDB" and maybe others. We could
+ * do that for you, but you really should just
+ * put them in the config file.
+ */
+ (void)fputs(
+ "-g is obsolete (use makeoptions DEBUG=\"-g\")\n",
+ stderr);
+ goto usage;
+
+ case 'p':
+ /*
+ * Essentially the same as makeoptions PROF="-pg",
+ * but also changes the path from ../../compile/FOO
+ * to ../../compile/FOO.prof; i.e., compile a
+ * profiling kernel based on a typical "regular"
+ * kernel.
+ *
+ * Note that if you always want profiling, you
+ * can (and should) use a "makeoptions" line.
+ */
+ pflag = 1;
+ break;
+
+ case '?':
+ default:
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
+usage:
+ (void)fputs("usage: config [-p] sysname\n", stderr);
+ exit(1);
+ }
+ conffile = argv[0];
+ if (firstfile(conffile)) {
+ (void)fprintf(stderr, "config: cannot read %s: %s\n",
+ conffile, strerror(errno));
+ exit(2);
+ }
+
+ /*
+ * Init variables.
+ */
+ minmaxusers = 1;
+ maxmaxusers = 10000;
+ initintern();
+ initfiles();
+ initsem();
+ devbasetab = ht_new();
+ selecttab = ht_new();
+ needcnttab = ht_new();
+ opttab = ht_new();
+ mkopttab = ht_new();
+ nextopt = &options;
+ nextmkopt = &mkoptions;
+
+ /*
+ * Handle profiling (must do this before we try to create any
+ * files).
+ */
+ if (pflag) {
+ char *s;
+
+ s = emalloc(strlen(conffile) + sizeof(".PROF"));
+ (void)sprintf(s, "%s.PROF", conffile);
+ confdirbase = s;
+ (void)addmkoption(intern("PROF"), "-pg");
+ (void)addoption(intern("GPROF"), NULL);
+ } else
+ confdirbase = conffile;
+
+ /*
+ * Verify, creating if necessary, the compilation directory.
+ */
+ p = path(NULL);
+ if (stat(p, &st)) {
+ if (mkdir(p, 0777)) {
+ (void)fprintf(stderr, "config: cannot create %s: %s\n",
+ p, strerror(errno));
+ exit(2);
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ (void)fprintf(stderr, "config: %s is not a directory\n", p);
+ exit(2);
+ }
+
+ /*
+ * Parse config file (including machine definitions).
+ */
+ if (yyparse())
+ stop();
+
+ /*
+ * Fix (as in `set firmly in place') files.
+ */
+ if (fixfiles())
+ stop();
+
+ /*
+ * Perform cross-checking.
+ */
+ if (maxusers == 0) {
+ if (defmaxusers) {
+ (void)printf("maxusers not specified; %d assumed\n",
+ defmaxusers);
+ maxusers = defmaxusers;
+ } else {
+ (void)fprintf(stderr,
+ "config: need \"maxusers\" line\n");
+ errors++;
+ }
+ }
+ if (crosscheck() || errors)
+ stop();
+
+ /*
+ * Squeeze things down and finish cross-checks (STAR checks must
+ * run after packing).
+ */
+ pack();
+ if (badstar())
+ stop();
+
+ /*
+ * Ready to go. Build all the various files.
+ */
+ if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
+ mkioconf())
+ stop();
+ (void)printf("Don't forget to run \"make depend\"\n");
+ exit(0);
+}
+
+/*
+ * Make a symlink for "machine" so that "#include <machine/foo.h>" works,
+ * and for the machine's CPU architecture, so that works as well.
+ */
+static int
+mksymlinks()
+{
+ int ret;
+ char *p, buf[200];
+
+ p = path("machine");
+ (void)sprintf(buf, "../../include", machine);
+ (void)unlink(p);
+ ret = symlink(buf, p);
+ if (ret)
+ (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
+ p, buf, strerror(errno));
+ free(p);
+
+ if (machinearch != NULL) {
+ p = path(machinearch);
+ (void)sprintf(buf, "../../../%s/include", machinearch);
+ } else {
+ p = path(machine);
+ (void)sprintf(buf, "machine");
+ }
+ (void)unlink(p);
+ ret = symlink(buf, p);
+ if (ret)
+ (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
+ p, buf, strerror(errno));
+ free(p);
+
+ return (ret);
+}
+
+static __dead void
+stop()
+{
+ (void)fprintf(stderr, "*** Stop.\n");
+ exit(1);
+}
+
+/*
+ * Add an option from "options FOO". Note that this selects things that
+ * are "optional foo".
+ */
+void
+addoption(name, value)
+ const char *name, *value;
+{
+ register const char *n;
+ register char *p, c;
+ char low[500];
+
+ if (do_option(opttab, &nextopt, name, value, "options"))
+ return;
+
+ /* make lowercase, then add to select table */
+ for (n = name, p = low; (c = *n) != '\0'; n++)
+ *p++ = isupper(c) ? tolower(c) : c;
+ *p = 0;
+ n = intern(low);
+ (void)ht_insert(selecttab, n, (void *)n);
+}
+
+/*
+ * Add a "make" option.
+ */
+void
+addmkoption(name, value)
+ const char *name, *value;
+{
+
+ (void)do_option(mkopttab, &nextmkopt, name, value, "mkoptions");
+}
+
+/*
+ * Add a name=value pair to an option list. The value may be NULL.
+ */
+static int
+do_option(ht, nppp, name, value, type)
+ struct hashtab *ht;
+ struct nvlist ***nppp;
+ const char *name, *value, *type;
+{
+ register struct nvlist *nv;
+
+ /* assume it will work */
+ nv = newnv(name, value, NULL, 0);
+ if (ht_insert(ht, name, nv) == 0) {
+ **nppp = nv;
+ *nppp = &nv->nv_next;
+ return (0);
+ }
+
+ /* oops, already got that option */
+ nvfree(nv);
+ if ((nv = ht_lookup(ht, name)) == NULL)
+ panic("do_option");
+ if (nv->nv_str != NULL)
+ error("already have %s `%s=%s'", type, name, nv->nv_str);
+ else
+ error("already have %s `%s'", type, name);
+ return (1);
+}
+
+/*
+ * Return true if there is at least one instance of the given unit
+ * on the given base (or any units, if unit == WILD).
+ */
+static int
+has_instances(dev, unit)
+ register struct devbase *dev;
+ int unit;
+{
+ register struct devi *i;
+
+ if (unit == WILD)
+ return (dev->d_ihead != NULL);
+ for (i = dev->d_ihead; i != NULL; i = i->i_bsame)
+ if (unit == i->i_unit)
+ return (1);
+ return (0);
+}
+
+static int
+hasparent(i)
+ register struct devi *i;
+{
+ register struct nvlist *nv;
+ int atunit = i->i_atunit;
+
+ if (i->i_atdev != NULL && has_instances(i->i_atdev, atunit))
+ return (1);
+ if (i->i_atattr != NULL)
+ for (nv = i->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
+ if (has_instances(nv->nv_ptr, atunit))
+ return (1);
+ return (0);
+}
+
+static int
+cfcrosscheck(cf, what, nv)
+ register struct config *cf;
+ const char *what;
+ register struct nvlist *nv;
+{
+ register struct devbase *dev;
+ register struct devi *pd;
+ int errs;
+
+ for (errs = 0; nv != NULL; nv = nv->nv_next) {
+ if (nv->nv_name == NULL)
+ continue;
+ dev = ht_lookup(devbasetab, nv->nv_name);
+ if (dev == NULL)
+ panic("cfcrosscheck(%s)", nv->nv_name);
+ if (has_instances(dev, STAR) ||
+ has_instances(dev, minor(nv->nv_int) / maxpartitions))
+ continue;
+ for (pd = allpseudo; pd != NULL; pd = pd->i_next)
+ if (pd->i_base == dev &&
+ (minor(nv->nv_int) / maxpartitions) < dev->d_umax &&
+ (minor(nv->nv_int) / maxpartitions) >= 0)
+ goto loop;
+ (void)fprintf(stderr,
+ "%s%d: %s says %s on %s, but there's no %s\n",
+ conffile, cf->cf_lineno,
+ cf->cf_name, what, nv->nv_str, nv->nv_str);
+ errs++;
+loop:
+ }
+ return (errs);
+}
+
+/*
+ * Cross-check the configuration: make sure that each target device
+ * or attribute (`at foo[0*?]') names at least one real device. Also
+ * see that the root, swap, and dump devices for all configurations
+ * are there.
+ */
+int
+crosscheck()
+{
+ register struct devi *i;
+ register struct config *cf;
+ int errs;
+
+ errs = 0;
+ for (i = alldevi; i != NULL; i = i->i_next) {
+ if (i->i_at == NULL || hasparent(i))
+ continue;
+ xerror(conffile, i->i_lineno,
+ "%s at %s is orphaned", i->i_name, i->i_at);
+ if (i->i_atunit == WILD)
+ (void)fprintf(stderr, " (no %s's declared)\n",
+ i->i_base->d_name);
+ else
+ (void)fprintf(stderr, " (no %s declared)\n", i->i_at);
+ errs++;
+ }
+ if (allcf == NULL) {
+ (void)fprintf(stderr, "%s has no configurations!\n",
+ conffile);
+ errs++;
+ }
+ for (cf = allcf; cf != NULL; cf = cf->cf_next) {
+ if (cf->cf_root != NULL) { /* i.e., not swap generic */
+ errs += cfcrosscheck(cf, "root", cf->cf_root);
+ errs += cfcrosscheck(cf, "swap", cf->cf_swap);
+ errs += cfcrosscheck(cf, "dumps", cf->cf_dump);
+ }
+ }
+ return (errs);
+}
+
+/*
+ * Check to see if there is more than one *'d unit for any device,
+ * or a *'d unit with a needs-count file.
+ */
+int
+badstar()
+{
+ register struct devbase *d;
+ register struct devi *i;
+ register int errs, n;
+
+ errs = 0;
+ for (d = allbases; d != NULL; d = d->d_next) {
+ for (i = d->d_ihead; i != NULL; i = i->i_bsame)
+ if (i->i_unit == STAR)
+ goto foundstar;
+ continue;
+ foundstar:
+ if (ht_lookup(needcnttab, d->d_name)) {
+ (void)fprintf(stderr,
+ "config: %s's cannot be *'d until its driver is fixed\n",
+ d->d_name);
+ errs++;
+ continue;
+ }
+ for (n = 0; i != NULL; i = i->i_alias)
+ if (!i->i_collapsed)
+ n++;
+ if (n < 1)
+ panic("badstar() n<1");
+ if (n == 1)
+ continue;
+ (void)fprintf(stderr,
+ "config: %d %s*'s in configuration; can only have 1\n",
+ n, d->d_name);
+ errs++;
+ }
+ return (errs);
+}
diff --git a/usr.sbin/config/mkheaders.c b/usr.sbin/config/mkheaders.c
new file mode 100644
index 00000000000..12de3a7606f
--- /dev/null
+++ b/usr.sbin/config/mkheaders.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)mkheaders.c 8.1 (Berkeley) 6/6/93
+ * $Id: mkheaders.c,v 1.1.1.1 1995/10/18 08:48:33 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+static int emitcnt __P((struct nvlist *));
+static int err __P((const char *, char *, FILE *));
+static char *cntname __P((const char *));
+
+/*
+ * Make headers containing counts, as needed.
+ */
+int
+mkheaders()
+{
+ register struct files *fi;
+
+ for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
+ if (fi->fi_flags & FI_HIDDEN)
+ continue;
+ if (fi->fi_flags & (FI_NEEDSCOUNT | FI_NEEDSFLAG) &&
+ emitcnt(fi->fi_opt))
+ return (1);
+ }
+ return (0);
+}
+
+static int
+emitcnt(head)
+ register struct nvlist *head;
+{
+ register struct nvlist *nv;
+ register FILE *fp;
+ register char *fname;
+ int cnt;
+ char nam[100];
+ char buf[BUFSIZ];
+
+ (void)sprintf(buf, "%s.h", head->nv_name);
+ fname = path(buf);
+ if ((fp = fopen(fname, "r")) == NULL)
+ goto writeit;
+ nv = head;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (nv == NULL)
+ goto writeit;
+ if (sscanf(buf, "#define %s %d", nam, &cnt) != 2 ||
+ strcmp(nam, cntname(nv->nv_name)) != 0 ||
+ cnt != nv->nv_int)
+ goto writeit;
+ nv = nv->nv_next;
+ }
+ if (ferror(fp))
+ return (err("read", fname, fp));
+ (void)fclose(fp);
+ if (nv == NULL)
+ return (0);
+writeit:
+ if ((fp = fopen(fname, "w")) == NULL) {
+ (void)fprintf(stderr, "config: cannot write %s: %s\n",
+ fname, strerror(errno));
+ return (1);
+ }
+ for (nv = head; nv != NULL; nv = nv->nv_next)
+ if (fprintf(fp, "#define\t%s\t%d\n",
+ cntname(nv->nv_name), nv->nv_int) < 0)
+ return (err("writ", fname, fp));
+ if (fclose(fp))
+ return (err("writ", fname, NULL));
+ return (0);
+}
+
+static int
+err(what, fname, fp)
+ const char *what;
+ char *fname;
+ FILE *fp;
+{
+
+ (void)fprintf(stderr, "config: error %sing %s: %s\n",
+ what, fname, strerror(errno));
+ if (fp)
+ (void)fclose(fp);
+ free(fname);
+ return (1);
+}
+
+static char *
+cntname(src)
+ register const char *src;
+{
+ register char *dst, c;
+ static char buf[100];
+
+ dst = buf;
+ *dst++ = 'N';
+ while ((c = *src++) != 0)
+ *dst++ = islower(c) ? toupper(c) : c;
+ *dst = 0;
+ return (buf);
+}
diff --git a/usr.sbin/config/mkioconf.c b/usr.sbin/config/mkioconf.c
new file mode 100644
index 00000000000..593aa7892d8
--- /dev/null
+++ b/usr.sbin/config/mkioconf.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)mkioconf.c 8.1 (Berkeley) 6/6/93
+ * $Id: mkioconf.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+/*
+ * Make ioconf.c.
+ */
+static int cforder __P((const void *, const void *));
+static int emitcfdata __P((FILE *));
+static int emitexterns __P((FILE *));
+static int emithdr __P((FILE *));
+static int emitloc __P((FILE *));
+static int emitpseudo __P((FILE *));
+static int emitpv __P((FILE *));
+static int emitroots __P((FILE *));
+static int emitvec __P((FILE *));
+static char *vecname __P((char *, const char *, int));
+
+static const char *s_i386;
+
+#define SEP(pos, max) (((u_int)(pos) % (max)) == 0 ? "\n\t" : " ")
+
+/*
+ * NEWLINE can only be used in the emitXXX functions.
+ * In most cases it can be subsumed into an fprintf.
+ */
+#define NEWLINE if (putc('\n', fp) < 0) return (1)
+
+int
+mkioconf()
+{
+ register FILE *fp;
+ register char *fname;
+ int v;
+
+ s_i386 = intern("i386");
+
+ fname = path("ioconf.c");
+ qsort(packed, npacked, sizeof *packed, cforder);
+ if ((fp = fopen(fname, "w")) == NULL) {
+ (void)fprintf(stderr, "config: cannot write %s: %s\n",
+ fname, strerror(errno));
+ return (1);
+ }
+ v = emithdr(fp);
+ if (v != 0 || emitvec(fp) || emitexterns(fp) || emitloc(fp) ||
+ emitpv(fp) || emitcfdata(fp) || emitroots(fp) || emitpseudo(fp)) {
+ if (v >= 0)
+ (void)fprintf(stderr,
+ "config: error writing %s: %s\n",
+ fname, strerror(errno));
+ (void)fclose(fp);
+ /* (void)unlink(fname); */
+ free(fname);
+ return (1);
+ }
+ (void)fclose(fp);
+ free(fname);
+ return (0);
+}
+
+static int
+cforder(a, b)
+ const void *a, *b;
+{
+ register int n1, n2;
+
+ n1 = (*(struct devi **)a)->i_cfindex;
+ n2 = (*(struct devi **)b)->i_cfindex;
+ return (n1 - n2);
+}
+
+static int
+emithdr(ofp)
+ register FILE *ofp;
+{
+ register FILE *ifp;
+ register int n;
+ char ifn[200], buf[BUFSIZ];
+
+ if (fprintf(ofp, "\
+/*\n\
+ * MACHINE GENERATED: DO NOT EDIT\n\
+ *\n\
+ * ioconf.c, from \"%s\"\n\
+ */\n\n", conffile) < 0)
+ return (1);
+ (void)sprintf(ifn, "ioconf.incl.%s", machine);
+ if ((ifp = fopen(ifn, "r")) != NULL) {
+ while ((n = fread(buf, 1, sizeof(buf), ifp)) > 0)
+ if (fwrite(buf, 1, n, ofp) != n)
+ return (1);
+ if (ferror(ifp)) {
+ (void)fprintf(stderr, "config: error reading %s: %s\n",
+ ifn, strerror(errno));
+ (void)fclose(ifp);
+ return (-1);
+ }
+ (void)fclose(ifp);
+ } else {
+ if (fputs("\
+#include <sys/param.h>\n\
+#include <sys/device.h>\n", ofp) < 0)
+ return (1);
+ }
+ return (0);
+}
+
+static int
+emitexterns(fp)
+ register FILE *fp;
+{
+ register struct devbase *d;
+
+ NEWLINE;
+ for (d = allbases; d != NULL; d = d->d_next) {
+ if (d->d_ihead == NULL)
+ continue;
+ if (fprintf(fp, "extern struct cfdriver %scd;\n",
+ d->d_name) < 0)
+ return (1);
+ }
+ NEWLINE;
+ return (0);
+}
+
+static int
+emitloc(fp)
+ register FILE *fp;
+{
+ register int i;
+
+ if (fprintf(fp, "\n/* locators */\n\
+static int loc[%d] = {", locators.used) < 0)
+ return (1);
+ for (i = 0; i < locators.used; i++)
+ if (fprintf(fp, "%s%s,", SEP(i, 8), locators.vec[i]) < 0)
+ return (1);
+ return (fprintf(fp, "\n};\n") < 0);
+}
+
+/*
+ * Emit global parents-vector.
+ */
+static int
+emitpv(fp)
+ register FILE *fp;
+{
+ register int i;
+
+ if (fprintf(fp, "\n/* parent vectors */\n\
+static short pv[%d] = {", parents.used) < 0)
+ return (1);
+ for (i = 0; i < parents.used; i++)
+ if (fprintf(fp, "%s%d,", SEP(i, 16), parents.vec[i]) < 0)
+ return (1);
+ return (fprintf(fp, "\n};\n") < 0);
+}
+
+/*
+ * Emit the cfdata array.
+ */
+static int
+emitcfdata(fp)
+ register FILE *fp;
+{
+ register struct devi **p, *i, **par;
+ register int unit, v;
+ register const char *vs, *state, *basename;
+ register struct nvlist *nv;
+ register struct attr *a;
+ char *loc;
+ char locbuf[20];
+
+ if (fprintf(fp, "\n\
+#define NORM FSTATE_NOTFOUND\n\
+#define STAR FSTATE_STAR\n\
+\n\
+struct cfdata cfdata[] = {\n\
+\t/* driver unit state loc flags parents ivstubs */\n") < 0)
+ return (1);
+ for (p = packed; (i = *p) != NULL; p++) {
+ /* the description */
+ if (fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name) < 0)
+ return (1);
+ par = i->i_parents;
+ for (v = 0; v < i->i_pvlen; v++)
+ if (fprintf(fp, "%s%s", v == 0 ? "" : "|",
+ i->i_parents[v]->i_name) < 0)
+ return (1);
+ if (v == 0 && fputs("root", fp) < 0)
+ return (1);
+ a = i->i_atattr;
+ nv = a->a_locs;
+ for (nv = a->a_locs, v = 0; nv != NULL; nv = nv->nv_next, v++)
+ if (fprintf(fp, " %s %s",
+ nv->nv_name, i->i_locs[v]) < 0)
+ return (1);
+ if (fputs(" */\n", fp) < 0)
+ return (-1);
+
+ /* then the actual defining line */
+ basename = i->i_base->d_name;
+ if (i->i_unit == STAR) {
+ unit = i->i_base->d_umax;
+ state = "STAR";
+ } else {
+ unit = i->i_unit;
+ state = "NORM";
+ }
+ if (i->i_ivoff < 0) {
+ vs = "";
+ v = 0;
+ } else {
+ vs = "vec+";
+ v = i->i_ivoff;
+ }
+ if (i->i_locoff >= 0) {
+ (void)sprintf(locbuf, "loc+%3d", i->i_locoff);
+ loc = locbuf;
+ } else
+ loc = "loc";
+ if (fprintf(fp, "\
+\t{&%scd,%s%2d, %s, %7s, %#6x, pv+%2d, %s%d},\n",
+ basename, strlen(basename) < 3 ? "\t\t" : "\t", unit,
+ state, loc, i->i_cfflags, i->i_pvoff, vs, v) < 0)
+ return (1);
+ }
+ return (fputs("\t{0}\n};\n", fp) < 0);
+}
+
+/*
+ * Emit the table of potential roots.
+ */
+static int
+emitroots(fp)
+ register FILE *fp;
+{
+ register struct devi **p, *i;
+
+ if (fputs("\nshort cfroots[] = {\n", fp) < 0)
+ return (1);
+ for (p = packed; (i = *p) != NULL; p++) {
+ if (i->i_at != NULL)
+ continue;
+ if (i->i_unit != 0 &&
+ (i->i_unit != STAR || i->i_base->d_umax != 0))
+ (void)fprintf(stderr,
+ "config: warning: `%s at root' is not unit 0\n",
+ i->i_name);
+ if (fprintf(fp, "\t%2d /* %s */,\n",
+ i->i_cfindex, i->i_name) < 0)
+ return (1);
+ }
+ return (fputs("\t-1\n};\n", fp) < 0);
+}
+
+/*
+ * Emit pseudo-device initialization.
+ */
+static int
+emitpseudo(fp)
+ register FILE *fp;
+{
+ register struct devi *i;
+ register struct devbase *d;
+
+ if (fputs("\n/* pseudo-devices */\n", fp) < 0)
+ return (1);
+ for (i = allpseudo; i != NULL; i = i->i_next)
+ if (fprintf(fp, "extern void %sattach __P((int));\n",
+ i->i_base->d_name) < 0)
+ return (1);
+ if (fputs("\nstruct pdevinit pdevinit[] = {\n", fp) < 0)
+ return (1);
+ for (i = allpseudo; i != NULL; i = i->i_next) {
+ d = i->i_base;
+ if (fprintf(fp, "\t{ %sattach, %d },\n",
+ d->d_name, d->d_umax) < 0)
+ return (1);
+ }
+ return (fputs("\t{ 0, 0 }\n};\n", fp) < 0);
+}
+
+/*
+ * Emit interrupt vector declarations, and calculate offsets.
+ */
+static int
+emitvec(fp)
+ register FILE *fp;
+{
+ register struct nvlist *head, *nv;
+ register struct devi **p, *i;
+ register int j, nvec, unit;
+ char buf[200];
+
+ nvec = 0;
+ for (p = packed; (i = *p) != NULL; p++) {
+ if ((head = i->i_base->d_vectors) == NULL)
+ continue;
+ if ((unit = i->i_unit) == STAR)
+ panic("emitvec unit==STAR");
+ if (nvec == 0)
+ NEWLINE;
+ for (j = 0, nv = head; nv != NULL; j++, nv = nv->nv_next)
+ if (fprintf(fp,
+ "/* IVEC %s %d */ extern void %s();\n",
+ nv->nv_name, unit,
+ vecname(buf, nv->nv_name, unit)) < 0)
+ return (1);
+ nvec += j + 1;
+ }
+ if (nvec == 0)
+ return (0);
+ if (fprintf(fp, "\nstatic void (*vec[%d]) __P((void)) = {", nvec) < 0)
+ return (1);
+ nvec = 0;
+ for (p = packed; (i = *p) != NULL; p++) {
+ if ((head = i->i_base->d_vectors) == NULL)
+ continue;
+ i->i_ivoff = nvec;
+ unit = i->i_unit;
+ for (nv = head; nv != NULL; nv = nv->nv_next)
+ if (fprintf(fp, "%s%s,",
+ SEP(nvec++, 4),
+ vecname(buf, nv->nv_name, unit)) < 0)
+ return (1);
+ if (fprintf(fp, "%s0,", SEP(nvec++, 4)) < 0)
+ return (1);
+ }
+ return (fputs("\n};\n", fp) < 0);
+}
+
+static char *
+vecname(buf, name, unit)
+ char *buf;
+ const char *name;
+ int unit;
+{
+
+ /* @#%* 386 uses a different name format */
+ if (machine == s_i386) {
+ (void)sprintf(buf, "V%s%d", name, unit);
+ return (buf);
+ }
+ (void)sprintf(buf, "X%s%d", name, unit);
+ return (buf);
+}
diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c
new file mode 100644
index 00000000000..042b00aa95b
--- /dev/null
+++ b/usr.sbin/config/mkmakefile.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)mkmakefile.c 8.1 (Berkeley) 6/6/93
+ * $Id: mkmakefile.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "sem.h"
+/*
+ * Make the Makefile.
+ */
+
+static int emitdefs __P((FILE *));
+static int emitobjs __P((FILE *));
+static int emitcfiles __P((FILE *));
+static int emitsfiles __P((FILE *));
+static int emitfiles __P((FILE *, int));
+static int emitrules __P((FILE *));
+static int emitload __P((FILE *));
+
+int
+mkmakefile()
+{
+ register FILE *ifp, *ofp;
+ register int lineno;
+ register int (*fn) __P((FILE *));
+ register char *ofname;
+ char line[BUFSIZ], ifname[200];
+
+ (void)sprintf(ifname, "Makefile.%s", machine);
+ if ((ifp = fopen(ifname, "r")) == NULL) {
+ (void)fprintf(stderr, "config: cannot read %s: %s\n",
+ ifname, strerror(errno));
+ return (1);
+ }
+ ofname = path("Makefile");
+ if ((ofp = fopen(ofname, "w")) == NULL) {
+ (void)fprintf(stderr, "config: cannot write %s: %s\n",
+ ofname, strerror(errno));
+ free(ofname);
+ return (1);
+ }
+ if (emitdefs(ofp) != 0)
+ goto wrerror;
+ lineno = 0;
+ while (fgets(line, sizeof(line), ifp) != NULL) {
+ lineno++;
+ if (line[0] != '%') {
+ if (fputs(line, ofp) < 0)
+ goto wrerror;
+ continue;
+ }
+ if (strcmp(line, "%OBJS\n") == 0)
+ fn = emitobjs;
+ else if (strcmp(line, "%CFILES\n") == 0)
+ fn = emitcfiles;
+ else if (strcmp(line, "%SFILES\n") == 0)
+ fn = emitsfiles;
+ else if (strcmp(line, "%RULES\n") == 0)
+ fn = emitrules;
+ else if (strcmp(line, "%LOAD\n") == 0)
+ fn = emitload;
+ else {
+ xerror(ifname, lineno,
+ "unknown %% construct ignored: %s", line);
+ continue;
+ }
+ if ((*fn)(ofp))
+ goto wrerror;
+ }
+ if (ferror(ifp)) {
+ (void)fprintf(stderr,
+ "config: error reading %s (at line %d): %s\n",
+ ifname, lineno, strerror(errno));
+ goto bad;
+ /* (void)unlink(ofname); */
+ free(ofname);
+ return (1);
+ }
+ if (fclose(ofp)) {
+ ofp = NULL;
+ goto wrerror;
+ }
+ (void)fclose(ifp);
+ free(ofname);
+ return (0);
+wrerror:
+ (void)fprintf(stderr, "config: error writing %s: %s\n",
+ ofname, strerror(errno));
+bad:
+ if (ofp != NULL)
+ (void)fclose(ofp);
+ /* (void)unlink(ofname); */
+ free(ofname);
+ return (1);
+}
+
+static int
+emitdefs(fp)
+ register FILE *fp;
+{
+ register struct nvlist *nv;
+ register char *sp;
+
+ if (fputs("IDENT=", fp) < 0)
+ return (1);
+ sp = "";
+ for (nv = options; nv != NULL; nv = nv->nv_next) {
+ if (fprintf(fp, "%s-D%s", sp, nv->nv_name) < 0)
+ return 1;
+ if (nv->nv_str)
+ if (fprintf(fp, "=\"%s\"", nv->nv_str) < 0)
+ return 1;
+ sp = " ";
+ }
+ if (putc('\n', fp) < 0)
+ return (1);
+ if (fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers) < 0)
+ return (1);
+ for (nv = mkoptions; nv != NULL; nv = nv->nv_next)
+ if (fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str) < 0)
+ return (1);
+ return (0);
+}
+
+static int
+emitobjs(fp)
+ register FILE *fp;
+{
+ register struct files *fi;
+ register int lpos, len, sp;
+
+ if (fputs("OBJS=", fp) < 0)
+ return (1);
+ sp = '\t';
+ lpos = 7;
+ for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
+ if ((fi->fi_flags & FI_SEL) == 0)
+ continue;
+ len = strlen(fi->fi_base) + 2;
+ if (lpos + len > 72) {
+ if (fputs(" \\\n", fp) < 0)
+ return (1);
+ sp = '\t';
+ lpos = 7;
+ }
+ if (fprintf(fp, "%c%s.o", sp, fi->fi_base) < 0)
+ return (1);
+ lpos += len + 1;
+ sp = ' ';
+ }
+ if (lpos != 7 && putc('\n', fp) < 0)
+ return (1);
+ return (0);
+}
+
+static int
+emitcfiles(fp)
+ FILE *fp;
+{
+
+ return (emitfiles(fp, 'c'));
+}
+
+static int
+emitsfiles(fp)
+ FILE *fp;
+{
+
+ return (emitfiles(fp, 's'));
+}
+
+static int
+emitfiles(fp, suffix)
+ register FILE *fp;
+ int suffix;
+{
+ register struct files *fi;
+ register struct config *cf;
+ register int lpos, len, sp;
+ char swapname[100];
+
+ if (fprintf(fp, "%cFILES=", toupper(suffix)) < 0)
+ return (1);
+ sp = '\t';
+ lpos = 7;
+ for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
+ if ((fi->fi_flags & FI_SEL) == 0)
+ continue;
+ len = strlen(fi->fi_path);
+ if (fi->fi_path[len - 1] != suffix)
+ continue;
+ if (*fi->fi_path != '/')
+ len += 3; /* "$S/" */
+ if (lpos + len > 72) {
+ if (fputs(" \\\n", fp) < 0)
+ return (1);
+ sp = '\t';
+ lpos = 7;
+ }
+ if (fprintf(fp, "%c%s%s", sp, *fi->fi_path != '/' ? "$S/" : "",
+ fi->fi_path) < 0)
+ return (1);
+ lpos += len + 1;
+ sp = ' ';
+ }
+ /*
+ * The allfiles list does not include the configuration-specific
+ * C source files. These files should be eliminated someday, but
+ * for now, we have to add them to ${CFILES} (and only ${CFILES}).
+ */
+ if (suffix == 'c') {
+ for (cf = allcf; cf != NULL; cf = cf->cf_next) {
+ if (cf->cf_root == NULL)
+ (void)sprintf(swapname,
+ "$S/arch/%s/%s/swapgeneric.c",
+ machine, machine);
+ else
+ (void)sprintf(swapname, "swap%s.c",
+ cf->cf_name);
+ len = strlen(swapname);
+ if (lpos + len > 72) {
+ if (fputs(" \\\n", fp) < 0)
+ return (1);
+ sp = '\t';
+ lpos = 7;
+ }
+ if (fprintf(fp, "%c%s", sp, swapname) < 0)
+ return (1);
+ lpos += len + 1;
+ sp = ' ';
+ }
+ }
+ if (lpos != 7 && putc('\n', fp) < 0)
+ return (1);
+ return (0);
+}
+
+/*
+ * Emit the make-rules.
+ */
+static int
+emitrules(fp)
+ register FILE *fp;
+{
+ register struct files *fi;
+ register const char *cp;
+ int ch;
+ char buf[200];
+
+ for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
+ if ((fi->fi_flags & FI_SEL) == 0)
+ continue;
+ if (fprintf(fp, "%s.o: %s%s\n", fi->fi_base,
+ *fi->fi_path != '/' ? "$S/" : "", fi->fi_path) < 0)
+ return (1);
+ if ((cp = fi->fi_mkrule) == NULL) {
+ cp = fi->fi_flags & FI_DRIVER ? "DRIVER" : "NORMAL";
+ ch = fi->fi_lastc;
+ if (islower(ch))
+ ch = toupper(ch);
+ (void)sprintf(buf, "${%s_%c%s}", cp, ch,
+ fi->fi_flags & FI_CONFIGDEP ? "_C" : "");
+ cp = buf;
+ }
+ if (fprintf(fp, "\t%s\n\n", cp) < 0)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Emit the load commands.
+ *
+ * This function is not to be called `spurt'.
+ */
+static int
+emitload(fp)
+ register FILE *fp;
+{
+ register struct config *cf;
+ register const char *nm, *swname;
+ int first;
+
+ if (fputs("all:", fp) < 0)
+ return (1);
+ for (cf = allcf; cf != NULL; cf = cf->cf_next) {
+ if (fprintf(fp, " %s", cf->cf_name) < 0)
+ return (1);
+ }
+ if (fputs("\n\n", fp) < 0)
+ return (1);
+ for (first = 1, cf = allcf; cf != NULL; cf = cf->cf_next) {
+ nm = cf->cf_name;
+ swname =
+ cf->cf_root != NULL ? cf->cf_name : "generic";
+ if (fprintf(fp, "%s: ${SYSTEM_DEP} swap%s.o", nm, swname) < 0)
+ return (1);
+ if (first) {
+ if (fputs(" newvers", fp) < 0)
+ return (1);
+ first = 0;
+ }
+ if (fprintf(fp, "\n\
+\t${SYSTEM_LD_HEAD}\n\
+\t${SYSTEM_LD} swap%s.o\n\
+\t${SYSTEM_LD_TAIL}\n\
+\n\
+swap%s.o: ", swname, swname) < 0)
+ return (1);
+ if (cf->cf_root != NULL) {
+ if (fprintf(fp, "swap%s.c\n", nm) < 0)
+ return (1);
+ } else {
+ if (fprintf(fp, "$S/arch/%s/%s/swapgeneric.c\n",
+ machine, machine) < 0)
+ return (1);
+ }
+ if (fputs("\t${NORMAL_C}\n\n", fp) < 0)
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/config/mkswap.c b/usr.sbin/config/mkswap.c
new file mode 100644
index 00000000000..01f3b00b458
--- /dev/null
+++ b/usr.sbin/config/mkswap.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)mkswap.c 8.1 (Berkeley) 6/6/93
+ * $Id: mkswap.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "sem.h"
+
+static int mkoneswap __P((struct config *));
+
+/*
+ * Make the various swap*.c files. Nothing to do for generic swap.
+ */
+int
+mkswap()
+{
+ register struct config *cf;
+
+ for (cf = allcf; cf != NULL; cf = cf->cf_next)
+ if (cf->cf_root != NULL && mkoneswap(cf))
+ return (1);
+ return (0);
+}
+
+static char *
+mkdevstr(d)
+dev_t d;
+{
+ static char buf[32];
+
+ if (d == NODEV)
+ (void)sprintf(buf, "NODEV");
+ else
+ (void)sprintf(buf, "makedev(%d, %d)", major(d), minor(d));
+ return buf;
+}
+
+static int
+mkoneswap(cf)
+ register struct config *cf;
+{
+ register struct nvlist *nv;
+ register FILE *fp;
+ register char *fname;
+ char buf[200];
+ char *mountroot;
+
+ (void)sprintf(buf, "swap%s.c", cf->cf_name);
+ fname = path(buf);
+ if ((fp = fopen(fname, "w")) == NULL) {
+ (void)fprintf(stderr, "config: cannot write %s: %s\n",
+ fname, strerror(errno));
+ return (1);
+ }
+ if (fputs("\
+#include <sys/param.h>\n\
+#include <sys/conf.h>\n\n", fp) < 0)
+ goto wrerror;
+ nv = cf->cf_root;
+ if (fprintf(fp, "dev_t\trootdev = %s;\t/* %s */\n",
+ mkdevstr(nv->nv_int), nv->nv_str) < 0)
+ goto wrerror;
+ nv = cf->cf_dump;
+ if (fprintf(fp, "dev_t\tdumpdev = %s;\t/* %s */\n",
+ mkdevstr(nv->nv_int), nv->nv_str) < 0)
+ goto wrerror;
+ if (fputs("\nstruct\tswdevt swdevt[] = {\n", fp) < 0)
+ goto wrerror;
+ for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next)
+ if (fprintf(fp, "\t{ %s,\t0,\t0 },\t/* %s */\n",
+ mkdevstr(nv->nv_int), nv->nv_str) < 0)
+ goto wrerror;
+ if (fputs("\t{ NODEV, 0, 0 }\n};\n\n", fp) < 0)
+ goto wrerror;
+ mountroot =
+ cf->cf_root->nv_str == s_nfs ? "nfs_mountroot" : "ffs_mountroot";
+ if (fprintf(fp, "extern int %s();\n", mountroot) < 0)
+ goto wrerror;
+ if (fprintf(fp, "int (*mountroot)() = %s;\n", mountroot) < 0)
+ goto wrerror;
+
+ if (fclose(fp)) {
+ fp = NULL;
+ goto wrerror;
+ }
+ free(fname);
+ return (0);
+wrerror:
+ (void)fprintf(stderr, "config: error writing %s: %s\n",
+ fname, strerror(errno));
+ if (fp != NULL)
+ (void)fclose(fp);
+ /* (void)unlink(fname); */
+ free(fname);
+ return (1);
+}
diff --git a/usr.sbin/config/pack.c b/usr.sbin/config/pack.c
new file mode 100644
index 00000000000..4bb82796238
--- /dev/null
+++ b/usr.sbin/config/pack.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)pack.c 8.1 (Berkeley) 6/6/93
+ * $Id: pack.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+/*
+ * Packing. We have three separate kinds of packing here.
+ *
+ * First, we pack device instances, to collapse things like
+ *
+ * uba0 at sbi0 nexus ?
+ * uba0 at bi0 nexus ?
+ *
+ * into a single instance that is "at sbi0 or bi0".
+ *
+ * Second, we pack locators. Given something like
+ *
+ * hp0 at mba0 drive 0
+ * hp* at mba* drive ?
+ * ht0 at mba0 drive 0
+ * tu0 at ht0 slave 0
+ * ht* at mba* drive ?
+ * tu* at ht* slave ?
+ *
+ * (where the default drive and slave numbers are -1), we have three
+ * locators whose value is 0 and three whose value is -1. Rather than
+ * emitting six integers, we emit just two.
+ *
+ * Finally, we pack parent vectors. This is very much like packing
+ * locators. Unlike locators, however, parent vectors are always
+ * terminated by -1 (rather like the way C strings always end with
+ * a NUL).
+ *
+ * When packing locators, we would like to find sequences such as
+ * {1 2 3} {2 3 4} {3} {4 5}
+ * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
+ * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
+ * When we pack parent vectors, overlap of this sort is impossible.
+ * Non-overlapping packing is much easier, and so we use that here
+ * and miss out on the chance to squeeze the locator sequence optimally.
+ * (So it goes.)
+ */
+
+typedef int (*vec_cmp_func) __P((const void *, int, int));
+
+#define TAILHSIZE 128
+#define PVHASH(i) ((i) & (TAILHSIZE - 1))
+#define LOCHASH(l) (((long)(l) >> 2) & (TAILHSIZE - 1))
+struct tails {
+ struct tails *t_next;
+ int t_ends_at;
+};
+
+static struct tails *tails[TAILHSIZE];
+static int locspace;
+static int pvecspace;
+static int longest_pvec;
+
+static void packdevi __P((void));
+static void packlocs __P((void));
+static void packpvec __P((void));
+
+static void addparents __P((struct devi *src, struct devi *dst));
+static int nparents __P((struct devi **, struct devbase *, int));
+static int sameas __P((struct devi *, struct devi *));
+static int findvec __P((const void *, int, int, vec_cmp_func, int));
+static int samelocs __P((const void *, int, int));
+static int addlocs __P((const char **, int));
+static int loclencmp __P((const void *, const void *));
+static int samepv __P((const void *, int, int));
+static int addpv __P((short *, int));
+static int pvlencmp __P((const void *, const void *));
+static void resettails __P((void));
+
+void
+pack()
+{
+ register struct devi *i;
+ register int n;
+
+ /* Pack instances and make parent vectors. */
+ packdevi();
+
+ /*
+ * Now that we know what we have, find upper limits on space
+ * needed for the loc[] and pv[] tables, and find the longest
+ * single pvec. The loc and pv table sizes are bounded by
+ * what we would get if no packing occurred.
+ */
+ locspace = pvecspace = 0;
+ for (i = alldevi; i != NULL; i = i->i_next) {
+ if (i->i_collapsed)
+ continue;
+ locspace += i->i_atattr->a_loclen;
+ n = i->i_pvlen + 1;
+ if (n > longest_pvec)
+ longest_pvec = n;
+ pvecspace += n;
+ }
+
+ /* Allocate and pack loc[]. */
+ locators.vec = emalloc(locspace * sizeof(*locators.vec));
+ locators.used = 0;
+ packlocs();
+
+ /* Allocate and pack pv[]. */
+ parents.vec = emalloc(pvecspace * sizeof(*parents.vec));
+ parents.used = 0;
+ packpvec();
+}
+
+/*
+ * Pack instances together wherever possible. When everything is
+ * packed, go back and set up the parents for each. We must do this
+ * on a second pass because during the first one, we do not know which,
+ * if any, of the parents will collapse during packing.
+ */
+void
+packdevi()
+{
+ register struct devi *i, *l, *p;
+ register struct devbase *d;
+ register int j, m, n;
+
+ packed = emalloc((ndevi + 1) * sizeof *packed);
+ n = 0;
+ for (d = allbases; d != NULL; d = d->d_next) {
+ /*
+ * For each instance of each device, add or collapse
+ * all its aliases.
+ */
+ for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
+ m = n;
+ for (l = i; l != NULL; l = l->i_alias) {
+ l->i_pvlen = 0;
+ l->i_pvoff = -1;
+ l->i_locoff = -1;
+ l->i_ivoff = -1;
+ /* try to find an equivalent for l */
+ for (j = m; j < n; j++) {
+ p = packed[j];
+ if (sameas(l, p)) {
+ l->i_collapsed = 1;
+ l->i_cfindex = p->i_cfindex;
+ goto nextalias;
+ }
+ }
+ /* could not find a suitable alias */
+ l->i_collapsed = 0;
+ l->i_cfindex = n;
+ l->i_parents = emalloc(sizeof(*l->i_parents));
+ l->i_parents[0] = NULL;
+ packed[n++] = l;
+ nextalias:;
+ }
+ }
+ }
+ npacked = n;
+ packed[n] = NULL;
+ for (i = alldevi; i != NULL; i = i->i_next)
+ addparents(i, packed[i->i_cfindex]);
+}
+
+/*
+ * Return true if two aliases are "the same". In this case, they need
+ * to have the same config flags and the same locators.
+ */
+static int
+sameas(i1, i2)
+ register struct devi *i1, *i2;
+{
+ register const char **p1, **p2;
+
+ if (i1->i_cfflags != i2->i_cfflags)
+ return (0);
+ for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
+ if (*p1++ == 0)
+ return (1);
+ return 0;
+}
+
+/*
+ * Add the parents associated with "src" to the (presumably uncollapsed)
+ * instance "dst".
+ */
+static void
+addparents(src, dst)
+ register struct devi *src, *dst;
+{
+ register struct nvlist *nv;
+ register struct devi *i, **p, **q;
+ register int j, n, old, new, ndup;
+
+ if (dst->i_collapsed)
+ panic("addparents() i_collapsed");
+
+ /* Collect up list of parents to add. */
+ if (src->i_at == NULL) /* none, 'cuz "at root" */
+ return;
+ if (src->i_atdev != NULL) {
+ n = nparents(NULL, src->i_atdev, src->i_atunit);
+ p = emalloc(n * sizeof *p);
+ if (n == 0)
+ return;
+ (void)nparents(p, src->i_atdev, src->i_atunit);
+ } else {
+ n = 0;
+ for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
+ n += nparents(NULL, nv->nv_ptr, src->i_atunit);
+ if (n == 0)
+ return;
+ p = emalloc(n * sizeof *p);
+ n = 0;
+ for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
+ n += nparents(p + n, nv->nv_ptr, src->i_atunit);
+ }
+ /* Now elide duplicates. */
+ ndup = 0;
+ for (j = 0; j < n; j++) {
+ i = p[j];
+ for (q = dst->i_parents; *q != NULL; q++) {
+ if (*q == i) {
+ ndup++;
+ p[j] = NULL;
+ break;
+ }
+ }
+ }
+ /* Finally, add all the non-duplicates. */
+ old = dst->i_pvlen;
+ new = old + (n - ndup);
+ if (old > new)
+ panic("addparents() old > new");
+ if (old == new) {
+ free(p);
+ return;
+ }
+ dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q));
+ dst->i_pvlen = new;
+ q[new] = NULL;
+ q += old;
+ for (j = 0; j < n; j++)
+ if (p[j] != NULL)
+ *q++ = p[j];
+ free(p);
+}
+
+/*
+ * Count up parents, and optionally store pointers to each.
+ */
+static int
+nparents(p, dev, unit)
+ register struct devi **p;
+ register struct devbase *dev;
+ register int unit;
+{
+ register struct devi *i, *l;
+ register int n;
+
+ n = 0;
+ /* for each instance ... */
+ for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
+ /* ... take each un-collapsed alias */
+ for (l = i; l != NULL; l = l->i_alias) {
+ if (!l->i_collapsed &&
+ (unit == WILD || unit == l->i_unit)) {
+ if (p != NULL)
+ *p++ = l;
+ n++;
+ }
+ }
+ }
+ return (n);
+}
+
+static void
+packlocs()
+{
+ register struct devi **p, *i;
+ register int l, o;
+
+ qsort(packed, npacked, sizeof *packed, loclencmp);
+ for (p = packed; (i = *p) != NULL; p++) {
+ if ((l = i->i_atattr->a_loclen) > 0) {
+ o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l,
+ samelocs, locators.used);
+ i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o;
+ } else
+ i->i_locoff = -1;
+ }
+ resettails();
+}
+
+static void
+packpvec()
+{
+ register struct devi **p, *i, **par;
+ register int l, v, o;
+ register short *vec;
+
+ vec = emalloc(longest_pvec * sizeof(*vec));
+ qsort(packed, npacked, sizeof *packed, pvlencmp);
+ for (p = packed; (i = *p) != NULL; p++) {
+ l = i->i_pvlen;
+if (l > longest_pvec) panic("packpvec");
+ par = i->i_parents;
+ for (v = 0; v < l; v++)
+ vec[v] = par[v]->i_cfindex;
+ if (l == 0 ||
+ (o = findvec(vec, PVHASH(vec[l - 1]), l,
+ samepv, parents.used)) < 0)
+ o = addpv(vec, l);
+ i->i_pvoff = o;
+ }
+ free(vec);
+ resettails();
+}
+
+/*
+ * Return the index at which the given vector already exists, or -1
+ * if it is not anywhere in the current set. If we return -1, we assume
+ * our caller will add it at the end of the current set, and we make
+ * sure that next time, we will find it there.
+ */
+static int
+findvec(ptr, hash, len, cmp, nextplace)
+ const void *ptr;
+ int hash, len;
+ vec_cmp_func cmp;
+ int nextplace;
+{
+ register struct tails *t, **hp;
+ register int off;
+
+ hp = &tails[hash];
+ for (t = *hp; t != NULL; t = t->t_next) {
+ off = t->t_ends_at - len;
+ if (off >= 0 && (*cmp)(ptr, off, len))
+ return (off);
+ }
+ t = emalloc(sizeof(*t));
+ t->t_next = *hp;
+ *hp = t;
+ t->t_ends_at = nextplace + len;
+ return (-1);
+}
+
+/*
+ * Comparison function for locators.
+ */
+static int
+samelocs(ptr, off, len)
+ const void *ptr;
+ int off;
+ register int len;
+{
+ register const char **p, **q;
+
+ for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;)
+ if (*p++ != *q++)
+ return (0); /* different */
+ return (1); /* same */
+}
+
+/*
+ * Add the given locators at the end of the global loc[] table.
+ */
+static int
+addlocs(locs, len)
+ register const char **locs;
+ register int len;
+{
+ register const char **p;
+ register int ret;
+
+ ret = locators.used;
+ if ((locators.used = ret + len) > locspace)
+ panic("addlocs: overrun");
+ for (p = &locators.vec[ret]; --len >= 0;)
+ *p++ = *locs++;
+ return (ret);
+}
+
+/*
+ * Comparison function for qsort-by-locator-length, longest first.
+ * We rashly assume that subtraction of these lengths does not overflow.
+ */
+static int
+loclencmp(a, b)
+ const void *a, *b;
+{
+ register int l1, l2;
+
+ l1 = (*(struct devi **)a)->i_atattr->a_loclen;
+ l2 = (*(struct devi **)b)->i_atattr->a_loclen;
+ return (l2 - l1);
+}
+
+/*
+ * Comparison function for parent vectors.
+ */
+static int
+samepv(ptr, off, len)
+ const void *ptr;
+ int off;
+ register int len;
+{
+ register short *p, *q;
+
+ for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
+ if (*p++ != *q++)
+ return (0); /* different */
+ return (1); /* same */
+}
+
+/*
+ * Add the given parent vectors at the end of the global pv[] table.
+ */
+static int
+addpv(pv, len)
+ register short *pv;
+ register int len;
+{
+ register short *p;
+ register int ret;
+ static int firstend = -1;
+
+ /*
+ * If the vector is empty, reuse the first -1. It will be
+ * there if there are any nonempty vectors at all, since we
+ * do the longest first. If there are no nonempty vectors,
+ * something is probably wrong, but we will ignore that here.
+ */
+ if (len == 0 && firstend >= 0)
+ return (firstend);
+ len++; /* account for trailing -1 */
+ ret = parents.used;
+ if ((parents.used = ret + len) > pvecspace)
+ panic("addpv: overrun");
+ for (p = &parents.vec[ret]; --len > 0;)
+ *p++ = *pv++;
+ *p = -1;
+ if (firstend < 0)
+ firstend = parents.used - 1;
+ return (ret);
+}
+
+/*
+ * Comparison function for qsort-by-parent-vector-length, longest first.
+ * We rashly assume that subtraction of these lengths does not overflow.
+ */
+static int
+pvlencmp(a, b)
+ const void *a, *b;
+{
+ register int l1, l2;
+
+ l1 = (*(struct devi **)a)->i_pvlen;
+ l2 = (*(struct devi **)b)->i_pvlen;
+ return (l2 - l1);
+}
+
+static void
+resettails()
+{
+ register struct tails **p, *t, *next;
+ register int i;
+
+ for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
+ for (t = *p; t != NULL; t = next) {
+ next = t->t_next;
+ free(t);
+ }
+ *p = NULL;
+ }
+}
diff --git a/usr.sbin/config/scan.l b/usr.sbin/config/scan.l
new file mode 100644
index 00000000000..a4a2c0b1e23
--- /dev/null
+++ b/usr.sbin/config/scan.l
@@ -0,0 +1,240 @@
+%{
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)scan.l 8.1 (Berkeley) 6/6/93
+ * $Id: scan.l,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "config.h"
+#include "y.tab.h"
+
+int yyline;
+const char *yyfile;
+const char *lastfile;
+
+int include __P((const char *, int));
+
+/*
+ * Data for returning to previous files from include files.
+ */
+struct incl {
+ struct incl *in_prev; /* previous includes in effect, if any */
+ YY_BUFFER_STATE in_buf; /* previous lex state */
+ const char *in_fname; /* previous file name */
+ int in_lineno; /* previous line number */
+ int in_preveof; /* previous eoftoken */
+};
+static struct incl *incl;
+static int eoftoken; /* current EOF token */
+static void endinclude __P((void));
+
+#define yywrap() 1
+
+%}
+
+PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
+WORD [A-Za-z_][-A-Za-z_0-9]*
+
+%%
+
+ /* plain keywords */
+and { return AND; }
+at { return AT; }
+compile-with { return COMPILE_WITH; }
+config { return CONFIG; }
+define { return DEFINE; }
+device { return DEVICE; }
+dumps { return DUMPS; }
+flags { return FLAGS; }
+file { return XFILE; }
+include { return INCLUDE; }
+machine { return XMACHINE; }
+major { return MAJOR; }
+makeoptions { return MAKEOPTIONS; }
+maxusers { return MAXUSERS; }
+maxpartitions { return MAXPARTITIONS; }
+minor { return MINOR; }
+on { return ON; }
+options { return OPTIONS; }
+"pseudo-device" { return PSEUDO_DEVICE; }
+root { return ROOT; }
+swap { return SWAP; }
+vector { return VECTOR; }
+
+ /* keywords with values */
+config-dependent { yylval.val = FI_CONFIGDEP; return FFLAG; }
+device-driver { yylval.val = FI_DRIVER; return FFLAG; }
+needs-count { yylval.val = FI_NEEDSCOUNT; return FFLAG; }
+needs-flag { yylval.val = FI_NEEDSFLAG; return FFLAG; }
+
+ /* all the rest */
+{PATH} { yylval.str = intern(yytext); return PATHNAME; }
+{WORD} { yylval.str = intern(yytext); return WORD; }
+
+\"([^"]|\\\")*/\" {
+ yylval.str = intern(yytext + 1);
+ (void)input(); /* eat closing quote */
+ return WORD;
+ }
+0[0-7]* {
+ yylval.val = strtol(yytext, NULL, 8);
+ return NUMBER;
+ }
+0[xX][0-9a-fA-F]+ {
+ yylval.val = strtoul(yytext + 2, NULL, 16);
+ return NUMBER;
+ }
+[1-9][0-9]* {
+ yylval.val = strtol(yytext, NULL, 10);
+ return NUMBER;
+ }
+\n/[ \t] {
+ yyline++;
+ }
+\n {
+ yyline++;
+ return '\n';
+ }
+#.* { /* ignored (comment) */; }
+[ \t]* { /* ignored (white space) */; }
+. { return yytext[0]; }
+<<EOF>> {
+ int tok;
+
+ tok = eoftoken;
+ eoftoken = YY_NULL;
+ if (incl != NULL)
+ endinclude();
+ return (tok);
+ }
+
+%%
+
+/*
+ * Open the "main" file (conffile).
+ */
+int
+firstfile(fname)
+ const char *fname;
+{
+
+ if ((yyin = fopen(fname, "r")) == NULL)
+ return (-1);
+ yyfile = conffile = fname;
+ yyline = 1;
+ eoftoken = YY_NULL;
+ return (0);
+}
+
+/*
+ * Open the named file for inclusion at the current point. Returns 0 on
+ * success (file opened and previous state pushed), nonzero on failure
+ * (fopen failed, complaint made). The `ateof' parameter controls the
+ * token to be returned at the end of the include file (typically '\n'
+ * or ENDFILE).
+ */
+int
+include(fname, ateof)
+ const char *fname;
+ int ateof;
+{
+ register FILE *fp;
+ register struct incl *in;
+
+ if ((fp = fopen(fname, "r")) == NULL) {
+ error("cannot open %s for reading: %s\n",
+ fname, strerror(errno));
+ return (-1);
+ }
+ in = emalloc(sizeof *in);
+ in->in_prev = incl;
+ in->in_buf = YY_CURRENT_BUFFER;
+ in->in_fname = yyfile;
+ in->in_lineno = yyline;
+ in->in_preveof = eoftoken;
+ incl = in;
+ yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+ yyfile = intern(fname);
+ yyline = 1;
+ eoftoken = ateof;
+ return (0);
+}
+
+/*
+ * Terminate the most recent inclusion.
+ */
+static void
+endinclude()
+{
+ register struct incl *in;
+
+ if ((in = incl) == NULL)
+ panic("endinclude");
+ incl = in->in_prev;
+ lastfile = yyfile;
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ (void)fclose(yyin);
+ yy_switch_to_buffer(in->in_buf);
+ yyfile = in->in_fname;
+ yyline = in->in_lineno;
+ eoftoken = in->in_preveof;
+ free(in);
+}
+
+/*
+ * Return the current line number. If yacc has looked ahead and caused
+ * us to consume a newline, we have to subtract one. yychar is yacc's
+ * token lookahead, so we can tell.
+ */
+int
+currentline()
+{
+ extern int yychar;
+
+ return (yyline - (yychar == '\n'));
+}
diff --git a/usr.sbin/config/sem.c b/usr.sbin/config/sem.c
new file mode 100644
index 00000000000..01a53f519ad
--- /dev/null
+++ b/usr.sbin/config/sem.c
@@ -0,0 +1,989 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)sem.c 8.1 (Berkeley) 6/6/93
+ * $Id: sem.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "sem.h"
+
+/*
+ * config semantics.
+ */
+
+#define NAMESIZE 100 /* local name buffers */
+
+const char *s_generic;
+const char *s_nfs;
+static const char *s_qmark;
+
+static struct hashtab *attrtab; /* for attribute lookup */
+static struct hashtab *cfhashtab; /* for config lookup */
+static struct hashtab *devitab; /* etc */
+
+static struct attr errattr;
+static struct devbase errdev;
+static struct devbase **nextbase;
+static struct config **nextcf;
+static struct devi **nextdevi;
+static struct devi **nextpseudo;
+
+static int has_errobj __P((struct nvlist *, void *));
+static struct nvlist *addtoattr __P((struct nvlist *, struct devbase *));
+static int exclude __P((struct nvlist *, const char *, const char *));
+static int resolve __P((struct nvlist **, const char *, const char *,
+ struct nvlist *, int));
+static int lresolve __P((struct nvlist **, const char *, const char *,
+ struct nvlist *, int));
+static struct devi *newdevi __P((const char *, int, struct devbase *d));
+static struct devi *getdevi __P((const char *));
+static const char *concat __P((const char *, int));
+static int split __P((const char *, size_t, char *, size_t, int *));
+static void selectbase __P((struct devbase *));
+static int onlist __P((struct nvlist *, void *));
+static const char **fixloc __P((const char *, struct attr *, struct nvlist *));
+
+void
+initsem()
+{
+
+ attrtab = ht_new();
+ errattr.a_name = "<internal>";
+
+ allbases = NULL;
+ nextbase = &allbases;
+
+ cfhashtab = ht_new();
+ allcf = NULL;
+ nextcf = &allcf;
+
+ devitab = ht_new();
+ alldevi = NULL;
+ nextdevi = &alldevi;
+ errdev.d_name = "<internal>";
+
+ allpseudo = NULL;
+ nextpseudo = &allpseudo;
+
+ s_generic = intern("generic");
+ s_nfs = intern("nfs");
+ s_qmark = intern("?");
+}
+
+void
+enddefs(fname)
+ const char *fname;
+{
+ register struct devbase *dev;
+
+ for (dev = allbases; dev != NULL; dev = dev->d_next) {
+ if (!dev->d_isdef) {
+ (void)fprintf(stderr,
+ "%s: device `%s' used but not defined\n",
+ fname, dev->d_name);
+ errors++;
+ continue;
+ }
+ }
+ if (errors) {
+ (void)fprintf(stderr, "*** Stop.\n");
+ exit(1);
+ }
+}
+
+void
+setdefmaxusers(min, def, max)
+ int min, def, max;
+{
+
+ if (min < 1 || min > def || def > max)
+ error("maxusers must have 1 <= min <= default <= max");
+ else {
+ minmaxusers = min;
+ defmaxusers = def;
+ maxmaxusers = max;
+ }
+}
+
+void
+setmaxusers(n)
+ int n;
+{
+
+ if (maxusers != 0) {
+ error("duplicate maxusers parameter");
+ return;
+ }
+ maxusers = n;
+ if (n < minmaxusers) {
+ error("warning: minimum of %d maxusers assumed\n", minmaxusers);
+ errors--; /* take it away */
+ maxusers = minmaxusers;
+ } else if (n > maxmaxusers) {
+ error("warning: maxusers (%d) > %d", n, maxmaxusers);
+ errors--;
+ }
+}
+
+/*
+ * Define an attribute, optionally with an interface (a locator list).
+ * Since an empty locator list is logically different from "no interface",
+ * all locator lists include a dummy head node, which we discard here.
+ */
+int
+defattr(name, locs)
+ const char *name;
+ struct nvlist *locs;
+{
+ register struct attr *a;
+ register struct nvlist *nv;
+ register int len;
+
+ a = emalloc(sizeof *a);
+ if (ht_insert(attrtab, name, a)) {
+ free(a);
+ error("attribute `%s' already defined", name);
+ nvfreel(locs);
+ return (1);
+ }
+ a->a_name = name;
+ if (locs != NULL) {
+ a->a_iattr = 1;
+ a->a_locs = locs->nv_next;
+ nvfree(locs);
+ } else {
+ a->a_iattr = 0;
+ a->a_locs = NULL;
+ }
+ len = 0;
+ for (nv = a->a_locs; nv != NULL; nv = nv->nv_next)
+ len++;
+ a->a_loclen = len;
+ a->a_devs = NULL;
+ a->a_refs = NULL;
+ return (0);
+}
+
+/*
+ * Return true if the given `error object' is embedded in the given
+ * pointer list.
+ */
+static int
+has_errobj(nv, obj)
+ register struct nvlist *nv;
+ register void *obj;
+{
+
+ for (; nv != NULL; nv = nv->nv_next)
+ if (nv->nv_ptr == obj)
+ return (1);
+ return (0);
+}
+
+/*
+ * Add a device base to a list in an attribute (actually, to any list).
+ * Note that this does not check for duplicates, and does reverse the
+ * list order, but no one cares anyway.
+ */
+static struct nvlist *
+addtoattr(l, dev)
+ register struct nvlist *l;
+ register struct devbase *dev;
+{
+ register struct nvlist *n;
+
+ n = newnv(NULL, NULL, dev, 0);
+ n->nv_next = l;
+ return (n);
+}
+
+/*
+ * Device a device, giving its allowable parent attachments, if any.
+ * This may (or may not) also define an interface attribute and/or refer
+ * to existing attributes. There may be a list of vectors.
+ */
+void
+defdev(dev, ispseudo, atlist, vectors, loclist, attrs)
+ register struct devbase *dev;
+ int ispseudo;
+ struct nvlist *atlist, *vectors, *loclist, *attrs;
+{
+ register struct nvlist *nv;
+ register struct attr *a;
+
+ if (dev == &errdev)
+ goto bad;
+ if (dev->d_isdef) {
+ error("redefinition of `%s'", dev->d_name);
+ goto bad;
+ }
+ dev->d_isdef = 1;
+ if (has_errobj(attrs, &errattr))
+ goto bad;
+
+ /*
+ * Handle implicit attribute definition from locator list. Do
+ * this before scanning the `at' list so that we can have, e.g.:
+ * device foo at other, foo { slot = -1 }
+ * (where you can plug in a foo-bus extender to a foo-bus).
+ */
+ if (loclist != NULL) {
+ nv = loclist;
+ loclist = NULL; /* defattr disposes of them for us */
+ if (defattr(dev->d_name, nv))
+ goto bad;
+ nv = newnv(dev->d_name, NULL, getattr(dev->d_name), 0);
+ nv->nv_next = attrs;
+ attrs = nv;
+ }
+
+ /* Committed! Set up fields. */
+ dev->d_ispseudo = ispseudo;
+ dev->d_atlist = atlist;
+ dev->d_vectors = vectors;
+ dev->d_attrs = attrs;
+
+ /*
+ * Turn the `at' list into interface attributes (map each
+ * nv_name to an attribute, or to NULL for root), and add
+ * this device to those attributes, so that children can
+ * be listed at this particular device if they are supported
+ * by that attribute.
+ */
+ for (nv = atlist; nv != NULL; nv = nv->nv_next) {
+ if (nv->nv_name == NULL) {
+ nv->nv_ptr = NULL; /* at root */
+ continue;
+ }
+ nv->nv_ptr = a = getattr(nv->nv_name);
+ if (a == &errattr)
+ continue; /* already complained */
+ if (!a->a_iattr)
+ error("%s cannot be at plain attribute `%s'",
+ dev->d_name, a->a_name);
+ else
+ a->a_devs = addtoattr(a->a_devs, dev);
+ }
+
+ /*
+ * For each interface attribute this device refers to, add this
+ * device to its reference list. This makes, e.g., finding all
+ * "scsi"s easier.
+ */
+ for (nv = attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ if (a->a_iattr)
+ a->a_refs = addtoattr(a->a_refs, dev);
+ }
+ return;
+bad:
+ nvfreel(atlist);
+ nvfreel(vectors);
+ nvfreel(loclist);
+ nvfreel(attrs);
+}
+
+/*
+ * Look up a devbase. Also makes sure it is a reasonable name,
+ * i.e., does not end in a digit or contain special characters.
+ */
+struct devbase *
+getdevbase(name)
+ const char *name;
+{
+ register u_char *p;
+ register struct devbase *dev;
+
+ p = (u_char *)name;
+ if (!isalpha(*p))
+ goto badname;
+ while (*++p) {
+ if (!isalnum(*p) && *p != '_')
+ goto badname;
+ }
+ if (isdigit(*--p)) {
+badname:
+ error("bad device base name `%s'", name);
+ return (&errdev);
+ }
+ dev = ht_lookup(devbasetab, name);
+ if (dev == NULL) {
+ dev = emalloc(sizeof *dev);
+ dev->d_name = name;
+ dev->d_next = NULL;
+ dev->d_isdef = 0;
+ dev->d_major = NODEV;
+ dev->d_atlist = NULL;
+ dev->d_vectors = NULL;
+ dev->d_attrs = NULL;
+ dev->d_ihead = NULL;
+ dev->d_ipp = &dev->d_ihead;
+ dev->d_umax = 0;
+ *nextbase = dev;
+ nextbase = &dev->d_next;
+ if (ht_insert(devbasetab, name, dev))
+ panic("getdevbase(%s)", name);
+ }
+ return (dev);
+}
+
+/*
+ * Look up an attribute.
+ */
+struct attr *
+getattr(name)
+ const char *name;
+{
+ struct attr *a;
+
+ if ((a = ht_lookup(attrtab, name)) == NULL) {
+ error("undefined attribute `%s'", name);
+ a = &errattr;
+ }
+ return (a);
+}
+
+/*
+ * Set the major device number for a device, so that it can be used
+ * as a root/swap/dumps "on" device in a configuration.
+ */
+void
+setmajor(d, n)
+ struct devbase *d;
+ int n;
+{
+
+ if (d != &errdev && d->d_major != NODEV)
+ error("device `%s' is already major %d",
+ d->d_name, d->d_major);
+ else
+ d->d_major = n;
+}
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int
+exclude(nv, name, what)
+ struct nvlist *nv;
+ const char *name, *what;
+{
+
+ if (nv != NULL) {
+ error("%s: swap generic must not specify %s", name, what);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a').
+ * Handle the case where the device number is given but there is no
+ * corresponding name, and map NULL to the default.
+ */
+static int
+resolve(nvp, name, what, dflt, part)
+ register struct nvlist **nvp;
+ const char *name, *what;
+ struct nvlist *dflt;
+ register int part;
+{
+ register struct nvlist *nv;
+ register struct devbase *dev;
+ register const char *cp;
+ register int maj, min, l;
+ int unit;
+ char buf[NAMESIZE];
+
+ if ((u_int)(part -= 'a') >= maxpartitions)
+ panic("resolve");
+ if ((nv = *nvp) == NULL) {
+ dev_t d = NODEV;
+ /*
+ * Apply default. Easiest to do this by number.
+ * Make sure to retain NODEVness, if this is dflt's disposition.
+ */
+ if (dflt->nv_int != NODEV) {
+ maj = major(dflt->nv_int);
+ min = (minor(dflt->nv_int) / maxpartitions) + part;
+ d = makedev(maj, min);
+ }
+ *nvp = nv = newnv(NULL, NULL, NULL, d);
+ }
+ if (nv->nv_int != NODEV) {
+ /*
+ * By the numbers. Find the appropriate major number
+ * to make a name.
+ */
+ maj = major(nv->nv_int);
+ min = minor(nv->nv_int);
+ for (dev = allbases; dev != NULL; dev = dev->d_next)
+ if (dev->d_major == maj)
+ break;
+ if (dev == NULL)
+ (void)sprintf(buf, "<%d/%d>", maj, min);
+ else
+ (void)sprintf(buf, "%s%d%c", dev->d_name,
+ min / maxpartitions, (min % maxpartitions) + 'a');
+ nv->nv_str = intern(buf);
+ return (0);
+ }
+
+ if (nv->nv_str == NULL || nv->nv_str == s_nfs)
+ /*
+ * NFS spec. Leave as NODEV.
+ */
+ return (0);
+
+ /*
+ * The normal case: things like "ra2b". Check for partition
+ * suffix, remove it if there, and split into name ("ra") and
+ * unit (2).
+ */
+ l = strlen(nv->nv_str);
+ cp = &nv->nv_str[l];
+ if (l > 1 && *--cp >= 'a' && *cp <= 'a'+maxpartitions &&
+ isdigit(cp[-1])) {
+ l--;
+ part = *cp - 'a';
+ }
+ cp = nv->nv_str;
+ if (split(cp, l, buf, sizeof buf, &unit)) {
+ error("%s: invalid %s device name `%s'", name, what, cp);
+ return (1);
+ }
+ dev = ht_lookup(devbasetab, intern(buf));
+ if (dev == NULL || dev->d_major == NODEV) {
+ error("%s: can't make %s device from `%s'",
+ name, what, nv->nv_str);
+ return (1);
+ }
+ nv->nv_name = dev->d_name;
+ nv->nv_int = makedev(dev->d_major, unit * maxpartitions + part);
+ return (0);
+}
+
+static int
+lresolve(nvp, name, what, dflt, part)
+ register struct nvlist **nvp;
+ const char *name, *what;
+ struct nvlist *dflt;
+ int part;
+{
+ int err;
+
+ while ((err = resolve(nvp, name, what, dflt, part)) == 0 &&
+ (*nvp)->nv_next != NULL)
+ nvp = &(*nvp)->nv_next;
+ return (err);
+}
+
+/*
+ * Add a completed configuration to the list.
+ */
+void
+addconf(cf0)
+ register struct config *cf0;
+{
+ register struct config *cf;
+ register struct nvlist *nv;
+ const char *name;
+
+ name = cf0->cf_name;
+ cf = emalloc(sizeof *cf);
+ if (ht_insert(cfhashtab, name, cf)) {
+ error("configuration `%s' already defined", name);
+ free(cf);
+ goto bad;
+ }
+ *cf = *cf0;
+
+ /*
+ * Look for "swap generic".
+ */
+ for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next)
+ if (nv->nv_str == s_generic)
+ break;
+ if (nv != NULL) {
+ /*
+ * Make sure no root or dump device specified, and no
+ * other swap devices. Note single | here (check all).
+ */
+ nv = cf->cf_swap;
+ if (exclude(cf->cf_root, name, "root device") |
+ exclude(nv->nv_next, name, "additional swap devices") |
+ exclude(cf->cf_dump, name, "dump device"))
+ goto bad;
+ } else {
+ nv = cf->cf_root;
+ if (nv == NULL) {
+ error("%s: no root device specified", name);
+ goto bad;
+ }
+ if (resolve(&cf->cf_root, name, "root", nv, 'a') |
+ lresolve(&cf->cf_swap, name, "swap", nv, 'b') |
+ resolve(&cf->cf_dump, name, "dumps", nv, 'b'))
+ goto bad;
+ }
+ *nextcf = cf;
+ nextcf = &cf->cf_next;
+ return;
+bad:
+ nvfreel(cf0->cf_root);
+ nvfreel(cf0->cf_swap);
+ nvfreel(cf0->cf_dump);
+}
+
+void
+setconf(npp, what, v)
+ register struct nvlist **npp;
+ const char *what;
+ struct nvlist *v;
+{
+
+ if (*npp != NULL) {
+ error("duplicate %s specification", what);
+ nvfreel(v);
+ } else
+ *npp = v;
+}
+
+static struct devi *
+newdevi(name, unit, d)
+ const char *name;
+ int unit;
+ struct devbase *d;
+{
+ register struct devi *i;
+
+ i = emalloc(sizeof *i);
+ i->i_name = name;
+ i->i_unit = unit;
+ i->i_base = d;
+ i->i_next = NULL;
+ i->i_bsame = NULL;
+ i->i_alias = NULL;
+ i->i_at = NULL;
+ i->i_atattr = NULL;
+ i->i_atdev = NULL;
+ i->i_locs = NULL;
+ i->i_cfflags = 0;
+ i->i_lineno = currentline();
+ if (unit >= d->d_umax)
+ d->d_umax = unit + 1;
+ return (i);
+}
+
+/*
+ * Add the named device as attaching to the named attribute (or perhaps
+ * another device instead) plus unit number.
+ */
+void
+adddev(name, at, loclist, flags)
+ const char *name, *at;
+ struct nvlist *loclist;
+ int flags;
+{
+ register struct devi *i; /* the new instance */
+ register struct attr *attr; /* attribute that allows attach */
+ register struct devbase *ib; /* i->i_base */
+ register struct devbase *ab; /* not NULL => at another dev */
+ register struct nvlist *nv;
+ const char *cp;
+ int atunit;
+ char atbuf[NAMESIZE];
+
+ ab = NULL;
+ if (at == NULL) {
+ /* "at root" */
+ if ((i = getdevi(name)) == NULL)
+ goto bad;
+ /*
+ * Must warn about i_unit > 0 later, after taking care of
+ * the STAR cases (we could do non-star's here but why
+ * bother?). Make sure this device can be at root.
+ */
+ ib = i->i_base;
+ if (!onlist(ib->d_atlist, NULL)) {
+ error("%s's cannot attach to the root", ib->d_name);
+ goto bad;
+ }
+ attr = &errattr; /* a convenient "empty" attr */
+ } else {
+ if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
+ error("invalid attachment name `%s'", at);
+ /* (void)getdevi(name); -- ??? */
+ goto bad;
+ }
+ if ((i = getdevi(name)) == NULL)
+ goto bad;
+ ib = i->i_base;
+ cp = intern(atbuf);
+ if ((attr = ht_lookup(attrtab, cp)) == NULL) {
+ /*
+ * Have to work a bit harder to see whether we have
+ * something like "tg0 at esp0" (where esp is merely
+ * not an attribute) or "tg0 at nonesuch0" (where
+ * nonesuch is not even a device).
+ */
+ if ((ab = ht_lookup(devbasetab, cp)) == NULL) {
+ error("%s at %s: `%s' unknown",
+ name, at, atbuf);
+ goto bad;
+ }
+ /*
+ * See if the named parent carries an attribute
+ * that allows it to supervise device ib.
+ */
+ for (nv = ab->d_attrs; nv != NULL; nv = nv->nv_next) {
+ attr = nv->nv_ptr;
+ if (onlist(attr->a_devs, ib))
+ goto ok;
+ }
+ attr = &errattr;/* now onlist below will fail */
+ }
+ if (!onlist(attr->a_devs, ib)) {
+ error("%s's cannot attach to %s's", ib->d_name, atbuf);
+ goto bad;
+ }
+ }
+ok:
+ if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
+ goto bad;
+ if (i->i_unit == STAR && ib->d_vectors != NULL) {
+ error("%s's cannot be *'d as they have preset vectors",
+ ib->d_name);
+ goto bad;
+ }
+ i->i_at = at;
+ i->i_atattr = attr;
+ i->i_atdev = ab;
+ i->i_atunit = atunit;
+ i->i_cfflags = flags;
+ selectbase(ib);
+ /* all done, fall into ... */
+bad:
+ nvfreel(loclist);
+ return;
+}
+
+void
+addpseudo(name, number)
+ const char *name;
+ int number;
+{
+ register struct devbase *d;
+ register struct devi *i;
+
+ d = ht_lookup(devbasetab, name);
+ if (d == NULL) {
+ error("undefined pseudo-device %s", name);
+ return;
+ }
+ if (!d->d_ispseudo) {
+ error("%s is a real device, not a pseudo-device", name);
+ return;
+ }
+ if (ht_lookup(devitab, name) != NULL) {
+ error("`%s' already defined", name);
+ return;
+ }
+ i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */
+ if (ht_insert(devitab, name, i))
+ panic("addpseudo(%s)", name);
+ selectbase(d);
+ *nextpseudo = i;
+ nextpseudo = &i->i_next;
+ npseudo++;
+}
+
+/*
+ * Define a new instance of a specific device.
+ */
+static struct devi *
+getdevi(name)
+ const char *name;
+{
+ register struct devi *i, *firsti;
+ register struct devbase *d;
+ int unit;
+ char base[NAMESIZE];
+
+ if (split(name, strlen(name), base, sizeof base, &unit)) {
+ error("invalid device name `%s'", name);
+ return (NULL);
+ }
+ d = ht_lookup(devbasetab, intern(base));
+ if (d == NULL) {
+ error("%s: unknown device `%s'", name, base);
+ return (NULL);
+ }
+ if (d->d_ispseudo) {
+ error("%s: %s is a pseudo-device", name, base);
+ return (NULL);
+ }
+ firsti = ht_lookup(devitab, name);
+ i = newdevi(name, unit, d);
+ if (firsti == NULL) {
+ if (ht_insert(devitab, name, i))
+ panic("getdevi(%s)", name);
+ *d->d_ipp = i;
+ d->d_ipp = &i->i_bsame;
+ } else {
+ while (firsti->i_alias)
+ firsti = firsti->i_alias;
+ firsti->i_alias = i;
+ }
+ *nextdevi = i;
+ nextdevi = &i->i_next;
+ ndevi++;
+ return (i);
+}
+
+static const char *
+concat(name, c)
+ const char *name;
+ int c;
+{
+ register int len;
+ char buf[NAMESIZE];
+
+ len = strlen(name);
+ if (len + 2 > sizeof(buf)) {
+ error("device name `%s%c' too long", name, c);
+ len = sizeof(buf) - 2;
+ }
+ bcopy(name, buf, len);
+ buf[len] = c;
+ buf[len + 1] = 0;
+ return (intern(buf));
+}
+
+const char *
+starref(name)
+ const char *name;
+{
+
+ return (concat(name, '*'));
+}
+
+const char *
+wildref(name)
+ const char *name;
+{
+
+ return (concat(name, '?'));
+}
+
+/*
+ * Split a name like "foo0" into base name (foo) and unit number (0).
+ * Return 0 on success. To make this useful for names like "foo0a",
+ * the length of the "foo0" part is one of the arguments.
+ */
+static int
+split(name, nlen, base, bsize, aunit)
+ register const char *name;
+ size_t nlen;
+ char *base;
+ size_t bsize;
+ int *aunit;
+{
+ register const char *cp;
+ register int c, l;
+
+ l = nlen;
+ if (l < 2 || l >= bsize || isdigit(*name))
+ return (1);
+ c = (u_char)name[--l];
+ if (!isdigit(c)) {
+ if (c == '*')
+ *aunit = STAR;
+ else if (c == '?')
+ *aunit = WILD;
+ else
+ return (1);
+ } else {
+ cp = &name[l];
+ while (isdigit(cp[-1]))
+ l--, cp--;
+ *aunit = atoi(cp);
+ }
+ bcopy(name, base, l);
+ base[l] = 0;
+ return (0);
+}
+
+/*
+ * We have an instance of the base foo, so select it and all its
+ * attributes for "optional foo".
+ */
+static void
+selectbase(d)
+ register struct devbase *d;
+{
+ register struct attr *a;
+ register struct nvlist *nv;
+
+ (void)ht_insert(selecttab, d->d_name, (char *)d->d_name);
+ for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ (void)ht_insert(selecttab, a->a_name, (char *)a->a_name);
+ }
+}
+
+/*
+ * Is the given pointer on the given list of pointers?
+ */
+static int
+onlist(nv, ptr)
+ register struct nvlist *nv;
+ register void *ptr;
+{
+ for (; nv != NULL; nv = nv->nv_next)
+ if (nv->nv_ptr == ptr)
+ return (1);
+ return (0);
+}
+
+static char *
+extend(p, name)
+ register char *p;
+ const char *name;
+{
+ register int l;
+
+ l = strlen(name);
+ bcopy(name, p, l);
+ p += l;
+ *p++ = ',';
+ *p++ = ' ';
+ return (p);
+}
+
+/*
+ * Check that we got all required locators, and default any that are
+ * given as "?" and have defaults. Return 0 on success.
+ */
+static const char **
+fixloc(name, attr, got)
+ const char *name;
+ register struct attr *attr;
+ register struct nvlist *got;
+{
+ register struct nvlist *m, *n;
+ register int ord;
+ register const char **lp;
+ int nmissing, nextra, nnodefault;
+ char *mp, *ep, *ndp;
+ char missing[1000], extra[1000], nodefault[1000];
+ static const char *nullvec[1];
+
+ /*
+ * Look for all required locators, and number the given ones
+ * according to the required order. While we are numbering,
+ * set default values for defaulted locators.
+ */
+ if (attr->a_loclen == 0) /* e.g., "at root" */
+ lp = nullvec;
+ else
+ lp = emalloc((attr->a_loclen + 1) * sizeof(const char *));
+ for (n = got; n != NULL; n = n->nv_next)
+ n->nv_int = -1;
+ nmissing = 0;
+ mp = missing;
+ /* yes, this is O(mn), but m and n should be small */
+ for (ord = 0, m = attr->a_locs; m != NULL; m = m->nv_next, ord++) {
+ for (n = got; n != NULL; n = n->nv_next) {
+ if (n->nv_name == m->nv_name) {
+ n->nv_int = ord;
+ break;
+ }
+ }
+ if (n == NULL && m->nv_int == 0) {
+ nmissing++;
+ mp = extend(mp, m->nv_name);
+ }
+ lp[ord] = m->nv_str;
+ }
+ if (ord != attr->a_loclen)
+ panic("fixloc");
+ lp[ord] = NULL;
+ nextra = 0;
+ ep = extra;
+ nnodefault = 0;
+ ndp = nodefault;
+ for (n = got; n != NULL; n = n->nv_next) {
+ if (n->nv_int >= 0) {
+ if (n->nv_str != NULL)
+ lp[n->nv_int] = n->nv_str;
+ else if (lp[n->nv_int] == NULL) {
+ nnodefault++;
+ ndp = extend(ndp, n->nv_name);
+ }
+ } else {
+ nextra++;
+ ep = extend(ep, n->nv_name);
+ }
+ }
+ if (nextra) {
+ ep[-2] = 0; /* kill ", " */
+ error("%s: extraneous locator%s: %s",
+ name, nextra > 1 ? "s" : "", extra);
+ }
+ if (nmissing) {
+ mp[-2] = 0;
+ error("%s: must specify %s", name, missing);
+ }
+ if (nnodefault) {
+ ndp[-2] = 0;
+ error("%s: cannot wildcard %s", name, nodefault);
+ }
+ if (nmissing || nnodefault) {
+ free(lp);
+ lp = NULL;
+ }
+ return (lp);
+}
diff --git a/usr.sbin/config/sem.h b/usr.sbin/config/sem.h
new file mode 100644
index 00000000000..87b75e395e3
--- /dev/null
+++ b/usr.sbin/config/sem.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)sem.h 8.1 (Berkeley) 6/6/93
+ * $Id: sem.h,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+void enddefs __P((const char *));
+
+void setdefmaxusers __P((int, int, int));
+void setmaxusers __P((int));
+int defattr __P((const char *, struct nvlist *));
+void defdev __P((struct devbase *, int, struct nvlist *,
+ struct nvlist *, struct nvlist *, struct nvlist *));
+struct devbase *getdevbase __P((const char *name));
+struct attr *getattr __P((const char *name));
+void setmajor __P((struct devbase *d, int n));
+void addconf __P((struct config *));
+void setconf __P((struct nvlist **, const char *, struct nvlist *));
+void adddev __P((const char *, const char *, struct nvlist *, int));
+void addpseudo __P((const char *name, int number));
+const char *ref __P((const char *name));
+const char *starref __P((const char *name));
+const char *wildref __P((const char *name));
+
+extern const char *s_generic;
+extern const char *s_nfs;
diff --git a/usr.sbin/config/util.c b/usr.sbin/config/util.c
new file mode 100644
index 00000000000..095a7763bdf
--- /dev/null
+++ b/usr.sbin/config/util.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * from: @(#)util.c 8.1 (Berkeley) 6/6/93
+ * $Id: util.c,v 1.1.1.1 1995/10/18 08:48:34 deraadt Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <sys/types.h>
+#include "config.h"
+
+static void nomem __P((void));
+static void vxerror __P((const char *, int, const char *, va_list));
+
+/*
+ * Malloc, with abort on error.
+ */
+void *
+emalloc(size)
+ size_t size;
+{
+ void *p;
+
+ if ((p = malloc(size)) == NULL)
+ nomem();
+ return (p);
+}
+
+/*
+ * Realloc, with abort on error.
+ */
+void *
+erealloc(p, size)
+ void *p;
+ size_t size;
+{
+
+ if ((p = realloc(p, size)) == NULL)
+ nomem();
+ return (p);
+}
+
+static void
+nomem()
+{
+
+ (void)fprintf(stderr, "config: out of memory\n");
+ exit(1);
+}
+
+/*
+ * Prepend the compilation directory to a file name.
+ */
+char *
+path(file)
+ const char *file;
+{
+ register char *cp;
+#define CDIR "../compile/"
+
+ if (file == NULL) {
+ cp = emalloc(sizeof(CDIR) + strlen(confdirbase));
+ (void)sprintf(cp, "%s%s", CDIR, confdirbase);
+ } else {
+ cp = emalloc(sizeof(CDIR) + strlen(confdirbase) + 1 +
+ strlen(file));
+ (void)sprintf(cp, "%s%s/%s", CDIR, confdirbase, file);
+ }
+ return (cp);
+}
+
+static struct nvlist *nvhead;
+
+struct nvlist *
+newnv(name, str, ptr, i)
+ const char *name, *str;
+ void *ptr;
+ int i;
+{
+ register struct nvlist *nv;
+
+ if ((nv = nvhead) == NULL)
+ nv = emalloc(sizeof(*nv));
+ else
+ nvhead = nv->nv_next;
+ nv->nv_next = NULL;
+ nv->nv_name = name;
+ if (ptr == NULL)
+ nv->nv_str = str;
+ else {
+ if (str != NULL)
+ panic("newnv");
+ nv->nv_ptr = ptr;
+ }
+ nv->nv_int = i;
+ return (nv);
+}
+
+/*
+ * Free an nvlist structure (just one).
+ */
+void
+nvfree(nv)
+ register struct nvlist *nv;
+{
+
+ nv->nv_next = nvhead;
+ nvhead = nv;
+}
+
+/*
+ * Free an nvlist (the whole list).
+ */
+void
+nvfreel(nv)
+ register struct nvlist *nv;
+{
+ register struct nvlist *next;
+
+ for (; nv != NULL; nv = next) {
+ next = nv->nv_next;
+ nv->nv_next = nvhead;
+ nvhead = nv;
+ }
+}
+
+/*
+ * External (config file) error. Complain, using current file
+ * and line number.
+ */
+void
+#if __STDC__
+error(const char *fmt, ...)
+#else
+error(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ extern const char *yyfile;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vxerror(yyfile, currentline(), fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Delayed config file error (i.e., something was wrong but we could not
+ * find out about it until later).
+ */
+void
+#if __STDC__
+xerror(const char *file, int line, const char *fmt, ...)
+#else
+xerror(file, line, fmt, va_alist)
+ const char *file;
+ int line;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vxerror(file, line, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Internal form of error() and xerror().
+ */
+static void
+vxerror(file, line, fmt, ap)
+ const char *file;
+ int line;
+ const char *fmt;
+ va_list ap;
+{
+
+ (void)fprintf(stderr, "%s:%d: ", file, line);
+ (void)vfprintf(stderr, fmt, ap);
+ (void)putc('\n', stderr);
+ errors++;
+}
+
+/*
+ * Internal error, abort.
+ */
+__dead void
+#if __STDC__
+panic(const char *fmt, ...)
+#else
+panic(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "config: panic: ");
+ (void)vfprintf(stderr, fmt, ap);
+ (void)putc('\n', stderr);
+ va_end(ap);
+ exit(2);
+}
diff --git a/usr.sbin/cron/Makefile b/usr.sbin/cron/Makefile
new file mode 100644
index 00000000000..b14743dc4b3
--- /dev/null
+++ b/usr.sbin/cron/Makefile
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+
+PROG= cron
+SRCS= cron.c database.c user.c entry.c job.c do_command.c \
+ misc.c env.c popen.c
+CFLAGS+=-I${.CURDIR}
+MAN= cron.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/cron/compat.c b/usr.sbin/cron/compat.c
new file mode 100644
index 00000000000..67814253d9b
--- /dev/null
+++ b/usr.sbin/cron/compat.c
@@ -0,0 +1,233 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: compat.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+/* vix 30dec93 [broke this out of misc.c - see RCS log for history]
+ * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
+ */
+
+
+#include "cron.h"
+#ifdef NEED_GETDTABLESIZE
+# include <limits.h>
+#endif
+#if defined(NEED_SETSID) && defined(BSD)
+# include <sys/ioctl.h>
+#endif
+#include <errno.h>
+
+
+/* the code does not depend on any of vfork's
+ * side-effects; it just uses it as a quick
+ * fork-and-exec.
+ */
+#ifdef NEED_VFORK
+PID_T
+vfork() {
+ return (fork());
+}
+#endif
+
+
+#ifdef NEED_STRDUP
+char *
+strdup(str)
+ char *str;
+{
+ char *temp;
+
+ temp = malloc(strlen(str) + 1);
+ (void) strcpy(temp, str);
+ return temp;
+}
+#endif
+
+
+#ifdef NEED_STRERROR
+char *
+strerror(error)
+ int error;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ static char buf[32];
+
+ if ((error <= sys_nerr) && (error > 0)) {
+ return sys_errlist[error];
+ }
+
+ sprintf(buf, "Unknown error: %d", error);
+ return buf;
+}
+#endif
+
+
+#ifdef NEED_STRCASECMP
+int
+strcasecmp(left, right)
+ char *left;
+ char *right;
+{
+ while (*left && (MkLower(*left) == MkLower(*right))) {
+ left++;
+ right++;
+ }
+ return MkLower(*left) - MkLower(*right);
+}
+#endif
+
+
+#ifdef NEED_SETSID
+int
+setsid()
+{
+ int newpgrp;
+# if defined(BSD)
+ int fd;
+# if defined(POSIX)
+ newpgrp = setpgid((pid_t)0, getpid());
+# else
+ newpgrp = setpgrp(0, getpid());
+# endif
+ if ((fd = open("/dev/tty", 2)) >= 0)
+ {
+ (void) ioctl(fd, TIOCNOTTY, (char*)0);
+ (void) close(fd);
+ }
+# else /*BSD*/
+ newpgrp = setpgrp();
+
+ (void) close(STDIN); (void) open("/dev/null", 0);
+ (void) close(STDOUT); (void) open("/dev/null", 1);
+ (void) close(STDERR); (void) open("/dev/null", 2);
+# endif /*BSD*/
+ return newpgrp;
+}
+#endif /*NEED_SETSID*/
+
+
+#ifdef NEED_GETDTABLESIZE
+int
+getdtablesize() {
+#ifdef _SC_OPEN_MAX
+ return sysconf(_SC_OPEN_MAX);
+#else
+ return _POSIX_OPEN_MAX;
+#endif
+}
+#endif
+
+
+#ifdef NEED_FLOCK
+/* The following flock() emulation snarfed intact *) from the HP-UX
+ * "BSD to HP-UX porting tricks" maintained by
+ * system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson))
+ * from the version "last updated: 11-Jan-1993"
+ * Snarfage done by Jarkko Hietaniemi <Jarkko.Hietaniemi@hut.fi>
+ * *) well, almost, had to K&R the function entry, HPUX "cc"
+ * does not grok ANSI function prototypes */
+
+/*
+ * flock (fd, operation)
+ *
+ * This routine performs some file locking like the BSD 'flock'
+ * on the object described by the int file descriptor 'fd',
+ * which must already be open.
+ *
+ * The operations that are available are:
+ *
+ * LOCK_SH - get a shared lock.
+ * LOCK_EX - get an exclusive lock.
+ * LOCK_NB - don't block (must be ORed with LOCK_SH or LOCK_EX).
+ * LOCK_UN - release a lock.
+ *
+ * Return value: 0 if lock successful, -1 if failed.
+ *
+ * Note that whether the locks are enforced or advisory is
+ * controlled by the presence or absence of the SETGID bit on
+ * the executable.
+ *
+ * Note that there is no difference between shared and exclusive
+ * locks, since the 'lockf' system call in SYSV doesn't make any
+ * distinction.
+ *
+ * The file "<sys/file.h>" should be modified to contain the definitions
+ * of the available operations, which must be added manually (see below
+ * for the values).
+ */
+
+/* this code has been reformatted by vixie */
+
+int
+flock(fd, operation)
+ int fd;
+ int operation;
+{
+ int i;
+
+ switch (operation) {
+ case LOCK_SH: /* get a shared lock */
+ case LOCK_EX: /* get an exclusive lock */
+ i = lockf (fd, F_LOCK, 0);
+ break;
+
+ case LOCK_SH|LOCK_NB: /* get a non-blocking shared lock */
+ case LOCK_EX|LOCK_NB: /* get a non-blocking exclusive lock */
+ i = lockf (fd, F_TLOCK, 0);
+ if (i == -1)
+ if ((errno == EAGAIN) || (errno == EACCES))
+ errno = EWOULDBLOCK;
+ break;
+
+ case LOCK_UN: /* unlock */
+ i = lockf (fd, F_ULOCK, 0);
+ break;
+
+ default: /* can't decipher operation */
+ i = -1;
+ errno = EINVAL;
+ break;
+ }
+
+ return (i);
+}
+#endif /*NEED_FLOCK*/
+
+
+#ifdef NEED_SETENV
+int
+setenv(name, value, overwrite)
+ char *name, *value;
+ int overwrite;
+{
+ char *tmp;
+
+ if (overwrite && getenv(name))
+ return -1;
+
+ if (!(tmp = malloc(strlen(name) + strlen(value) + 2))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ sprintf("%s=%s", name, value);
+ return putenv(tmp); /* intentionally orphan 'tmp' storage */
+}
+#endif
diff --git a/usr.sbin/cron/compat.h b/usr.sbin/cron/compat.h
new file mode 100644
index 00000000000..c3015064682
--- /dev/null
+++ b/usr.sbin/cron/compat.h
@@ -0,0 +1,137 @@
+/* Copyright 1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+/*
+ * $Id: compat.h,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+ */
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# define const
+# endif
+#endif
+
+#if defined(UNIXPC) || defined(unixpc)
+# define UNIXPC 1
+# define ATT 1
+#endif
+
+#if defined(hpux) || defined(_hpux) || defined(__hpux)
+# define HPUX 1
+# define seteuid(e) setresuid(-1,e,-1)
+# define setreuid(r,e) setresuid(r,e,-1)
+#endif
+
+#if defined(_IBMR2)
+# define AIX 1
+#endif
+
+#if defined(__convex__)
+# define CONVEX 1
+#endif
+
+#if defined(sgi) || defined(_sgi) || defined(__sgi)
+# define IRIX 1
+/* IRIX 4 hdrs are broken: one cannot #include both <stdio.h>
+ * and <stdlib.h> because they disagree on system(), perror().
+ * Therefore we must zap the "const" keyword BEFORE including
+ * either of them.
+ */
+# define const
+#endif
+
+#if defined(_UNICOS)
+# define UNICOS 1
+#endif
+
+#ifndef POSIX
+# if (BSD >= 199103) || defined(__linux) || defined(ultrix) || defined(AIX) ||\
+ defined(HPUX) || defined(CONVEX) || defined(IRIX)
+# define POSIX
+# endif
+#endif
+
+#ifndef BSD
+# if defined(ultrix)
+# define BSD 198902
+# endif
+#endif
+
+/*****************************************************************/
+
+#if !defined(BSD) && !defined(HPUX) && !defined(CONVEX) && !defined(__linux)
+# define NEED_VFORK
+#endif
+
+#if (!defined(BSD) || (BSD < 198902)) && !defined(__linux) && \
+ !defined(IRIX) && !defined(NeXT) && !defined(HPUX)
+# define NEED_STRCASECMP
+#endif
+
+#if (!defined(BSD) || (BSD < 198911)) && !defined(__linux) &&\
+ !defined(IRIX) && !defined(UNICOS) && !defined(HPUX)
+# define NEED_STRDUP
+#endif
+
+#if (!defined(BSD) || (BSD < 198911)) && !defined(POSIX) && !defined(NeXT)
+# define NEED_STRERROR
+#endif
+
+#if defined(HPUX) || defined(AIX) || defined(UNIXPC)
+# define NEED_FLOCK
+#endif
+
+#ifndef POSIX
+# define NEED_SETSID
+#endif
+
+#if (defined(POSIX) && !defined(BSD)) && !defined(__linux)
+# define NEED_GETDTABLESIZE
+#endif
+
+#if (BSD >= 199103)
+# define HAVE_SAVED_UIDS
+#endif
+
+#if !defined(ATT) && !defined(__linux) && !defined(IRIX) && !defined(UNICOS)
+# define USE_SIGCHLD
+#endif
+
+#if !defined(AIX) && !defined(UNICOS)
+# define SYS_TIME_H 1
+#else
+# define SYS_TIME_H 0
+#endif
+
+#if defined(BSD) && !defined(POSIX)
+# define USE_UTIMES
+#endif
+
+#if defined(AIX) || defined(HPUX) || defined(IRIX)
+# define NEED_SETENV
+#endif
+
+#if !defined(UNICOS) && !defined(UNIXPC)
+# define HAS_FCHOWN
+#endif
+
+#if !defined(UNICOS) && !defined(UNIXPC)
+# define HAS_FCHMOD
+#endif
diff --git a/usr.sbin/cron/config.h b/usr.sbin/cron/config.h
new file mode 100644
index 00000000000..26f93527199
--- /dev/null
+++ b/usr.sbin/cron/config.h
@@ -0,0 +1,87 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+/* config.h - configurables for Vixie Cron
+ *
+ * $Id: config.h,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+ */
+
+#if !defined(_PATH_SENDMAIL)
+# define _PATH_SENDMAIL "/usr/lib/sendmail"
+#endif /*SENDMAIL*/
+
+/*
+ * these are site-dependent
+ */
+
+#ifndef DEBUGGING
+#define DEBUGGING 1 /* 1 or 0 -- do you want debugging code built in? */
+#endif
+
+ /*
+ * choose one of these MAILCMD commands. I use
+ * /bin/mail for speed; it makes biff bark but doesn't
+ * do aliasing. /usr/lib/sendmail does aliasing but is
+ * a hog for short messages. aliasing is not needed
+ * if you make use of the MAILTO= feature in crontabs.
+ * (hint: MAILTO= was added for this reason).
+ */
+
+#define MAILCMD _PATH_SENDMAIL /*-*/
+#define MAILARGS "%s -FCronDaemon -odi -oem -oi -or0s -t" /*-*/
+ /* -Fx = set full-name of sender
+ * -odi = Option Deliverymode Interactive
+ * -oem = Option Errors Mailedtosender
+ * -or0s = Option Readtimeout -- don't time out
+ * -t = read recipient from header of message
+ */
+
+/* #define MAILCMD "/bin/mail" /*-*/
+/* #define MAILARGS "%s -d %s" /*-*/
+ /* -d = undocumented but common flag: deliver locally?
+ */
+
+/* #define MAILCMD "/usr/mmdf/bin/submit" /*-*/
+/* #define MAILARGS "%s -mlrxto %s" /*-*/
+
+/* #define MAIL_DATE /*-*/
+ /* should we include an ersatz Date: header in
+ * generated mail? if you are using sendmail
+ * for MAILCMD, it is better to let sendmail
+ * generate the Date: header.
+ */
+
+ /* if ALLOW_FILE and DENY_FILE are not defined or are
+ * defined but neither exists, should crontab(1) be
+ * usable only by root?
+ */
+/*#define ALLOW_ONLY_ROOT /*-*/
+
+ /* if you want to use syslog(3) instead of appending
+ * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
+ * SYSLOG here. Note that quite a bit of logging
+ * info is written, and that you probably don't want
+ * to use this on 4.2bsd since everything goes in
+ * /usr/spool/mqueue/syslog. On 4.[34]bsd you can
+ * tell /etc/syslog.conf to send cron's logging to
+ * a separate file.
+ *
+ * Note that if this and LOG_FILE in "pathnames.h"
+ * are both defined, then logging will go to both
+ * places.
+ */
+#define SYSLOG /*-*/
diff --git a/usr.sbin/cron/cron.8 b/usr.sbin/cron/cron.8
new file mode 100644
index 00000000000..fd1f960777a
--- /dev/null
+++ b/usr.sbin/cron/cron.8
@@ -0,0 +1,61 @@
+.\"/* Copyright 1988,1990,1993 by Paul Vixie
+.\" * All rights reserved
+.\" *
+.\" * Distribute freely, except: don't remove my name from the source or
+.\" * documentation (don't take credit for my work), mark your changes (don't
+.\" * get me blamed for your possible bugs), don't alter or remove this
+.\" * notice. May be sold if buildable source is provided to buyer. No
+.\" * warrantee of any kind, express or implied, is included with this
+.\" * software; use at your own risk, responsibility for damages (if any) to
+.\" * anyone resulting from the use of this software rests entirely with the
+.\" * user.
+.\" *
+.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+.\" * I'll try to keep a version up to date. I can be reached as follows:
+.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+.\" */
+.\"
+.\" $Id: cron.8,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+.\"
+.TH CRON 8 "20 December 1993"
+.UC 4
+.SH NAME
+cron \- daemon to execute scheduled commands (Vixie Cron)
+.SH SYNOPSIS
+cron
+.SH DESCRIPTION
+.I Cron
+should be started from /etc/rc or /etc/rc.local. It will return immediately,
+so you don't need to start it with '&'.
+.PP
+.I Cron
+searches /var/cron/tabs for crontab files which are named after accounts in
+/etc/passwd; crontabs found are loaded into memory.
+.I Cron
+also searches for /etc/crontab which is in a different format (see
+.IR crontab(5)).
+.I Cron
+then wakes up every minute, examining all stored crontabs, checking each
+command to see if it should be run in the current minute. When executing
+commands, any output is mailed to the owner of the crontab (or to the user
+named in the MAILTO environment variable in the crontab, if such exists).
+.PP
+Additionally,
+.I cron
+checks each minute to see if its spool directory's modtime (or the modtime
+on
+.IR /etc/crontab)
+has changed, and if it has,
+.I cron
+will then examine the modtime on all crontabs and reload those which have
+changed. Thus
+.I cron
+need not be restarted whenever a crontab file is modified. Note that the
+.IR Crontab (1)
+command updates the modtime of the spool directory whenever it changes a
+crontab.
+.SH "SEE ALSO"
+crontab(1), crontab(5)
+.SH AUTHOR
+.nf
+Paul Vixie <paul@vix.com>
diff --git a/usr.sbin/cron/cron.c b/usr.sbin/cron/cron.c
new file mode 100644
index 00000000000..0b9aac8c1ae
--- /dev/null
+++ b/usr.sbin/cron/cron.c
@@ -0,0 +1,301 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: cron.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+
+#define MAIN_PROGRAM
+
+
+#include "cron.h"
+#include <sys/signal.h>
+#if SYS_TIME_H
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+
+
+static void usage __P((void)),
+ run_reboot_jobs __P((cron_db *)),
+ cron_tick __P((cron_db *)),
+ cron_sync __P((void)),
+ cron_sleep __P((void)),
+#ifdef USE_SIGCHLD
+ sigchld_handler __P((int)),
+#endif
+ sighup_handler __P((int)),
+ parse_args __P((int c, char *v[]));
+
+
+static void
+usage() {
+ fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
+ exit(ERROR_EXIT);
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ cron_db database;
+
+ ProgramName = argv[0];
+
+#if defined(BSD)
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+#endif
+
+ parse_args(argc, argv);
+
+#ifdef USE_SIGCHLD
+ (void) signal(SIGCHLD, sigchld_handler);
+#else
+ (void) signal(SIGCLD, SIG_IGN);
+#endif
+ (void) signal(SIGHUP, sighup_handler);
+
+ acquire_daemonlock(0);
+ set_cron_uid();
+ set_cron_cwd();
+
+#if defined(POSIX)
+ setenv("PATH", _PATH_DEFPATH, 1);
+#endif
+
+ /* if there are no debug flags turned on, fork as a daemon should.
+ */
+# if DEBUGGING
+ if (DebugFlags) {
+# else
+ if (0) {
+# endif
+ (void) fprintf(stderr, "[%d] cron started\n", getpid());
+ } else {
+ switch (fork()) {
+ case -1:
+ log_it("CRON",getpid(),"DEATH","can't fork");
+ exit(0);
+ break;
+ case 0:
+ /* child process */
+ log_it("CRON",getpid(),"STARTUP","fork ok");
+ (void) setsid();
+ break;
+ default:
+ /* parent process should just die */
+ _exit(0);
+ }
+ }
+
+ acquire_daemonlock(0);
+ database.head = NULL;
+ database.tail = NULL;
+ database.mtime = (time_t) 0;
+ load_database(&database);
+ run_reboot_jobs(&database);
+ cron_sync();
+ while (TRUE) {
+# if DEBUGGING
+ if (!(DebugFlags & DTEST))
+# endif /*DEBUGGING*/
+ cron_sleep();
+
+ load_database(&database);
+
+ /* do this iteration
+ */
+ cron_tick(&database);
+
+ /* sleep 1 minute
+ */
+ TargetTime += 60;
+ }
+}
+
+
+static void
+run_reboot_jobs(db)
+ cron_db *db;
+{
+ register user *u;
+ register entry *e;
+
+ for (u = db->head; u != NULL; u = u->next) {
+ for (e = u->crontab; e != NULL; e = e->next) {
+ if (e->flags & WHEN_REBOOT) {
+ job_add(e, u);
+ }
+ }
+ }
+ (void) job_runqueue();
+}
+
+
+static void
+cron_tick(db)
+ cron_db *db;
+{
+ register struct tm *tm = localtime(&TargetTime);
+ register int minute, hour, dom, month, dow;
+ register user *u;
+ register entry *e;
+
+ /* make 0-based values out of these so we can use them as indicies
+ */
+ minute = tm->tm_min -FIRST_MINUTE;
+ hour = tm->tm_hour -FIRST_HOUR;
+ dom = tm->tm_mday -FIRST_DOM;
+ month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
+ dow = tm->tm_wday -FIRST_DOW;
+
+ Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
+ getpid(), minute, hour, dom, month, dow))
+
+ /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
+ * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
+ * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
+ * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
+ * like many bizarre things, it's the standard.
+ */
+ for (u = db->head; u != NULL; u = u->next) {
+ for (e = u->crontab; e != NULL; e = e->next) {
+ Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
+ env_get("LOGNAME", e->envp),
+ e->uid, e->gid, e->cmd))
+ if (bit_test(e->minute, minute)
+ && bit_test(e->hour, hour)
+ && bit_test(e->month, month)
+ && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
+ ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
+ : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
+ )
+ ) {
+ job_add(e, u);
+ }
+ }
+ }
+}
+
+
+/* the task here is to figure out how long it's going to be until :00 of the
+ * following minute and initialize TargetTime to this value. TargetTime
+ * will subsequently slide 60 seconds at a time, with correction applied
+ * implicitly in cron_sleep(). it would be nice to let cron execute in
+ * the "current minute" before going to sleep, but by restarting cron you
+ * could then get it to execute a given minute's jobs more than once.
+ * instead we have the chance of missing a minute's jobs completely, but
+ * that's something sysadmin's know to expect what with crashing computers..
+ */
+static void
+cron_sync() {
+ register struct tm *tm;
+
+ TargetTime = time((time_t*)0);
+ tm = localtime(&TargetTime);
+ TargetTime += (60 - tm->tm_sec);
+}
+
+
+static void
+cron_sleep() {
+ register int seconds_to_wait;
+
+ do {
+ seconds_to_wait = (int) (TargetTime - time((time_t*)0));
+ Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
+ getpid(), TargetTime, seconds_to_wait))
+
+ /* if we intend to sleep, this means that it's finally
+ * time to empty the job queue (execute it).
+ *
+ * if we run any jobs, we'll probably screw up our timing,
+ * so go recompute.
+ *
+ * note that we depend here on the left-to-right nature
+ * of &&, and the short-circuiting.
+ */
+ } while (seconds_to_wait > 0 && job_runqueue());
+
+ while (seconds_to_wait > 0) {
+ Debug(DSCH, ("[%d] sleeping for %d seconds\n",
+ getpid(), seconds_to_wait))
+ seconds_to_wait = (int) sleep((unsigned int) seconds_to_wait);
+ }
+}
+
+
+#ifdef USE_SIGCHLD
+static void
+sigchld_handler(x) {
+ WAIT_T waiter;
+ PID_T pid;
+
+ for (;;) {
+#ifdef POSIX
+ pid = waitpid(-1, &waiter, WNOHANG);
+#else
+ pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
+#endif
+ switch (pid) {
+ case -1:
+ Debug(DPROC,
+ ("[%d] sigchld...no children\n", getpid()))
+ return;
+ case 0:
+ Debug(DPROC,
+ ("[%d] sigchld...no dead kids\n", getpid()))
+ return;
+ default:
+ Debug(DPROC,
+ ("[%d] sigchld...pid #%d died, stat=%d\n",
+ getpid(), pid, WEXITSTATUS(waiter)))
+ }
+ }
+}
+#endif /*USE_SIGCHLD*/
+
+
+static void
+sighup_handler(x) {
+ log_close();
+}
+
+
+static void
+parse_args(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int argch;
+
+ while (EOF != (argch = getopt(argc, argv, "x:"))) {
+ switch (argch) {
+ default:
+ usage();
+ case 'x':
+ if (!set_debug_flags(optarg))
+ usage();
+ break;
+ }
+ }
+}
diff --git a/usr.sbin/cron/cron.h b/usr.sbin/cron/cron.h
new file mode 100644
index 00000000000..9e92554a308
--- /dev/null
+++ b/usr.sbin/cron/cron.h
@@ -0,0 +1,277 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+/* cron.h - header for vixie's cron
+ *
+ * $Id: cron.h,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+ *
+ * vix 14nov88 [rest of log is in RCS]
+ * vix 14jan87 [0 or 7 can be sunday; thanks, mwm@berkeley]
+ * vix 30dec86 [written]
+ */
+
+/* reorder these #include's at your peril */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include "compat.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <bitstring.h>
+#include <pwd.h>
+#include <sys/wait.h>
+
+#include "pathnames.h"
+#include "config.h"
+#include "externs.h"
+
+ /* these are really immutable, and are
+ * defined for symbolic convenience only
+ * TRUE, FALSE, and ERR must be distinct
+ * ERR must be < OK.
+ */
+#define TRUE 1
+#define FALSE 0
+ /* system calls return this on success */
+#define OK 0
+ /* or this on error */
+#define ERR (-1)
+
+ /* turn this on to get '-x' code */
+#ifndef DEBUGGING
+#define DEBUGGING FALSE
+#endif
+
+#define READ_PIPE 0 /* which end of a pipe pair do you read? */
+#define WRITE_PIPE 1 /* or write to? */
+#define STDIN 0 /* what is stdin's file descriptor? */
+#define STDOUT 1 /* stdout's? */
+#define STDERR 2 /* stderr's? */
+#define ERROR_EXIT 1 /* exit() with this will scare the shell */
+#define OK_EXIT 0 /* exit() with this is considered 'normal' */
+#define MAX_FNAME 100 /* max length of internally generated fn */
+#define MAX_COMMAND 1000 /* max length of internally generated cmd */
+#define MAX_ENVSTR 1000 /* max length of envvar=value\0 strings */
+#define MAX_TEMPSTR 100 /* obvious */
+#define MAX_UNAME 20 /* max length of username, should be overkill */
+#define ROOT_UID 0 /* don't change this, it really must be root */
+#define ROOT_USER "root" /* ditto */
+
+ /* NOTE: these correspond to DebugFlagNames,
+ * defined below.
+ */
+#define DEXT 0x0001 /* extend flag for other debug masks */
+#define DSCH 0x0002 /* scheduling debug mask */
+#define DPROC 0x0004 /* process control debug mask */
+#define DPARS 0x0008 /* parsing debug mask */
+#define DLOAD 0x0010 /* database loading debug mask */
+#define DMISC 0x0020 /* misc debug mask */
+#define DTEST 0x0040 /* test mode: don't execute any commands */
+#define DBIT 0x0080 /* bit twiddling shown (long) */
+
+#define CRON_TAB(u) "%s/%s", SPOOL_DIR, u
+#define REG register
+#define PPC_NULL ((char **)NULL)
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define Skip_Blanks(c, f) \
+ while (c == '\t' || c == ' ') \
+ c = get_char(f);
+
+#define Skip_Nonblanks(c, f) \
+ while (c!='\t' && c!=' ' && c!='\n' && c != EOF) \
+ c = get_char(f);
+
+#define Skip_Line(c, f) \
+ do {c = get_char(f);} while (c != '\n' && c != EOF);
+
+#if DEBUGGING
+# define Debug(mask, message) \
+ if ( (DebugFlags & (mask) ) == (mask) ) \
+ printf message;
+#else /* !DEBUGGING */
+# define Debug(mask, message) \
+ ;
+#endif /* DEBUGGING */
+
+#define MkLower(ch) (isupper(ch) ? tolower(ch) : ch)
+#define MkUpper(ch) (islower(ch) ? toupper(ch) : ch)
+#define Set_LineNum(ln) {Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
+ LineNumber = ln; \
+ }
+
+#define FIRST_MINUTE 0
+#define LAST_MINUTE 59
+#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
+
+#define FIRST_HOUR 0
+#define LAST_HOUR 23
+#define HOUR_COUNT (LAST_HOUR - FIRST_HOUR + 1)
+
+#define FIRST_DOM 1
+#define LAST_DOM 31
+#define DOM_COUNT (LAST_DOM - FIRST_DOM + 1)
+
+#define FIRST_MONTH 1
+#define LAST_MONTH 12
+#define MONTH_COUNT (LAST_MONTH - FIRST_MONTH + 1)
+
+/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
+#define FIRST_DOW 0
+#define LAST_DOW 7
+#define DOW_COUNT (LAST_DOW - FIRST_DOW + 1)
+
+ /* each user's crontab will be held as a list of
+ * the following structure.
+ *
+ * These are the cron commands.
+ */
+
+typedef struct _entry {
+ struct _entry *next;
+ uid_t uid;
+ gid_t gid;
+ char **envp;
+ char *cmd;
+ bitstr_t bit_decl(minute, MINUTE_COUNT);
+ bitstr_t bit_decl(hour, HOUR_COUNT);
+ bitstr_t bit_decl(dom, DOM_COUNT);
+ bitstr_t bit_decl(month, MONTH_COUNT);
+ bitstr_t bit_decl(dow, DOW_COUNT);
+ int flags;
+#define DOM_STAR 0x01
+#define DOW_STAR 0x02
+#define WHEN_REBOOT 0x04
+} entry;
+
+ /* the crontab database will be a list of the
+ * following structure, one element per user
+ * plus one for the system.
+ *
+ * These are the crontabs.
+ */
+
+typedef struct _user {
+ struct _user *next, *prev; /* links */
+ char *name;
+ time_t mtime; /* last modtime of crontab */
+ entry *crontab; /* this person's crontab */
+} user;
+
+typedef struct _cron_db {
+ user *head, *tail; /* links */
+ time_t mtime; /* last modtime on spooldir */
+} cron_db;
+
+
+void set_cron_uid __P((void)),
+ set_cron_cwd __P((void)),
+ load_database __P((cron_db *)),
+ open_logfile __P((void)),
+ sigpipe_func __P((void)),
+ job_add __P((entry *, user *)),
+ do_command __P((entry *, user *)),
+ link_user __P((cron_db *, user *)),
+ unlink_user __P((cron_db *, user *)),
+ free_user __P((user *)),
+ env_free __P((char **)),
+ unget_char __P((int, FILE *)),
+ free_entry __P((entry *)),
+ acquire_daemonlock __P((int)),
+ skip_comments __P((FILE *)),
+ log_it __P((char *, int, char *, char *)),
+ log_close __P((void));
+
+int job_runqueue __P((void)),
+ set_debug_flags __P((char *)),
+ get_char __P((FILE *)),
+ get_string __P((char *, int, FILE *, char *)),
+ swap_uids __P((void)),
+ load_env __P((char *, FILE *)),
+ cron_pclose __P((FILE *)),
+ strcmp_until __P((char *, char *, int)),
+ allowed __P((char *)),
+ strdtb __P((char *));
+
+char *env_get __P((char *, char **)),
+ *arpadate __P((time_t *)),
+ *mkprints __P((unsigned char *, unsigned int)),
+ *first_word __P((char *, char *)),
+ **env_init __P((void)),
+ **env_copy __P((char **)),
+ **env_set __P((char **, char *));
+
+user *load_user __P((int, struct passwd *, char *)),
+ *find_user __P((cron_db *, char *));
+
+entry *load_entry __P((FILE *, void (*)(),
+ struct passwd *, char **));
+
+FILE *cron_popen __P((char *, char *));
+
+
+ /* in the C tradition, we only create
+ * variables for the main program, just
+ * extern them elsewhere.
+ */
+
+#ifdef MAIN_PROGRAM
+# if !defined(LINT) && !defined(lint)
+char *copyright[] = {
+ "@(#) Copyright 1988,1989,1990,1993,1994 by Paul Vixie",
+ "@(#) All rights reserved"
+ };
+# endif
+
+char *MonthNames[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ NULL
+ };
+
+char *DowNames[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
+ NULL
+ };
+
+char *ProgramName;
+int LineNumber;
+time_t TargetTime;
+
+# if DEBUGGING
+int DebugFlags;
+char *DebugFlagNames[] = { /* sync with #defines */
+ "ext", "sch", "proc", "pars", "load", "misc", "test", "bit",
+ NULL /* NULL must be last element */
+ };
+# endif /* DEBUGGING */
+#else /*MAIN_PROGRAM*/
+extern char *copyright[],
+ *MonthNames[],
+ *DowNames[],
+ *ProgramName;
+extern int LineNumber;
+extern time_t TargetTime;
+# if DEBUGGING
+extern int DebugFlags;
+extern char *DebugFlagNames[];
+# endif /* DEBUGGING */
+#endif /*MAIN_PROGRAM*/
diff --git a/usr.sbin/cron/crontab.1 b/usr.sbin/cron/crontab.1
new file mode 100644
index 00000000000..135d309d585
--- /dev/null
+++ b/usr.sbin/cron/crontab.1
@@ -0,0 +1,100 @@
+.\"/* Copyright 1988,1990,1993 by Paul Vixie
+.\" * All rights reserved
+.\" *
+.\" * Distribute freely, except: don't remove my name from the source or
+.\" * documentation (don't take credit for my work), mark your changes (don't
+.\" * get me blamed for your possible bugs), don't alter or remove this
+.\" * notice. May be sold if buildable source is provided to buyer. No
+.\" * warrantee of any kind, express or implied, is included with this
+.\" * software; use at your own risk, responsibility for damages (if any) to
+.\" * anyone resulting from the use of this software rests entirely with the
+.\" * user.
+.\" *
+.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+.\" * I'll try to keep a version up to date. I can be reached as follows:
+.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+.\" */
+.\"
+.\" $Id: crontab.1,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+.\"
+.TH CRONTAB 1 "29 December 1993"
+.UC 4
+.SH NAME
+crontab \- maintain crontab files for individual users (V3)
+.SH SYNOPSIS
+crontab [ -u user ] file
+.br
+crontab [ -u user ] [ -l | -r | -e ]
+.SH DESCRIPTION
+.I Crontab
+is the program used to install, deinstall or list the tables
+used to drive the
+.IR cron (8)
+daemon in Vixie Cron. Each user can have their own crontab, and though
+these are files in /var, they are not intended to be edited directly.
+.PP
+If the
+.I allow
+file exists, then you must be listed therein in order to be allowed to use
+this command. If the
+.I allow
+file does not exist but the
+.I deny
+file does exist, then you must \fBnot\fR be listed in the
+.I deny
+file in order to use this command. If neither of these files exists, then
+depending on site-dependent configuration parameters, only the super user
+will be allowed to use this command, or all users will be able to use this
+command.
+.PP
+If the
+.I -u
+option is given, it specifies the name of the user whose crontab is to be
+tweaked. If this option is not given,
+.I crontab
+examines "your" crontab, i.e., the crontab of the person executing the
+command. Note that
+.IR su (8)
+can confuse
+.I crontab
+and that if you are running inside of
+.IR su (8)
+you should always use the
+.I -u
+option for safety's sake.
+.PP
+The first form of this command is used to install a new crontab from some
+named file or standard input if the pseudo-filename ``-'' is given.
+.PP
+The
+.I -l
+option causes the current crontab to be displayed on standard output.
+.PP
+The
+.I -r
+option causes the current crontab to be removed.
+.PP
+The
+.I -e
+option is used to edit the current crontab using the editor specified by
+the \s-1VISUAL\s+1 or \s-1EDITOR\s+1 environment variables. After you exit
+from the editor, the modified crontab will be installed automatically.
+.SH "SEE ALSO"
+crontab(5), cron(8)
+.SH FILES
+.nf
+/var/cron/allow
+/var/cron/deny
+.fi
+.SH STANDARDS
+The
+.I crontab
+command conforms to IEEE Std1003.2-1992 (``POSIX''). This new command syntax
+differs from previous versions of Vixie Cron, as well as from the classic
+SVR3 syntax.
+.SH DIAGNOSTICS
+A fairly informative usage message appears if you run it with a bad command
+line.
+.SH AUTHOR
+.nf
+Paul Vixie <paul@vix.com>
diff --git a/usr.sbin/cron/crontab.5 b/usr.sbin/cron/crontab.5
new file mode 100644
index 00000000000..4230d135e68
--- /dev/null
+++ b/usr.sbin/cron/crontab.5
@@ -0,0 +1,188 @@
+.\"/* Copyright 1988,1990,1993,1994 by Paul Vixie
+.\" * All rights reserved
+.\" *
+.\" * Distribute freely, except: don't remove my name from the source or
+.\" * documentation (don't take credit for my work), mark your changes (don't
+.\" * get me blamed for your possible bugs), don't alter or remove this
+.\" * notice. May be sold if buildable source is provided to buyer. No
+.\" * warrantee of any kind, express or implied, is included with this
+.\" * software; use at your own risk, responsibility for damages (if any) to
+.\" * anyone resulting from the use of this software rests entirely with the
+.\" * user.
+.\" *
+.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+.\" * I'll try to keep a version up to date. I can be reached as follows:
+.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+.\" */
+.\"
+.\" $Id: crontab.5,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+.\"
+.TH CRONTAB 5 "24 January 1994"
+.UC 4
+.SH NAME
+crontab \- tables for driving cron
+.SH DESCRIPTION
+A
+.I crontab
+file contains instructions to the
+.IR cron (8)
+daemon of the general form: ``run this command at this time on this date''.
+Each user has their own crontab, and commands in any given crontab will be
+executed as the user who owns the crontab. Uucp and News will usually have
+their own crontabs, eliminating the need for explicitly running
+.IR su (1)
+as part of a cron command.
+.PP
+Blank lines and leading spaces and tabs are ignored. Lines whose first
+non-space character is a pound-sign (#) are comments, and are ignored.
+Note that comments are not allowed on the same line as cron commands, since
+they will be taken to be part of the command. Similarly, comments are not
+allowed on the same line as environment variable settings.
+.PP
+An active line in a crontab will be either an environment setting or a cron
+command. An environment setting is of the form,
+.PP
+ name = value
+.PP
+where the spaces around the equal-sign (=) are optional, and any subsequent
+non-leading spaces in
+.I value
+will be part of the value assigned to
+.IR name .
+The
+.I value
+string may be placed in quotes (single or double, but matching) to preserve
+leading or trailing blanks.
+.PP
+Several environment variables are set up
+automatically by the
+.IR cron (8)
+daemon.
+SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
+line of the crontab's owner.
+HOME and SHELL may be overridden by settings in the crontab; LOGNAME may not.
+.PP
+(Another note: the LOGNAME variable is sometimes called USER on BSD systems...
+on these systems, USER will be set also.)
+.PP
+In addition to LOGNAME, HOME, and SHELL,
+.IR cron (8)
+will look at MAILTO if it has any reason to send mail as a result of running
+commands in ``this'' crontab. If MAILTO is defined (and non-empty), mail is
+sent to the user so named. If MAILTO is defined but empty (MAILTO=""), no
+mail will be sent. Otherwise mail is sent to the owner of the crontab. This
+option is useful if you decide on /bin/mail instead of /usr/lib/sendmail as
+your mailer when you install cron -- /bin/mail doesn't do aliasing, and UUCP
+usually doesn't read its mail.
+.PP
+The format of a cron command is very much the V7 standard, with a number of
+upward-compatible extensions. Each line has five time and date fields,
+followed by a user name if this is the system crontab file,
+followed by a command. Commands are executed by
+.IR cron (8)
+when the minute, hour, and month of year fields match the current time,
+.I and
+when at least one of the two day fields (day of month, or day of week)
+match the current time (see ``Note'' below).
+.IR cron (8)
+examines cron entries once every minute.
+The time and date fields are:
+.IP
+.ta 1.5i
+field allowed values
+.br
+----- --------------
+.br
+minute 0-59
+.br
+hour 0-23
+.br
+day of month 0-31
+.br
+month 0-12 (or names, see below)
+.br
+day of week 0-7 (0 or 7 is Sun, or use names)
+.br
+.PP
+A field may be an asterisk (*), which always stands for ``first\-last''.
+.PP
+Ranges of numbers are allowed. Ranges are two numbers separated
+with a hyphen. The specified range is inclusive. For example,
+8-11 for an ``hours'' entry specifies execution at hours 8, 9, 10
+and 11.
+.PP
+Lists are allowed. A list is a set of numbers (or ranges)
+separated by commas. Examples: ``1,2,5,9'', ``0-4,8-12''.
+.PP
+Step values can be used in conjunction with ranges. Following
+a range with ``/<number>'' specifies skips of the number's value
+through the range. For example, ``0-23/2'' can be used in the hours
+field to specify command execution every other hour (the alternative
+in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22''). Steps are
+also permitted after an asterisk, so if you want to say ``every two
+hours'', just use ``*/2''.
+.PP
+Names can also be used for the ``month'' and ``day of week''
+fields. Use the first three letters of the particular
+day or month (case doesn't matter). Ranges or
+lists of names are not allowed.
+.PP
+The ``sixth'' field (the rest of the line) specifies the command to be
+run.
+The entire command portion of the line, up to a newline or %
+character, will be executed by /bin/sh or by the shell
+specified in the SHELL variable of the cronfile.
+Percent-signs (%) in the command, unless escaped with backslash
+(\\), will be changed into newline characters, and all data
+after the first % will be sent to the command as standard
+input.
+.PP
+Note: The day of a command's execution can be specified by two
+fields \(em day of month, and day of week. If both fields are
+restricted (ie, aren't *), the command will be run when
+.I either
+field matches the current time. For example,
+.br
+``30 4 1,15 * 5''
+would cause a command to be run at 4:30 am on the 1st and 15th of each
+month, plus every Friday.
+.SH EXAMPLE CRON FILE
+.nf
+
+# use /bin/sh to run commands, no matter what /etc/passwd says
+SHELL=/bin/sh
+# mail any output to `paul', no matter whose crontab this is
+MAILTO=paul
+#
+# run five minutes after midnight, every day
+5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
+# run at 2:15pm on the first of every month -- output mailed to paul
+15 14 1 * * $HOME/bin/monthly
+# run at 10 pm on weekdays, annoy Joe
+0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
+23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
+5 4 * * sun echo "run at 5 after 4 every sunday"
+.fi
+.SH SEE ALSO
+cron(8), crontab(1)
+.SH EXTENSIONS
+When specifying day of week, both day 0 and day 7 will be considered Sunday.
+BSD and ATT seem to disagree about this.
+.PP
+Lists and ranges are allowed to co-exist in the same field. "1-3,7-9" would
+be rejected by ATT or BSD cron -- they want to see "1-3" or "7,8,9" ONLY.
+.PP
+Ranges can include "steps", so "1-9/2" is the same as "1,3,5,7,9".
+.PP
+Names of months or days of the week can be specified by name.
+.PP
+Environment variables can be set in the crontab. In BSD or ATT, the
+environment handed to child processes is basically the one from /etc/rc.
+.PP
+Command output is mailed to the crontab owner (BSD can't do this), can be
+mailed to a person other than the crontab owner (SysV can't do this), or the
+feature can be turned off and no mail will be sent at all (SysV can't do this
+either).
+.SH AUTHOR
+.nf
+Paul Vixie <paul@vix.com>
diff --git a/usr.sbin/cron/crontab.c b/usr.sbin/cron/crontab.c
new file mode 100644
index 00000000000..46b47f0e44d
--- /dev/null
+++ b/usr.sbin/cron/crontab.c
@@ -0,0 +1,624 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: crontab.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+/* crontab - install and manage per-user crontab files
+ * vix 02may87 [RCS has the rest of the log]
+ * vix 26jan87 [original]
+ */
+
+
+#define MAIN_PROGRAM
+
+
+#include "cron.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#ifdef USE_UTIMES
+# include <sys/time.h>
+#else
+# include <time.h>
+# include <utime.h>
+#endif
+#if defined(POSIX)
+# include <locale.h>
+#endif
+
+
+#define NHEADER_LINES 3
+
+
+enum opt_t { opt_unknown, opt_list, opt_delete, opt_edit, opt_replace };
+
+#if DEBUGGING
+static char *Options[] = { "???", "list", "delete", "edit", "replace" };
+#endif
+
+
+static PID_T Pid;
+static char User[MAX_UNAME], RealUser[MAX_UNAME];
+static char Filename[MAX_FNAME];
+static FILE *NewCrontab;
+static int CheckErrorCount;
+static enum opt_t Option;
+static struct passwd *pw;
+static void list_cmd __P((void)),
+ delete_cmd __P((void)),
+ edit_cmd __P((void)),
+ poke_daemon __P((void)),
+ check_error __P((char *)),
+ parse_args __P((int c, char *v[]));
+static int replace_cmd __P((void));
+
+
+static void
+usage(msg)
+ char *msg;
+{
+ fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
+ fprintf(stderr, "usage:\t%s [-u user] file\n", ProgramName);
+ fprintf(stderr, "\t%s [-u user] [ -e | -l | -r ]\n", ProgramName);
+ fprintf(stderr, "\t\t(default operation is replace, per 1003.2)\n");
+ fprintf(stderr, "\t-e\t(edit user's crontab)\n");
+ fprintf(stderr, "\t-l\t(list user's crontab)\n");
+ fprintf(stderr, "\t-r\t(delete user's crontab)\n");
+ exit(ERROR_EXIT);
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int exitstatus;
+
+ Pid = getpid();
+ ProgramName = argv[0];
+
+#if defined(POSIX)
+ setlocale(LC_ALL, "");
+#endif
+
+#if defined(BSD)
+ setlinebuf(stderr);
+#endif
+ parse_args(argc, argv); /* sets many globals, opens a file */
+ set_cron_uid();
+ set_cron_cwd();
+ if (!allowed(User)) {
+ fprintf(stderr,
+ "You (%s) are not allowed to use this program (%s)\n",
+ User, ProgramName);
+ fprintf(stderr, "See crontab(1) for more information\n");
+ log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
+ exit(ERROR_EXIT);
+ }
+ exitstatus = OK_EXIT;
+ switch (Option) {
+ case opt_list: list_cmd();
+ break;
+ case opt_delete: delete_cmd();
+ break;
+ case opt_edit: edit_cmd();
+ break;
+ case opt_replace: if (replace_cmd() < 0)
+ exitstatus = ERROR_EXIT;
+ break;
+ }
+ exit(0);
+ /*NOTREACHED*/
+}
+
+
+static void
+parse_args(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int argch;
+
+ if (!(pw = getpwuid(getuid()))) {
+ fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
+ ProgramName);
+ fprintf(stderr, "bailing out.\n");
+ exit(ERROR_EXIT);
+ }
+ strcpy(User, pw->pw_name);
+ strcpy(RealUser, User);
+ Filename[0] = '\0';
+ Option = opt_unknown;
+ while (EOF != (argch = getopt(argc, argv, "u:lerx:"))) {
+ switch (argch) {
+ case 'x':
+ if (!set_debug_flags(optarg))
+ usage("bad debug option");
+ break;
+ case 'u':
+ if (getuid() != ROOT_UID)
+ {
+ fprintf(stderr,
+ "must be privileged to use -u\n");
+ exit(ERROR_EXIT);
+ }
+ if (!(pw = getpwnam(optarg)))
+ {
+ fprintf(stderr, "%s: user `%s' unknown\n",
+ ProgramName, optarg);
+ exit(ERROR_EXIT);
+ }
+ (void) strcpy(User, optarg);
+ break;
+ case 'l':
+ if (Option != opt_unknown)
+ usage("only one operation permitted");
+ Option = opt_list;
+ break;
+ case 'r':
+ if (Option != opt_unknown)
+ usage("only one operation permitted");
+ Option = opt_delete;
+ break;
+ case 'e':
+ if (Option != opt_unknown)
+ usage("only one operation permitted");
+ Option = opt_edit;
+ break;
+ default:
+ usage("unrecognized option");
+ }
+ }
+
+ endpwent();
+
+ if (Option != opt_unknown) {
+ if (argv[optind] != NULL) {
+ usage("no arguments permitted after this option");
+ }
+ } else {
+ if (argv[optind] != NULL) {
+ Option = opt_replace;
+ (void) strcpy (Filename, argv[optind]);
+ } else {
+ usage("file name must be specified for replace");
+ }
+ }
+
+ if (Option == opt_replace) {
+ /* we have to open the file here because we're going to
+ * chdir(2) into /var/cron before we get around to
+ * reading the file.
+ */
+ if (!strcmp(Filename, "-")) {
+ NewCrontab = stdin;
+ } else {
+ /* relinquish the setuid status of the binary during
+ * the open, lest nonroot users read files they should
+ * not be able to read. we can't use access() here
+ * since there's a race condition. thanks go out to
+ * Arnt Gulbrandsen <agulbra@pvv.unit.no> for spotting
+ * the race.
+ */
+
+ if (swap_uids() < OK) {
+ perror("swapping uids");
+ exit(ERROR_EXIT);
+ }
+ if (!(NewCrontab = fopen(Filename, "r"))) {
+ perror(Filename);
+ exit(ERROR_EXIT);
+ }
+ if (swap_uids() < OK) {
+ perror("swapping uids back");
+ exit(ERROR_EXIT);
+ }
+ }
+ }
+
+ Debug(DMISC, ("user=%s, file=%s, option=%s\n",
+ User, Filename, Options[(int)Option]))
+}
+
+
+static void
+list_cmd() {
+ char n[MAX_FNAME];
+ FILE *f;
+ int ch;
+
+ log_it(RealUser, Pid, "LIST", User);
+ (void) sprintf(n, CRON_TAB(User));
+ if (!(f = fopen(n, "r"))) {
+ if (errno == ENOENT)
+ fprintf(stderr, "no crontab for %s\n", User);
+ else
+ perror(n);
+ exit(ERROR_EXIT);
+ }
+
+ /* file is open. copy to stdout, close.
+ */
+ Set_LineNum(1)
+ while (EOF != (ch = get_char(f)))
+ putchar(ch);
+ fclose(f);
+}
+
+
+static void
+delete_cmd() {
+ char n[MAX_FNAME];
+
+ log_it(RealUser, Pid, "DELETE", User);
+ (void) sprintf(n, CRON_TAB(User));
+ if (unlink(n)) {
+ if (errno == ENOENT)
+ fprintf(stderr, "no crontab for %s\n", User);
+ else
+ perror(n);
+ exit(ERROR_EXIT);
+ }
+ poke_daemon();
+}
+
+
+static void
+check_error(msg)
+ char *msg;
+{
+ CheckErrorCount++;
+ fprintf(stderr, "\"%s\":%d: %s\n", Filename, LineNumber-1, msg);
+}
+
+
+static void
+edit_cmd() {
+ char n[MAX_FNAME], q[MAX_TEMPSTR], *editor;
+ FILE *f;
+ int ch, t, x;
+ struct stat statbuf;
+ time_t mtime;
+ WAIT_T waiter;
+ PID_T pid, xpid;
+
+ log_it(RealUser, Pid, "BEGIN EDIT", User);
+ (void) sprintf(n, CRON_TAB(User));
+ if (!(f = fopen(n, "r"))) {
+ if (errno != ENOENT) {
+ perror(n);
+ exit(ERROR_EXIT);
+ }
+ fprintf(stderr, "no crontab for %s - using an empty one\n",
+ User);
+ if (!(f = fopen("/dev/null", "r"))) {
+ perror("/dev/null");
+ exit(ERROR_EXIT);
+ }
+ }
+
+ (void) sprintf(Filename, "/tmp/crontab.%d", Pid);
+ if (-1 == (t = open(Filename, O_CREAT|O_EXCL|O_RDWR, 0600))) {
+ perror(Filename);
+ goto fatal;
+ }
+#ifdef HAS_FCHOWN
+ if (fchown(t, getuid(), getgid()) < 0) {
+#else
+ if (chown(Filename, getuid(), getgid()) < 0) {
+#endif
+ perror("fchown");
+ goto fatal;
+ }
+ if (!(NewCrontab = fdopen(t, "r+"))) {
+ perror("fdopen");
+ goto fatal;
+ }
+
+ Set_LineNum(1)
+
+ /* ignore the top few comments since we probably put them there.
+ */
+ for (x = 0; x < NHEADER_LINES; x++) {
+ ch = get_char(f);
+ if (EOF == ch)
+ break;
+ if ('#' != ch) {
+ putc(ch, NewCrontab);
+ break;
+ }
+ while (EOF != (ch = get_char(f)))
+ if (ch == '\n')
+ break;
+ if (EOF == ch)
+ break;
+ }
+
+ /* copy the rest of the crontab (if any) to the temp file.
+ */
+ if (EOF != ch)
+ while (EOF != (ch = get_char(f)))
+ putc(ch, NewCrontab);
+ fclose(f);
+ if (fflush(NewCrontab) < OK) {
+ perror(Filename);
+ exit(ERROR_EXIT);
+ }
+ again:
+ rewind(NewCrontab);
+ if (ferror(NewCrontab)) {
+ fprintf(stderr, "%s: error while writing new crontab to %s\n",
+ ProgramName, Filename);
+ fatal: unlink(Filename);
+ exit(ERROR_EXIT);
+ }
+ if (fstat(t, &statbuf) < 0) {
+ perror("fstat");
+ goto fatal;
+ }
+ mtime = statbuf.st_mtime;
+
+ if ((!(editor = getenv("VISUAL")))
+ && (!(editor = getenv("EDITOR")))
+ ) {
+ editor = EDITOR;
+ }
+
+ /* we still have the file open. editors will generally rewrite the
+ * original file rather than renaming/unlinking it and starting a
+ * new one; even backup files are supposed to be made by copying
+ * rather than by renaming. if some editor does not support this,
+ * then don't use it. the security problems are more severe if we
+ * close and reopen the file around the edit.
+ */
+
+ switch (pid = fork()) {
+ case -1:
+ perror("fork");
+ goto fatal;
+ case 0:
+ /* child */
+ if (setuid(getuid()) < 0) {
+ perror("setuid(getuid())");
+ exit(ERROR_EXIT);
+ }
+ if (chdir("/tmp") < 0) {
+ perror("chdir(/tmp)");
+ exit(ERROR_EXIT);
+ }
+ if (strlen(editor) + strlen(Filename) + 2 >= MAX_TEMPSTR) {
+ fprintf(stderr, "%s: editor or filename too long\n",
+ ProgramName);
+ exit(ERROR_EXIT);
+ }
+ sprintf(q, "%s %s", editor, Filename);
+ execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", q, NULL);
+ perror(editor);
+ exit(ERROR_EXIT);
+ /*NOTREACHED*/
+ default:
+ /* parent */
+ break;
+ }
+
+ /* parent */
+ xpid = wait(&waiter);
+ if (xpid != pid) {
+ fprintf(stderr, "%s: wrong PID (%d != %d) from \"%s\"\n",
+ ProgramName, xpid, pid, editor);
+ goto fatal;
+ }
+ if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
+ fprintf(stderr, "%s: \"%s\" exited with status %d\n",
+ ProgramName, editor, WEXITSTATUS(waiter));
+ goto fatal;
+ }
+ if (WIFSIGNALED(waiter)) {
+ fprintf(stderr,
+ "%s: \"%s\" killed; signal %d (%score dumped)\n",
+ ProgramName, editor, WTERMSIG(waiter),
+ WCOREDUMP(waiter) ?"" :"no ");
+ goto fatal;
+ }
+ if (fstat(t, &statbuf) < 0) {
+ perror("fstat");
+ goto fatal;
+ }
+ if (mtime == statbuf.st_mtime) {
+ fprintf(stderr, "%s: no changes made to crontab\n",
+ ProgramName);
+ goto remove;
+ }
+ fprintf(stderr, "%s: installing new crontab\n", ProgramName);
+ switch (replace_cmd()) {
+ case 0:
+ break;
+ case -1:
+ for (;;) {
+ printf("Do you want to retry the same edit? ");
+ fflush(stdout);
+ q[0] = '\0';
+ (void) fgets(q, sizeof q, stdin);
+ switch (islower(q[0]) ? q[0] : tolower(q[0])) {
+ case 'y':
+ goto again;
+ case 'n':
+ goto abandon;
+ default:
+ fprintf(stderr, "Enter Y or N\n");
+ }
+ }
+ /*NOTREACHED*/
+ case -2:
+ abandon:
+ fprintf(stderr, "%s: edits left in %s\n",
+ ProgramName, Filename);
+ goto done;
+ default:
+ fprintf(stderr, "%s: panic: bad switch() in replace_cmd()\n");
+ goto fatal;
+ }
+ remove:
+ unlink(Filename);
+ done:
+ log_it(RealUser, Pid, "END EDIT", User);
+}
+
+
+/* returns 0 on success
+ * -1 on syntax error
+ * -2 on install error
+ */
+static int
+replace_cmd() {
+ char n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
+ FILE *tmp;
+ int ch, eof;
+ entry *e;
+ time_t now = time(NULL);
+ char **envp = env_init();
+
+ (void) sprintf(n, "tmp.%d", Pid);
+ (void) sprintf(tn, CRON_TAB(n));
+ if (!(tmp = fopen(tn, "w+"))) {
+ perror(tn);
+ return (-2);
+ }
+
+ /* write a signature at the top of the file.
+ *
+ * VERY IMPORTANT: make sure NHEADER_LINES agrees with this code.
+ */
+ fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
+ fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
+ fprintf(tmp, "# (Cron version -- %s)\n", rcsid);
+
+ /* copy the crontab to the tmp
+ */
+ rewind(NewCrontab);
+ Set_LineNum(1)
+ while (EOF != (ch = get_char(NewCrontab)))
+ putc(ch, tmp);
+ ftruncate(fileno(tmp), ftell(tmp));
+ fflush(tmp); rewind(tmp);
+
+ if (ferror(tmp)) {
+ fprintf(stderr, "%s: error while writing new crontab to %s\n",
+ ProgramName, tn);
+ fclose(tmp); unlink(tn);
+ return (-2);
+ }
+
+ /* check the syntax of the file being installed.
+ */
+
+ /* BUG: was reporting errors after the EOF if there were any errors
+ * in the file proper -- kludged it by stopping after first error.
+ * vix 31mar87
+ */
+ Set_LineNum(1 - NHEADER_LINES)
+ CheckErrorCount = 0; eof = FALSE;
+ while (!CheckErrorCount && !eof) {
+ switch (load_env(envstr, tmp)) {
+ case ERR:
+ eof = TRUE;
+ break;
+ case FALSE:
+ e = load_entry(tmp, check_error, pw, envp);
+ if (e)
+ free(e);
+ break;
+ case TRUE:
+ break;
+ }
+ }
+
+ if (CheckErrorCount != 0) {
+ fprintf(stderr, "errors in crontab file, can't install.\n");
+ fclose(tmp); unlink(tn);
+ return (-1);
+ }
+
+#ifdef HAS_FCHOWN
+ if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
+#else
+ if (chown(tn, ROOT_UID, -1) < OK)
+#endif
+ {
+ perror("chown");
+ fclose(tmp); unlink(tn);
+ return (-2);
+ }
+
+#ifdef HAS_FCHMOD
+ if (fchmod(fileno(tmp), 0600) < OK)
+#else
+ if (chmod(tn, 0600) < OK)
+#endif
+ {
+ perror("chown");
+ fclose(tmp); unlink(tn);
+ return (-2);
+ }
+
+ if (fclose(tmp) == EOF) {
+ perror("fclose");
+ unlink(tn);
+ return (-2);
+ }
+
+ (void) sprintf(n, CRON_TAB(User));
+ if (rename(tn, n)) {
+ fprintf(stderr, "%s: error renaming %s to %s\n",
+ ProgramName, tn, n);
+ perror("rename");
+ unlink(tn);
+ return (-2);
+ }
+ log_it(RealUser, Pid, "REPLACE", User);
+
+ poke_daemon();
+
+ return (0);
+}
+
+
+static void
+poke_daemon() {
+#ifdef USE_UTIMES
+ struct timeval tvs[2];
+ struct timezone tz;
+
+ (void) gettimeofday(&tvs[0], &tz);
+ tvs[1] = tvs[0];
+ if (utimes(SPOOL_DIR, tvs) < OK) {
+ fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+ perror(SPOOL_DIR);
+ return;
+ }
+#else
+ if (utime(SPOOL_DIR, NULL) < OK) {
+ fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+ perror(SPOOL_DIR);
+ return;
+ }
+#endif /*USE_UTIMES*/
+}
diff --git a/usr.sbin/cron/database.c b/usr.sbin/cron/database.c
new file mode 100644
index 00000000000..8c3ad734a63
--- /dev/null
+++ b/usr.sbin/cron/database.c
@@ -0,0 +1,261 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: database.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+/* vix 26jan87 [RCS has the log]
+ */
+
+
+#include "cron.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+
+#define TMAX(a,b) ((a)>(b)?(a):(b))
+
+
+static void process_crontab __P((char *, char *, char *,
+ struct stat *,
+ cron_db *, cron_db *));
+
+
+void
+load_database(old_db)
+ cron_db *old_db;
+{
+ DIR *dir;
+ struct stat statbuf;
+ struct stat syscron_stat;
+ DIR_T *dp;
+ cron_db new_db;
+ user *u, *nu;
+
+ Debug(DLOAD, ("[%d] load_database()\n", getpid()))
+
+ /* before we start loading any data, do a stat on SPOOL_DIR
+ * so that if anything changes as of this moment (i.e., before we've
+ * cached any of the database), we'll see the changes next time.
+ */
+ if (stat(SPOOL_DIR, &statbuf) < OK) {
+ log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
+ (void) exit(ERROR_EXIT);
+ }
+
+ /* track system crontab file
+ */
+ if (stat(SYSCRONTAB, &syscron_stat) < OK)
+ syscron_stat.st_mtime = 0;
+
+ /* if spooldir's mtime has not changed, we don't need to fiddle with
+ * the database.
+ *
+ * Note that old_db->mtime is initialized to 0 in main(), and
+ * so is guaranteed to be different than the stat() mtime the first
+ * time this function is called.
+ */
+ if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
+ Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
+ getpid()))
+ return;
+ }
+
+ /* something's different. make a new database, moving unchanged
+ * elements from the old database, reloading elements that have
+ * actually changed. Whatever is left in the old database when
+ * we're done is chaff -- crontabs that disappeared.
+ */
+ new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
+ new_db.head = new_db.tail = NULL;
+
+ if (syscron_stat.st_mtime) {
+ process_crontab("root", "*system*",
+ SYSCRONTAB, &syscron_stat,
+ &new_db, old_db);
+ }
+
+ /* we used to keep this dir open all the time, for the sake of
+ * efficiency. however, we need to close it in every fork, and
+ * we fork a lot more often than the mtime of the dir changes.
+ */
+ if (!(dir = opendir(SPOOL_DIR))) {
+ log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
+ (void) exit(ERROR_EXIT);
+ }
+
+ while (NULL != (dp = readdir(dir))) {
+ char fname[MAXNAMLEN+1],
+ tabname[MAXNAMLEN+1];
+
+ /* avoid file names beginning with ".". this is good
+ * because we would otherwise waste two guaranteed calls
+ * to getpwnam() for . and .., and also because user names
+ * starting with a period are just too nasty to consider.
+ */
+ if (dp->d_name[0] == '.')
+ continue;
+
+ (void) strcpy(fname, dp->d_name);
+ sprintf(tabname, CRON_TAB(fname));
+
+ process_crontab(fname, fname, tabname,
+ &statbuf, &new_db, old_db);
+ }
+ closedir(dir);
+
+ /* if we don't do this, then when our children eventually call
+ * getpwnam() in do_command.c's child_process to verify MAILTO=,
+ * they will screw us up (and v-v).
+ */
+ endpwent();
+
+ /* whatever's left in the old database is now junk.
+ */
+ Debug(DLOAD, ("unlinking old database:\n"))
+ for (u = old_db->head; u != NULL; u = nu) {
+ Debug(DLOAD, ("\t%s\n", u->name))
+ nu = u->next;
+ unlink_user(old_db, u);
+ free_user(u);
+ }
+
+ /* overwrite the database control block with the new one.
+ */
+ *old_db = new_db;
+ Debug(DLOAD, ("load_database is done\n"))
+}
+
+
+void
+link_user(db, u)
+ cron_db *db;
+ user *u;
+{
+ if (db->head == NULL)
+ db->head = u;
+ if (db->tail)
+ db->tail->next = u;
+ u->prev = db->tail;
+ u->next = NULL;
+ db->tail = u;
+}
+
+
+void
+unlink_user(db, u)
+ cron_db *db;
+ user *u;
+{
+ if (u->prev == NULL)
+ db->head = u->next;
+ else
+ u->prev->next = u->next;
+
+ if (u->next == NULL)
+ db->tail = u->prev;
+ else
+ u->next->prev = u->prev;
+}
+
+
+user *
+find_user(db, name)
+ cron_db *db;
+ char *name;
+{
+ char *env_get();
+ user *u;
+
+ for (u = db->head; u != NULL; u = u->next)
+ if (!strcmp(u->name, name))
+ break;
+ return u;
+}
+
+
+static void
+process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
+ char *uname;
+ char *fname;
+ char *tabname;
+ struct stat *statbuf;
+ cron_db *new_db;
+ cron_db *old_db;
+{
+ struct passwd *pw = NULL;
+ int crontab_fd = OK - 1;
+ user *u;
+
+ if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
+ /* file doesn't have a user in passwd file.
+ */
+ log_it(fname, getpid(), "ORPHAN", "no passwd entry");
+ goto next_crontab;
+ }
+
+ if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
+ /* crontab not accessible?
+ */
+ log_it(fname, getpid(), "CAN'T OPEN", tabname);
+ goto next_crontab;
+ }
+
+ if (fstat(crontab_fd, statbuf) < OK) {
+ log_it(fname, getpid(), "FSTAT FAILED", tabname);
+ goto next_crontab;
+ }
+
+ Debug(DLOAD, ("\t%s:", fname))
+ u = find_user(old_db, fname);
+ if (u != NULL) {
+ /* if crontab has not changed since we last read it
+ * in, then we can just use our existing entry.
+ */
+ if (u->mtime == statbuf->st_mtime) {
+ Debug(DLOAD, (" [no change, using old data]"))
+ unlink_user(old_db, u);
+ link_user(new_db, u);
+ goto next_crontab;
+ }
+
+ /* before we fall through to the code that will reload
+ * the user, let's deallocate and unlink the user in
+ * the old database. This is more a point of memory
+ * efficiency than anything else, since all leftover
+ * users will be deleted from the old database when
+ * we finish with the crontab...
+ */
+ Debug(DLOAD, (" [delete old data]"))
+ unlink_user(old_db, u);
+ free_user(u);
+ log_it(fname, getpid(), "RELOAD", tabname);
+ }
+ u = load_user(crontab_fd, pw, fname);
+ if (u != NULL) {
+ u->mtime = statbuf->st_mtime;
+ link_user(new_db, u);
+ }
+
+next_crontab:
+ if (crontab_fd >= OK) {
+ Debug(DLOAD, (" [done]\n"))
+ close(crontab_fd);
+ }
+}
diff --git a/usr.sbin/cron/do_command.c b/usr.sbin/cron/do_command.c
new file mode 100644
index 00000000000..eee5e19a67e
--- /dev/null
+++ b/usr.sbin/cron/do_command.c
@@ -0,0 +1,501 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: do_command.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+
+#include "cron.h"
+#include <sys/signal.h>
+#if defined(sequent)
+# include <sys/universe.h>
+#endif
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
+
+
+static void child_process __P((entry *, user *)),
+ do_univ __P((user *));
+
+
+void
+do_command(e, u)
+ entry *e;
+ user *u;
+{
+ Debug(DPROC, ("[%d] do_command(%s, (%s,%d,%d))\n",
+ getpid(), e->cmd, u->name, e->uid, e->gid))
+
+ /* fork to become asynchronous -- parent process is done immediately,
+ * and continues to run the normal cron code, which means return to
+ * tick(). the child and grandchild don't leave this function, alive.
+ *
+ * vfork() is unsuitable, since we have much to do, and the parent
+ * needs to be able to run off and fork other processes.
+ */
+ switch (fork()) {
+ case -1:
+ log_it("CRON",getpid(),"error","can't fork");
+ break;
+ case 0:
+ /* child process */
+ acquire_daemonlock(1);
+ child_process(e, u);
+ Debug(DPROC, ("[%d] child process done, exiting\n", getpid()))
+ _exit(OK_EXIT);
+ break;
+ default:
+ /* parent process */
+ break;
+ }
+ Debug(DPROC, ("[%d] main process returning to work\n", getpid()))
+}
+
+
+static void
+child_process(e, u)
+ entry *e;
+ user *u;
+{
+ int stdin_pipe[2], stdout_pipe[2];
+ register char *input_data;
+ char *usernm, *mailto;
+ int children = 0;
+
+ Debug(DPROC, ("[%d] child_process('%s')\n", getpid(), e->cmd))
+
+ /* mark ourselves as different to PS command watchers by upshifting
+ * our program name. This has no effect on some kernels.
+ */
+ /*local*/{
+ register char *pch;
+
+ for (pch = ProgramName; *pch; pch++)
+ *pch = MkUpper(*pch);
+ }
+
+ /* discover some useful and important environment settings
+ */
+ usernm = env_get("LOGNAME", e->envp);
+ mailto = env_get("MAILTO", e->envp);
+
+#ifdef USE_SIGCHLD
+ /* our parent is watching for our death by catching SIGCHLD. we
+ * do not care to watch for our children's deaths this way -- we
+ * use wait() explictly. so we have to disable the signal (which
+ * was inherited from the parent).
+ */
+ (void) signal(SIGCHLD, SIG_IGN);
+#else
+ /* on system-V systems, we are ignoring SIGCLD. we have to stop
+ * ignoring it now or the wait() in cron_pclose() won't work.
+ * because of this, we have to wait() for our children here, as well.
+ */
+ (void) signal(SIGCLD, SIG_DFL);
+#endif /*BSD*/
+
+ /* create some pipes to talk to our future child
+ */
+ pipe(stdin_pipe); /* child's stdin */
+ pipe(stdout_pipe); /* child's stdout */
+
+ /* since we are a forked process, we can diddle the command string
+ * we were passed -- nobody else is going to use it again, right?
+ *
+ * if a % is present in the command, previous characters are the
+ * command, and subsequent characters are the additional input to
+ * the command. Subsequent %'s will be transformed into newlines,
+ * but that happens later.
+ */
+ /*local*/{
+ register int escaped = FALSE;
+ register int ch;
+
+ for (input_data = e->cmd; ch = *input_data; input_data++) {
+ if (escaped) {
+ escaped = FALSE;
+ continue;
+ }
+ if (ch == '\\') {
+ escaped = TRUE;
+ continue;
+ }
+ if (ch == '%') {
+ *input_data++ = '\0';
+ break;
+ }
+ }
+ }
+
+ /* fork again, this time so we can exec the user's command.
+ */
+ switch (vfork()) {
+ case -1:
+ log_it("CRON",getpid(),"error","can't vfork");
+ exit(ERROR_EXIT);
+ /*NOTREACHED*/
+ case 0:
+ Debug(DPROC, ("[%d] grandchild process Vfork()'ed\n",
+ getpid()))
+
+ /* write a log message. we've waited this long to do it
+ * because it was not until now that we knew the PID that
+ * the actual user command shell was going to get and the
+ * PID is part of the log message.
+ */
+ /*local*/{
+ char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+
+ log_it(usernm, getpid(), "CMD", x);
+ free(x);
+ }
+
+ /* that's the last thing we'll log. close the log files.
+ */
+#ifdef SYSLOG
+ closelog();
+#endif
+
+ /* get new pgrp, void tty, etc.
+ */
+ (void) setsid();
+
+ /* close the pipe ends that we won't use. this doesn't affect
+ * the parent, who has to read and write them; it keeps the
+ * kernel from recording us as a potential client TWICE --
+ * which would keep it from sending SIGPIPE in otherwise
+ * appropriate circumstances.
+ */
+ close(stdin_pipe[WRITE_PIPE]);
+ close(stdout_pipe[READ_PIPE]);
+
+ /* grandchild process. make std{in,out} be the ends of
+ * pipes opened by our daddy; make stderr go to stdout.
+ */
+ close(STDIN); dup2(stdin_pipe[READ_PIPE], STDIN);
+ close(STDOUT); dup2(stdout_pipe[WRITE_PIPE], STDOUT);
+ close(STDERR); dup2(STDOUT, STDERR);
+
+ /* close the pipes we just dup'ed. The resources will remain.
+ */
+ close(stdin_pipe[READ_PIPE]);
+ close(stdout_pipe[WRITE_PIPE]);
+
+ /* set our login universe. Do this in the grandchild
+ * so that the child can invoke /usr/lib/sendmail
+ * without surprises.
+ */
+ do_univ(u);
+
+ /* set our directory, uid and gid. Set gid first, since once
+ * we set uid, we've lost root privledges.
+ */
+ setgid(e->gid);
+# if defined(BSD)
+ initgroups(env_get("LOGNAME", e->envp), e->gid);
+# endif
+ setuid(e->uid); /* we aren't root after this... */
+ chdir(env_get("HOME", e->envp));
+
+ /* exec the command.
+ */
+ {
+ char *shell = env_get("SHELL", e->envp);
+
+# if DEBUGGING
+ if (DebugFlags & DTEST) {
+ fprintf(stderr,
+ "debug DTEST is on, not exec'ing command.\n");
+ fprintf(stderr,
+ "\tcmd='%s' shell='%s'\n", e->cmd, shell);
+ _exit(OK_EXIT);
+ }
+# endif /*DEBUGGING*/
+ execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
+ fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
+ perror("execl");
+ _exit(ERROR_EXIT);
+ }
+ break;
+ default:
+ /* parent process */
+ break;
+ }
+
+ children++;
+
+ /* middle process, child of original cron, parent of process running
+ * the user's command.
+ */
+
+ Debug(DPROC, ("[%d] child continues, closing pipes\n", getpid()))
+
+ /* close the ends of the pipe that will only be referenced in the
+ * grandchild process...
+ */
+ close(stdin_pipe[READ_PIPE]);
+ close(stdout_pipe[WRITE_PIPE]);
+
+ /*
+ * write, to the pipe connected to child's stdin, any input specified
+ * after a % in the crontab entry. while we copy, convert any
+ * additional %'s to newlines. when done, if some characters were
+ * written and the last one wasn't a newline, write a newline.
+ *
+ * Note that if the input data won't fit into one pipe buffer (2K
+ * or 4K on most BSD systems), and the child doesn't read its stdin,
+ * we would block here. thus we must fork again.
+ */
+
+ if (*input_data && fork() == 0) {
+ register FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
+ register int need_newline = FALSE;
+ register int escaped = FALSE;
+ register int ch;
+
+ Debug(DPROC, ("[%d] child2 sending data to grandchild\n", getpid()))
+
+ /* close the pipe we don't use, since we inherited it and
+ * are part of its reference count now.
+ */
+ close(stdout_pipe[READ_PIPE]);
+
+ /* translation:
+ * \% -> %
+ * % -> \n
+ * \x -> \x for all x != %
+ */
+ while (ch = *input_data++) {
+ if (escaped) {
+ if (ch != '%')
+ putc('\\', out);
+ } else {
+ if (ch == '%')
+ ch = '\n';
+ }
+
+ if (!(escaped = (ch == '\\'))) {
+ putc(ch, out);
+ need_newline = (ch != '\n');
+ }
+ }
+ if (escaped)
+ putc('\\', out);
+ if (need_newline)
+ putc('\n', out);
+
+ /* close the pipe, causing an EOF condition. fclose causes
+ * stdin_pipe[WRITE_PIPE] to be closed, too.
+ */
+ fclose(out);
+
+ Debug(DPROC, ("[%d] child2 done sending to grandchild\n", getpid()))
+ exit(0);
+ }
+
+ /* close the pipe to the grandkiddie's stdin, since its wicked uncle
+ * ernie back there has it open and will close it when he's done.
+ */
+ close(stdin_pipe[WRITE_PIPE]);
+
+ children++;
+
+ /*
+ * read output from the grandchild. it's stderr has been redirected to
+ * it's stdout, which has been redirected to our pipe. if there is any
+ * output, we'll be mailing it to the user whose crontab this is...
+ * when the grandchild exits, we'll get EOF.
+ */
+
+ Debug(DPROC, ("[%d] child reading output from grandchild\n", getpid()))
+
+ /*local*/{
+ register FILE *in = fdopen(stdout_pipe[READ_PIPE], "r");
+ register int ch = getc(in);
+
+ if (ch != EOF) {
+ register FILE *mail;
+ register int bytes = 1;
+ int status = 0;
+
+ Debug(DPROC|DEXT,
+ ("[%d] got data (%x:%c) from grandchild\n",
+ getpid(), ch, ch))
+
+ /* get name of recipient. this is MAILTO if set to a
+ * valid local username; USER otherwise.
+ */
+ if (mailto) {
+ /* MAILTO was present in the environment
+ */
+ if (!*mailto) {
+ /* ... but it's empty. set to NULL
+ */
+ mailto = NULL;
+ }
+ } else {
+ /* MAILTO not present, set to USER.
+ */
+ mailto = usernm;
+ }
+
+ /* if we are supposed to be mailing, MAILTO will
+ * be non-NULL. only in this case should we set
+ * up the mail command and subjects and stuff...
+ */
+
+ if (mailto) {
+ register char **env;
+ auto char mailcmd[MAX_COMMAND];
+ auto char hostname[MAXHOSTNAMELEN];
+
+ (void) gethostname(hostname, MAXHOSTNAMELEN);
+ (void) snprintf(mailcmd, sizeof(mailcmd),
+ MAILARGS, MAILCMD);
+ if (!(mail = cron_popen(mailcmd, "w"))) {
+ perror(MAILCMD);
+ (void) _exit(ERROR_EXIT);
+ }
+ fprintf(mail, "From: root (Cron Daemon)\n");
+ fprintf(mail, "To: %s\n", mailto);
+ fprintf(mail, "Subject: Cron <%s@%s> %s\n",
+ usernm, first_word(hostname, "."),
+ e->cmd);
+# if defined(MAIL_DATE)
+ fprintf(mail, "Date: %s\n",
+ arpadate(&TargetTime));
+# endif /* MAIL_DATE */
+ for (env = e->envp; *env; env++)
+ fprintf(mail, "X-Cron-Env: <%s>\n",
+ *env);
+ fprintf(mail, "\n");
+
+ /* this was the first char from the pipe
+ */
+ putc(ch, mail);
+ }
+
+ /* we have to read the input pipe no matter whether
+ * we mail or not, but obviously we only write to
+ * mail pipe if we ARE mailing.
+ */
+
+ while (EOF != (ch = getc(in))) {
+ bytes++;
+ if (mailto)
+ putc(ch, mail);
+ }
+
+ /* only close pipe if we opened it -- i.e., we're
+ * mailing...
+ */
+
+ if (mailto) {
+ Debug(DPROC, ("[%d] closing pipe to mail\n",
+ getpid()))
+ /* Note: the pclose will probably see
+ * the termination of the grandchild
+ * in addition to the mail process, since
+ * it (the grandchild) is likely to exit
+ * after closing its stdout.
+ */
+ status = cron_pclose(mail);
+ }
+
+ /* if there was output and we could not mail it,
+ * log the facts so the poor user can figure out
+ * what's going on.
+ */
+ if (mailto && status) {
+ char buf[MAX_TEMPSTR];
+
+ sprintf(buf,
+ "mailed %d byte%s of output but got status 0x%04x\n",
+ bytes, (bytes==1)?"":"s",
+ status);
+ log_it(usernm, getpid(), "MAIL", buf);
+ }
+
+ } /*if data from grandchild*/
+
+ Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
+
+ fclose(in); /* also closes stdout_pipe[READ_PIPE] */
+ }
+
+ /* wait for children to die.
+ */
+ for (; children > 0; children--)
+ {
+ WAIT_T waiter;
+ PID_T pid;
+
+ Debug(DPROC, ("[%d] waiting for grandchild #%d to finish\n",
+ getpid(), children))
+ pid = wait(&waiter);
+ if (pid < OK) {
+ Debug(DPROC, ("[%d] no more grandchildren--mail written?\n",
+ getpid()))
+ break;
+ }
+ Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x",
+ getpid(), pid, WEXITSTATUS(waiter)))
+ if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
+ Debug(DPROC, (", dumped core"))
+ Debug(DPROC, ("\n"))
+ }
+}
+
+
+static void
+do_univ(u)
+ user *u;
+{
+#if defined(sequent)
+/* Dynix (Sequent) hack to put the user associated with
+ * the passed user structure into the ATT universe if
+ * necessary. We have to dig the gecos info out of
+ * the user's password entry to see if the magic
+ * "universe(att)" string is present.
+ */
+
+ struct passwd *p;
+ char *s;
+ int i;
+
+ p = getpwuid(u->uid);
+ (void) endpwent();
+
+ if (p == NULL)
+ return;
+
+ s = p->pw_gecos;
+
+ for (i = 0; i < 4; i++)
+ {
+ if ((s = strchr(s, ',')) == NULL)
+ return;
+ s++;
+ }
+ if (strcmp(s, "universe(att)"))
+ return;
+
+ (void) universe(U_ATT);
+#endif
+}
diff --git a/usr.sbin/cron/entry.c b/usr.sbin/cron/entry.c
new file mode 100644
index 00000000000..f88b48c26d2
--- /dev/null
+++ b/usr.sbin/cron/entry.c
@@ -0,0 +1,507 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: entry.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+/* vix 26jan87 [RCS'd; rest of log is in RCS file]
+ * vix 01jan87 [added line-level error recovery]
+ * vix 31dec86 [added /step to the from-to range, per bob@acornrc]
+ * vix 30dec86 [written]
+ */
+
+
+#include "cron.h"
+
+
+typedef enum ecode {
+ e_none, e_minute, e_hour, e_dom, e_month, e_dow,
+ e_cmd, e_timespec, e_username
+} ecode_e;
+
+static char get_list __P((bitstr_t *, int, int, char *[], int, FILE *)),
+ get_range __P((bitstr_t *, int, int, char *[], int, FILE *)),
+ get_number __P((int *, int, char *[], int, FILE *));
+static int set_element __P((bitstr_t *, int, int, int));
+
+static char *ecodes[] =
+ {
+ "no error",
+ "bad minute",
+ "bad hour",
+ "bad day-of-month",
+ "bad month",
+ "bad day-of-week",
+ "bad command",
+ "bad time specifier",
+ "bad username",
+ };
+
+
+void
+free_entry(e)
+ entry *e;
+{
+ free(e->cmd);
+ env_free(e->envp);
+ free(e);
+}
+
+
+/* return NULL if eof or syntax error occurs;
+ * otherwise return a pointer to a new entry.
+ */
+entry *
+load_entry(file, error_func, pw, envp)
+ FILE *file;
+ void (*error_func)();
+ struct passwd *pw;
+ char **envp;
+{
+ /* this function reads one crontab entry -- the next -- from a file.
+ * it skips any leading blank lines, ignores comments, and returns
+ * EOF if for any reason the entry can't be read and parsed.
+ *
+ * the entry is also parsed here.
+ *
+ * syntax:
+ * user crontab:
+ * minutes hours doms months dows cmd\n
+ * system crontab (/etc/crontab):
+ * minutes hours doms months dows USERNAME cmd\n
+ */
+
+ ecode_e ecode = e_none;
+ entry *e;
+ int ch;
+ char cmd[MAX_COMMAND];
+ char envstr[MAX_ENVSTR];
+
+ Debug(DPARS, ("load_entry()...about to eat comments\n"))
+
+ skip_comments(file);
+
+ ch = get_char(file);
+ if (ch == EOF)
+ return NULL;
+
+ /* ch is now the first useful character of a useful line.
+ * it may be an @special or it may be the first character
+ * of a list of minutes.
+ */
+
+ e = (entry *) calloc(sizeof(entry), sizeof(char));
+
+ if (ch == '@') {
+ /* all of these should be flagged and load-limited; i.e.,
+ * instead of @hourly meaning "0 * * * *" it should mean
+ * "close to the front of every hour but not 'til the
+ * system load is low". Problems are: how do you know
+ * what "low" means? (save me from /etc/cron.conf!) and:
+ * how to guarantee low variance (how low is low?), which
+ * means how to we run roughly every hour -- seems like
+ * we need to keep a history or let the first hour set
+ * the schedule, which means we aren't load-limited
+ * anymore. too much for my overloaded brain. (vix, jan90)
+ * HINT
+ */
+ ch = get_string(cmd, MAX_COMMAND, file, " \t\n");
+ if (!strcmp("reboot", cmd)) {
+ e->flags |= WHEN_REBOOT;
+ } else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
+ bit_set(e->minute, 0);
+ bit_set(e->hour, 0);
+ bit_set(e->dom, 0);
+ bit_set(e->month, 0);
+ bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ } else if (!strcmp("monthly", cmd)) {
+ bit_set(e->minute, 0);
+ bit_set(e->hour, 0);
+ bit_set(e->dom, 0);
+ bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ } else if (!strcmp("weekly", cmd)) {
+ bit_set(e->minute, 0);
+ bit_set(e->hour, 0);
+ bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
+ bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ bit_set(e->dow, 0);
+ } else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
+ bit_set(e->minute, 0);
+ bit_set(e->hour, 0);
+ bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
+ bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ } else if (!strcmp("hourly", cmd)) {
+ bit_set(e->minute, 0);
+ bit_set(e->hour, (LAST_HOUR-FIRST_HOUR+1));
+ bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
+ bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ } else {
+ ecode = e_timespec;
+ goto eof;
+ }
+ } else {
+ Debug(DPARS, ("load_entry()...about to parse numerics\n"))
+
+ ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE,
+ PPC_NULL, ch, file);
+ if (ch == EOF) {
+ ecode = e_minute;
+ goto eof;
+ }
+
+ /* hours
+ */
+
+ ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR,
+ PPC_NULL, ch, file);
+ if (ch == EOF) {
+ ecode = e_hour;
+ goto eof;
+ }
+
+ /* DOM (days of month)
+ */
+
+ if (ch == '*')
+ e->flags |= DOM_STAR;
+ ch = get_list(e->dom, FIRST_DOM, LAST_DOM,
+ PPC_NULL, ch, file);
+ if (ch == EOF) {
+ ecode = e_dom;
+ goto eof;
+ }
+
+ /* month
+ */
+
+ ch = get_list(e->month, FIRST_MONTH, LAST_MONTH,
+ MonthNames, ch, file);
+ if (ch == EOF) {
+ ecode = e_month;
+ goto eof;
+ }
+
+ /* DOW (days of week)
+ */
+
+ if (ch == '*')
+ e->flags |= DOW_STAR;
+ ch = get_list(e->dow, FIRST_DOW, LAST_DOW,
+ DowNames, ch, file);
+ if (ch == EOF) {
+ ecode = e_dow;
+ goto eof;
+ }
+ }
+
+ /* make sundays equivilent */
+ if (bit_test(e->dow, 0) || bit_test(e->dow, 7)) {
+ bit_set(e->dow, 0);
+ bit_set(e->dow, 7);
+ }
+
+ /* ch is the first character of a command, or a username */
+ unget_char(ch, file);
+
+ if (!pw) {
+ char *username = cmd; /* temp buffer */
+
+ Debug(DPARS, ("load_entry()...about to parse username\n"))
+ ch = get_string(username, MAX_COMMAND, file, " \t");
+
+ Debug(DPARS, ("load_entry()...got %s\n",username))
+ if (ch == EOF) {
+ ecode = e_cmd;
+ goto eof;
+ }
+
+ pw = getpwnam(username);
+ if (pw == NULL) {
+ ecode = e_username;
+ goto eof;
+ }
+ Debug(DPARS, ("load_entry()...uid %d, gid %d\n",e->uid,e->gid))
+ }
+
+ e->uid = pw->pw_uid;
+ e->gid = pw->pw_gid;
+
+ /* copy and fix up environment. some variables are just defaults and
+ * others are overrides.
+ */
+ e->envp = env_copy(envp);
+ if (!env_get("SHELL", e->envp)) {
+ sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
+ e->envp = env_set(e->envp, envstr);
+ }
+ if (!env_get("HOME", e->envp)) {
+ sprintf(envstr, "HOME=%s", pw->pw_dir);
+ e->envp = env_set(e->envp, envstr);
+ }
+ if (!env_get("PATH", e->envp)) {
+ sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
+ e->envp = env_set(e->envp, envstr);
+ }
+ sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name);
+ e->envp = env_set(e->envp, envstr);
+#if defined(BSD)
+ sprintf(envstr, "%s=%s", "USER", pw->pw_name);
+ e->envp = env_set(e->envp, envstr);
+#endif
+
+ Debug(DPARS, ("load_entry()...about to parse command\n"))
+
+ /* Everything up to the next \n or EOF is part of the command...
+ * too bad we don't know in advance how long it will be, since we
+ * need to malloc a string for it... so, we limit it to MAX_COMMAND.
+ * XXX - should use realloc().
+ */
+ ch = get_string(cmd, MAX_COMMAND, file, "\n");
+
+ /* a file without a \n before the EOF is rude, so we'll complain...
+ */
+ if (ch == EOF) {
+ ecode = e_cmd;
+ goto eof;
+ }
+
+ /* got the command in the 'cmd' string; save it in *e.
+ */
+ e->cmd = strdup(cmd);
+
+ Debug(DPARS, ("load_entry()...returning successfully\n"))
+
+ /* success, fini, return pointer to the entry we just created...
+ */
+ return e;
+
+ eof:
+ free(e);
+ if (ecode != e_none && error_func)
+ (*error_func)(ecodes[(int)ecode]);
+ while (ch != EOF && ch != '\n')
+ ch = get_char(file);
+ return NULL;
+}
+
+
+static char
+get_list(bits, low, high, names, ch, file)
+ bitstr_t *bits; /* one bit per flag, default=FALSE */
+ int low, high; /* bounds, impl. offset for bitstr */
+ char *names[]; /* NULL or *[] of names for these elements */
+ int ch; /* current character being processed */
+ FILE *file; /* file being read */
+{
+ register int done;
+
+ /* we know that we point to a non-blank character here;
+ * must do a Skip_Blanks before we exit, so that the
+ * next call (or the code that picks up the cmd) can
+ * assume the same thing.
+ */
+
+ Debug(DPARS|DEXT, ("get_list()...entered\n"))
+
+ /* list = range {"," range}
+ */
+
+ /* clear the bit string, since the default is 'off'.
+ */
+ bit_nclear(bits, 0, (high-low+1));
+
+ /* process all ranges
+ */
+ done = FALSE;
+ while (!done) {
+ ch = get_range(bits, low, high, names, ch, file);
+ if (ch == ',')
+ ch = get_char(file);
+ else
+ done = TRUE;
+ }
+
+ /* exiting. skip to some blanks, then skip over the blanks.
+ */
+ Skip_Nonblanks(ch, file)
+ Skip_Blanks(ch, file)
+
+ Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch))
+
+ return ch;
+}
+
+
+static char
+get_range(bits, low, high, names, ch, file)
+ bitstr_t *bits; /* one bit per flag, default=FALSE */
+ int low, high; /* bounds, impl. offset for bitstr */
+ char *names[]; /* NULL or names of elements */
+ int ch; /* current character being processed */
+ FILE *file; /* file being read */
+{
+ /* range = number | number "-" number [ "/" number ]
+ */
+
+ register int i;
+ auto int num1, num2, num3;
+
+ Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n"))
+
+ if (ch == '*') {
+ /* '*' means "first-last" but can still be modified by /step
+ */
+ num1 = low;
+ num2 = high;
+ ch = get_char(file);
+ if (ch == EOF)
+ return EOF;
+ } else {
+ if (EOF == (ch = get_number(&num1, low, names, ch, file)))
+ return EOF;
+
+ if (ch != '-') {
+ /* not a range, it's a single number.
+ */
+ if (EOF == set_element(bits, low, high, num1))
+ return EOF;
+ return ch;
+ } else {
+ /* eat the dash
+ */
+ ch = get_char(file);
+ if (ch == EOF)
+ return EOF;
+
+ /* get the number following the dash
+ */
+ ch = get_number(&num2, low, names, ch, file);
+ if (ch == EOF)
+ return EOF;
+ }
+ }
+
+ /* check for step size
+ */
+ if (ch == '/') {
+ /* eat the slash
+ */
+ ch = get_char(file);
+ if (ch == EOF)
+ return EOF;
+
+ /* get the step size -- note: we don't pass the
+ * names here, because the number is not an
+ * element id, it's a step size. 'low' is
+ * sent as a 0 since there is no offset either.
+ */
+ ch = get_number(&num3, 0, PPC_NULL, ch, file);
+ if (ch == EOF)
+ return EOF;
+ } else {
+ /* no step. default==1.
+ */
+ num3 = 1;
+ }
+
+ /* range. set all elements from num1 to num2, stepping
+ * by num3. (the step is a downward-compatible extension
+ * proposed conceptually by bob@acornrc, syntactically
+ * designed then implmented by paul vixie).
+ */
+ for (i = num1; i <= num2; i += num3)
+ if (EOF == set_element(bits, low, high, i))
+ return EOF;
+
+ return ch;
+}
+
+
+static char
+get_number(numptr, low, names, ch, file)
+ int *numptr; /* where does the result go? */
+ int low; /* offset applied to result if symbolic enum used */
+ char *names[]; /* symbolic names, if any, for enums */
+ int ch; /* current character */
+ FILE *file; /* source */
+{
+ char temp[MAX_TEMPSTR], *pc;
+ int len, i, all_digits;
+
+ /* collect alphanumerics into our fixed-size temp array
+ */
+ pc = temp;
+ len = 0;
+ all_digits = TRUE;
+ while (isalnum(ch)) {
+ if (++len >= MAX_TEMPSTR)
+ return EOF;
+
+ *pc++ = ch;
+
+ if (!isdigit(ch))
+ all_digits = FALSE;
+
+ ch = get_char(file);
+ }
+ *pc = '\0';
+
+ /* try to find the name in the name list
+ */
+ if (names) {
+ for (i = 0; names[i] != NULL; i++) {
+ Debug(DPARS|DEXT,
+ ("get_num, compare(%s,%s)\n", names[i], temp))
+ if (!strcasecmp(names[i], temp)) {
+ *numptr = i+low;
+ return ch;
+ }
+ }
+ }
+
+ /* no name list specified, or there is one and our string isn't
+ * in it. either way: if it's all digits, use its magnitude.
+ * otherwise, it's an error.
+ */
+ if (all_digits) {
+ *numptr = atoi(temp);
+ return ch;
+ }
+
+ return EOF;
+}
+
+
+static int
+set_element(bits, low, high, number)
+ bitstr_t *bits; /* one bit per flag, default=FALSE */
+ int low;
+ int high;
+ int number;
+{
+ Debug(DPARS|DEXT, ("set_element(?,%d,%d,%d)\n", low, high, number))
+
+ if (number < low || number > high)
+ return EOF;
+
+ bit_set(bits, (number-low));
+ return OK;
+}
diff --git a/usr.sbin/cron/env.c b/usr.sbin/cron/env.c
new file mode 100644
index 00000000000..c9cd3a5e75c
--- /dev/null
+++ b/usr.sbin/cron/env.c
@@ -0,0 +1,178 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: env.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+
+#include "cron.h"
+
+
+char **
+env_init()
+{
+ register char **p = (char **) malloc(sizeof(char **));
+
+ p[0] = NULL;
+ return (p);
+}
+
+
+void
+env_free(envp)
+ char **envp;
+{
+ char **p;
+
+ for (p = envp; *p; p++)
+ free(*p);
+ free(envp);
+}
+
+
+char **
+env_copy(envp)
+ register char **envp;
+{
+ register int count, i;
+ register char **p;
+
+ for (count = 0; envp[count] != NULL; count++)
+ ;
+ p = (char **) malloc((count+1) * sizeof(char *)); /* 1 for the NULL */
+ for (i = 0; i < count; i++)
+ p[i] = strdup(envp[i]);
+ p[count] = NULL;
+ return (p);
+}
+
+
+char **
+env_set(envp, envstr)
+ char **envp;
+ char *envstr;
+{
+ register int count, found;
+ register char **p;
+
+ /*
+ * count the number of elements, including the null pointer;
+ * also set 'found' to -1 or index of entry if already in here.
+ */
+ found = -1;
+ for (count = 0; envp[count] != NULL; count++) {
+ if (!strcmp_until(envp[count], envstr, '='))
+ found = count;
+ }
+ count++; /* for the NULL */
+
+ if (found != -1) {
+ /*
+ * it exists already, so just free the existing setting,
+ * save our new one there, and return the existing array.
+ */
+ free(envp[found]);
+ envp[found] = strdup(envstr);
+ return (envp);
+ }
+
+ /*
+ * it doesn't exist yet, so resize the array, move null pointer over
+ * one, save our string over the old null pointer, and return resized
+ * array.
+ */
+ p = (char **) realloc((void *) envp,
+ (unsigned) ((count+1) * sizeof(char **)));
+ p[count] = p[count-1];
+ p[count-1] = strdup(envstr);
+ return (p);
+}
+
+
+/* return ERR = end of file
+ * FALSE = not an env setting (file was repositioned)
+ * TRUE = was an env setting
+ */
+int
+load_env(envstr, f)
+ char *envstr;
+ FILE *f;
+{
+ long filepos;
+ int fileline;
+ char name[MAX_TEMPSTR], val[MAX_ENVSTR];
+ int fields;
+
+ filepos = ftell(f);
+ fileline = LineNumber;
+ skip_comments(f);
+ if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
+ return (ERR);
+
+ Debug(DPARS, ("load_env, read <%s>\n", envstr))
+
+ name[0] = val[0] = '\0';
+ fields = sscanf(envstr, "%[^ =] = %[^\n#]", name, val);
+ if (fields != 2) {
+ Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
+ fseek(f, filepos, 0);
+ Set_LineNum(fileline);
+ return (FALSE);
+ }
+
+ /* 2 fields from scanf; looks like an env setting
+ */
+
+ /*
+ * process value string
+ */
+ /*local*/{
+ int len = strdtb(val);
+
+ if (len >= 2) {
+ if (val[0] == '\'' || val[0] == '"') {
+ if (val[len-1] == val[0]) {
+ val[len-1] = '\0';
+ (void) strcpy(val, val+1);
+ }
+ }
+ }
+ }
+
+ (void) sprintf(envstr, "%s=%s", name, val);
+ Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
+ return (TRUE);
+}
+
+
+char *
+env_get(name, envp)
+ register char *name;
+ register char **envp;
+{
+ register int len = strlen(name);
+ register char *p, *q;
+
+ while (p = *envp++) {
+ if (!(q = strchr(p, '=')))
+ continue;
+ if ((q - p) == len && !strncmp(p, name, len))
+ return (q+1);
+ }
+ return (NULL);
+}
diff --git a/usr.sbin/cron/externs.h b/usr.sbin/cron/externs.h
new file mode 100644
index 00000000000..3efe605897e
--- /dev/null
+++ b/usr.sbin/cron/externs.h
@@ -0,0 +1,145 @@
+/* Copyright 1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if defined(POSIX) || defined(ATT)
+# include <stdlib.h>
+# include <unistd.h>
+# include <string.h>
+# include <dirent.h>
+# define DIR_T struct dirent
+# define WAIT_T int
+# define WAIT_IS_INT 1
+extern char *tzname[2];
+# define TZONE(tm) tzname[(tm).tm_isdst]
+#endif
+
+#if defined(UNIXPC)
+# undef WAIT_T
+# undef WAIT_IS_INT
+# define WAIT_T union wait
+#endif
+
+#if defined(POSIX)
+# define SIG_T sig_t
+# define TIME_T time_t
+# define PID_T pid_t
+#endif
+
+#if defined(ATT)
+# define SIG_T void
+# define TIME_T long
+# define PID_T int
+#endif
+
+#if !defined(POSIX) && !defined(ATT)
+/* classic BSD */
+extern time_t time();
+extern unsigned sleep();
+extern struct tm *localtime();
+extern struct passwd *getpwnam();
+extern int errno;
+extern void perror(), exit(), free();
+extern char *getenv(), *strcpy(), *strchr(), *strtok();
+extern void *malloc(), *realloc();
+# define SIG_T void
+# define TIME_T long
+# define PID_T int
+# define WAIT_T union wait
+# define DIR_T struct direct
+# include <sys/dir.h>
+# define TZONE(tm) (tm).tm_zone
+#endif
+
+/* getopt() isn't part of POSIX. some systems define it in <stdlib.h> anyway.
+ * of those that do, some complain that our definition is different and some
+ * do not. to add to the misery and confusion, some systems define getopt()
+ * in ways that we cannot predict or comprehend, yet do not define the adjunct
+ * external variables needed for the interface.
+ */
+#if (!defined(BSD) || (BSD < 198911)) && !defined(ATT) && !defined(UNICOS)
+int getopt __P((int, char * const *, const char *));
+#endif
+
+#if (!defined(BSD) || (BSD < 199103))
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+
+#if WAIT_IS_INT
+# ifndef WEXITSTATUS
+# define WEXITSTATUS(x) (((x) >> 8) & 0xff)
+# endif
+# ifndef WTERMSIG
+# define WTERMSIG(x) ((x) & 0x7f)
+# endif
+# ifndef WCOREDUMP
+# define WCOREDUMP(x) ((x) & 0x80)
+# endif
+#else /*WAIT_IS_INT*/
+# ifndef WEXITSTATUS
+# define WEXITSTATUS(x) ((x).w_retcode)
+# endif
+# ifndef WTERMSIG
+# define WTERMSIG(x) ((x).w_termsig)
+# endif
+# ifndef WCOREDUMP
+# define WCOREDUMP(x) ((x).w_coredump)
+# endif
+#endif /*WAIT_IS_INT*/
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(x) (WTERMSIG(x) != 0)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(x) (WTERMSIG(x) == 0)
+#endif
+
+#ifdef NEED_STRCASECMP
+extern int strcasecmp __P((char *, char *));
+#endif
+
+#ifdef NEED_STRDUP
+extern char *strdup __P((char *));
+#endif
+
+#ifdef NEED_STRERROR
+extern char *strerror __P((int));
+#endif
+
+#ifdef NEED_FLOCK
+extern int flock __P((int, int));
+# define LOCK_SH 1
+# define LOCK_EX 2
+# define LOCK_NB 4
+# define LOCK_UN 8
+#endif
+
+#ifdef NEED_SETSID
+extern int setsid __P((void));
+#endif
+
+#ifdef NEED_GETDTABLESIZE
+extern int getdtablesize __P((void));
+#endif
+
+#ifdef NEED_SETENV
+extern int setenv __P((char *, char *, int));
+#endif
+
+#ifdef NEED_VFORK
+extern PID_T vfork __P((void));
+#endif
diff --git a/usr.sbin/cron/job.c b/usr.sbin/cron/job.c
new file mode 100644
index 00000000000..69047fc0940
--- /dev/null
+++ b/usr.sbin/cron/job.c
@@ -0,0 +1,74 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: job.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+
+#include "cron.h"
+
+
+typedef struct _job {
+ struct _job *next;
+ entry *e;
+ user *u;
+} job;
+
+
+static job *jhead = NULL, *jtail = NULL;
+
+
+void
+job_add(e, u)
+ register entry *e;
+ register user *u;
+{
+ register job *j;
+
+ /* if already on queue, keep going */
+ for (j=jhead; j; j=j->next)
+ if (j->e == e && j->u == u) { return; }
+
+ /* build a job queue element */
+ j = (job*)malloc(sizeof(job));
+ j->next = (job*) NULL;
+ j->e = e;
+ j->u = u;
+
+ /* add it to the tail */
+ if (!jhead) { jhead=j; }
+ else { jtail->next=j; }
+ jtail = j;
+}
+
+
+int
+job_runqueue()
+{
+ register job *j, *jn;
+ register int run = 0;
+
+ for (j=jhead; j; j=jn) {
+ do_command(j->e, j->u);
+ jn = j->next;
+ free(j);
+ run++;
+ }
+ jhead = jtail = NULL;
+ return run;
+}
diff --git a/usr.sbin/cron/misc.c b/usr.sbin/cron/misc.c
new file mode 100644
index 00000000000..20b44c8ef22
--- /dev/null
+++ b/usr.sbin/cron/misc.c
@@ -0,0 +1,664 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: misc.c,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $";
+#endif
+
+/* vix 26jan87 [RCS has the rest of the log]
+ * vix 30dec86 [written]
+ */
+
+
+#include "cron.h"
+#if SYS_TIME_H
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#if defined(SYSLOG)
+# include <syslog.h>
+#endif
+
+
+#if defined(LOG_DAEMON) && !defined(LOG_CRON)
+#define LOG_CRON LOG_DAEMON
+#endif
+
+
+static int LogFD = ERR;
+
+
+int
+strcmp_until(left, right, until)
+ char *left;
+ char *right;
+ int until;
+{
+ register int diff;
+
+ while (*left && *left != until && *left == *right) {
+ left++;
+ right++;
+ }
+
+ if ((*left=='\0' || *left == until) &&
+ (*right=='\0' || *right == until)) {
+ diff = 0;
+ } else {
+ diff = *left - *right;
+ }
+
+ return diff;
+}
+
+
+/* strdtb(s) - delete trailing blanks in string 's' and return new length
+ */
+int
+strdtb(s)
+ char *s;
+{
+ char *x = s;
+
+ /* scan forward to the null
+ */
+ while (*x)
+ x++;
+
+ /* scan backward to either the first character before the string,
+ * or the last non-blank in the string, whichever comes first.
+ */
+ do {x--;}
+ while (x >= s && isspace(*x));
+
+ /* one character beyond where we stopped above is where the null
+ * goes.
+ */
+ *++x = '\0';
+
+ /* the difference between the position of the null character and
+ * the position of the first character of the string is the length.
+ */
+ return x - s;
+}
+
+
+int
+set_debug_flags(flags)
+ char *flags;
+{
+ /* debug flags are of the form flag[,flag ...]
+ *
+ * if an error occurs, print a message to stdout and return FALSE.
+ * otherwise return TRUE after setting ERROR_FLAGS.
+ */
+
+#if !DEBUGGING
+
+ printf("this program was compiled without debugging enabled\n");
+ return FALSE;
+
+#else /* DEBUGGING */
+
+ char *pc = flags;
+
+ DebugFlags = 0;
+
+ while (*pc) {
+ char **test;
+ int mask;
+
+ /* try to find debug flag name in our list.
+ */
+ for ( test = DebugFlagNames, mask = 1;
+ *test && strcmp_until(*test, pc, ',');
+ test++, mask <<= 1
+ )
+ ;
+
+ if (!*test) {
+ fprintf(stderr,
+ "unrecognized debug flag <%s> <%s>\n",
+ flags, pc);
+ return FALSE;
+ }
+
+ DebugFlags |= mask;
+
+ /* skip to the next flag
+ */
+ while (*pc && *pc != ',')
+ pc++;
+ if (*pc == ',')
+ pc++;
+ }
+
+ if (DebugFlags) {
+ int flag;
+
+ fprintf(stderr, "debug flags enabled:");
+
+ for (flag = 0; DebugFlagNames[flag]; flag++)
+ if (DebugFlags & (1 << flag))
+ fprintf(stderr, " %s", DebugFlagNames[flag]);
+ fprintf(stderr, "\n");
+ }
+
+ return TRUE;
+
+#endif /* DEBUGGING */
+}
+
+
+void
+set_cron_uid()
+{
+#if defined(BSD) || defined(POSIX)
+ if (seteuid(ROOT_UID) < OK) {
+ perror("seteuid");
+ exit(ERROR_EXIT);
+ }
+#else
+ if (setuid(ROOT_UID) < OK) {
+ perror("setuid");
+ exit(ERROR_EXIT);
+ }
+#endif
+}
+
+
+void
+set_cron_cwd()
+{
+ struct stat sb;
+
+ /* first check for CRONDIR ("/var/cron" or some such)
+ */
+ if (stat(CRONDIR, &sb) < OK && errno == ENOENT) {
+ perror(CRONDIR);
+ if (OK == mkdir(CRONDIR, 0700)) {
+ fprintf(stderr, "%s: created\n", CRONDIR);
+ stat(CRONDIR, &sb);
+ } else {
+ fprintf(stderr, "%s: ", CRONDIR);
+ perror("mkdir");
+ exit(ERROR_EXIT);
+ }
+ }
+ if (!(sb.st_mode & S_IFDIR)) {
+ fprintf(stderr, "'%s' is not a directory, bailing out.\n",
+ CRONDIR);
+ exit(ERROR_EXIT);
+ }
+ if (chdir(CRONDIR) < OK) {
+ fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
+ perror(CRONDIR);
+ exit(ERROR_EXIT);
+ }
+
+ /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such)
+ */
+ if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) {
+ perror(SPOOL_DIR);
+ if (OK == mkdir(SPOOL_DIR, 0700)) {
+ fprintf(stderr, "%s: created\n", SPOOL_DIR);
+ stat(SPOOL_DIR, &sb);
+ } else {
+ fprintf(stderr, "%s: ", SPOOL_DIR);
+ perror("mkdir");
+ exit(ERROR_EXIT);
+ }
+ }
+ if (!(sb.st_mode & S_IFDIR)) {
+ fprintf(stderr, "'%s' is not a directory, bailing out.\n",
+ SPOOL_DIR);
+ exit(ERROR_EXIT);
+ }
+}
+
+
+/* acquire_daemonlock() - write our PID into /etc/cron.pid, unless
+ * another daemon is already running, which we detect here.
+ *
+ * note: main() calls us twice; once before forking, once after.
+ * we maintain static storage of the file pointer so that we
+ * can rewrite our PID into the PIDFILE after the fork.
+ *
+ * it would be great if fflush() disassociated the file buffer.
+ */
+void
+acquire_daemonlock(closeflag)
+ int closeflag;
+{
+ static FILE *fp = NULL;
+
+ if (closeflag && fp) {
+ fclose(fp);
+ fp = NULL;
+ return;
+ }
+
+ if (!fp) {
+ char pidfile[MAX_FNAME];
+ char buf[MAX_TEMPSTR];
+ int fd, otherpid;
+
+ (void) sprintf(pidfile, PIDFILE, PIDDIR);
+ if ((-1 == (fd = open(pidfile, O_RDWR|O_CREAT, 0644)))
+ || (NULL == (fp = fdopen(fd, "r+")))
+ ) {
+ sprintf(buf, "can't open or create %s: %s",
+ pidfile, strerror(errno));
+ fprintf(stderr, "%s: %s\n", ProgramName, buf);
+ log_it("CRON", getpid(), "DEATH", buf);
+ exit(ERROR_EXIT);
+ }
+
+ if (flock(fd, LOCK_EX|LOCK_NB) < OK) {
+ int save_errno = errno;
+
+ fscanf(fp, "%d", &otherpid);
+ sprintf(buf, "can't lock %s, otherpid may be %d: %s",
+ pidfile, otherpid, strerror(save_errno));
+ fprintf(stderr, "%s: %s\n", ProgramName, buf);
+ log_it("CRON", getpid(), "DEATH", buf);
+ exit(ERROR_EXIT);
+ }
+
+ (void) fcntl(fd, F_SETFD, 1);
+ }
+
+ rewind(fp);
+ fprintf(fp, "%d\n", getpid());
+ fflush(fp);
+ (void) ftruncate(fileno(fp), ftell(fp));
+
+ /* abandon fd and fp even though the file is open. we need to
+ * keep it open and locked, but we don't need the handles elsewhere.
+ */
+}
+
+/* get_char(file) : like getc() but increment LineNumber on newlines
+ */
+int
+get_char(file)
+ FILE *file;
+{
+ int ch;
+
+ ch = getc(file);
+ if (ch == '\n')
+ Set_LineNum(LineNumber + 1)
+ return ch;
+}
+
+
+/* unget_char(ch, file) : like ungetc but do LineNumber processing
+ */
+void
+unget_char(ch, file)
+ int ch;
+ FILE *file;
+{
+ ungetc(ch, file);
+ if (ch == '\n')
+ Set_LineNum(LineNumber - 1)
+}
+
+
+/* get_string(str, max, file, termstr) : like fgets() but
+ * (1) has terminator string which should include \n
+ * (2) will always leave room for the null
+ * (3) uses get_char() so LineNumber will be accurate
+ * (4) returns EOF or terminating character, whichever
+ */
+int
+get_string(string, size, file, terms)
+ char *string;
+ int size;
+ FILE *file;
+ char *terms;
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
+ if (size > 1) {
+ *string++ = (char) ch;
+ size--;
+ }
+ }
+
+ if (size > 0)
+ *string = '\0';
+
+ return ch;
+}
+
+
+/* skip_comments(file) : read past comment (if any)
+ */
+void
+skip_comments(file)
+ FILE *file;
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file))) {
+ /* ch is now the first character of a line.
+ */
+
+ while (ch == ' ' || ch == '\t')
+ ch = get_char(file);
+
+ if (ch == EOF)
+ break;
+
+ /* ch is now the first non-blank character of a line.
+ */
+
+ if (ch != '\n' && ch != '#')
+ break;
+
+ /* ch must be a newline or comment as first non-blank
+ * character on a line.
+ */
+
+ while (ch != '\n' && ch != EOF)
+ ch = get_char(file);
+
+ /* ch is now the newline of a line which we're going to
+ * ignore.
+ */
+ }
+ if (ch != EOF)
+ unget_char(ch, file);
+}
+
+
+/* int in_file(char *string, FILE *file)
+ * return TRUE if one of the lines in file matches string exactly,
+ * FALSE otherwise.
+ */
+static int
+in_file(string, file)
+ char *string;
+ FILE *file;
+{
+ char line[MAX_TEMPSTR];
+
+ rewind(file);
+ while (fgets(line, MAX_TEMPSTR, file)) {
+ if (line[0] != '\0')
+ line[strlen(line)-1] = '\0';
+ if (0 == strcmp(line, string))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/* int allowed(char *username)
+ * returns TRUE if (ALLOW_FILE exists and user is listed)
+ * or (DENY_FILE exists and user is NOT listed)
+ * or (neither file exists but user=="root" so it's okay)
+ */
+int
+allowed(username)
+ char *username;
+{
+ static int init = FALSE;
+ static FILE *allow, *deny;
+
+ if (!init) {
+ init = TRUE;
+#if defined(ALLOW_FILE) && defined(DENY_FILE)
+ allow = fopen(ALLOW_FILE, "r");
+ deny = fopen(DENY_FILE, "r");
+ Debug(DMISC, ("allow/deny enabled, %d/%d\n", !!allow, !!deny))
+#else
+ allow = NULL;
+ deny = NULL;
+#endif
+ }
+
+ if (allow)
+ return (in_file(username, allow));
+ if (deny)
+ return (!in_file(username, deny));
+
+#if defined(ALLOW_ONLY_ROOT)
+ return (strcmp(username, ROOT_USER) == 0);
+#else
+ return TRUE;
+#endif
+}
+
+
+void
+log_it(username, xpid, event, detail)
+ char *username;
+ int xpid;
+ char *event;
+ char *detail;
+{
+ PID_T pid = xpid;
+#if defined(LOG_FILE)
+ char *msg;
+ TIME_T now = time((TIME_T) 0);
+ register struct tm *t = localtime(&now);
+#endif /*LOG_FILE*/
+
+#if defined(SYSLOG)
+ static int syslog_open = 0;
+#endif
+
+#if defined(LOG_FILE)
+ /* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
+ */
+ msg = malloc(strlen(username)
+ + strlen(event)
+ + strlen(detail)
+ + MAX_TEMPSTR);
+
+ if (LogFD < OK) {
+ LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
+ if (LogFD < OK) {
+ fprintf(stderr, "%s: can't open log file\n",
+ ProgramName);
+ perror(LOG_FILE);
+ } else {
+ (void) fcntl(LogFD, F_SETFD, 1);
+ }
+ }
+
+ /* we have to sprintf() it because fprintf() doesn't always write
+ * everything out in one chunk and this has to be atomically appended
+ * to the log file.
+ */
+ sprintf(msg, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
+ username,
+ t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid,
+ event, detail);
+
+ /* we have to run strlen() because sprintf() returns (char*) on old BSD
+ */
+ if (LogFD < OK || write(LogFD, msg, strlen(msg)) < OK) {
+ if (LogFD >= OK)
+ perror(LOG_FILE);
+ fprintf(stderr, "%s: can't write to log file\n", ProgramName);
+ write(STDERR, msg, strlen(msg));
+ }
+
+ free(msg);
+#endif /*LOG_FILE*/
+
+#if defined(SYSLOG)
+ if (!syslog_open) {
+ /* we don't use LOG_PID since the pid passed to us by
+ * our client may not be our own. therefore we want to
+ * print the pid ourselves.
+ */
+# ifdef LOG_DAEMON
+ openlog(ProgramName, LOG_PID, LOG_CRON);
+# else
+ openlog(ProgramName, LOG_PID);
+# endif
+ syslog_open = TRUE; /* assume openlog success */
+ }
+
+ syslog(LOG_INFO, "(%s) %s (%s)\n", username, event, detail);
+
+#endif /*SYSLOG*/
+
+#if DEBUGGING
+ if (DebugFlags) {
+ fprintf(stderr, "log_it: (%s %d) %s (%s)\n",
+ username, pid, event, detail);
+ }
+#endif
+}
+
+
+void
+log_close() {
+ if (LogFD != ERR) {
+ close(LogFD);
+ LogFD = ERR;
+ }
+}
+
+
+/* two warnings:
+ * (1) this routine is fairly slow
+ * (2) it returns a pointer to static storage
+ */
+char *
+first_word(s, t)
+ register char *s; /* string we want the first word of */
+ register char *t; /* terminators, implicitly including \0 */
+{
+ static char retbuf[2][MAX_TEMPSTR + 1]; /* sure wish C had GC */
+ static int retsel = 0;
+ register char *rb, *rp;
+
+ /* select a return buffer */
+ retsel = 1-retsel;
+ rb = &retbuf[retsel][0];
+ rp = rb;
+
+ /* skip any leading terminators */
+ while (*s && (NULL != strchr(t, *s))) {
+ s++;
+ }
+
+ /* copy until next terminator or full buffer */
+ while (*s && (NULL == strchr(t, *s)) && (rp < &rb[MAX_TEMPSTR])) {
+ *rp++ = *s++;
+ }
+
+ /* finish the return-string and return it */
+ *rp = '\0';
+ return rb;
+}
+
+
+/* warning:
+ * heavily ascii-dependent.
+ */
+void
+mkprint(dst, src, len)
+ register char *dst;
+ register unsigned char *src;
+ register int len;
+{
+ while (len-- > 0)
+ {
+ register unsigned char ch = *src++;
+
+ if (ch < ' ') { /* control character */
+ *dst++ = '^';
+ *dst++ = ch + '@';
+ } else if (ch < 0177) { /* printable */
+ *dst++ = ch;
+ } else if (ch == 0177) { /* delete/rubout */
+ *dst++ = '^';
+ *dst++ = '?';
+ } else { /* parity character */
+ sprintf(dst, "\\%03o", ch);
+ dst += 4;
+ }
+ }
+ *dst = '\0';
+}
+
+
+/* warning:
+ * returns a pointer to malloc'd storage, you must call free yourself.
+ */
+char *
+mkprints(src, len)
+ register unsigned char *src;
+ register unsigned int len;
+{
+ register char *dst = malloc(len*4 + 1);
+
+ mkprint(dst, src, len);
+
+ return dst;
+}
+
+
+#ifdef MAIL_DATE
+/* Sat, 27 Feb 93 11:44:51 CST
+ * 123456789012345678901234567
+ */
+char *
+arpadate(clock)
+ time_t *clock;
+{
+ time_t t = clock ?*clock :time(0L);
+ struct tm *tm = localtime(&t);
+ static char ret[30]; /* zone name might be >3 chars */
+
+ (void) sprintf(ret, "%s, %2d %s %2d %02d:%02d:%02d %s",
+ DowNames[tm->tm_wday],
+ tm->tm_mday,
+ MonthNames[tm->tm_mon],
+ tm->tm_year,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ TZONE(*tm));
+ return ret;
+}
+#endif /*MAIL_DATE*/
+
+
+#ifdef HAVE_SAVED_UIDS
+static int save_euid;
+int swap_uids() { save_euid = geteuid(); return seteuid(getuid()); }
+int swap_uids_back() { return seteuid(save_euid); }
+#else /*HAVE_SAVED_UIDS*/
+int swap_uids() { return setreuid(geteuid(), getuid()); }
+int swap_uids_back() { return swap_uids(); }
+#endif /*HAVE_SAVED_UIDS*/
diff --git a/usr.sbin/cron/pathnames.h b/usr.sbin/cron/pathnames.h
new file mode 100644
index 00000000000..b6819ceb2a7
--- /dev/null
+++ b/usr.sbin/cron/pathnames.h
@@ -0,0 +1,81 @@
+/* Copyright 1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+/*
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:30 deraadt Exp $
+ */
+
+#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
+# include <paths.h>
+#endif /*BSD*/
+
+#ifndef CRONDIR
+ /* CRONDIR is where crond(8) and crontab(1) both chdir
+ * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE
+ * are all relative to this directory.
+ */
+#define CRONDIR "/var/cron"
+#endif
+
+ /* SPOOLDIR is where the crontabs live.
+ * This directory will have its modtime updated
+ * whenever crontab(1) changes a crontab; this is
+ * the signal for crond(8) to look at each individual
+ * crontab file and reload those whose modtimes are
+ * newer than they were last time around (or which
+ * didn't exist last time around...)
+ */
+#define SPOOL_DIR "tabs"
+
+ /* undefining these turns off their features. note
+ * that ALLOW_FILE and DENY_FILE must both be defined
+ * in order to enable the allow/deny code. If neither
+ * LOG_FILE or SYSLOG is defined, we don't log. If
+ * both are defined, we log both ways.
+ */
+#define ALLOW_FILE "allow" /*-*/
+#define DENY_FILE "deny" /*-*/
+/* #define LOG_FILE "log" /*-*/
+
+ /* where should the daemon stick its PID?
+ */
+#ifdef _PATH_VARRUN
+# define PIDDIR _PATH_VARRUN
+#else
+# define PIDDIR "/etc/"
+#endif
+#define PIDFILE "%scron.pid"
+
+ /* 4.3BSD-style crontab */
+#define SYSCRONTAB "/etc/crontab"
+
+ /* what editor to use if no EDITOR or VISUAL
+ * environment variable specified.
+ */
+#if defined(_PATH_VI)
+# define EDITOR _PATH_VI
+#else
+# define EDITOR "/usr/ucb/vi"
+#endif
+
+#ifndef _PATH_BSHELL
+# define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef _PATH_DEFPATH
+# define _PATH_DEFPATH "/usr/bin:/bin"
+#endif
diff --git a/usr.sbin/cron/popen.c b/usr.sbin/cron/popen.c
new file mode 100644
index 00000000000..44638dacba5
--- /dev/null
+++ b/usr.sbin/cron/popen.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/* this came out of the ftpd sources; it's been modified to avoid the
+ * globbing stuff since we don't need it. also execvp instead of execv.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: popen.c,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $";
+static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89";
+#endif /* not lint */
+
+#include "cron.h"
+#include <sys/signal.h>
+
+
+#define MAX_ARGS 100
+#define WANT_GLOBBING 0
+
+/*
+ * Special version of popen which avoids call to shell. This insures noone
+ * may create a pipe to a hidden program as a side effect of a list or dir
+ * command.
+ */
+static PID_T *pids;
+static int fds;
+
+FILE *
+cron_popen(program, type)
+ char *program, *type;
+{
+ register char *cp;
+ FILE *iop;
+ int argc, pdes[2];
+ PID_T pid;
+ char *argv[MAX_ARGS + 1];
+#if WANT_GLOBBING
+ char **pop, *vv[2];
+ int gargc;
+ char *gargv[1000];
+ extern char **glob(), **copyblk();
+#endif
+
+ if (*type != 'r' && *type != 'w' || type[1])
+ return(NULL);
+
+ if (!pids) {
+ if ((fds = getdtablesize()) <= 0)
+ return(NULL);
+ if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
+ return(NULL);
+ bzero((char *)pids, fds * sizeof(PID_T));
+ }
+ if (pipe(pdes) < 0)
+ return(NULL);
+
+ /* break up string into pieces */
+ for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
+ if (!(argv[argc++] = strtok(cp, " \t\n")))
+ break;
+
+#if WANT_GLOBBING
+ /* glob each piece */
+ gargv[0] = argv[0];
+ for (gargc = argc = 1; argv[argc]; argc++) {
+ if (!(pop = glob(argv[argc]))) { /* globbing failed */
+ vv[0] = argv[argc];
+ vv[1] = NULL;
+ pop = copyblk(vv);
+ }
+ argv[argc] = (char *)pop; /* save to free later */
+ while (*pop && gargc < 1000)
+ gargv[gargc++] = *pop++;
+ }
+ gargv[gargc] = NULL;
+#endif
+
+ iop = NULL;
+ switch(pid = vfork()) {
+ case -1: /* error */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ goto pfree;
+ /* NOTREACHED */
+ case 0: /* child */
+ if (*type == 'r') {
+ if (pdes[1] != 1) {
+ dup2(pdes[1], 1);
+ dup2(pdes[1], 2); /* stderr, too! */
+ (void)close(pdes[1]);
+ }
+ (void)close(pdes[0]);
+ } else {
+ if (pdes[0] != 0) {
+ dup2(pdes[0], 0);
+ (void)close(pdes[0]);
+ }
+ (void)close(pdes[1]);
+ }
+#if WANT_GLOBBING
+ execvp(gargv[0], gargv);
+#else
+ execvp(argv[0], argv);
+#endif
+ _exit(1);
+ }
+ /* parent; assume fdopen can't fail... */
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ (void)close(pdes[1]);
+ } else {
+ iop = fdopen(pdes[1], type);
+ (void)close(pdes[0]);
+ }
+ pids[fileno(iop)] = pid;
+
+pfree:
+#if WANT_GLOBBING
+ for (argc = 1; argv[argc] != NULL; argc++) {
+/* blkfree((char **)argv[argc]); */
+ free((char *)argv[argc]);
+ }
+#endif
+ return(iop);
+}
+
+int
+cron_pclose(iop)
+ FILE *iop;
+{
+ register int fdes;
+ int omask;
+ WAIT_T stat_loc;
+ PID_T pid;
+
+ /*
+ * pclose returns -1 if stream is not associated with a
+ * `popened' command, or, if already `pclosed'.
+ */
+ if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+ return(-1);
+ (void)fclose(iop);
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
+ ;
+ (void)sigsetmask(omask);
+ pids[fdes] = 0;
+ return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
+}
diff --git a/usr.sbin/cron/user.c b/usr.sbin/cron/user.c
new file mode 100644
index 00000000000..1354dea8eca
--- /dev/null
+++ b/usr.sbin/cron/user.c
@@ -0,0 +1,102 @@
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
+ */
+
+#if !defined(lint) && !defined(LINT)
+static char rcsid[] = "$Id: user.c,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $";
+#endif
+
+/* vix 26jan87 [log is in RCS file]
+ */
+
+
+#include "cron.h"
+
+
+void
+free_user(u)
+ user *u;
+{
+ entry *e, *ne;
+
+ free(u->name);
+ for (e = u->crontab; e != NULL; e = ne) {
+ ne = e->next;
+ free_entry(e);
+ }
+ free(u);
+}
+
+
+user *
+load_user(crontab_fd, pw, name)
+ int crontab_fd;
+ struct passwd *pw; /* NULL implies syscrontab */
+ char *name;
+{
+ char envstr[MAX_ENVSTR];
+ FILE *file;
+ user *u;
+ entry *e;
+ int status;
+ char **envp;
+
+ if (!(file = fdopen(crontab_fd, "r"))) {
+ perror("fdopen on crontab_fd in load_user");
+ return NULL;
+ }
+
+ Debug(DPARS, ("load_user()\n"))
+
+ /* file is open. build user entry, then read the crontab file.
+ */
+ u = (user *) malloc(sizeof(user));
+ u->name = strdup(name);
+ u->crontab = NULL;
+
+ /*
+ * init environment. this will be copied/augmented for each entry.
+ */
+ envp = env_init();
+
+ /*
+ * load the crontab
+ */
+ while ((status = load_env(envstr, file)) >= OK) {
+ switch (status) {
+ case ERR:
+ free_user(u);
+ u = NULL;
+ goto done;
+ case FALSE:
+ e = load_entry(file, NULL, pw, envp);
+ if (e) {
+ e->next = u->crontab;
+ u->crontab = e;
+ }
+ break;
+ case TRUE:
+ envp = env_set(envp, envstr);
+ break;
+ }
+ }
+
+ done:
+ env_free(envp);
+ fclose(file);
+ Debug(DPARS, ("...load_user() done\n"))
+ return u;
+}
diff --git a/usr.sbin/dbsym/Makefile b/usr.sbin/dbsym/Makefile
new file mode 100644
index 00000000000..c8c189e767b
--- /dev/null
+++ b/usr.sbin/dbsym/Makefile
@@ -0,0 +1,6 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $
+
+PROG=dbsym
+MAN=dbsym.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/dbsym/dbsym.8 b/usr.sbin/dbsym/dbsym.8
new file mode 100644
index 00000000000..8ca0d0b4264
--- /dev/null
+++ b/usr.sbin/dbsym/dbsym.8
@@ -0,0 +1,46 @@
+.\" $Id: dbsym.8,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $
+.\"
+.Dd 12 May 1994
+.Dt DBSYM 8 sun3
+.Os
+.Sh NAME
+.Nm dbsym
+.Nd copy kernel symbol table into db_symtab space
+.Sh SYNOPSIS
+.Nm dbsym
+.Ar kernel
+.Sh DESCRIPTION
+.Nm dbsym
+is used to copy the symbol table in a newly linked kernel into the
+.Nm db_symtab
+array (in the data section) so that the
+.Nm ddb
+kernel debugger can find the symbols. This is program is only used
+on systems for which the boot program does not load the symbol table
+into memory with the kernel. The space for these symbols is
+reserved in the data segment using a config option like:
+.Pp
+.Li options SYMTAB_SPACE=72000
+.Pp
+The size of the db_symtab array (the value of SYMTAB_SPACE) must be
+at least as large as the kernel symbol table. If insufficient space
+is reserved, dbsym will refuse to copy the symbol table.
+.Pp
+Note that debugging symbols are not useful to the
+.Nm ddb
+kernel debugger, so to minimize the size of the kernel, one should
+either compile the kernel without debugging symbols (no
+.Nm -g
+flag) or use the
+.Nm strip
+command to strip debugging symbols from the kernel before
+.Nm dbsym
+is used to copy the symbol table. The command
+.Pp
+.Li strip -d netbsd
+.Pp
+will strip out debugging symbols.
+.Sh "SEE ALSO"
+.Xr strip 1
+.Xr ddb 8
+.\" XXX - Reminder, need: /src/share/man/man8/ddb.8
diff --git a/usr.sbin/dbsym/dbsym.c b/usr.sbin/dbsym/dbsym.c
new file mode 100644
index 00000000000..1f80b85d402
--- /dev/null
+++ b/usr.sbin/dbsym/dbsym.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: dbsym.c,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $
+ */
+
+/* Copy the symbol table into the space reserved for it. */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <a.out.h>
+
+extern off_t lseek();
+
+struct exec head;
+char *file;
+
+/* Virtual addresses of the symbols we frob. */
+long db_symtab_va, db_symtabsize_va;
+
+/* Offsets relative to start of data segment. */
+long db_symtab_off, db_symtabsize_off;
+
+/* value in the location at db_symtabsize_off */
+int db_symtabsize_val;
+
+/* pointers to pieces of mapped file */
+char *dataseg;
+char *symbols;
+char *strings;
+int *strtab;
+/* and lengths */
+int strtab_len;
+int file_len;
+int data_off;
+int data_pgoff;
+
+main(argc,argv)
+ char **argv;
+{
+ int fd, n;
+ int *ip;
+ char *cp;
+
+ if (argc < 2) {
+ printf("%s: missing file name\n", argv[0]);
+ exit(1);
+ }
+ file = argv[1];
+
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ perror(file);
+ exit(1);
+ }
+
+ n = read(fd, &head, sizeof(head));
+ if (n < sizeof(head)) {
+ printf("%s: reading header\n", file);
+ exit(1);
+ }
+ file_len = lseek(fd, (off_t)0, 2);
+
+ if (N_BADMAG(head)) {
+ printf("%s: bad magic number\n");
+ exit(1);
+ }
+
+#ifdef DEBUG
+ printf(" text: %9d\n", head.a_text);
+ printf(" data: %9d\n", head.a_data);
+ printf(" bss: %9d\n", head.a_bss);
+ printf(" syms: %9d\n", head.a_syms);
+ printf("entry: 0x%08X\n", head.a_entry);
+ printf("trsiz: %9d\n", head.a_trsize);
+ printf("drsiz: %9d\n", head.a_drsize);
+#endif
+
+ if (head.a_syms <= 0) {
+ printf("%s: no symbols\n", file);
+ exit(1);
+ }
+ if (head.a_trsize ||
+ head.a_drsize)
+ {
+ printf("%s: has relocations\n");
+ exit(1);
+ }
+
+ find_db_symtab(file);
+
+ /*
+ * Map in the file from start of data to EOF.
+ * The file offset needs to be page aligned.
+ */
+ data_off = N_DATOFF(head);
+ data_pgoff = N_PAGSIZ(head) - 1;
+ data_pgoff &= data_off;
+ data_off -= data_pgoff;
+ dataseg = mmap(NULL, /* any address is ok */
+ file_len - data_off, /* length */
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd, data_off);
+ if ((long)dataseg == -1) {
+ printf("%s: can not map data seg\n", file);
+ perror(file);
+ exit(1);
+ }
+ dataseg += data_pgoff;
+ symbols = dataseg + head.a_data;
+ strings = symbols + head.a_syms;
+ /* Find the string table length (first word after symtab). */
+ strtab_len = *((int*)strings);
+#ifdef DEBUG
+ printf("strtab_len: %d\n", strtab_len);
+#endif
+
+ /*
+ * Find value in the location: db_symtabsize
+ */
+ ip = (int*) (dataseg + db_symtabsize_off);
+ db_symtabsize_val = *ip;
+#ifdef DEBUG
+ printf("db_symtabsize val: 0x%08X (%d)\n",
+ db_symtabsize_val, db_symtabsize_val);
+#endif
+ /* Is there room for the symbols + strings? */
+ if (db_symtabsize_val < (head.a_syms + strtab_len)) {
+ printf("%s: symbol space too small (%d < %d)\n", argv[0],
+ db_symtabsize_val, (head.a_syms + strtab_len));
+ exit(1);
+ }
+ printf("Symbols use %d of %d bytes available (%d%%)\n",
+ head.a_syms + strtab_len,
+ db_symtabsize_val,
+ (head.a_syms + strtab_len) * 100 /
+ db_symtabsize_val);
+
+ /*
+ * Copy the symbol table and string table.
+ */
+#ifdef DEBUG
+ printf("copying symbol table...\n");
+#endif
+ ip = (int*) (dataseg + db_symtab_off);
+ /* Write symtab length */
+ *ip++ = head.a_syms;
+ memcpy((char*)ip, symbols, head.a_syms + strtab_len);
+
+ msync(dataseg - data_pgoff, file_len - data_off
+#ifdef sun
+ ,0
+#endif
+ );
+
+#ifdef DEBUG
+ printf("...done\n");
+#endif
+ close(fd);
+ exit(0);
+}
+
+
+/*
+ * Find locations of the symbols to patch.
+ */
+struct nlist wantsyms[] = {
+ { "_db_symtabsize", 0 },
+ { "_db_symtab", 0 },
+ { NULL, 0 },
+};
+
+find_db_symtab(file)
+ char *file;
+{
+ int data_va;
+ int std_entry;
+
+ if (nlist(file, wantsyms)) {
+ printf("%s: no db_symtab symbols?\n", file);
+ exit(1);
+ }
+ std_entry = N_TXTADDR(head) +
+ (head.a_entry & (N_PAGSIZ(head)-1));
+ data_va = N_DATADDR(head);
+ if (head.a_entry != std_entry) {
+ printf("%s: warning: non-standard entry point: 0x%08x\n",
+ file, head.a_entry);
+ printf("\texpecting entry=0x%X\n", std_entry);
+ data_va += (head.a_entry - std_entry);
+ }
+
+ db_symtabsize_off = wantsyms[0].n_value - data_va;
+ db_symtab_off = wantsyms[1].n_value - data_va;
+#ifdef DEBUG
+ printf(".data segment va: 0x%08X\n", data_va);
+ printf("db_symtabsize va: 0x%08X\n", wantsyms[0].n_value);
+ printf("db_symtab va: 0x%08X\n", wantsyms[1].n_value);
+ printf("db_symtabsize off: 0x%08X\n", db_symtabsize_off);
+ printf("db_symtab off: 0x%08X\n", db_symtab_off);
+#endif
+
+ /*
+ * Sanity check locations of db_* symbols
+ */
+ if (db_symtab_off < 0 || db_symtab_off >= head.a_data) {
+ printf("%s: db_symtab not in data segment?\n", file);
+ exit(1);
+ }
+ if (db_symtabsize_off < 0 || db_symtabsize_off >= head.a_data) {
+ printf("%s: db_symtabsize not in data segment?\n", file);
+ exit(1);
+ }
+}
diff --git a/usr.sbin/dbsym/dbtest.c b/usr.sbin/dbsym/dbtest.c
new file mode 100644
index 00000000000..3db6c667c77
--- /dev/null
+++ b/usr.sbin/dbsym/dbtest.c
@@ -0,0 +1,58 @@
+
+#include <stdio.h>
+#include <a.out.h>
+
+#define SYMTAB_SPACE 0x8000
+int db_symtabsize = SYMTAB_SPACE;
+char db_symtab[SYMTAB_SPACE] = { 0,0,0,0,1 };
+/*
+ * The actual format of the above is:
+ * int symtab_length = NSYMS;
+ * struct nlist[NSYMS];
+ * int strtab_length;
+ * char strtab[];
+ */
+
+/* Print out our symbol table. */
+main()
+{
+ struct nlist *nl;
+ int symtab_len, strtab_len;
+ char *strtab;
+ char *p;
+ int *ip;
+ int st, sc, x;
+
+ /* symbol table */
+ ip = (int*) db_symtab;
+ symtab_len = *ip++;
+ if (symtab_len < 4) {
+ printf("no symbol table\n");
+ exit(1);
+ }
+ nl = (struct nlist *) ip;
+
+ /* string table pointer and length */
+ ip = (int*) ((char*)ip + symtab_len);
+ strtab = (char*)ip;
+ strtab_len = *ip;
+
+ if (strtab_len > (SYMTAB_SPACE - symtab_len))
+ strtab_len = (SYMTAB_SPACE - symtab_len);
+
+ /* print symbol table */
+ while ((x=nl->n_un.n_strx) != 0) {
+ if (x < 0 || x >= strtab_len) p = "?";
+ else p = strtab + x;
+ st = nl->n_type & 0x1F;
+ sc = "uatdbxxxxcxxxxxxx"[st>1];
+ if (st & 1) sc &= ~0x20; /* to upper */
+ printf("%08X %c %s\n", nl->n_value, sc, p);
+ nl++;
+ if ((char*)nl >= strtab) {
+ printf("symbol table missing null terminator\n");
+ break;
+ }
+ }
+ exit(0);
+}
diff --git a/usr.sbin/dev_mkdb/Makefile b/usr.sbin/dev_mkdb/Makefile
new file mode 100644
index 00000000000..f0e21895128
--- /dev/null
+++ b/usr.sbin/dev_mkdb/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $
+
+PROG= dev_mkdb
+MAN= dev_mkdb.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/dev_mkdb/dev_mkdb.8 b/usr.sbin/dev_mkdb/dev_mkdb.8
new file mode 100644
index 00000000000..d29813d9d9f
--- /dev/null
+++ b/usr.sbin/dev_mkdb/dev_mkdb.8
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1990, 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.
+.\"
+.\" from: @(#)dev_mkdb.8 8.1 (Berkeley) 6/6/93
+.\" $Id: dev_mkdb.8,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Os
+.Dt DEV_MKDB 8
+.Sh NAME
+.Nm dev_mkdb
+.Nd create
+.Pa /dev
+database
+.Sh SYNOPSIS
+.Nm dev_mkdb
+.Sh DESCRIPTION
+The
+.Nm dev_mkdb
+command creates a
+.Xr db 3
+hash access method database in
+.Dq Pa /var/run/dev.db
+which contains the names of all of the character and block special
+files in the
+.Dq Pa /dev
+directory, using the file type and the
+.Fa st_rdev
+field as the key.
+.Pp
+Keys are a structure containing a mode_t followed by a dev_t,
+with any padding zero'd out.
+The former is the type of the file (st_mode & S_IFMT),
+the latter is the st_rdev field.
+.Sh FILES
+.Bl -tag -width /var/run/dev.db -compact
+.It Pa /dev
+Device directory.
+.It Pa /var/run/dev.db
+Database file.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr stat 2 ,
+.Xr db 3 ,
+.Xr devname 3 ,
+.Xr kvm_nlist 3 ,
+.Xr ttyname 3 ,
+.Xr kvm_mkdb 8
+.Sh HISTORY
+The
+.Nm dev_mkdb
+command appeared in
+.Bx 4.4 .
diff --git a/usr.sbin/dev_mkdb/dev_mkdb.c b/usr.sbin/dev_mkdb/dev_mkdb.c
new file mode 100644
index 00000000000..c549c6a1eaf
--- /dev/null
+++ b/usr.sbin/dev_mkdb/dev_mkdb.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 1990, 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) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)dev_mkdb.c 8.1 (Berkeley) 6/6/93";*/
+static char rcsid[] = "$Id: dev_mkdb.c,v 1.1.1.1 1995/10/18 08:47:31 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register DIR *dirp;
+ register struct dirent *dp;
+ struct stat sb;
+ struct {
+ mode_t type;
+ dev_t dev;
+ } bkey;
+ DB *db;
+ DBT data, key;
+ int ch;
+ u_char buf[MAXNAMLEN + 1];
+ char dbtmp[MAXPATHLEN + 1], dbname[MAXPATHLEN + 1];
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch((char)ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ usage();
+
+ if (chdir(_PATH_DEV))
+ err(1, "%s", _PATH_DEV);
+
+ dirp = opendir(".");
+
+ (void)snprintf(dbtmp, sizeof(dbtmp), "%sdev.tmp", _PATH_VARRUN);
+ (void)snprintf(dbname, sizeof(dbtmp), "%sdev.db", _PATH_VARRUN);
+ db = dbopen(dbtmp, O_CREAT|O_EXLOCK|O_RDWR|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, DB_HASH, NULL);
+ if (db == NULL)
+ err(1, "%s", dbtmp);
+
+ /*
+ * Keys are a mode_t followed by a dev_t. The former is the type of
+ * the file (mode & S_IFMT), the latter is the st_rdev field. Note
+ * that the structure may contain padding, so we have to clear it
+ * out here.
+ */
+ bzero(&bkey, sizeof(bkey));
+ key.data = &bkey;
+ key.size = sizeof(bkey);
+ data.data = buf;
+ while (dp = readdir(dirp)) {
+ if (lstat(dp->d_name, &sb)) {
+ warn("%s", dp->d_name);
+ continue;
+ }
+
+ /* Create the key. */
+ if (S_ISCHR(sb.st_mode))
+ bkey.type = S_IFCHR;
+ else if (S_ISBLK(sb.st_mode))
+ bkey.type = S_IFBLK;
+ else
+ continue;
+ bkey.dev = sb.st_rdev;
+
+ /*
+ * Create the data; nul terminate the name so caller doesn't
+ * have to.
+ */
+ bcopy(dp->d_name, buf, dp->d_namlen);
+ buf[dp->d_namlen] = '\0';
+ data.size = dp->d_namlen + 1;
+ if ((db->put)(db, &key, &data, 0))
+ err(1, "dbput %s", dbtmp);
+ }
+ (void)(db->close)(db);
+ if (rename(dbtmp, dbname))
+ err(1, "rename %s to %s", dbtmp, dbname);
+ exit(0);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: dev_mkdb\n");
+ exit(1);
+}
diff --git a/usr.sbin/diskpart/Makefile b/usr.sbin/diskpart/Makefile
new file mode 100644
index 00000000000..888f1275795
--- /dev/null
+++ b/usr.sbin/diskpart/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:32 deraadt Exp $
+
+PROG= diskpart
+MAN= diskpart.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/diskpart/diskpart.8 b/usr.sbin/diskpart/diskpart.8
new file mode 100644
index 00000000000..29415fe2d29
--- /dev/null
+++ b/usr.sbin/diskpart/diskpart.8
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\" from: @(#)diskpart.8 6.6 (Berkeley) 3/16/91
+.\" $Id: diskpart.8,v 1.1.1.1 1995/10/18 08:47:32 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt DISKPART 8
+.Os BSD 4
+.Sh NAME
+.Nm diskpart
+.Nd calculate default disk partition sizes
+.Sh SYNOPSIS
+.Nm diskpart
+.Op Fl p
+.Op Fl d
+.Op Fl s Ar size
+.Ar disk-type
+.Sh DESCRIPTION
+.Nm Diskpart
+is used to calculate the disk partition sizes based on the
+default rules used at Berkeley.
+.Pp
+Available options and operands:
+.Bl -tag -width Fl
+.It Fl p
+Tables suitable for inclusion in a device driver
+are produced.
+.It Fl d
+An entry suitable for inclusion in the disk
+description file
+.Pa /etc/disktab
+is generated; for example,
+.Xr disktab 5 .
+.It Fl s Ar size
+The size of the disk may be limited to
+.Ar size
+with the
+.Fl s
+option.
+.El
+.Pp
+On disks that use
+.Xr bad144 8
+type of
+bad-sector forwarding,
+space is normally left in the last partition on the disk
+for a bad sector forwarding table, although this space
+is not reflected in the tables produced. The space reserved
+is one track for the replicated copies of the table and
+sufficient tracks to hold a pool of 126 sectors to which bad sectors
+are mapped. For more information, see
+.Xr bad144 8 .
+The
+.Fl s
+option is intended for other controllers which reserve some space at the end
+of the disk for bad-sector replacements or other control areas,
+even if not a multiple of cylinders.
+.Pp
+The disk partition sizes are based on the total amount of
+space on the disk as given in the table below (all values
+are supplied in units of sectors). The
+.Ql c
+partition
+is, by convention, used to access the entire physical disk.
+The device driver tables include
+the space reserved for the bad sector forwarding table in the
+.Ql c
+partition;
+those used in the disktab and default formats exclude reserved tracks.
+In normal operation, either the
+.Ql g
+partition is used, or the
+.Ql d ,
+.Ql e ,
+and
+.Ql f
+partitions are used. The
+.Ql g
+and
+.Ql f
+partitions
+are variable-sized, occupying whatever space remains after allocation
+of the fixed sized partitions.
+If the disk is smaller than 20 Megabytes, then
+.Nm diskpart
+aborts with the message
+.Dq Li disk too small, calculate by hand .
+.Bl -column Partition 20-60\ MB 61-205\ MB 206-355\ MB 356+\ MB
+Partition 20-60 MB 61-205 MB 206-355 MB 356+ MB
+a 15884 15884 15884 15884
+b 10032 33440 33440 66880
+d 15884 15884 15884 15884
+e unused 55936 55936 307200
+h unused unused 291346 291346
+.El
+.Pp
+If an unknown disk type is specified,
+.Nm diskpart
+will prompt for the required disk geometry information.
+.Sh SEE ALSO
+.Xr disktab 5 ,
+.Xr bad144 8
+.Sh BUGS
+Most default partition sizes are based on historical artifacts
+(like the RP06), and may result in unsatisfactory layouts.
+.Pp
+When using the
+.Fl d
+flag, alternate disk names are not included
+in the output.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/diskpart/diskpart.c b/usr.sbin/diskpart/diskpart.c
new file mode 100644
index 00000000000..a7e3a174389
--- /dev/null
+++ b/usr.sbin/diskpart/diskpart.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 1983, 1988 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
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)diskpart.c 5.11 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: diskpart.c,v 1.1.1.1 1995/10/18 08:47:32 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Program to calculate standard disk partition sizes.
+ */
+#include <sys/param.h>
+#define DKTYPENAMES
+#include <sys/disklabel.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#define for_now /* show all of `c' partition for disklabel */
+#define NPARTITIONS 8
+#define PART(x) (x - 'a')
+
+/*
+ * Default partition sizes, where they exist.
+ */
+#define NDEFAULTS 4
+int defpart[NDEFAULTS][NPARTITIONS] = {
+ { 15884, 66880, 0, 15884, 307200, 0, 0, 291346 }, /* ~ 356+ Mbytes */
+ { 15884, 33440, 0, 15884, 55936, 0, 0, 291346 }, /* ~ 206-355 Mbytes */
+ { 15884, 33440, 0, 15884, 55936, 0, 0, 0 }, /* ~ 61-205 Mbytes */
+ { 15884, 10032, 0, 15884, 0, 0, 0, 0 }, /* ~ 20-60 Mbytes */
+};
+
+/*
+ * Each array defines a layout for a disk;
+ * that is, the collection of partitions totally
+ * covers the physical space on a disk.
+ */
+#define NLAYOUTS 3
+char layouts[NLAYOUTS][NPARTITIONS] = {
+ { 'a', 'b', 'h', 'g' },
+ { 'a', 'b', 'h', 'd', 'e', 'f' },
+ { 'c' },
+};
+
+/*
+ * Default disk block and disk block fragment
+ * sizes for each file system. Those file systems
+ * with zero block and frag sizes are special cases
+ * (e.g. swap areas or for access to the entire device).
+ */
+struct partition defparam[NPARTITIONS] = {
+ { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* a */
+ { 0, 0, 1024, FS_SWAP, 8, 0 }, /* b */
+ { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* c */
+ { 0, 0, 512, FS_UNUSED, 8, 0 }, /* d */
+ { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* e */
+ { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* f */
+ { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* g */
+ { 0, 0, 1024, FS_UNUSED, 8, 0 } /* h */
+};
+
+/*
+ * Each disk has some space reserved for a bad sector
+ * forwarding table. DEC standard 144 uses the first
+ * 5 even numbered sectors in the last track of the
+ * last cylinder for replicated storage of the bad sector
+ * table; another 126 sectors past this is needed as a
+ * pool of replacement sectors.
+ */
+int badsecttable = 126; /* # sectors */
+
+int pflag; /* print device driver partition tables */
+int dflag; /* print disktab entry */
+
+struct disklabel *promptfordisk();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct disklabel *dp;
+ register int curcyl, spc, def, part, layout, j;
+ int threshhold, numcyls[NPARTITIONS], startcyl[NPARTITIONS];
+ int totsize = 0;
+ char *lp, *tyname;
+
+ argc--, argv++;
+ if (argc < 1) {
+ fprintf(stderr,
+ "usage: diskpart [ -p ] [ -d ] [ -s size ] disk-type\n");
+ exit(1);
+ }
+ if (argc > 0 && strcmp(*argv, "-p") == 0) {
+ pflag++;
+ argc--, argv++;
+ }
+ if (argc > 0 && strcmp(*argv, "-d") == 0) {
+ dflag++;
+ argc--, argv++;
+ }
+ if (argc > 1 && strcmp(*argv, "-s") == 0) {
+ totsize = atoi(argv[1]);
+ argc += 2, argv += 2;
+ }
+ dp = getdiskbyname(*argv);
+ if (dp == NULL) {
+ if (isatty(0))
+ dp = promptfordisk(*argv);
+ if (dp == NULL) {
+ fprintf(stderr, "%s: unknown disk type\n", *argv);
+ exit(2);
+ }
+ } else {
+ if (dp->d_flags & D_REMOVABLE)
+ tyname = "removable";
+ else if (dp->d_flags & D_RAMDISK)
+ tyname = "simulated";
+ else
+ tyname = "winchester";
+ }
+ spc = dp->d_secpercyl;
+ /*
+ * Bad sector table contains one track for the replicated
+ * copies of the table and enough full tracks preceding
+ * the last track to hold the pool of free blocks to which
+ * bad sectors are mapped.
+ * If disk size was specified explicitly, use specified size.
+ */
+ if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT &&
+ totsize == 0) {
+ badsecttable = dp->d_nsectors +
+ roundup(badsecttable, dp->d_nsectors);
+ threshhold = howmany(spc, badsecttable);
+ } else {
+ badsecttable = 0;
+ threshhold = 0;
+ }
+ /*
+ * If disk size was specified, recompute number of cylinders
+ * that may be used, and set badsecttable to any remaining
+ * fraction of the last cylinder.
+ */
+ if (totsize != 0) {
+ dp->d_ncylinders = howmany(totsize, spc);
+ badsecttable = spc * dp->d_ncylinders - totsize;
+ }
+
+ /*
+ * Figure out if disk is large enough for
+ * expanded swap area and 'd', 'e', and 'f'
+ * partitions. Otherwise, use smaller defaults
+ * based on RK07.
+ */
+ for (def = 0; def < NDEFAULTS; def++) {
+ curcyl = 0;
+ for (part = PART('a'); part < NPARTITIONS; part++)
+ curcyl += howmany(defpart[def][part], spc);
+ if (curcyl < dp->d_ncylinders - threshhold)
+ break;
+ }
+ if (def >= NDEFAULTS) {
+ fprintf(stderr, "%s: disk too small, calculate by hand\n",
+ *argv);
+ exit(3);
+ }
+
+ /*
+ * Calculate number of cylinders allocated to each disk
+ * partition. We may waste a bit of space here, but it's
+ * in the interest of (very backward) compatibility
+ * (for mixed disk systems).
+ */
+ for (curcyl = 0, part = PART('a'); part < NPARTITIONS; part++) {
+ numcyls[part] = 0;
+ if (defpart[def][part] != 0) {
+ numcyls[part] = howmany(defpart[def][part], spc);
+ curcyl += numcyls[part];
+ }
+ }
+ numcyls[PART('f')] = dp->d_ncylinders - curcyl;
+ numcyls[PART('g')] =
+ numcyls[PART('d')] + numcyls[PART('e')] + numcyls[PART('f')];
+ numcyls[PART('c')] = dp->d_ncylinders;
+ defpart[def][PART('f')] = numcyls[PART('f')] * spc - badsecttable;
+ defpart[def][PART('g')] = numcyls[PART('g')] * spc - badsecttable;
+ defpart[def][PART('c')] = numcyls[PART('c')] * spc;
+#ifndef for_now
+ if (totsize || !pflag)
+#else
+ if (totsize)
+#endif
+ defpart[def][PART('c')] -= badsecttable;
+
+ /*
+ * Calculate starting cylinder number for each partition.
+ * Note the 'h' partition is physically located before the
+ * 'g' or 'd' partition. This is reflected in the layout
+ * arrays defined above.
+ */
+ for (layout = 0; layout < NLAYOUTS; layout++) {
+ curcyl = 0;
+ for (lp = layouts[layout]; *lp != 0; lp++) {
+ startcyl[PART(*lp)] = curcyl;
+ curcyl += numcyls[PART(*lp)];
+ }
+ }
+
+ if (pflag) {
+ printf("}, %s_sizes[%d] = {\n", dp->d_typename, NPARTITIONS);
+ for (part = PART('a'); part < NPARTITIONS; part++) {
+ if (numcyls[part] == 0) {
+ printf("\t0,\t0,\n");
+ continue;
+ }
+ if (dp->d_type != DTYPE_MSCP) {
+ printf("\t%d,\t%d,\t\t/* %c=cyl %d thru %d */\n",
+ defpart[def][part], startcyl[part],
+ 'A' + part, startcyl[part],
+ startcyl[part] + numcyls[part] - 1);
+ continue;
+ }
+ printf("\t%d,\t%d,\t\t/* %c=sectors %d thru %d */\n",
+ defpart[def][part], spc * startcyl[part],
+ 'A' + part, spc * startcyl[part],
+ spc * startcyl[part] + defpart[def][part] - 1);
+ }
+ exit(0);
+ }
+ if (dflag) {
+ int nparts;
+
+ /*
+ * In case the disk is in the ``in-between'' range
+ * where the 'g' partition is smaller than the 'h'
+ * partition, reverse the frag sizes so the /usr partition
+ * is always set up with a frag size larger than the
+ * user's partition.
+ */
+ if (defpart[def][PART('g')] < defpart[def][PART('h')]) {
+ int temp;
+
+ temp = defparam[PART('h')].p_fsize;
+ defparam[PART('h')].p_fsize =
+ defparam[PART('g')].p_fsize;
+ defparam[PART('g')].p_fsize = temp;
+ }
+ printf("%s:\\\n", dp->d_typename);
+ printf("\t:ty=%s:ns#%d:nt#%d:nc#%d:", tyname,
+ dp->d_nsectors, dp->d_ntracks, dp->d_ncylinders);
+ if (dp->d_secpercyl != dp->d_nsectors * dp->d_ntracks)
+ printf("sc#%d:", dp->d_secpercyl);
+ if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT)
+ printf("sf:");
+ printf("\\\n\t:dt=%s:", dktypenames[dp->d_type]);
+ for (part = NDDATA - 1; part >= 0; part--)
+ if (dp->d_drivedata[part])
+ break;
+ for (j = 0; j <= part; j++)
+ printf("d%d#%d:", j, dp->d_drivedata[j]);
+ printf("\\\n");
+ for (nparts = 0, part = PART('a'); part < NPARTITIONS; part++)
+ if (defpart[def][part] != 0)
+ nparts++;
+ for (part = PART('a'); part < NPARTITIONS; part++) {
+ if (defpart[def][part] == 0)
+ continue;
+ printf("\t:p%c#%d:", 'a' + part, defpart[def][part]);
+ printf("o%c#%d:b%c#%d:f%c#%d:",
+ 'a' + part, spc * startcyl[part],
+ 'a' + part,
+ defparam[part].p_frag * defparam[part].p_fsize,
+ 'a' + part, defparam[part].p_fsize);
+ if (defparam[part].p_fstype == FS_SWAP)
+ printf("t%c=swap:", 'a' + part);
+ nparts--;
+ printf("%s\n", nparts > 0 ? "\\" : "");
+ }
+#ifdef for_now
+ defpart[def][PART('c')] -= badsecttable;
+ part = PART('c');
+ printf("#\t:p%c#%d:", 'a' + part, defpart[def][part]);
+ printf("o%c#%d:b%c#%d:f%c#%d:\n",
+ 'a' + part, spc * startcyl[part],
+ 'a' + part,
+ defparam[part].p_frag * defparam[part].p_fsize,
+ 'a' + part, defparam[part].p_fsize);
+#endif
+ exit(0);
+ }
+ printf("%s: #sectors/track=%d, #tracks/cylinder=%d #cylinders=%d\n",
+ dp->d_typename, dp->d_nsectors, dp->d_ntracks,
+ dp->d_ncylinders);
+ printf("\n Partition\t Size\t Offset\t Range\n");
+ for (part = PART('a'); part < NPARTITIONS; part++) {
+ printf("\t%c\t", 'a' + part);
+ if (numcyls[part] == 0) {
+ printf(" unused\n");
+ continue;
+ }
+ printf("%7d\t%7d\t%4d - %d%s\n",
+ defpart[def][part], startcyl[part] * spc,
+ startcyl[part], startcyl[part] + numcyls[part] - 1,
+ defpart[def][part] % spc ? "*" : "");
+ }
+}
+
+struct disklabel disk;
+
+struct field {
+ char *f_name;
+ char *f_defaults;
+ u_int32_t *f_location;
+} fields[] = {
+ { "sector size", "512", &disk.d_secsize },
+ { "#sectors/track", 0, &disk.d_nsectors },
+ { "#tracks/cylinder", 0, &disk.d_ntracks },
+ { "#cylinders", 0, &disk.d_ncylinders },
+ { 0, 0, 0 },
+};
+
+struct disklabel *
+promptfordisk(name)
+ char *name;
+{
+ register struct disklabel *dp = &disk;
+ register struct field *fp;
+ register i;
+ char buf[BUFSIZ], **tp, *cp, *gets();
+
+ strncpy(dp->d_typename, name, sizeof(dp->d_typename));
+ fprintf(stderr,
+ "%s: unknown disk type, want to supply parameters (y/n)? ",
+ name);
+ (void) gets(buf);
+ if (*buf != 'y')
+ return ((struct disklabel *)0);
+ for (;;) {
+ fprintf(stderr, "Disk/controller type (%s)? ", dktypenames[1]);
+ (void) gets(buf);
+ if (buf[0] == 0)
+ dp->d_type = 1;
+ else
+ dp->d_type = gettype(buf, dktypenames);
+ if ((int16_t)dp->d_type >= 0)
+ break;
+ fprintf(stderr, "%s: unrecognized controller type\n", buf);
+ fprintf(stderr, "use one of:\n", buf);
+ for (tp = dktypenames; *tp; tp++)
+ if (index(*tp, ' ') == 0)
+ fprintf(stderr, "\t%s\n", *tp);
+ }
+gettype:
+ dp->d_flags = 0;
+ fprintf(stderr, "type (winchester|removable|simulated)? ");
+ (void) gets(buf);
+ if (strcmp(buf, "removable") == 0)
+ dp->d_flags = D_REMOVABLE;
+ else if (strcmp(buf, "simulated") == 0)
+ dp->d_flags = D_RAMDISK;
+ else if (strcmp(buf, "winchester")) {
+ fprintf(stderr, "%s: bad disk type\n", buf);
+ goto gettype;
+ }
+ strncpy(dp->d_typename, buf, sizeof(dp->d_typename));
+ fprintf(stderr, "(type <cr> to get default value, if only one)\n");
+ if (dp->d_type == DTYPE_SMD)
+ fprintf(stderr, "Do %ss support bad144 bad block forwarding (yes)? ",
+ dp->d_typename);
+ (void) gets(buf);
+ if (*buf != 'n')
+ dp->d_flags |= D_BADSECT;
+ for (fp = fields; fp->f_name != NULL; fp++) {
+again:
+ fprintf(stderr, "%s ", fp->f_name);
+ if (fp->f_defaults != NULL)
+ fprintf(stderr, "(%s)", fp->f_defaults);
+ fprintf(stderr, "? ");
+ cp = gets(buf);
+ if (*cp == '\0') {
+ if (fp->f_defaults == NULL) {
+ fprintf(stderr, "no default value\n");
+ goto again;
+ }
+ cp = fp->f_defaults;
+ }
+ *fp->f_location = atol(cp);
+ if (*fp->f_location == 0) {
+ fprintf(stderr, "%s: bad value\n", cp);
+ goto again;
+ }
+ }
+ fprintf(stderr, "sectors/cylinder (%d)? ",
+ dp->d_nsectors * dp->d_ntracks);
+ (void) gets(buf);
+ if (buf[0] == 0)
+ dp->d_secpercyl = dp->d_nsectors * dp->d_ntracks;
+ else
+ dp->d_secpercyl = atol(buf);
+ fprintf(stderr, "Drive-type-specific parameters, <cr> to terminate:\n");
+ for (i = 0; i < NDDATA; i++) {
+ fprintf(stderr, "d%d? ", i);
+ (void) gets(buf);
+ if (buf[0] == 0)
+ break;
+ dp->d_drivedata[i] = atol(buf);
+ }
+ return (dp);
+}
+
+gettype(t, names)
+ char *t;
+ char **names;
+{
+ register char **nm;
+
+ for (nm = names; *nm; nm++)
+ if (ustrcmp(t, *nm) == 0)
+ return (nm - names);
+ if (isdigit(*t))
+ return (atoi(t));
+ return (-1);
+}
+
+ustrcmp(s1, s2)
+ register char *s1, *s2;
+{
+#define lower(c) (islower(c) ? (c) : tolower(c))
+
+ for (; *s1; s1++, s2++) {
+ if (*s1 == *s2)
+ continue;
+ if (isalpha(*s1) && isalpha(*s2) &&
+ lower(*s1) == lower(*s2))
+ continue;
+ return (*s2 - *s1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/edquota/Makefile b/usr.sbin/edquota/Makefile
new file mode 100644
index 00000000000..c0b8adee69f
--- /dev/null
+++ b/usr.sbin/edquota/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $
+
+PROG= edquota
+MAN= edquota.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/edquota/edquota.8 b/usr.sbin/edquota/edquota.8
new file mode 100644
index 00000000000..77e32688d75
--- /dev/null
+++ b/usr.sbin/edquota/edquota.8
@@ -0,0 +1,161 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)edquota.8 8.1 (Berkeley) 6/6/93
+.\" $Id: edquota.8,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt EDQUOTA 8
+.Os
+.Sh NAME
+.Nm edquota
+.Nd edit user quotas
+.Sh SYNOPSIS
+.Nm edquota
+.Op Fl u
+.Op Fl p Ar proto-username
+.Ar username ...
+.Nm edquota
+.Fl g
+.Op Fl p Ar proto-groupname
+.Ar groupname ...
+.Nm edquota
+.Fl t
+.Op Fl u
+.Nm edquota
+.Fl t
+.Fl g
+.Sh DESCRIPTION
+.Nm Edquota
+is a quota editor.
+By default, or if the
+.Fl u
+flag is specified,
+one or more users may be specified on the command line.
+For each user a temporary file is created
+with an ASCII representation of the current
+disk quotas for that user.
+The list of filesystems with user quotas is determined from
+.Pa /etc/fstab .
+An editor is invoked on the ASCII file.
+The editor invoked is
+.Xr vi 1
+unless the environment variable
+.Ev EDITOR
+specifies otherwise.
+.Pp
+The quotas may then be modified, new quotas added, etc.
+Setting a quota to zero indicates that no quota should be imposed.
+Setting a hard limit to one indicates that no allocations should
+be permitted.
+Setting a soft limit to one with a hard limit of zero
+indicates that allocations should be permitted on
+only a temporary basis (see
+.Fl t
+below).
+The current usage information in the file is for informational purposes;
+only the hard and soft limits can be changed.
+.Pp
+On leaving the editor,
+.Nm edquota
+reads the temporary file and modifies the binary
+quota files to reflect the changes made.
+.Pp
+If the
+.Fl p
+flag is specified,
+.Nm edquota
+will duplicate the quotas of the prototypical user
+specified for each user specified.
+This is the normal mechanism used to
+initialize quotas for groups of users.
+.Pp
+If the
+.Fl g
+flag is specified,
+.Nm edquota
+is invoked to edit the quotas of
+one or more groups specified on the command line.
+The
+.Fl p
+flag can be specified in conjunction with
+the
+.Fl g
+flag to specify a prototypical group
+to be duplicated among the listed set of groups.
+.Pp
+Users are permitted to exceed their soft limits
+for a grace period that may be specified per filesystem.
+Once the grace period has expired,
+the soft limit is enforced as a hard limit.
+The default grace period for a filesystem is specified in
+.Pa /usr/include/ufs/ufs/quota.h .
+The
+.Fl t
+flag can be used to change the grace period.
+By default, or when invoked with the
+.Fl u
+flag, the grace period is set for all the filesystems with user
+quotas specified in
+.Pa /etc/fstab .
+When invoked with the
+.Fl g
+flag the grace period is
+set for all the filesystems with group quotas specified in
+.Pa /etc/fstab .
+The grace period may be specified in days, hours, minutes, or seconds.
+Setting a grace period to zero indicates that the default
+grace period should be imposed.
+Setting a grace period to one second indicates that no
+grace period should be granted.
+.Pp
+Only the super-user may edit quotas.
+.Sh FILES
+.Bl -tag -width 24n -compact
+.It Pa quota.user
+at the filesystem root with user quotas
+.It Pa quota.group
+at the filesystem root with group quotas
+.It Pa /etc/fstab
+to find filesystem names and locations
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr fstab 5 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8 ,
+.Xr repquota 8
+.Sh DIAGNOSTICS
+Various messages about inaccessible files; self-explanatory.
diff --git a/usr.sbin/edquota/edquota.c b/usr.sbin/edquota/edquota.c
new file mode 100644
index 00000000000..b8ea8c392d5
--- /dev/null
+++ b/usr.sbin/edquota/edquota.c
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)edquota.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: edquota.c,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Disk quota editor.
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <ufs/ufs/quota.h>
+#include <errno.h>
+#include <fstab.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+char *quotagroup = QUOTAGROUP;
+char tmpfil[] = _PATH_TMP;
+
+struct quotause {
+ struct quotause *next;
+ long flags;
+ struct dqblk dqblk;
+ char fsname[MAXPATHLEN + 1];
+ char qfname[1]; /* actually longer */
+} *getprivs();
+#define FOUND 0x01
+
+main(argc, argv)
+ register char **argv;
+ int argc;
+{
+ register struct quotause *qup, *protoprivs, *curprivs;
+ extern char *optarg;
+ extern int optind;
+ register long id, protoid;
+ register int quotatype, tmpfd;
+ char *protoname, ch;
+ int tflag = 0, pflag = 0;
+
+ if (argc < 2)
+ usage();
+ if (getuid()) {
+ fprintf(stderr, "edquota: permission denied\n");
+ exit(1);
+ }
+ quotatype = USRQUOTA;
+ while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
+ switch(ch) {
+ case 'p':
+ protoname = optarg;
+ pflag++;
+ break;
+ case 'g':
+ quotatype = GRPQUOTA;
+ break;
+ case 'u':
+ quotatype = USRQUOTA;
+ break;
+ case 't':
+ tflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (pflag) {
+ if ((protoid = getentry(protoname, quotatype)) == -1)
+ exit(1);
+ protoprivs = getprivs(protoid, quotatype);
+ for (qup = protoprivs; qup; qup = qup->next) {
+ qup->dqblk.dqb_btime = 0;
+ qup->dqblk.dqb_itime = 0;
+ }
+ while (argc-- > 0) {
+ if ((id = getentry(*argv++, quotatype)) < 0)
+ continue;
+ putprivs(id, quotatype, protoprivs);
+ }
+ exit(0);
+ }
+ tmpfd = mkstemp(tmpfil);
+ fchown(tmpfd, getuid(), getgid());
+ if (tflag) {
+ protoprivs = getprivs(0, quotatype);
+ if (writetimes(protoprivs, tmpfd, quotatype) == 0)
+ exit(1);
+ if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
+ putprivs(0, quotatype, protoprivs);
+ freeprivs(protoprivs);
+ exit(0);
+ }
+ for ( ; argc > 0; argc--, argv++) {
+ if ((id = getentry(*argv, quotatype)) == -1)
+ continue;
+ curprivs = getprivs(id, quotatype);
+ if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
+ continue;
+ if (editit(tmpfil) && readprivs(curprivs, tmpfd))
+ putprivs(id, quotatype, curprivs);
+ freeprivs(curprivs);
+ }
+ close(tmpfd);
+ unlink(tmpfil);
+ exit(0);
+}
+
+usage()
+{
+ fprintf(stderr, "%s%s%s%s",
+ "Usage: edquota [-u] [-p username] username ...\n",
+ "\tedquota -g [-p groupname] groupname ...\n",
+ "\tedquota [-u] -t\n", "\tedquota -g -t\n");
+ exit(1);
+}
+
+/*
+ * This routine converts a name for a particular quota type to
+ * an identifier. This routine must agree with the kernel routine
+ * getinoquota as to the interpretation of quota types.
+ */
+getentry(name, quotatype)
+ char *name;
+ int quotatype;
+{
+ struct passwd *pw;
+ struct group *gr;
+
+ if (alldigits(name))
+ return (atoi(name));
+ switch(quotatype) {
+ case USRQUOTA:
+ if (pw = getpwnam(name))
+ return (pw->pw_uid);
+ fprintf(stderr, "%s: no such user\n", name);
+ break;
+ case GRPQUOTA:
+ if (gr = getgrnam(name))
+ return (gr->gr_gid);
+ fprintf(stderr, "%s: no such group\n", name);
+ break;
+ default:
+ fprintf(stderr, "%d: unknown quota type\n", quotatype);
+ break;
+ }
+ sleep(1);
+ return (-1);
+}
+
+/*
+ * Collect the requested quota information.
+ */
+struct quotause *
+getprivs(id, quotatype)
+ register long id;
+ int quotatype;
+{
+ register struct fstab *fs;
+ register struct quotause *qup, *quptail;
+ struct quotause *quphead;
+ int qcmd, qupsize, fd;
+ char *qfpathname;
+ static int warned = 0;
+ extern int errno;
+
+ setfsent();
+ quphead = (struct quotause *)0;
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+ while (fs = getfsent()) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (!hasquota(fs, quotatype, &qfpathname))
+ continue;
+ qupsize = sizeof(*qup) + strlen(qfpathname);
+ if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
+ fprintf(stderr, "edquota: out of memory\n");
+ exit(2);
+ }
+ if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
+ if (errno == EOPNOTSUPP && !warned) {
+ warned++;
+ fprintf(stderr, "Warning: %s\n",
+ "Quotas are not compiled into this kernel");
+ sleep(3);
+ }
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
+ if (fd < 0 && errno != ENOENT) {
+ perror(qfpathname);
+ free(qup);
+ continue;
+ }
+ fprintf(stderr, "Creating quota file %s\n",
+ qfpathname);
+ sleep(3);
+ (void) fchown(fd, getuid(),
+ getentry(quotagroup, GRPQUOTA));
+ (void) fchmod(fd, 0640);
+ }
+ lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
+ switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
+ case 0: /* EOF */
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t)&qup->dqblk,
+ sizeof(struct dqblk));
+ break;
+
+ case sizeof(struct dqblk): /* OK */
+ break;
+
+ default: /* ERROR */
+ fprintf(stderr, "edquota: read error in ");
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ close(fd);
+ }
+ strcpy(qup->qfname, qfpathname);
+ strcpy(qup->fsname, fs->fs_file);
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+ endfsent();
+ return (quphead);
+}
+
+/*
+ * Store the requested quota information.
+ */
+putprivs(id, quotatype, quplist)
+ long id;
+ int quotatype;
+ struct quotause *quplist;
+{
+ register struct quotause *qup;
+ int qcmd, fd;
+
+ qcmd = QCMD(Q_SETQUOTA, quotatype);
+ for (qup = quplist; qup; qup = qup->next) {
+ if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
+ continue;
+ if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
+ perror(qup->qfname);
+ } else {
+ lseek(fd, (off_t)(id * sizeof (struct dqblk)), 0);
+ if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
+ sizeof (struct dqblk)) {
+ fprintf(stderr, "edquota: ");
+ perror(qup->qfname);
+ }
+ close(fd);
+ }
+ }
+}
+
+/*
+ * Take a list of priviledges and get it edited.
+ */
+editit(tmpfile)
+ char *tmpfile;
+{
+ long omask;
+ int pid, stat;
+ extern char *getenv();
+
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ top:
+ if ((pid = fork()) < 0) {
+ extern errno;
+
+ if (errno == EPROCLIM) {
+ fprintf(stderr, "You have too many processes\n");
+ return(0);
+ }
+ if (errno == EAGAIN) {
+ sleep(1);
+ goto top;
+ }
+ perror("fork");
+ return (0);
+ }
+ if (pid == 0) {
+ register char *ed;
+
+ sigsetmask(omask);
+ setgid(getgid());
+ setuid(getuid());
+ if ((ed = getenv("EDITOR")) == (char *)0)
+ ed = _PATH_VI;
+ execlp(ed, ed, tmpfile, 0);
+ perror(ed);
+ exit(1);
+ }
+ waitpid(pid, &stat, 0);
+ sigsetmask(omask);
+ if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
+ return (0);
+ return (1);
+}
+
+/*
+ * Convert a quotause list to an ASCII file.
+ */
+writeprivs(quplist, outfd, name, quotatype)
+ struct quotause *quplist;
+ int outfd;
+ char *name;
+ int quotatype;
+{
+ register struct quotause *qup;
+ FILE *fd;
+
+ ftruncate(outfd, 0);
+ lseek(outfd, 0, L_SET);
+ if ((fd = fdopen(dup(outfd), "w")) == NULL) {
+ fprintf(stderr, "edquota: ");
+ perror(tmpfil);
+ exit(1);
+ }
+ fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
+ for (qup = quplist; qup; qup = qup->next) {
+ fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
+ qup->fsname, "blocks in use:",
+ dbtob(qup->dqblk.dqb_curblocks) / 1024,
+ dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
+ dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
+ fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
+ "\tinodes in use:", qup->dqblk.dqb_curinodes,
+ qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
+ }
+ fclose(fd);
+ return (1);
+}
+
+/*
+ * Merge changes to an ASCII file into a quotause list.
+ */
+readprivs(quplist, infd)
+ struct quotause *quplist;
+ int infd;
+{
+ register struct quotause *qup;
+ FILE *fd;
+ int cnt;
+ register char *cp;
+ struct dqblk dqblk;
+ char *fsp, line1[BUFSIZ], line2[BUFSIZ];
+
+ lseek(infd, 0, L_SET);
+ fd = fdopen(dup(infd), "r");
+ if (fd == NULL) {
+ fprintf(stderr, "Can't re-read temp file!!\n");
+ return (0);
+ }
+ /*
+ * Discard title line, then read pairs of lines to process.
+ */
+ (void) fgets(line1, sizeof (line1), fd);
+ while (fgets(line1, sizeof (line1), fd) != NULL &&
+ fgets(line2, sizeof (line2), fd) != NULL) {
+ if ((fsp = strtok(line1, " \t:")) == NULL) {
+ fprintf(stderr, "%s: bad format\n", line1);
+ return (0);
+ }
+ if ((cp = strtok((char *)0, "\n")) == NULL) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp,
+ &fsp[strlen(fsp) + 1]);
+ return (0);
+ }
+ cnt = sscanf(cp,
+ " blocks in use: %d, limits (soft = %d, hard = %d)",
+ &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
+ &dqblk.dqb_bhardlimit);
+ if (cnt != 3) {
+ fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
+ return (0);
+ }
+ dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
+ dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
+ dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
+ if ((cp = strtok(line2, "\n")) == NULL) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
+ return (0);
+ }
+ cnt = sscanf(cp,
+ "\tinodes in use: %d, limits (soft = %d, hard = %d)",
+ &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
+ &dqblk.dqb_ihardlimit);
+ if (cnt != 3) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
+ return (0);
+ }
+ for (qup = quplist; qup; qup = qup->next) {
+ if (strcmp(fsp, qup->fsname))
+ continue;
+ /*
+ * Cause time limit to be reset when the quota
+ * is next used if previously had no soft limit
+ * or were under it, but now have a soft limit
+ * and are over it.
+ */
+ if (dqblk.dqb_bsoftlimit &&
+ qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
+ (qup->dqblk.dqb_bsoftlimit == 0 ||
+ qup->dqblk.dqb_curblocks <
+ qup->dqblk.dqb_bsoftlimit))
+ qup->dqblk.dqb_btime = 0;
+ if (dqblk.dqb_isoftlimit &&
+ qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
+ (qup->dqblk.dqb_isoftlimit == 0 ||
+ qup->dqblk.dqb_curinodes <
+ qup->dqblk.dqb_isoftlimit))
+ qup->dqblk.dqb_itime = 0;
+ qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
+ qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
+ qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
+ qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
+ qup->flags |= FOUND;
+ if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
+ dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
+ break;
+ fprintf(stderr,
+ "%s: cannot change current allocation\n", fsp);
+ break;
+ }
+ }
+ fclose(fd);
+ /*
+ * Disable quotas for any filesystems that have not been found.
+ */
+ for (qup = quplist; qup; qup = qup->next) {
+ if (qup->flags & FOUND) {
+ qup->flags &= ~FOUND;
+ continue;
+ }
+ qup->dqblk.dqb_bsoftlimit = 0;
+ qup->dqblk.dqb_bhardlimit = 0;
+ qup->dqblk.dqb_isoftlimit = 0;
+ qup->dqblk.dqb_ihardlimit = 0;
+ }
+ return (1);
+}
+
+/*
+ * Convert a quotause list to an ASCII file of grace times.
+ */
+writetimes(quplist, outfd, quotatype)
+ struct quotause *quplist;
+ int outfd;
+ int quotatype;
+{
+ register struct quotause *qup;
+ char *cvtstoa();
+ FILE *fd;
+
+ ftruncate(outfd, 0);
+ lseek(outfd, 0, L_SET);
+ if ((fd = fdopen(dup(outfd), "w")) == NULL) {
+ fprintf(stderr, "edquota: ");
+ perror(tmpfil);
+ exit(1);
+ }
+ fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
+ fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
+ qfextension[quotatype]);
+ for (qup = quplist; qup; qup = qup->next) {
+ fprintf(fd, "%s: block grace period: %s, ",
+ qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
+ fprintf(fd, "file grace period: %s\n",
+ cvtstoa(qup->dqblk.dqb_itime));
+ }
+ fclose(fd);
+ return (1);
+}
+
+/*
+ * Merge changes of grace times in an ASCII file into a quotause list.
+ */
+readtimes(quplist, infd)
+ struct quotause *quplist;
+ int infd;
+{
+ register struct quotause *qup;
+ FILE *fd;
+ int cnt;
+ register char *cp;
+ time_t itime, btime, iseconds, bseconds;
+ char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
+
+ lseek(infd, 0, L_SET);
+ fd = fdopen(dup(infd), "r");
+ if (fd == NULL) {
+ fprintf(stderr, "Can't re-read temp file!!\n");
+ return (0);
+ }
+ /*
+ * Discard two title lines, then read lines to process.
+ */
+ (void) fgets(line1, sizeof (line1), fd);
+ (void) fgets(line1, sizeof (line1), fd);
+ while (fgets(line1, sizeof (line1), fd) != NULL) {
+ if ((fsp = strtok(line1, " \t:")) == NULL) {
+ fprintf(stderr, "%s: bad format\n", line1);
+ return (0);
+ }
+ if ((cp = strtok((char *)0, "\n")) == NULL) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp,
+ &fsp[strlen(fsp) + 1]);
+ return (0);
+ }
+ cnt = sscanf(cp,
+ " block grace period: %d %s file grace period: %d %s",
+ &btime, bunits, &itime, iunits);
+ if (cnt != 4) {
+ fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
+ return (0);
+ }
+ if (cvtatos(btime, bunits, &bseconds) == 0)
+ return (0);
+ if (cvtatos(itime, iunits, &iseconds) == 0)
+ return (0);
+ for (qup = quplist; qup; qup = qup->next) {
+ if (strcmp(fsp, qup->fsname))
+ continue;
+ qup->dqblk.dqb_btime = bseconds;
+ qup->dqblk.dqb_itime = iseconds;
+ qup->flags |= FOUND;
+ break;
+ }
+ }
+ fclose(fd);
+ /*
+ * reset default grace periods for any filesystems
+ * that have not been found.
+ */
+ for (qup = quplist; qup; qup = qup->next) {
+ if (qup->flags & FOUND) {
+ qup->flags &= ~FOUND;
+ continue;
+ }
+ qup->dqblk.dqb_btime = 0;
+ qup->dqblk.dqb_itime = 0;
+ }
+ return (1);
+}
+
+/*
+ * Convert seconds to ASCII times.
+ */
+char *
+cvtstoa(time)
+ time_t time;
+{
+ static char buf[20];
+
+ if (time % (24 * 60 * 60) == 0) {
+ time /= 24 * 60 * 60;
+ sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
+ } else if (time % (60 * 60) == 0) {
+ time /= 60 * 60;
+ sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
+ } else if (time % 60 == 0) {
+ time /= 60;
+ sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
+ } else
+ sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
+ return (buf);
+}
+
+/*
+ * Convert ASCII input times to seconds.
+ */
+cvtatos(time, units, seconds)
+ time_t time;
+ char *units;
+ time_t *seconds;
+{
+
+ if (bcmp(units, "second", 6) == 0)
+ *seconds = time;
+ else if (bcmp(units, "minute", 6) == 0)
+ *seconds = time * 60;
+ else if (bcmp(units, "hour", 4) == 0)
+ *seconds = time * 60 * 60;
+ else if (bcmp(units, "day", 3) == 0)
+ *seconds = time * 24 * 60 * 60;
+ else {
+ printf("%s: bad units, specify %s\n", units,
+ "days, hours, minutes, or seconds");
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Free a list of quotause structures.
+ */
+freeprivs(quplist)
+ struct quotause *quplist;
+{
+ register struct quotause *qup, *nextqup;
+
+ for (qup = quplist; qup; qup = nextqup) {
+ nextqup = qup->next;
+ free(qup);
+ }
+}
+
+/*
+ * Check whether a string is completely composed of digits.
+ */
+alldigits(s)
+ register char *s;
+{
+ register c;
+
+ c = *s++;
+ do {
+ if (!isdigit(c))
+ return (0);
+ } while (c = *s++);
+ return (1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
+ sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strcpy(buf, fs->fs_mntops);
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
diff --git a/usr.sbin/edquota/pathnames.h b/usr.sbin/edquota/pathnames.h
new file mode 100644
index 00000000000..b524d484093
--- /dev/null
+++ b/usr.sbin/edquota/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $
+ */
+
+#include <paths.h>
+
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/EdP.aXXXXX"
diff --git a/usr.sbin/eeprom/Makefile b/usr.sbin/eeprom/Makefile
new file mode 100644
index 00000000000..2ab07add8a4
--- /dev/null
+++ b/usr.sbin/eeprom/Makefile
@@ -0,0 +1,20 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $NetBSD: Makefile,v 1.1 1995/07/13 18:07:19 thorpej Exp $
+
+PROG= eeprom
+MAN= eeprom.8
+
+BINGRP= kmem
+BINMODE=2555
+
+SRCS= eehandlers.c getdate.c main.c
+
+.if ${MACHINE} == "sparc"
+SRCS+= ophandlers.c
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+.endif
+
+CLEANFILES+=getdate.c y.tab.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/eeprom/defs.h b/usr.sbin/eeprom/defs.h
new file mode 100644
index 00000000000..2b0edbe378a
--- /dev/null
+++ b/usr.sbin/eeprom/defs.h
@@ -0,0 +1,109 @@
+/* $NetBSD: defs.h,v 1.1 1995/07/13 18:08:56 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#undef BUFSIZE
+#define BUFSIZE 1024
+
+#define IO_READ 0
+#define IO_WRITE 1
+
+#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Misc. location declarations.
+ */
+#define EE_SIZE 0x500
+#define EE_WC_LOC 0x04
+#define EE_CKSUM_LOC 0x0c
+#define EE_HWUPDATE_LOC 0x10
+#define EE_BANNER_ENABLE_LOC 0x20
+
+/*
+ * Keyword table entry. Contains a pointer to the keyword, the
+ * offset into the prom where the value lives, and a pointer to
+ * the function that handles that value.
+ */
+struct keytabent {
+ char *kt_keyword; /* keyword for this entry */
+ u_int kt_offset; /* offset into prom of value */
+ void (*kt_handler) __P((struct keytabent *, char *));
+ /* handler function for this entry */
+};
+
+/*
+ * String-value table entry. Maps a string to a numeric value and
+ * vice-versa.
+ */
+struct strvaltabent {
+ char *sv_str; /* the string ... */
+ u_char sv_val; /* ... and the value */
+};
+
+#ifdef __sparc__
+/*
+ * This is an entry in a table which describes a set of `exceptions'.
+ * In other words, these are Openprom fields that we either can't
+ * `just print' or don't know how to deal with.
+ */
+struct extabent {
+ char *ex_keyword; /* keyword for this entry */
+ void (*ex_handler) __P((struct extabent *,
+ struct opiocdesc *, char *));
+ /* handler function for this entry */
+};
+#endif /* __sparc__ */
+
+/* Sun 3/4 EEPROM handlers. */
+void ee_hwupdate __P((struct keytabent *, char *));
+void ee_num8 __P((struct keytabent *, char *));
+void ee_num16 __P((struct keytabent *, char *));
+void ee_screensize __P((struct keytabent *, char *));
+void ee_truefalse __P((struct keytabent *, char *));
+void ee_bootdev __P((struct keytabent *, char *));
+void ee_kbdtype __P((struct keytabent *, char *));
+void ee_constype __P((struct keytabent *, char *));
+void ee_diagpath __P((struct keytabent *, char *));
+void ee_banner __P((struct keytabent *, char *));
+void ee_notsupp __P((struct keytabent *, char *));
+
+/* Sun 3/4 EEPROM checksum routines. */
+u_char ee_checksum __P((u_char *, size_t));
+void ee_updatechecksums __P((void));
+void ee_verifychecksums __P((void));
+
+#ifdef __sparc__
+/* Sparc Openprom handlers. */
+char *op_handler __P((char *, char *));
+void op_dump __P((void));
+#endif /* __sparc__ */
diff --git a/usr.sbin/eeprom/eehandlers.c b/usr.sbin/eeprom/eehandlers.c
new file mode 100644
index 00000000000..65633d4769f
--- /dev/null
+++ b/usr.sbin/eeprom/eehandlers.c
@@ -0,0 +1,687 @@
+/* $NetBSD: eehandlers.c,v 1.1 1995/07/13 18:10:29 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <machine/eeprom.h>
+#ifdef __sparc__
+#include <machine/openpromio.h>
+#endif /* __sparc__ */
+
+#include "defs.h"
+
+extern char *path_eeprom;
+extern int eval;
+extern int update_checksums;
+extern int ignore_checksum;
+extern int fix_checksum;
+extern int cksumfail;
+extern u_short writecount;
+
+struct timeb;
+extern time_t get_date __P((char *, struct timeb *));
+
+static char err_str[BUFSIZE];
+
+static void badval __P((struct keytabent *, char *));
+static int doio __P((struct keytabent *, u_char *, ssize_t, int));
+
+#define BARF(kt) { \
+ badval((kt), arg); \
+ ++eval; \
+ return; \
+}
+
+#define FAILEDREAD(kt) { \
+ warnx(err_str); \
+ warnx("failed to read field `%s'", (kt)->kt_keyword); \
+ ++eval; \
+ return; \
+}
+
+#define FAILEDWRITE(kt) { \
+ warnx(err_str); \
+ warnx("failed to update field `%s'", (kt)->kt_keyword); \
+ ++eval; \
+ return; \
+}
+
+void
+ee_hwupdate(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ time_t t;
+ char *cp, *cp2;
+
+ if (arg) {
+ if ((strcmp(arg, "now") == 0) ||
+ (strcmp(arg, "today") == 0)) {
+ if ((t = time(NULL)) == (time_t)(-1)) {
+ warnx("can't get current time");
+ ++eval;
+ return;
+ }
+ } else
+ if ((t = get_date(arg, NULL)) == (time_t)(-1))
+ BARF(ktent);
+
+ if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
+ FAILEDREAD(ktent);
+
+ cp = ctime(&t);
+ if ((cp2 = strrchr(cp, '\n')) != NULL)
+ *cp2 = '\0';
+
+ printf("%s=%d (%s)\n", ktent->kt_keyword, t, cp);
+}
+
+void
+ee_num8(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ u_char num8 = 0;
+ u_int num32;
+ int i;
+
+ if (arg) {
+ for (i = 0; i < (strlen(arg) - 1); ++i)
+ if (!isdigit(arg[i]))
+ BARF(ktent);
+ num32 = atoi(arg);
+ if (num32 > 0xff)
+ BARF(ktent);
+ num8 += num32;
+ if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, &num8, sizeof(num8), IO_READ))
+ FAILEDREAD(ktent);
+
+ printf("%s=%d\n", ktent->kt_keyword, num8);
+}
+
+void
+ee_num16(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ u_int16_t num16 = 0;
+ u_int num32;
+ int i;
+
+ if (arg) {
+ for (i = 0; i < (strlen(arg) - 1); ++i)
+ if (!isdigit(arg[i]))
+ BARF(ktent);
+ num32 = atoi(arg);
+ if (num32 > 0xffff)
+ BARF(ktent);
+ num16 += num32;
+ if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
+ FAILEDREAD(ktent);
+
+ printf("%s=%d\n", ktent->kt_keyword, num16);
+}
+
+static struct strvaltabent scrsizetab[] = {
+ { "1152x900", EE_SCR_1152X900 },
+ { "1024x1024", EE_SCR_1024X1024 },
+ { "1600x1280", EE_SCR_1600X1280 },
+ { "1440x1440", EE_SCR_1440X1440 },
+ { NULL, 0 },
+};
+
+void
+ee_screensize(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ struct strvaltabent *svp;
+ u_char scsize;
+
+ if (arg) {
+ for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
+ if (strcmp(svp->sv_str, arg) == 0)
+ break;
+ if (svp->sv_str == NULL)
+ BARF(ktent);
+
+ scsize = svp->sv_val;
+ if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else {
+ if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
+ FAILEDREAD(ktent);
+
+ for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
+ if (svp->sv_val == scsize)
+ break;
+ if (svp->sv_str == NULL) {
+ warnx("unknown %s value %d", ktent->kt_keyword,
+ scsize);
+ return;
+ }
+ }
+ printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
+}
+
+static struct strvaltabent truthtab[] = {
+ { "true", EE_TRUE },
+ { "false", EE_FALSE },
+ { NULL, 0 },
+};
+
+void
+ee_truefalse(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ struct strvaltabent *svp;
+ u_char truth;
+
+ if (arg) {
+ for (svp = truthtab; svp->sv_str != NULL; ++svp)
+ if (strcmp(svp->sv_str, arg) == 0)
+ break;
+ if (svp->sv_str == NULL)
+ BARF(ktent);
+
+ truth = svp->sv_val;
+ if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else {
+ if (doio(ktent, &truth, sizeof(truth), IO_READ))
+ FAILEDREAD(ktent);
+
+ for (svp = truthtab; svp->sv_str != NULL; ++svp)
+ if (svp->sv_val == truth)
+ break;
+ if (svp->sv_str == NULL) {
+ warnx("unknown truth value 0x%x for %s", truth,
+ ktent->kt_keyword);
+ return;
+ }
+ }
+ printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
+}
+
+void
+ee_bootdev(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ u_char dev[5];
+ int i;
+ size_t arglen;
+ char *cp;
+
+ if (arg) {
+ /*
+ * The format of the string we accept is the following:
+ * cc(n,n,n)
+ * where:
+ * c -- an alphabetical character [a-z]
+ * n -- a number in hexadecimal, between 0 and ff,
+ * with no leading `0x'.
+ */
+ arglen = strlen(arg);
+ if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
+ arg[arglen - 1] != ')')
+ BARF(ktent);
+
+ /* Handle the first 2 letters. */
+ for (i = 0; i < 2; ++i) {
+ if (arg[i] < 'a' || arg[i] > 'z')
+ BARF(ktent);
+ dev[i] = (u_char)arg[i];
+ }
+
+ /* Handle the 3 `0x'-less hex values. */
+ cp = &arg[3];
+ for (i = 2; i < 5; ++i) {
+ if (*cp == '\0')
+ BARF(ktent);
+
+ if (*cp >= '0' && *cp <= '9')
+ dev[i] = *cp++ - '0';
+ else if (*cp >= 'a' && *cp <= 'f')
+ dev[i] = 10 + (*cp++ - 'a');
+ else
+ BARF(ktent);
+
+ /* Deal with a second digit. */
+ if (*cp >= '0' && *cp <= '9') {
+ dev[i] <<= 4;
+ dev[i] &= 0xf0;
+ dev[i] += *cp++ - '0';
+ } else if (*cp >= 'a' && *cp <= 'f') {
+ dev[i] <<= 4;
+ dev[i] &= 0xf0;
+ dev[i] += 10 + (*cp++ - 'a');
+ }
+
+ /* Ensure we have the correct delimiter. */
+ if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
+ ++cp;
+ continue;
+ } else
+ BARF(ktent);
+ }
+ if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
+ FAILEDREAD(ktent);
+
+ printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
+ dev[1], dev[2], dev[3], dev[4]);
+}
+
+void
+ee_kbdtype(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ u_char kbd = 0;
+ u_int kbd2;
+ int i;
+
+ if (arg) {
+ for (i = 0; i < (strlen(arg) - 1); ++i)
+ if (!isdigit(arg[i]))
+ BARF(ktent);
+ kbd2 = atoi(arg);
+ if (kbd2 > 0xff)
+ BARF(ktent);
+ kbd += kbd2;
+ if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
+ FAILEDREAD(ktent);
+
+ printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
+}
+
+static struct strvaltabent constab[] = {
+ { "b&w", EE_CONS_BW },
+ { "ttya", EE_CONS_TTYA },
+ { "ttyb", EE_CONS_TTYB },
+ { "color", EE_CONS_COLOR },
+ { "p4opt", EE_CONS_P4OPT },
+ { NULL, 0 },
+};
+
+void
+ee_constype(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ struct strvaltabent *svp;
+ u_char cons;
+
+ if (arg) {
+ for (svp = constab; svp->sv_str != NULL; ++svp)
+ if (strcmp(svp->sv_str, arg) == 0)
+ break;
+ if (svp->sv_str == NULL)
+ BARF(ktent);
+
+ cons = svp->sv_val;
+ if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else {
+ if (doio(ktent, &cons, sizeof(cons), IO_READ))
+ FAILEDREAD(ktent);
+
+ for (svp = constab; svp->sv_str != NULL; ++svp)
+ if (svp->sv_val == cons)
+ break;
+ if (svp->sv_str == NULL) {
+ warnx("unknown type 0x%x for %s", cons,
+ ktent->kt_keyword);
+ return;
+ }
+ }
+ printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
+
+}
+
+void
+ee_diagpath(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ char path[40];
+
+ bzero(path, sizeof(path));
+ if (arg) {
+ if (strlen(arg) > sizeof(path))
+ BARF(ktent);
+ sprintf(path, arg);
+ if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else
+ if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
+ FAILEDREAD(ktent);
+
+ printf("%s=%s\n", ktent->kt_keyword, path);
+}
+
+void
+ee_banner(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+ char string[80];
+ u_char enable;
+ struct keytabent kt;
+
+ kt.kt_keyword = "enable_banner";
+ kt.kt_offset = EE_BANNER_ENABLE_LOC;
+ kt.kt_handler = ee_notsupp;
+
+ bzero(string, sizeof(string));
+ if (arg) {
+ if (strlen(arg) > sizeof(string))
+ BARF(ktent);
+ if (*arg != '\0') {
+ enable = EE_TRUE;
+ sprintf(string, arg);
+ if (doio(ktent, (u_char *)string,
+ sizeof(string), IO_WRITE))
+ FAILEDWRITE(ktent);
+ } else {
+ enable = EE_FALSE;
+ if (doio(ktent, (u_char *)string,
+ sizeof(string), IO_READ))
+ FAILEDREAD(ktent);
+ }
+
+ if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
+ FAILEDWRITE(&kt);
+ } else {
+ if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
+ FAILEDREAD(ktent);
+ if (doio(&kt, &enable, sizeof(enable), IO_READ))
+ FAILEDREAD(&kt);
+ }
+ printf("%s=%s (%s)\n", ktent->kt_keyword, string,
+ enable == EE_TRUE ? "enabled" : "disabled");
+}
+
+/* ARGSUSED */
+void
+ee_notsupp(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+
+ warnx("field `%s' not yet supported", ktent->kt_keyword);
+}
+
+static void
+badval(ktent, arg)
+ struct keytabent *ktent;
+ char *arg;
+{
+
+ warnx("inappropriate value `%s' for field `%s'", arg,
+ ktent->kt_keyword);
+}
+
+static int
+doio(ktent, buf, len, wr)
+ struct keytabent *ktent;
+ u_char *buf;
+ ssize_t len;
+ int wr;
+{
+ int fd, rval = 0;
+ u_char *buf2;
+
+ buf2 = (u_char *)calloc(1, len);
+ if (buf2 == NULL) {
+ sprintf(err_str, "memory allocation failed");
+ return (1);
+ }
+
+ fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
+ if (fd < 0) {
+ sprintf(err_str, "open: %s: %s", path_eeprom,
+ strerror(errno));
+ free(buf2);
+ return (1);
+ }
+
+ if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
+ sprintf(err_str, "lseek: %s:", path_eeprom,
+ strerror(errno));
+ rval = 1;
+ goto done;
+ }
+
+ if (read(fd, buf2, len) != len) {
+ sprintf(err_str, "read: %s: %s", path_eeprom,
+ strerror(errno));
+ return (1);
+ }
+
+ if (wr == IO_WRITE) {
+ if (bcmp(buf, buf2, len) == 0)
+ goto done;
+
+ if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
+ sprintf(err_str, "lseek: %s: %s", path_eeprom,
+ strerror(errno));
+ rval = 1;
+ goto done;
+ }
+
+ ++update_checksums;
+ if (write(fd, buf, len) < 0) {
+ sprintf(err_str, "write: %s: %s", path_eeprom,
+ strerror(errno));
+ rval = 1;
+ goto done;
+ }
+ } else
+ bcopy(buf2, buf, len);
+
+ done:
+ free(buf2);
+ (void)close(fd);
+ return (rval);
+}
+
+/*
+ * Read from eeLastHwUpdate to just before eeReserved. Calculate
+ * a checksum, and deposit 3 copies of it sequentially starting at
+ * eeChecksum[0]. Increment the write count, and deposit 3 copies
+ * of it sequentially starting at eeWriteCount[0].
+ */
+void
+ee_updatechecksums()
+{
+ struct keytabent kt;
+ u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
+ u_char checksum;
+ int i;
+
+ kt.kt_keyword = "eeprom contents";
+ kt.kt_offset = EE_HWUPDATE_LOC;
+ kt.kt_handler = ee_notsupp;
+
+ if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
+ cksumfail = 1;
+ FAILEDREAD(&kt);
+ }
+
+ checksum = ee_checksum(checkme, sizeof(checkme));
+
+ kt.kt_keyword = "eeprom checksum";
+ for (i = 0; i < 4; ++i) {
+ kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
+ if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
+ cksumfail = 1;
+ FAILEDWRITE(&kt);
+ }
+ }
+
+ kt.kt_keyword = "eeprom writecount";
+ for (i = 0; i < 4; ++i) {
+ kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
+ if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
+ IO_WRITE)) {
+ cksumfail = 1;
+ FAILEDWRITE(&kt);
+ }
+ }
+}
+
+void
+ee_verifychecksums()
+{
+ struct keytabent kt;
+ u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
+ u_char checksum, ochecksum[3];
+ u_short owritecount[3];
+
+ /*
+ * Verify that the EEPROM's write counts match, and update the
+ * global copy for use later.
+ */
+ kt.kt_keyword = "eeprom writecount";
+ kt.kt_offset = EE_WC_LOC;
+ kt.kt_handler = ee_notsupp;
+
+ if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
+ cksumfail = 1;
+ FAILEDREAD(&kt);
+ }
+
+ if (owritecount[0] != owritecount[1] ||
+ owritecount[0] != owritecount[2]) {
+ warnx("eeprom writecount mismatch %s",
+ ignore_checksum ? "(ignoring)" :
+ (fix_checksum ? "(fixing)" : ""));
+
+ if (!ignore_checksum && !fix_checksum) {
+ cksumfail = 1;
+ return;
+ }
+
+ writecount = MAXIMUM(owritecount[0], owritecount[1]);
+ writecount = MAXIMUM(writecount, owritecount[2]);
+ } else
+ writecount = owritecount[0];
+
+ /*
+ * Verify that the EEPROM's checksums match and are correct.
+ */
+ kt.kt_keyword = "eeprom checksum";
+ kt.kt_offset = EE_CKSUM_LOC;
+
+ if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
+ cksumfail = 1;
+ FAILEDREAD(&kt);
+ }
+
+ if (ochecksum[0] != ochecksum[1] ||
+ ochecksum[0] != ochecksum[2]) {
+ warnx("eeprom checksum mismatch %s",
+ ignore_checksum ? "(ignoring)" :
+ (fix_checksum ? "(fixing)" : ""));
+
+ if (!ignore_checksum && !fix_checksum) {
+ cksumfail = 1;
+ return;
+ }
+ }
+
+ kt.kt_keyword = "eeprom contents";
+ kt.kt_offset = EE_HWUPDATE_LOC;
+
+ if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
+ cksumfail = 1;
+ FAILEDREAD(&kt);
+ }
+
+ checksum = ee_checksum(checkme, sizeof(checkme));
+
+ if (ochecksum[0] != checksum) {
+ warnx("eeprom checksum incorrect %s",
+ ignore_checksum ? "(ignoring)" :
+ (fix_checksum ? "(fixing)" : ""));
+
+ if (!ignore_checksum && !fix_checksum) {
+ cksumfail = 1;
+ return;
+ }
+ }
+
+ if (fix_checksum)
+ ee_updatechecksums();
+}
+
+u_char
+ee_checksum(area, len)
+ u_char *area;
+ size_t len;
+{
+ u_char sum = 0;
+
+ while (len--)
+ sum += *area++;
+
+ return (0x100 - sum);
+}
diff --git a/usr.sbin/eeprom/eeprom.8 b/usr.sbin/eeprom/eeprom.8
new file mode 100644
index 00000000000..c8d9a002d10
--- /dev/null
+++ b/usr.sbin/eeprom/eeprom.8
@@ -0,0 +1,345 @@
+.\" $NetBSD: eeprom.8,v 1.1 1995/07/13 18:12:09 thorpej Exp $
+.\"
+.\" Copyright (c) 1995 Jason R. Thorpe.
+.\" 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 for the NetBSD Project
+.\" by Jason R. Thorpe.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd May 25, 1995
+.Dt EEPROM 8
+.Os
+.Sh NAME
+.Nm eeprom
+.Nd display or modify contents of the EEPROM or OpenProm
+.Sh SUN 3 SYNOPSIS
+.Nm eeprom
+.Op Fl
+.Op Fl c
+.Op Fl f Ar device
+.Op Fl i
+.Oo
+.Ar field Ns Oo
+.Li = Ns Ar value
+.Oc ...
+.Oc
+.Sh SPARC SYNOPSIS
+.Nm eeprom
+.Op Fl
+.Op Fl c
+.Op Fl f Ar device
+.Op Fl i
+.Op Fl v
+.Op Fl N Ar system
+.Oo
+.Ar field Ns Oo
+.Li = Ns Ar value
+.Oc ...
+.Oc
+.Sh DESCRIPTION
+.Nm Eeprom
+provides an interface for displaying and changing the contents of the
+EEPROM or OpenProm. Without any arguments,
+.Nm eeprom
+will list all of the known fields and their corresponding values.
+When given the name of a specific field,
+.Nm eeprom
+will display that value or set it if the field name is followed by
+.Sq =
+and a value. Only the super-user may modify the contents of the EEPROM
+or OpenProm.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl
+Commands are taken from stdin and displayed on stdout.
+.It Fl c
+.Nm Eeprom
+will fix incorrect checksum values and exit. This flag is quietly ignored
+on systems with an OpenProm.
+.It Fl f Ar device
+On systems with an EEPROM, use
+.Ar device
+instead of the default
+.Pa /dev/eeprom .
+On systems with an OpenProm, use
+.Ar device
+instead of the default
+.Pa /dev/openprom .
+.It Fl i
+If checksum values are incorrect,
+.Nm eeprom
+will ignore them and continue after displaying a warning. This flag is
+quietly ignored on systems with an OpenProm.
+.El
+.Pp
+The following options are valid only on the SPARC and will produce an
+error when used on a Sun 3:
+.Bl -tag -width indent
+.It Fl v
+On systems with an OpenProm, be verbose when setting a value. Systems
+with an EEPROM are always verbose.
+.It Fl N Ar system
+Use the system image
+.Ar system
+instead of the default
+.Pa /netbsd .
+.El
+.Sh FIELDS AND VALUES
+The following fields and values are for systems with an EEPROM:
+.Bl -tag -width "watchdog_reboot "
+.It hwupdate
+A valid date, such as
+.Dq 7/12/95 .
+The strings
+.Dq today
+and
+.Dq now
+are also acceptable.
+.It memsize
+How much memory, in megabytes, is installed in the system.
+.It memtest
+How much memory, in megabytes, is to be tested upon power-up.
+.It scrsize
+The size of the screen. Acceptable values are
+.Dq 1024x1024 ,
+.Dq 1152x900 ,
+.Dq 1600x1280 ,
+and
+.Dq 1440x1440 .
+.It watchdog_reboot
+If true, the system will reboot upon reset. Otherwise, the system will fall
+into the monitor.
+.It default_boot
+If true, the system will use the boot device stored in
+.Pa bootdev .
+.It bootdev
+Specifies the default boot device in the form cc(x,x,x), where
+.Sq cc
+is a combination of two letters such as
+.Sq sd
+or
+.Sq le
+and each
+.Sq x
+is a hexadecimal number between 0 and ff, less the prepending
+.Sq 0x .
+.It kbdtype
+This value is
+.Dq 0
+for all Sun keyboards.
+.It console
+Specifies the console type. Valid values are
+.Dq b&w ,
+.Dq ttya ,
+.Dq ttyb ,
+.Dq color ,
+and
+.Dq p4opt .
+.It keyclick
+If true, the keys click annoyingly.
+.It diagdev
+This is a string very similar to that used by
+.Pa bootdev .
+It specifies the default boot device when the diagnostic switch is
+turned on.
+.It diagpath
+A 40-character, NULL-terminated string specifying the kernel or standalone
+program to load when the diagnostic switch is turned on.
+.It columns
+An 8-bit integer specifying the number of columns on the console.
+.It rows
+An 8-bit integer specifying the number of rows on the console.
+.It ttya_use_baud
+Use the baud rate stored in
+.Pa ttya_baud
+instead of the default 9600.
+.It ttya_baud
+A 16-bit integer specifying the baud rate to use on ttya.
+.It ttya_no_rtsdtr
+If true, disables RTS/DTR.
+.It ttyb_use_baud
+Similar to
+.Pa ttya_use_baud ,
+but for ttyb.
+.It ttyb_baud
+Similar to
+.Pa ttya_baud ,
+but for ttyb.
+.It ttyb_no_rtsdtr
+Similar to
+.Pa ttya_no_rtsdtr ,
+but for ttyb.
+.It banner
+An 80-character, NULL-terminated string to use at power-up instead
+of the default Sun banner.
+.El
+.Pp
+Note that the
+.Pa secure ,
+.Pa bad_login ,
+and
+.Pa password
+fields are not currently supported.
+.Pp
+Since the OpenProm is designed such that the field names are arbitrary,
+explaining them here is dubious. Below are field names and values that
+one is likely to see on a system with an OpenProm. NOTE: this list
+may be incomplete or incorrect due to differences between revisions
+of the OpenProm.
+.Bl -tag -width "last-hardware-update "
+.It sunmon-compat?
+If true, the old EEPROM-style interface will be used while in the monitor,
+rather than the OpenProm-style interface.
+.It selftest-#megs
+A 32-bit inteteger specifying the number of megabytes of memory to
+test upon power-up.
+.It oem-logo
+A 64bitx64bit bitmap in Sun Iconedit format. To set the bitmap, give
+the pathname of the file containing the image. NOTE: this proprty is
+not yet supported.
+.It oem-logo?
+If true, enables the use of the bitmap stored in
+.Pa oem-logo
+rather than the default Sun logo.
+.It oem-banner
+A string to use at power up, rather than the default Sun banner.
+.It oem-banner?
+If true, emables the use of the banner stored in
+.Pa oem-banner
+rather than the default Sun banner.
+.It ttya-mode
+A string of five comma separated fields in the format
+.Dq 9600,8,n,1,- .
+The first field is the baud rate. The second field is the
+number of data bits. The third field is the parity; acceptable values
+for parity are
+.Sq n
+(none),
+.Sq e
+(even),
+.Sq o
+(odd),
+.Sq m
+(mark), and
+.Sq s
+(space). The
+fourth field is the number of stop bits. The fifth field is the
+.Sq handshake
+field; acceptable values are
+.Sq -
+(none),
+.Sq h
+(rts/cts), and
+.Sq s
+(xon/xoff).
+.It ttya-rts-dtr-off
+If true, the system will ignore RTS/DTR.
+.It ttya-ignore-cd
+If true, the system will ignore carrier detect.
+.It ttyb-mode
+Similar to
+.Pa ttya-mode ,
+but for ttyb.
+.It ttyb-rts-dtr-off
+Similar to
+.Pa ttya-rts-dtr-off ,
+but for ttyb.
+.It ttyb-ignore-cd
+Similar to
+.Pa ttya-ignore-cd ,
+but for ttyb.
+.It sbus-probe-list
+Four digits in the format
+.Dq 0123
+specifying which order to probe the sbus at power-up. It is unlikely that
+this value should ever be changed.
+.It screen-#columns
+An 8-bit integer specifying the number of columns on the console.
+.It screen-#rows
+An 8-bit integer specifying the number of rows on the console.
+.It auto-boot?
+If true, the system will boot automatically at power-up.
+.It watchdog-reboot?
+If true, the system will reboot upon reset. Otherwise, system will fall
+into the monitor.
+.It input-device
+One of the strings
+.Dq keyboard ,
+.Dq ttya ,
+or
+.Dq ttyb
+specifying the default console input device.
+.It output-device
+One of the strings
+.Dq screen ,
+.Dq ttya ,
+or
+.Dq ttyb
+specifying the default console output device.
+.It keyboard-click?
+If true, the keys click annoyingly.
+.It sd-targets
+A string in the format
+.Dq 31204567
+describing the translation of physical to logical target.
+.It st-targets
+Similar to
+.Pa sd-targets ,
+but for tapes. The default translation is
+.Dq 45670123 .
+.It scsi-initiator-id
+The SCSI ID of the on-board SCSI controller.
+.It hardware-revision
+A 7-character string describing a date, such as
+.Dq 25May95 .
+.It last-hardware-update
+Similar to
+.Pa hardware-revision ,
+describing when the CPU was last updated.
+.It diag-switch?
+If true, the system will boot and run in diagnostic mode.
+.El
+.Sh WARNINGS
+The fields and their values are not necessarily well defined on
+systems with an OpenProm. Your mileage may vary.
+.Pp
+There are a few fields known to exist in some revisions of the EEPROM
+and/or OpenProm that are not yet supported. Most notable are those
+relating to password protection of the EEPROM or OpenProm.
+.Pp
+Aviod gratuitously changing the contents of the EEPROM. It has a limited
+number of write cycles.
+.Pp
+The date parser isn't very intelligent.
+.Sh FILES
+.Bl -tag -width "/dev/openprom "
+.It /dev/eeprom
+The EEPROM device on systems with an EEPROM.
+.It /dev/openprom
+The OpenProm device on systems with an OpenProm.
+.El
diff --git a/usr.sbin/eeprom/getdate.y b/usr.sbin/eeprom/getdate.y
new file mode 100644
index 00000000000..3eedf882c9f
--- /dev/null
+++ b/usr.sbin/eeprom/getdate.y
@@ -0,0 +1,971 @@
+%{
+/* $NetBSD: getdate.y,v 1.1 1995/07/13 18:14:01 thorpej Exp $ */
+
+/*
+**
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+** send any email to Rich.
+**
+** This grammar has eight shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if !defined (USG) && !defined (sgi) && !defined (__NetBSD__)
+#include <sys/time.h>
+#endif
+
+#if defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#if defined(USG) || !defined(HAVE_FTIME)
+/*
+** If you need to do a tzset() call to set the
+** timezone, and don't have ftime().
+*/
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+ short timezone;
+ short dstflag; /* Field not used */
+};
+
+#else
+
+#include <sys/timeb.h>
+
+#endif /* defined(USG) && !defined(HAVE_FTIME) */
+
+#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
+#include <sys/time.h>
+#else
+#if defined(_AIX)
+#include <sys/time.h>
+#endif
+#include <time.h>
+#endif /* defined(BSD4_2) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+#if sgi
+#undef timezone
+#endif
+
+extern struct tm *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] =
+ "$Header: /home/cvs/src/usr.sbin/eeprom/getdate.y,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ time_t date_part;
+
+ date_part= $1/10000;
+ yyHaveDate++;
+ yyDay= (date_part)%100;
+ yyMonth= (date_part/100)%100;
+ yyYear = date_part/10000;
+ }
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+ char *s;
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ }
+ /* NOTREACHED */
+}
+
+
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+ time_t Month;
+ time_t Day;
+ time_t Year;
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+ DSTMODE DSTmode;
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+ time_t Start;
+ time_t Future;
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+ time_t Start;
+ time_t DayOrdinal;
+ time_t DayNumber;
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+ time_t Start;
+ time_t RelMonth;
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+ char *buff;
+{
+ register char *p;
+ register char *q;
+ register const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex()
+{
+ register char c;
+ register char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+#if !defined(HAVE_FTIME)
+ (void)time(&ftz.time);
+ /* Set the timezone global. */
+ tzset();
+ {
+#if sgi
+ ftz.timezone = (int) _timezone / 60;
+#else /* not sgi */
+#ifdef __NetBSD__
+ ftz.timezone = 0;
+#else /* neither sgi nor NetBSD */
+#if defined (USG)
+ extern time_t timezone;
+
+ ftz.timezone = (int) timezone / 60;
+#else /* neither sgi nor NetBSD nor USG */
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday (&tv, &tz);
+ ftz.timezone = (int) tz.tz_minuteswest;
+#endif /* neither sgi nor NetBSD nor USG */
+#endif /* neither sgi nor NetBSD */
+#endif /* not sgi */
+ }
+#else /* HAVE_FTIME */
+ (void)ftime(&ftz);
+#endif /* HAVE_FTIME */
+ }
+
+ tm = localtime(&now->time);
+ yyYear = tm->tm_year;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = now->timezone;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = now->time;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+main(ac, av)
+ int ac;
+ char *av[];
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff, (struct timeb *)NULL);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/usr.sbin/eeprom/main.c b/usr.sbin/eeprom/main.c
new file mode 100644
index 00000000000..2bebe79f978
--- /dev/null
+++ b/usr.sbin/eeprom/main.c
@@ -0,0 +1,303 @@
+/* $NetBSD: main.c,v 1.1 1995/07/13 18:15:44 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef __sparc__
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+
+#include <machine/openpromio.h>
+
+struct nlist nl[] = {
+ { "_cputyp" },
+#define SYM_CPUTYP 0
+ { NULL },
+};
+
+static char *system = NULL;
+#endif /* __sparc__ */
+
+#include <machine/eeprom.h>
+
+#include "defs.h"
+
+struct keytabent eekeytab[] = {
+ { "hwupdate", 0x10, ee_hwupdate },
+ { "memsize", 0x14, ee_num8 },
+ { "memtest", 0x15, ee_num8 },
+ { "scrsize", 0x16, ee_screensize },
+ { "watchdog_reboot", 0x17, ee_truefalse },
+ { "default_boot", 0x18, ee_truefalse },
+ { "bootdev", 0x19, ee_bootdev },
+ { "kbdtype", 0x1e, ee_kbdtype },
+ { "console", 0x1f, ee_constype },
+ { "keyclick", 0x21, ee_truefalse },
+ { "diagdev", 0x22, ee_bootdev },
+ { "diagpath", 0x28, ee_diagpath },
+ { "columns", 0x50, ee_num8 },
+ { "rows", 0x51, ee_num8 },
+ { "ttya_use_baud", 0x58, ee_truefalse },
+ { "ttya_baud", 0x59, ee_num16 },
+ { "ttya_no_rtsdtr", 0x5b, ee_truefalse },
+ { "ttyb_use_baud", 0x60, ee_truefalse },
+ { "ttyb_baud", 0x61, ee_num16 },
+ { "ttyb_no_rtsdtr", 0x63, ee_truefalse },
+ { "banner", 0x68, ee_banner },
+ { "secure", 0, ee_notsupp },
+ { "bad_login", 0, ee_notsupp },
+ { "password", 0, ee_notsupp },
+ { NULL, 0, ee_notsupp },
+};
+
+static void action __P((char *));
+static void dump_prom __P((void));
+static void usage __P((void));
+#ifdef __sparc__
+static int getcputype __P((void));
+#endif /* __sparc__ */
+
+char *path_eeprom = "/dev/eeprom";
+char *path_openprom = "/dev/openprom";
+int fix_checksum = 0;
+int ignore_checksum = 0;
+int update_checksums = 0;
+int cksumfail = 0;
+u_short writecount;
+int eval = 0;
+int use_openprom = 0;
+int verbose = 0;
+
+extern char *__progname;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch, do_stdin = 0;
+ char *cp, line[BUFSIZE];
+#ifdef __sparc__
+ char *optstring = "-cf:ivN:";
+#else
+ char *optstring = "-cf:i";
+#endif /* __sparc__ */
+
+ while ((ch = getopt(argc, argv, optstring)) != -1)
+ switch (ch) {
+ case '-':
+ do_stdin = 1;
+ break;
+
+ case 'c':
+ fix_checksum = 1;
+ break;
+
+ case 'f':
+ path_eeprom = path_openprom = optarg;
+ break;
+
+ case 'i':
+ ignore_checksum = 1;
+ break;
+#ifdef __sparc__
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'N':
+ system = optarg;
+ break;
+
+#endif /* __sparc__ */
+
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef __sparc__
+ if (getcputype() != CPU_SUN4)
+ use_openprom = 1;
+#endif /* __sparc__ */
+
+ if (use_openprom == 0) {
+ ee_verifychecksums();
+ if (fix_checksum || cksumfail)
+ exit(cksumfail);
+ }
+
+ if (do_stdin) {
+ while (fgets(line, BUFSIZE, stdin) != NULL) {
+ if (line[0] == '\n')
+ continue;
+ if ((cp = strrchr(line, '\n')) != NULL)
+ *cp = '\0';
+ action(line);
+ }
+ if (ferror(stdin))
+ err(++eval, "stdin");
+ } else {
+ if (argc == 0) {
+ dump_prom();
+ exit(eval + cksumfail);
+ }
+
+ while (argc) {
+ action(argv[argc - 1]);
+ ++argv;
+ --argc;
+ }
+ }
+
+ if (use_openprom == 0)
+ if (update_checksums) {
+ ++writecount;
+ ee_updatechecksums();
+ }
+
+ exit(eval + cksumfail);
+}
+
+#ifdef __sparc__
+#define KVM_ABORT(kd, str) { \
+ (void)kvm_close((kd)); \
+ errx(1, "%s: %s", (str), kvm_geterr((kd))); \
+}
+
+static int
+getcputype()
+{
+ char errbuf[_POSIX2_LINE_MAX];
+ int cputype;
+ kvm_t *kd;
+
+ bzero(errbuf, sizeof(errbuf));
+
+ if ((kd = kvm_openfiles(system, NULL, NULL, O_RDONLY, errbuf)) == NULL)
+ errx(1, "can't open kvm: %s", errbuf);
+
+ if (kvm_nlist(kd, nl))
+ KVM_ABORT(kd, "can't read symbol table");
+
+ if (kvm_read(kd, nl[SYM_CPUTYP].n_value, (char *)&cputype,
+ sizeof(cputype)) != sizeof(cputype))
+ KVM_ABORT(kd, "can't determine cpu type");
+
+ (void)kvm_close(kd);
+ return (cputype);
+}
+#endif /* __sparc__ */
+
+/*
+ * Separate the keyword from the argument (if any), find the keyword in
+ * the table, and call the corresponding handler function.
+ */
+static void
+action(line)
+ char *line;
+{
+ char *keyword, *arg, *cp;
+ struct keytabent *ktent;
+
+ keyword = strdup(line);
+ if ((arg = strrchr(keyword, '=')) != NULL)
+ *arg++ = '\0';
+
+#ifdef __sparc__
+ if (use_openprom) {
+ /*
+ * The whole point of the Openprom is that one
+ * isn't required to know the keywords. With this
+ * in mind, we just dump the whole thing off to
+ * the generic op_handler.
+ */
+ if ((cp = op_handler(keyword, arg)) != NULL)
+ warnx(cp);
+ return;
+ } else
+#endif /* __sparc__ */
+ for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
+ if (strcmp(ktent->kt_keyword, keyword) == 0) {
+ (*ktent->kt_handler)(ktent, arg);
+ return;
+ }
+ }
+
+ warnx("unknown keyword %s", keyword);
+ ++eval;
+}
+
+/*
+ * Dump the contents of the prom corresponding to all known keywords.
+ */
+static void
+dump_prom()
+{
+ struct keytabent *ktent;
+
+#ifdef __sparc__
+ if (use_openprom) {
+ /*
+ * We have a special dump routine for this.
+ */
+ op_dump();
+ } else
+#endif /* __sparc__ */
+ for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
+ (*ktent->kt_handler)(ktent, NULL);
+}
+
+static void
+usage()
+{
+
+#ifdef __sparc__
+ fprintf(stderr, "usage: %s %s %s\n", __progname,
+ "[-] [-c] [-f device] [-i] [-v]",
+ "[-N system] [field[=value] ...]");
+#else
+ fprintf(stderr, "usage: %s %s\n", __progname,
+ "[-] [-c] [-f device] [-i] [field[=value] ...]");
+#endif /* __sparc__ */
+ exit(1);
+}
diff --git a/usr.sbin/eeprom/ophandlers.c b/usr.sbin/eeprom/ophandlers.c
new file mode 100644
index 00000000000..f1bd663570b
--- /dev/null
+++ b/usr.sbin/eeprom/ophandlers.c
@@ -0,0 +1,258 @@
+/* $NetBSD: ophandlers.c,v 1.1 1995/07/13 18:17:28 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <machine/eeprom.h>
+#include <machine/openpromio.h>
+
+#include "defs.h"
+
+extern char *path_openprom;
+extern int eval;
+extern int verbose;
+
+static char err_str[BUFSIZE];
+
+static void op_notsupp __P((struct extabent *, struct opiocdesc *, char *));
+
+/*
+ * There are several known fields that I either don't know how to
+ * deal with or require special treatment.
+ */
+static struct extabent opextab[] = {
+ { "security-password", op_notsupp },
+ { "security-mode", op_notsupp },
+ { "oem-logo", op_notsupp },
+ { NULL, op_notsupp },
+};
+
+#define BARF(str1, str2) { \
+ sprintf(err_str, "%s: %s", (str1), (str2)); \
+ ++eval; \
+ return (err_str); \
+};
+
+char *
+op_handler(keyword, arg)
+ char *keyword, *arg;
+{
+ struct opiocdesc opio;
+ struct extabent *ex;
+ char opio_buf[BUFSIZE];
+ int fd, optnode;
+
+ if ((fd = open(path_openprom, arg ? O_RDWR : O_RDONLY, 0640)) < 0)
+ BARF(path_openprom, strerror(errno));
+
+ /* Check to see if it's a special-case keyword. */
+ for (ex = opextab; ex->ex_keyword != NULL; ++ex)
+ if (strcmp(ex->ex_keyword, keyword) == 0)
+ break;
+
+ if (ioctl(fd, OPIOCGETOPTNODE, (char *)&optnode) < 0)
+ BARF("OPIOCGETOPTNODE", strerror(errno));
+
+ bzero(&opio_buf[0], sizeof(opio_buf));
+ bzero(&opio, sizeof(opio));
+ opio.op_nodeid = optnode;
+ opio.op_name = keyword;
+ opio.op_namelen = strlen(opio.op_name);
+
+ if (arg) {
+ if (verbose) {
+ printf("old: ");
+
+ opio.op_buf = &opio_buf[0];
+ opio.op_buflen = sizeof(opio_buf);
+ if (ioctl(fd, OPIOCGET, (char *)&opio) < 0)
+ BARF("OPIOCGET", strerror(errno));
+
+ if (opio.op_buflen <= 0) {
+ printf("nothing available for %s\n");
+ goto out;
+ }
+
+ if (ex->ex_keyword != NULL)
+ (*ex->ex_handler)(ex, &opio, NULL);
+ else
+ printf("%s\n", opio.op_buf);
+ }
+ out:
+ if (ex->ex_keyword != NULL)
+ (*ex->ex_handler)(ex, &opio, arg);
+ else {
+ opio.op_buf = arg;
+ opio.op_buflen = strlen(arg);
+ }
+
+ if (ioctl(fd, OPIOCSET, (char *)&opio) < 0)
+ BARF("invalid keyword", keyword);
+
+ if (verbose) {
+ printf("new: ");
+ if (ex->ex_keyword != NULL)
+ (*ex->ex_handler)(ex, &opio, NULL);
+ else
+ printf("%s\n", opio.op_buf);
+ }
+ } else {
+ opio.op_buf = &opio_buf[0];
+ opio.op_buflen = sizeof(opio_buf);
+ if (ioctl(fd, OPIOCGET, (char *)&opio) < 0)
+ BARF("OPIOCGET", strerror(errno));
+
+ if (opio.op_buflen <= 0) {
+ sprintf(err_str, "nothing available for %s",
+ keyword);
+ return (err_str);
+ }
+
+ if (ex->ex_keyword != NULL)
+ (*ex->ex_handler)(ex, &opio, NULL);
+ else
+ printf("%s=%s\n", keyword, opio.op_buf);
+ }
+
+ (void)close(fd);
+ return (NULL);
+}
+
+/* ARGSUSED */
+static void
+op_notsupp(exent, opiop, arg)
+ struct extabent *exent;
+ struct opiocdesc *opiop;
+ char *arg;
+{
+
+ warnx("property `%s' not yet supported", exent->ex_keyword);
+}
+
+/*
+ * XXX: This code is quite ugly. You have been warned.
+ * (Really! This is the only way I could get it to work!)
+ */
+void
+op_dump()
+{
+ struct opiocdesc opio1, opio2;
+ struct extabent *ex;
+ char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], buf4[BUFSIZE];
+ int fd, optnode;
+
+ if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0)
+ err(1, "open: %s", path_openprom);
+
+ if (ioctl(fd, OPIOCGETOPTNODE, (char *)&optnode) < 0)
+ err(1, "OPIOCGETOPTNODE");
+
+ bzero(&opio1, sizeof(opio1));
+
+ /* This will grab the first property name from OPIOCNEXTPROP. */
+ bzero(buf1, sizeof(buf1));
+ bzero(buf2, sizeof(buf2));
+
+ opio1.op_nodeid = opio2.op_nodeid = optnode;
+
+ opio1.op_name = buf1;
+ opio1.op_buf = buf2;
+
+ opio2.op_name = buf3;
+ opio2.op_buf = buf4;
+
+ /*
+ * For reference: opio1 is for obtaining the name. Pass the
+ * name of the last property read in op_name, and the next one
+ * will be returned in op_buf. To get the first name, pass
+ * an empty string. There are no more properties when an
+ * empty string is returned.
+ *
+ * opio2 is for obtaining the value associated with that name.
+ * For some crazy reason, it seems as if we need to do all
+ * of that gratuitious zapping and copying. *sigh*
+ */
+ for (;;) {
+ opio1.op_namelen = strlen(opio1.op_name);
+ opio1.op_buflen = sizeof(buf2);
+
+ if (ioctl(fd, OPIOCNEXTPROP, (char *)&opio1) < 0)
+ err(1, "ioctl: OPIOCNEXTPROP");
+
+ /*
+ * The name of the property we wish to get the
+ * value for has been stored in the value field
+ * of opio1. If the length of the name is 0, there
+ * are no more properties left.
+ */
+ sprintf(opio2.op_name, opio1.op_buf);
+ opio2.op_namelen = strlen(opio2.op_name);
+
+ if (opio2.op_namelen == 0) {
+ (void)close(fd);
+ return;
+ }
+
+ bzero(opio2.op_buf, sizeof(buf4));
+ opio2.op_buflen = sizeof(buf4);
+
+ if (ioctl(fd, OPIOCGET, (char *)&opio2) < 0)
+ err(1, "ioctl: OPIOCGET");
+
+ for (ex = opextab; ex->ex_keyword != NULL; ++ex)
+ if (strcmp(ex->ex_keyword, opio2.op_name) == 0)
+ break;
+
+ if (ex->ex_keyword != NULL)
+ (*ex->ex_handler)(ex, &opio2, NULL);
+ else
+ printf("%s=%s\n", opio2.op_name, opio2.op_buf);
+
+ /*
+ * Place the name of the last read value back into
+ * opio1 so that we may obtain the next name.
+ */
+ bzero(opio1.op_name, sizeof(buf1));
+ bzero(opio1.op_buf, sizeof(buf2));
+ sprintf(opio1.op_name, opio2.op_name);
+ }
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/gettable/Makefile b/usr.sbin/gettable/Makefile
new file mode 100644
index 00000000000..e72efdbfdc3
--- /dev/null
+++ b/usr.sbin/gettable/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:33 deraadt Exp $
+
+PROG= gettable
+MAN= gettable.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gettable/gettable.8 b/usr.sbin/gettable/gettable.8
new file mode 100644
index 00000000000..99561fc681d
--- /dev/null
+++ b/usr.sbin/gettable/gettable.8
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\" from: @(#)gettable.8 6.5 (Berkeley) 3/16/91
+.\" $Id: gettable.8,v 1.1.1.1 1995/10/18 08:47:34 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt GETTABLE 8
+.Os BSD 4.2
+.Sh NAME
+.Nm gettable
+.Nd get
+.Tn NIC
+format host tables from a host
+.Sh SYNOPSIS
+.Nm gettable
+.Op Fl v
+.Ar host
+.Op Ar outfile
+.Sh DESCRIPTION
+.Nm Gettable
+is a simple program used to obtain the
+.Tn NIC
+standard
+host tables from a
+.Dq nicname
+server. The indicated
+.Ar host
+is queried for the tables. The tables, if retrieved,
+are placed in the file
+.Ar outfile
+or by default,
+.Pa hosts.txt .
+.Pp
+Available option:
+.Bl -tag -width Ds
+.It Fl v
+Get just the version number instead of the complete host table
+and put the output in the file
+.Ar outfile
+or by default,
+.Pa hosts.ver .
+.El
+.Pp
+.Nm Gettable
+operates by opening a
+.Tn TCP
+connection to the port indicated
+in the service specification for ``nicname''. A request
+is then made for
+.Dq ALL
+names and the resultant information
+is placed in the output file.
+.Pp
+.Nm Gettable
+is best used in conjunction with the
+.Xr htable 8
+program which converts the
+.Tn NIC
+standard file format to
+that used by the network library lookup routines.
+.Sh SEE ALSO
+.Xr intro 3 ,
+.Xr htable 8 ,
+.Xr named 8
+.Sh BUGS
+If the name-domain system provided network name mapping well as host
+name mapping,
+.Nm gettable
+would no longer be needed.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/gettable/gettable.c b/usr.sbin/gettable/gettable.c
new file mode 100644
index 00000000000..bacd2164bab
--- /dev/null
+++ b/usr.sbin/gettable/gettable.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)gettable.c 5.6 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: gettable.c,v 1.1.1.1 1995/10/18 08:47:34 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+
+#define OUTFILE "hosts.txt" /* default output file */
+#define VERFILE "hosts.ver" /* default version file */
+#define QUERY "ALL\r\n" /* query to hostname server */
+#define VERSION "VERSION\r\n" /* get version number */
+
+#define equaln(s1, s2, n) (!strncmp(s1, s2, n))
+
+struct sockaddr_in s_in;
+char buf[BUFSIZ];
+char *outfile = OUTFILE;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int s;
+ register len;
+ register FILE *sfi, *sfo, *hf;
+ char *host;
+ register struct hostent *hp;
+ struct servent *sp;
+ int version = 0;
+ int beginseen = 0;
+ int endseen = 0;
+
+ argv++, argc--;
+ if (*argv && **argv == '-') {
+ if (argv[0][1] != 'v')
+ fprintf(stderr, "unknown option %s ignored\n", *argv);
+ else
+ version++, outfile = VERFILE;
+ argv++, argc--;
+ }
+ if (argc < 1 || argc > 2) {
+ fprintf(stderr, "usage: gettable [-v] host [ file ]\n");
+ exit(1);
+ }
+ sp = getservbyname("hostnames", "tcp");
+ if (sp == NULL) {
+ fprintf(stderr, "gettable: hostnames/tcp: unknown service\n");
+ exit(3);
+ }
+ host = *argv;
+ argv++, argc--;
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "gettable: %s: ", host);
+ herror((char *)NULL);
+ exit(2);
+ }
+ host = hp->h_name;
+ if (argc > 0)
+ outfile = *argv;
+ s_in.sin_family = hp->h_addrtype;
+ s = socket(hp->h_addrtype, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("gettable: socket");
+ exit(4);
+ }
+ if (bind(s, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
+ perror("gettable: bind");
+ exit(5);
+ }
+ bcopy(hp->h_addr, &s_in.sin_addr, hp->h_length);
+ s_in.sin_port = sp->s_port;
+ if (connect(s, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
+ perror("gettable: connect");
+ exit(6);
+ }
+ fprintf(stderr, "Connection to %s opened.\n", host);
+ sfi = fdopen(s, "r");
+ sfo = fdopen(s, "w");
+ if (sfi == NULL || sfo == NULL) {
+ perror("gettable: fdopen");
+ close(s);
+ exit(1);
+ }
+ hf = fopen(outfile, "w");
+ if (hf == NULL) {
+ fprintf(stderr, "gettable: "); perror(outfile);
+ close(s);
+ exit(1);
+ }
+ fprintf(sfo, version ? VERSION : QUERY);
+ fflush(sfo);
+ while (fgets(buf, sizeof(buf), sfi) != NULL) {
+ len = strlen(buf);
+ buf[len-2] = '\0';
+ if (!version && equaln(buf, "BEGIN", 5)) {
+ if (beginseen || endseen) {
+ fprintf(stderr,
+ "gettable: BEGIN sequence error\n");
+ exit(90);
+ }
+ beginseen++;
+ continue;
+ }
+ if (!version && equaln(buf, "END", 3)) {
+ if (!beginseen || endseen) {
+ fprintf(stderr,
+ "gettable: END sequence error\n");
+ exit(91);
+ }
+ endseen++;
+ continue;
+ }
+ if (equaln(buf, "ERR", 3)) {
+ fprintf(stderr,
+ "gettable: hostname service error: %s", buf);
+ exit(92);
+ }
+ fprintf(hf, "%s\n", buf);
+ }
+ fclose(hf);
+ if (!version) {
+ if (!beginseen) {
+ fprintf(stderr, "gettable: no BEGIN seen\n");
+ exit(93);
+ }
+ if (!endseen) {
+ fprintf(stderr, "gettable: no END seen\n");
+ exit(94);
+ }
+ fprintf(stderr, "Host table received.\n");
+ } else
+ fprintf(stderr, "Version number received.\n");
+ close(s);
+ fprintf(stderr, "Connection to %s closed\n", host);
+ exit(0);
+}
diff --git a/usr.sbin/grfconfig/Makefile b/usr.sbin/grfconfig/Makefile
new file mode 100644
index 00000000000..34432f857a5
--- /dev/null
+++ b/usr.sbin/grfconfig/Makefile
@@ -0,0 +1,7 @@
+# $NetBSD: Makefile,v 1.1 1995/10/09 03:43:22 chopps Exp $
+
+PROG= grfconfig
+MAN= grfconfig.8
+CFLAGS+=-I${.CURDIR}/../../sys/arch -D${MACHINE}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/grfconfig/grfconfig.8 b/usr.sbin/grfconfig/grfconfig.8
new file mode 100644
index 00000000000..ed0a8bc0893
--- /dev/null
+++ b/usr.sbin/grfconfig/grfconfig.8
@@ -0,0 +1,135 @@
+.\" $NetBSD: grfconfig.8,v 1.2 1995/10/09 04:11:18 chopps Exp $
+.\"
+.\" Copyright (c) 1994 Ezra Story
+.\" 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 Ezra Story.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.Dd October 7, 1994
+.Dt GRFCONFIG 8 amiga
+.Os
+.Sh NAME
+.Nm grfconfig
+.Nd alter grf device screen mode definitions at run time
+.Sh SYNOPSIS
+.Nm grfconfig
+.Op Fl r
+.Ar device
+.Op Ar file
+.Sh DESCRIPTION
+.Nm Grfconfig
+is used to change or view the screen mode definition list contained
+in a grf device. You may also alter the sonsole screen definition as well
+as the definitions for the graphic screen. The console will automatically
+reinitialize itself to the new screen mode.
+.Pp
+The following flags and arguments are interpreted by
+.Nm grfconfig :
+.Bl -tag -width indent
+.It Fl r
+Print out a raw listing of the mode definitions instead of the
+pretty list normally shown.
+.It Ar device
+The grf device to manipulate. This argument is required.
+.It Ar file
+The file which contains the mode definitions. If this argument
+is not specified,
+.Nm grfconfig
+will print out of a list of the modes currently loaded into
+the grf device.
+.Pp
+.Sh MODE DEFINITION FILE
+THe mode definitions are taken from a file which has lines of the format:
+.Pp
+num clk wid hi dep hbs hss hse hbe ht vbs vss vse vbe vt
+.Pp
+.Bl -tag -width indent
+.It Ar num
+The mode number for 'c' for the console mode.
+.It Ar clk
+The pixel clock in Hz.
+.It Ar wid
+The screen mode's width.
+.It Ar hi
+The screen mode's height.
+.It Ar dep
+The bitdepth of the mode.
+.It Ar hbs hss hse hbe ht
+The horizonatal timing parameters for the mode in pixel values. All the
+values are relative to the end of the horizontal blank (beginning of the
+displayed area).
+.It Ar vbs vss vse vbe vt
+The vertical timing paramters for the mode in line values. All the
+values are relative to the end of vertical blank (beginning of the displayed
+area). If vbs is half the width, the grf device will interlace the
+display.
+If the vbs is twice the width, the grf device will scan double the display.
+This is provided the grf device supports those two modes of operation.
+.El
+.Pp
+.nf
+ ------------------------------------------------------
+ | ^ |
+ | vse |
+ | (0,0) |
+ | *----------------------------------- |
+ | | ^ ^ | |
+ | | vbe ! | |
+ | | ! | |
+ | | ! | |
+ |<-hse |<-hbe ! |<-hbs | | |
+ | | ! | hss->| hse->| hbe->|
+ | | hi | | | |
+ | | ! | |
+ | | ! | |
+ | |<============ wid =========+=====>| |
+ | | ! | |
+ | | ! | |
+ | | ! | |
+ | | v | |
+ | ------------------------------------ |
+ | ^ |
+ | vbs |
+ | |
+ ------------------------------------------------------
+ ^
+ vss
+ - ------- -
+ ^
+ vse
+ - ------- -
+ ^
+ vbe
+
+
+
+.Sh BUGS
+Some grf devices only understand horixontal cycle values instead of
+horizontal pixel values. Add
+the option
+.Nm -o
+to make grfconfig interpret values from the grf device as cycle values.
diff --git a/usr.sbin/grfconfig/grfconfig.c b/usr.sbin/grfconfig/grfconfig.c
new file mode 100644
index 00000000000..53ae7aff413
--- /dev/null
+++ b/usr.sbin/grfconfig/grfconfig.c
@@ -0,0 +1,205 @@
+/* $NetBSD: grfconfig.c,v 1.2 1995/10/09 04:11:20 chopps Exp $ */
+
+/*
+ * Copyright (c) 1995 Ezra Story
+ * 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 Ezra Story.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <amiga/dev/grfioctl.h>
+
+extern char *optarg;
+extern int optind;
+
+/*
+ * Dynamic mode loader for NetBSD/Amiga grf devices.
+ */
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ int c, y, grffd;
+ char rawdata = 0;
+ char oldmode = 1;
+ char *grfdevice = 0;
+ char *modefile = 0;
+ char buf[102];
+ char ystr[20];
+ FILE *fp;
+ struct grfvideo_mode gv[1];
+
+ while ((c = getopt(ac, av, "ro")) != -1) {
+ switch (c) {
+ case 'r': /* raw output */
+ rawdata = 1;
+ break;
+ case 'o':
+ oldmode = 8;
+ break;
+ default:
+ printf("grfconfig [-r] device [file]\n");
+ return (1);
+ }
+ }
+ ac -= optind;
+ av += optind;
+
+
+ if (ac >= 1)
+ grfdevice = av[0];
+ else {
+ printf("grfconfig: No grf device specified.\n");
+ return (1);
+ }
+
+ if (ac >= 2)
+ modefile = av[1];
+
+ if ((grffd = open(grfdevice, O_RDWR)) < 0) {
+ printf("grfconfig: can't open grf device.\n");
+ return (1);
+ }
+ /* If a mode file is specificied, load it in, don't display any info. */
+
+ if (modefile) {
+ if (!(fp = fopen(modefile, "r"))) {
+ printf("grfconfig: Cannot open mode definition file.\n");
+ return (1);
+ }
+ while (fgets(buf, 300, fp)) {
+ if (buf[0] == '#')
+ continue;
+
+ /* num clk wid hi dep hbs hss hse hbe ht vbs vss vse
+ * vbe vt */
+
+ c = sscanf(buf, "%9s %d %hd %hd %hd %hd %hd %hd "
+ "%hd %hd %hd %hd %hd %hd %hd",
+ ystr,
+ &gv->pixel_clock,
+ &gv->disp_width,
+ &gv->disp_height,
+ &gv->depth,
+ &gv->hblank_start,
+ &gv->hsync_start,
+ &gv->hsync_stop,
+ &gv->hblank_stop,
+ &gv->htotal,
+ &gv->vblank_start,
+ &gv->vsync_start,
+ &gv->vsync_stop,
+ &gv->vblank_stop,
+ &gv->vtotal);
+ if (c == 15) {
+ if (y = atoi(ystr))
+ gv->mode_num = y;
+ else
+ if (ystr[0] == 'c') {
+ gv->mode_num = 255;
+ gv->depth = 4;
+ }
+ gv->mode_descr[0] = 0;
+ if (ioctl(grffd, GRFIOCSETMON, (char *) gv) < 0)
+ printf("grfocnfig: bad monitor "
+ "definition.\n");
+ } else {
+ printf("grfconfig: bad line in mode "
+ "definition file.\n");
+ }
+ }
+ fclose(fp);
+ } else {
+ ioctl(grffd, GRFGETNUMVM, &y);
+ y += 2;
+ for (c = 1; c < y; c++) {
+ c = gv->mode_num = (c != (y - 1)) ? c : 255;
+ if (ioctl(grffd, GRFGETVMODE, gv) < 0)
+ continue;
+ if (rawdata) {
+ if (c == 255)
+ printf("c ");
+ else
+ printf("%d ", c);
+ printf("%d %d %d %d %d %d %d "
+ "%d %d %d %d %d %d %d\n",
+ gv->pixel_clock,
+ gv->disp_width,
+ gv->disp_height,
+ gv->depth,
+ gv->hblank_start,
+ gv->hsync_start,
+ gv->hsync_stop,
+ gv->hblank_stop,
+ gv->htotal,
+ gv->vblank_start,
+ gv->vsync_start,
+ gv->vsync_stop,
+ gv->vblank_stop,
+ gv->vtotal
+ );
+ continue;
+ }
+ if (c == 255)
+ printf("Console: ");
+ else
+ printf("%2d: ", gv->mode_num);
+
+ printf("%dx%d",
+ gv->disp_width,
+ gv->disp_height);
+
+ if (c != 255)
+ printf("x%d", gv->depth);
+ else
+ printf(" (%dx%d)",
+ gv->disp_width / 8,
+ gv->disp_height / gv->depth);
+
+ printf("\t%d.%dkHz @ %dHz %s\n",
+ gv->pixel_clock / (gv->htotal * 1000 * oldmode),
+ (gv->pixel_clock / (gv->htotal * 100 * oldmode))
+ % 10,
+ gv->pixel_clock / (gv->htotal * gv->vtotal *
+ oldmode),
+ gv->vblank_start + 100 < gv->disp_height ?
+ "I" :
+ (gv->vblank_start - 100) > gv->disp_height ?
+ "SD" :
+ "NI"
+ );
+ }
+ }
+
+ close(grffd);
+ return (0);
+}
diff --git a/usr.sbin/grfinfo/Makefile b/usr.sbin/grfinfo/Makefile
new file mode 100644
index 00000000000..2aaa0e053a1
--- /dev/null
+++ b/usr.sbin/grfinfo/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:34 deraadt Exp $
+
+PROG= grfinfo
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../sys/arch/hp300
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/grfinfo/grfinfo.c b/usr.sbin/grfinfo/grfinfo.c
new file mode 100644
index 00000000000..55709eb8f8c
--- /dev/null
+++ b/usr.sbin/grfinfo/grfinfo.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1987-1993, The University of Utah and
+ * the Center for Software Science at the University of Utah (CSS).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the Center
+ * for Software Science at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSS requests users of this software to return to css-dist@cs.utah.edu any
+ * improvements that they make and grant CSS redistribution rights.
+ *
+ * from: Utah $Hdr: grfinfo.c 1.3 94/04/04$
+ * $Id: grfinfo.c,v 1.1.1.1 1995/10/18 08:47:34 deraadt Exp $
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <dev/grfioctl.h>
+
+int aflg = 0;
+int tflg = 1;
+char *pname;
+char *dname, *tname();
+struct grfinfo gi;
+
+struct grf_info {
+ int grf_id;
+ char *grf_name;
+} info[] = {
+ GRFGATOR, "gatorbox",
+ GRFBOBCAT, "topcat",
+ GRFRBOX, "renaissance",
+ GRFDAVINCI, "davinci",
+ -1, "unknown",
+};
+
+main(argc, argv)
+ char **argv;
+{
+ extern int optind, optopt;
+ extern char *optarg;
+ register int c;
+
+ pname = argv[0];
+ while ((c = getopt(argc, argv, "at")) != EOF)
+ switch (c) {
+ /* everything */
+ case 'a':
+ aflg++;
+ break;
+ /* type */
+ case 't':
+ tflg++;
+ break;
+ /* bogon */
+ case '?':
+ usage();
+ }
+ if (optind == argc)
+ usage();
+ dname = argv[optind];
+ getinfo();
+ if (aflg)
+ printall();
+ else if (tflg)
+ printf("%s\n", tname());
+ exit(0);
+}
+
+getinfo()
+{
+ int f;
+
+ f = open(dname, 0);
+ if (f < 0 || ioctl(f, GRFIOCGINFO, &gi) < 0) {
+ if (tflg)
+ printf("none\n");
+ else
+ perror(dname);
+ exit(1);
+ }
+ close(f);
+}
+
+printall()
+{
+ printf("%s: %d x %d ", dname, gi.gd_dwidth, gi.gd_dheight);
+ if (gi.gd_colors < 3)
+ printf("monochrome");
+ else {
+ printf("%d color", gi.gd_colors);
+ if (gi.gd_planes)
+ printf(", %d plane", gi.gd_planes);
+ }
+ printf(" %s\n", tname());
+ printf("registers: 0x%x bytes at 0x%x\n",
+ gi.gd_regsize, gi.gd_regaddr);
+ printf("framebuf: 0x%x bytes at 0x%x (%d x %d)\n",
+ gi.gd_fbsize, gi.gd_fbaddr, gi.gd_fbwidth, gi.gd_fbheight);
+}
+
+char *
+tname()
+{
+ register struct grf_info *gp;
+
+ for (gp = info; gp->grf_id >= 0; gp++)
+ if (gi.gd_id == gp->grf_id)
+ break;
+ /*
+ * Heuristics to differentiate catseye from topcat:
+ * low-res color catseye has 1k x 1k framebuffer and 64 colors
+ * hi-res mono and color catseye have 1280 wide display
+ */
+ if (gi.gd_id == GRFBOBCAT &&
+ (gi.gd_dwidth == 1280 ||
+ gi.gd_fbsize == 0x100000 && gi.gd_colors == 64))
+ return("catseye");
+ return(gp->grf_name);
+}
+
+usage()
+{
+ fprintf(stderr, "usage: %s [-at] device\n", pname);
+ exit(1);
+}
diff --git a/usr.sbin/gspa/Makefile b/usr.sbin/gspa/Makefile
new file mode 100644
index 00000000000..95421eacf10
--- /dev/null
+++ b/usr.sbin/gspa/Makefile
@@ -0,0 +1,3 @@
+SUBDIR += gspa gspahextoc
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/gspa/Makefile.inc b/usr.sbin/gspa/Makefile.inc
new file mode 100644
index 00000000000..097c2dd906d
--- /dev/null
+++ b/usr.sbin/gspa/Makefile.inc
@@ -0,0 +1,4 @@
+# from: @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
+# $Id: Makefile.inc,v 1.1.1.1 1995/10/18 08:47:34 deraadt Exp $
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/gspa/gspa/Makefile b/usr.sbin/gspa/gspa/Makefile
new file mode 100644
index 00000000000..d4cd1a01ac4
--- /dev/null
+++ b/usr.sbin/gspa/gspa/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.1 1995/10/09 00:06:02 chopps Exp $
+
+PROG= gspa
+CFLAGS+=-I. -I${.CURDIR}
+HDRS= gsp_ass.h gsp_code.h
+SRCS= gspa.c gsp_out.c gsp_sym.c gsp_lex.c gsp_act.c gsp_eval.c \
+ gsp_inst.c gsp_pseu.c
+OBJS+= gsp_gram.o
+NOMAN= noman
+CLEANFILES= y.tab.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gspa/gspa/gsp_act.c b/usr.sbin/gspa/gspa/gsp_act.c
new file mode 100644
index 00000000000..252ec79ae22
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_act.c
@@ -0,0 +1,204 @@
+/*
+ * GSP assembler - semantic actions
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+
+void
+free_operands(operand l)
+{
+ register operand op, oq;
+
+ for( op = l; op != NULL; op = oq ){
+ oq = op->next;
+ if( op->type == EXPR || op->type == EA
+ && op->mode >= M_INDEX )
+ free_expr(op->op_u.value);
+ free(op);
+ }
+}
+
+operand
+add_operand(operand first, operand last)
+{
+ operand p;
+
+ for( p = first; p->next != NULL; p = p->next )
+ ;
+ p->next = last;
+ return first;
+}
+
+operand
+reg_op(int reg)
+{
+ register operand o;
+
+/* printf("reg_op reg=%d sign=%d\n", reg, sign); */
+ new(o);
+ o->type = REG;
+ o->reg_no = reg;
+ o->next = NULL;
+ return o;
+}
+
+operand
+expr_op(expr val)
+{
+ register operand o;
+
+/* printf("immed len=%d\n", len); */
+ new(o);
+ o->type = EXPR;
+ o->op_u.value = val;
+ o->next = NULL;
+ return o;
+}
+
+operand
+string_op(char *str)
+{
+ register operand o;
+
+/* printf("string_op str=%s\n", str); */
+ new(o);
+ o->type = STR_OPN;
+ o->op_u.string = str;
+ o->next = NULL;
+ return o;
+}
+
+operand
+abs_adr(expr adr)
+{
+ register operand o;
+
+/* printf("abs_adr len=%d\n", len); */
+ new(o);
+ o->type = EA;
+ o->mode = M_ABSOLUTE;
+ o->op_u.value = adr;
+ o->next = NULL;
+ return o;
+}
+
+operand
+reg_ind(int reg, int mode)
+{
+ register operand o;
+
+/* printf("reg_adr r1=%d r2=%d mode=%d\n", r1, r2, mode); */
+ new(o);
+ o->type = EA;
+ o->mode = mode;
+ o->reg_no = reg;
+ o->next = NULL;
+ return o;
+}
+
+operand
+reg_indxy(int reg, char *xy)
+{
+ register operand o;
+
+ ucasify(xy);
+ if( strcmp(xy, ".XY") != 0 )
+ perr("Register format must be .XY");
+ return reg_ind(reg, M_INDXY);
+}
+
+operand
+reg_index(int reg, expr disp)
+{
+ register operand o;
+
+ o = reg_ind(reg, M_INDEX);
+ o->op_u.value = disp;
+ return o;
+}
+
+expr
+id_expr(char *id)
+{
+ register expr x;
+
+/* printf("id_expr id=%s\n", id); */
+ new(x);
+ x->e_op = SYM;
+ x->e_sym = lookup(id, TRUE);
+ return x;
+}
+
+expr
+num_expr(int val)
+{
+ register expr x;
+
+/* printf("num_expr val=%d\n", val); */
+ new(x);
+ x->e_op = CONST;
+ x->e_val = val;
+ return x;
+}
+
+expr
+here_expr()
+{
+ register expr x;
+
+/* printf("here_expr()\n"); */
+ new(x);
+ x->e_op = '.';
+ return x;
+}
+
+expr
+bexpr(int op, expr l, expr r)
+{
+ register expr x;
+
+/* printf("bexpr op=%d\n", op); */
+ new(x);
+ x->e_op = op;
+ x->e_left = l;
+ x->e_right = r;
+ return x;
+}
+
+void
+free_expr(register expr x)
+{
+ if( x->e_op != SYM && x->e_op != CONST && x->e_op != '.' ){
+ free_expr(x->e_left);
+ if( x->e_right != NULL )
+ free_expr(x->e_right);
+ }
+ free(x);
+}
diff --git a/usr.sbin/gspa/gspa/gsp_ass.h b/usr.sbin/gspa/gspa/gsp_ass.h
new file mode 100644
index 00000000000..4201de43c94
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_ass.h
@@ -0,0 +1,180 @@
+/*
+ * GSP assembler - definitions
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/types.h>
+/*#include <alloca.h>*/
+
+#define MAXLINE 133
+
+typedef char bool;
+#define TRUE 1
+#define FALSE 0
+
+#define YYDEBUG 1
+
+/* Structure for symbol in symbol table */
+typedef struct symbol {
+ int16_t flags;
+ int16_t ndefn;
+ unsigned value;
+ unsigned lineno;
+ struct symbol *next;
+ struct numlab *nlab;
+ char name[1];
+} *symbol;
+
+/* Values for flags */
+#define DEFINED 1
+#define SET_LABEL 2
+#define NUMERIC_LABEL 4
+
+#define NOT_YET 65535U /* line no. for `not defined yet' */
+
+/* Info about successive numeric labels */
+struct numlab {
+ unsigned value;
+ unsigned lineno;
+ struct numlab *next;
+};
+
+/* Structure for expressions */
+typedef struct expr {
+ int e_op;
+ union {
+ struct {
+ struct expr *left;
+ struct expr *right;
+ } e_s;
+ symbol sym;
+ int32_t val;
+ } e_u;
+} *expr;
+#define e_left e_u.e_s.left
+#define e_right e_u.e_s.right
+#define e_sym e_u.sym
+#define e_val e_u.val
+
+/* Operators other than '+', '-', etc. */
+#define SYM 1
+#define CONST 2
+#define NEG 3
+
+/* Structure for an operand */
+typedef struct operand {
+ char type;
+ char mode; /* EA mode */
+ int16_t reg_no;
+ union {
+ expr value;
+ char *string;
+ } op_u;
+ struct operand *next;
+} *operand;
+
+/* Values for operand type */
+#define REG 1 /* register operand */
+#define EXPR 2 /* expression operand */
+#define EA 4 /* effective address */
+#define STR_OPN 8 /* string operand */
+
+/* Addressing modes */
+/* NB codes for modes with an expression must be > other modes */
+#define M_REG 0 /* R */
+#define M_IND 1 /* *R */
+#define M_POSTINC 2 /* *R+ */
+#define M_PREDEC 3 /* *-R */
+#define M_INDXY 4 /* *R.XY (pixt only) */
+#define M_INDEX 5 /* *R(n) */
+#define M_ABSOLUTE 6 /* @adr */
+
+/* Register names */
+#define A0 0x20
+#define B0 0x50
+#define SP 0x6F /* (r1 & r2 & REGFILE) != 0 iff */
+#define REGFILE 0x60 /* r1 and r2 are in the same file */
+
+/* Prototypes */
+void statement(char *opcode, operand operands);
+void do_asg(char *, expr, int flags);
+void set_label(char *);
+void set_numeric_label(int);
+void reset_numeric_labels(void);
+operand reg_op(int reg);
+operand expr_op(expr);
+operand string_op(char *);
+operand abs_adr(expr);
+operand reg_ind(int, int);
+operand reg_indxy(int, char *);
+operand reg_index(int, expr);
+operand add_operand(operand, operand);
+expr id_expr(char *);
+expr num_expr(int);
+expr here_expr(void);
+expr bexpr(int, expr, expr);
+void free_operands(operand);
+void free_expr(expr);
+
+void perr(char *fmt, ...);
+void p1err(char *fmt, ...);
+int get_line(char *lp, int maxlen);
+char *alloc(size_t nbytes);
+
+symbol lookup(char *id, bool makeit);
+expr fold(expr);
+int eval_expr(expr, int32_t *, unsigned *);
+void pseudo(int code, operand operands);
+
+void putcode(u_int16_t *, int);
+
+extern unsigned pc;
+extern short pass2;
+
+extern int lineno;
+extern int err_count;
+extern char line[], *lineptr;
+
+#if defined(sparc) && !defined(__NetBSD__)
+#include <alloca.h>
+#else
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+#endif
+
+#ifndef BSD
+#ifndef amiga
+#define bcopy(s, d, l) memcpy(d, s, l)
+#endif
+#endif
+
+#define new(x) ((x) = (typeof (x)) alloc (sizeof(*(x))))
diff --git a/usr.sbin/gspa/gspa/gsp_code.h b/usr.sbin/gspa/gspa/gsp_code.h
new file mode 100644
index 00000000000..33719fa368b
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_code.h
@@ -0,0 +1,41 @@
+/*
+ * GSP assembler - codes for assembler directives
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*#define EQU 0*/
+#define ORG 1
+#define INCL 2
+#define WORD 3
+#define LONG 4
+#define BLKB 5
+#define BLKW 6
+#define BLKL 7
+#define START 8
diff --git a/usr.sbin/gspa/gspa/gsp_eval.c b/usr.sbin/gspa/gspa/gsp_eval.c
new file mode 100644
index 00000000000..bfc77f03ede
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_eval.c
@@ -0,0 +1,138 @@
+/*
+ * GSP assembler - expression evaluation
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "y.tab.h"
+
+int32_t eval_op(int, int32_t, int32_t);
+int32_t eval_subtree(expr, unsigned *);
+
+expr
+fold(register expr x)
+{
+ register int32_t l;
+ register expr lp, rp;
+
+ switch( x->e_op ){
+ case SYM:
+ case CONST:
+ case '.':
+ return x;
+ }
+ x->e_left = lp = fold(x->e_left);
+ if( x->e_right != NULL )
+ x->e_right = rp = fold(x->e_right);
+ else
+ rp = NULL;
+ if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
+ /* operator with constant subtree(s) */
+ if( rp != NULL ){
+ l = eval_op(x->e_op, lp->e_val, rp->e_val);
+ free(rp);
+ } else
+ l = eval_op(x->e_op, lp->e_val, 0);
+ free(lp);
+ x->e_op = CONST;
+ x->e_val = l;
+ }
+ return x;
+}
+
+int32_t
+eval_op(int op, register int32_t l, register int32_t r)
+{
+ switch( op ){
+ case NEG: l = -l; break;
+ case '~': l = ~l; break;
+ case '+': l += r; break;
+ case '-': l -= r; break;
+ case '*': l *= r; break;
+ case '&': l &= r; break;
+ case '|': l |= r; break;
+ case '^': l ^= r; break;
+ case '/':
+ if( r == 0 )
+ perr("Divide by zero");
+ else
+ l /= r;
+ break;
+ case ':':
+ l = (l << 16) | (r & 0xFFFF);
+ break;
+ case LEFT_SHIFT:
+ l <<= r;
+ break;
+ case RIGHT_SHIFT:
+ l >>= r;
+ break;
+ }
+ return l;
+}
+
+int
+eval_expr(expr e, int32_t *vp, unsigned *lp)
+{
+ e = fold(e);
+ *vp = eval_subtree(e, lp);
+ return (*lp < NOT_YET);
+}
+
+int32_t
+eval_subtree(expr e, unsigned *lp)
+{
+ register symbol s;
+ int32_t v1, v2;
+ unsigned l2;
+
+ switch( e->e_op ){
+ case SYM:
+ s = e->e_sym;
+ *lp = s->lineno;
+ if( (s->flags & DEFINED) != 0 )
+ return s->value;
+ perr("Undefined symbol %s", s->name);
+ return 0;
+ case CONST:
+ *lp = 0;
+ return e->e_val;
+ case '.':
+ *lp = lineno;
+ return pc;
+ default:
+ v1 = eval_subtree(e->e_left, lp);
+ if( e->e_right == NULL )
+ return eval_op(e->e_op, v1, 0);
+ v2 = eval_subtree(e->e_right, &l2);
+ if( l2 > *lp )
+ *lp = l2;
+ return eval_op(e->e_op, v1, v2);
+ }
+}
diff --git a/usr.sbin/gspa/gspa/gsp_gram.y b/usr.sbin/gspa/gspa/gsp_gram.y
new file mode 100644
index 00000000000..79cd885f68f
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_gram.y
@@ -0,0 +1,122 @@
+/*
+ * Yacc syntax for GSP assembler
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* declarations */
+
+%{
+#include "gsp_ass.h"
+%}
+
+%union {
+ long y_int;
+ char *y_id;
+ expr y_expr;
+ operand y_opnd;
+}
+
+%token LEFT_SHIFT, RIGHT_SHIFT
+
+%term <y_id> ID, STRING
+%term <y_int> NUMBER, REGISTER
+%term UMINUS
+
+/* operator precedences - lowest to highest */
+%nonassoc ':' /* concatenate y:x */
+%left LEFT_SHIFT, RIGHT_SHIFT
+%left '^' /* EXCLUSIVE OR operator */
+%left '|' /* OR operator */
+%left '&' /* AND operator */
+%left '+', '-'
+%left '*', '/'
+%nonassoc '~', UMINUS /* NOT operator */
+
+%start line
+
+/* types of non-terminals */
+%type <y_expr> expr
+%type <y_opnd> operand, operands, ea
+
+%%
+/* rules */
+
+line : label ID operands { statement($2, $3); }
+ | ID operands { statement($1, $2); }
+ | label
+ | ID '=' expr { do_asg($1, $3, 0); }
+ | /* empty */
+ | error
+ ;
+
+label : ID ':' { set_label($1); }
+ | NUMBER ':' { set_numeric_label($1); }
+ ;
+
+operands : /* empty */ { $$ = NULL; }
+ | operand { $$ = $1; }
+ | operands ',' operand { $$ = add_operand($1, $3); }
+ ;
+
+operand : REGISTER { $$ = reg_op($1); }
+ | ea { $$ = $1; }
+ | expr { $$ = expr_op($1); }
+ | STRING { $$ = string_op($1); }
+ ;
+
+ea : '@' expr { $$ = abs_adr($2); }
+ | '*' REGISTER { $$ = reg_ind($2, M_IND); }
+ | '*' REGISTER ID { $$ = reg_indxy($2, $3); }
+ | '*' REGISTER '+' { $$ = reg_ind($2, M_POSTINC); }
+ | '*' '-' REGISTER { $$ = reg_ind($3, M_PREDEC); }
+ | '-' '*' REGISTER { $$ = reg_ind($3, M_PREDEC); }
+ | '*' REGISTER '(' expr ')'
+ { $$ = reg_index($2, $4); }
+ ;
+
+expr : ID { $$ = id_expr($1); }
+ | NUMBER { $$ = num_expr($1); }
+ | '.' { $$ = here_expr(); }
+ | '(' expr ')' { $$ = $2; }
+ | '~' expr { $$ = bexpr('~', $2, NULL); }
+ | '-' expr %prec UMINUS
+ { $$ = bexpr(NEG, $2, NULL); }
+ | expr '*' expr { $$ = bexpr('*', $1, $3); }
+ | expr '/' expr { $$ = bexpr('/', $1, $3); }
+ | expr '+' expr { $$ = bexpr('+', $1, $3); }
+ | expr '-' expr { $$ = bexpr('-', $1, $3); }
+ | expr '&' expr { $$ = bexpr('&', $1, $3); }
+ | expr '|' expr { $$ = bexpr('|', $1, $3); }
+ | expr '^' expr { $$ = bexpr('^', $1, $3); }
+ | expr ':' expr { $$ = bexpr(':', $1, $3); }
+ | expr LEFT_SHIFT expr { $$ = bexpr(LEFT_SHIFT, $1, $3); }
+ | expr RIGHT_SHIFT expr { $$ = bexpr(RIGHT_SHIFT, $1, $3); }
+ ;
+
diff --git a/usr.sbin/gspa/gspa/gsp_inst.c b/usr.sbin/gspa/gspa/gsp_inst.c
new file mode 100644
index 00000000000..87838b9ada5
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_inst.c
@@ -0,0 +1,748 @@
+/*
+ * TMS34010 GSP assembler - Instruction encoding
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "gsp_code.h"
+#include <string.h>
+
+struct inst {
+ char *opname;
+ u_int16_t opcode;
+ u_char class; /* instruction class + flags */
+ u_char optypes[4]; /* permissible operand classes */
+};
+
+/* Values for flags in class field */
+#define NOIMM16 0x80 /* can't have 16-bit immediate */
+#define K32 0x40 /* values 1..32 for K-type constant */
+#define IMMCOM 0x20 /* immediate value is complemented */
+#define IMMNEG 0x80 /* immediate value is negated */
+#define NODSJS 0x80 /* can't use 5-bit branch offset */
+#define DSHORT 0x40 /* must use 5-bit offset */
+
+#define CLASS 0x1F
+
+/* Values for class */
+#define NOP 0 /* no operands */
+#define ONEREG 1 /* reg */
+#define TWOREG 2 /* reg, reg */
+#define DYADIC 3 /* immediate or reg, reg */
+#define ADD (DYADIC|K32)
+#define SUB (DYADIC|IMMCOM|K32)
+#define CMP (DYADIC|IMMCOM)
+#define AND (DYADIC|NOIMM16|IMMCOM)
+#define OR (DYADIC|NOIMM16)
+#define IMMREG 4 /* immediate, reg */
+#define IMMREGC (IMMREG|IMMCOM)
+#define LIMREG (IMMREG|NOIMM16)
+#define LIMREGC (LIMREG|IMMCOM)
+#define KREG 5 /* short immediate, reg */
+#define K32REG (KREG|K32)
+#define SRA (KREG|IMMNEG)
+#define BTST (KREG|IMMCOM)
+#define CALL 6 /* reg or address */
+#define JUMP 7
+#define CLR 8 /* reg appears twice in encoding */
+#define DSJ 9
+#define DSJEQ (DSJ|NODSJS)
+#define DSJS (DSJ|DSHORT)
+#define EXGF 10
+#define SETF 11
+#define FILL 12
+#define LINE 13
+#define PIXBLT 14
+#define PIXT 15
+#define MMFM 16
+#define MOVB 17
+#define MOVE 18
+#define MOVEK (MOVE|K32)
+#define RETS 19
+#define PSEUDO 20
+
+/* Composite operand classes */
+#define EXREG (REG|EXPR)
+#define EAREG (REG|EA)
+#define EXAREG (REG|EXPR|EA)
+#define OPTOPRN 0x80 /* signals optional operand */
+#define SPEC (0x10|EXPR) /* field or length specifier */
+#define OPTREG (OPTOPRN|REG)
+#define OPTEXPR (OPTOPRN|EXPR)
+#define OPTSPEC (OPTOPRN|SPEC)
+#define OPTXREG (OPTOPRN|EXREG)
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
+/*
+ * N.B. This list must be sorted in order of opname.
+ */
+struct inst instructions[] = {
+ ".BLKB", BLKB, PSEUDO, {0, 0, 0, 0},
+ ".BLKL", BLKL, PSEUDO, {0, 0, 0, 0},
+ ".BLKW", BLKW, PSEUDO, {0, 0, 0, 0},
+#ifdef EQU
+ ".EQU", EQU, PSEUDO, {0, 0, 0, 0},
+#endif
+ ".INCLUDE", INCL, PSEUDO, {0, 0, 0, 0},
+ ".LONG",LONG, PSEUDO, {0, 0, 0, 0},
+ ".ORG", ORG, PSEUDO, {0, 0, 0, 0},
+ ".START",START, PSEUDO, {0, 0, 0, 0},
+ ".WORD",WORD, PSEUDO, {0, 0, 0, 0},
+ "ABS", 0x0380, ONEREG, {REG, 0, 0, 0},
+ "ADD", 0x4000, ADD, {EXREG, REG, OPTSPEC,0},
+ "ADDC", 0x4200, TWOREG, {REG, REG, 0, 0},
+ "ADDI", 0x0B20, IMMREG, {EXPR, REG, OPTSPEC,0},
+ "ADDK", 0x1000, K32REG, {EXPR, REG, 0, 0},
+ "ADDXY",0xE000, TWOREG, {REG, REG, 0, 0},
+ "AND", 0x5000, AND, {EXREG, REG, 0, 0},
+ "ANDI", 0x0B80, LIMREGC,{EXPR, REG, 0, 0},
+ "ANDN", 0x5200, OR, {EXREG, REG, 0, 0},
+ "ANDNI",0x0B80, LIMREG, {EXPR, REG, 0, 0},
+ "BTST", 0x1C00, BTST, {EXREG, REG, 0, 0},
+ "CALL", 0x0920, CALL, {EXREG, 0, 0, 0},
+ "CALLA",0x0D5F, CALL, {EXPR, 0, 0, 0},
+ "CALLR",0x0D3F, CALL, {EXPR, 0, 0, 0},
+ "CLR", 0x5600, CLR, {REG, 0, 0, 0},
+ "CLRC", 0x0320, NOP, {0, 0, 0, 0},
+ "CMP", 0x4800, CMP, {EXREG, REG, OPTSPEC,0},
+ "CMPI", 0x0B60, IMMREGC,{EXPR, REG, OPTSPEC,0},
+ "CMPXY",0xE400, TWOREG, {REG, REG, 0, 0},
+ "CPW", 0xE600, TWOREG, {REG, REG, 0, 0},
+ "CVXYL",0xE800, TWOREG, {REG, REG, 0, 0},
+ "DEC", 0x1420, ONEREG, {REG, 0, 0, 0},
+ "DINT", 0x0360, NOP, {0, 0, 0, 0},
+ "DIVS", 0x5800, TWOREG, {REG, REG, 0, 0},
+ "DIVU", 0x5A00, TWOREG, {REG, REG, 0, 0},
+ "DRAV", 0xF600, TWOREG, {REG, REG, 0, 0},
+ "DSJ", 0x0D80, DSJ, {REG, EXPR, 0, 0},
+ "DSJEQ",0x0DA0, DSJEQ, {REG, EXPR, 0, 0},
+ "DSJNE",0x0DC0, DSJEQ, {REG, EXPR, 0, 0},
+ "DSJS", 0x3800, DSJS, {REG, EXPR, 0, 0},
+ "EINT", 0x0D60, NOP, {0, 0, 0, 0},
+ "EMU", 0x0100, NOP, {0, 0, 0, 0},
+ "EXGF", 0xD500, EXGF, {REG, OPTSPEC,0, 0},
+ "EXGPC",0x0120, ONEREG, {REG, 0, 0, 0},
+ "FILL", 0x0FC0, FILL, {SPEC, 0, 0, 0},
+ "GETPC",0x0140, ONEREG, {REG, 0, 0, 0},
+ "GETST",0x0180, ONEREG, {REG, 0, 0, 0},
+ "INC", 0x1020, ONEREG, {REG, 0, 0, 0},
+ "JAB", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JAC", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JAEQ", 0xCA80, JUMP, {EXPR, 0, 0, 0},
+ "JAGE", 0xC580, JUMP, {EXPR, 0, 0, 0},
+ "JAGT", 0xC780, JUMP, {EXPR, 0, 0, 0},
+ "JAHI", 0xC380, JUMP, {EXPR, 0, 0, 0},
+ "JAHS", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JALE", 0xC680, JUMP, {EXPR, 0, 0, 0},
+ "JALO", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JALS", 0xC280, JUMP, {EXPR, 0, 0, 0},
+ "JALT", 0xC480, JUMP, {EXPR, 0, 0, 0},
+ "JAN", 0xCE80, JUMP, {EXPR, 0, 0, 0},
+ "JANB", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JANC", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JANE", 0xCB80, JUMP, {EXPR, 0, 0, 0},
+ "JANN", 0xCF80, JUMP, {EXPR, 0, 0, 0},
+ "JANV", 0xCD80, JUMP, {EXPR, 0, 0, 0},
+ "JANZ", 0xCB80, JUMP, {EXPR, 0, 0, 0},
+ "JAP", 0xC180, JUMP, {EXPR, 0, 0, 0},
+ "JAUC", 0xC080, JUMP, {EXPR, 0, 0, 0},
+ "JAV", 0xCC80, JUMP, {EXPR, 0, 0, 0},
+ "JAZ", 0xCA80, JUMP, {EXPR, 0, 0, 0},
+ "JRB", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRC", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JREQ", 0xCA00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRGE", 0xC500, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRGT", 0xC700, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRHI", 0xC300, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRHS", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLE", 0xC600, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLO", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLS", 0xC200, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLT", 0xC400, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRN", 0xCE00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNB", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNC", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNE", 0xCB00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNN", 0xCF00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNV", 0xCD00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNZ", 0xCB00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRP", 0xC100, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRUC", 0xC000, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRV", 0xCC00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRZ", 0xCA00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JUMP", 0x0160, JUMP, {EXREG, OPTSPEC,0, 0},
+ "LINE", 0xDF1A, LINE, {SPEC, 0, 0, 0},
+ "LMO", 0x6A00, TWOREG, {REG, REG, 0, 0},
+ "MMFM", 0x09A0, MMFM, {REG, OPTXREG,OPTREG, OPTREG},
+ "MMTM", 0x0980, MMFM, {REG, OPTXREG,OPTREG, OPTREG},
+ "MODS", 0x6C00, TWOREG, {REG, REG, 0, 0},
+ "MODU", 0x6E00, TWOREG, {REG, REG, 0, 0},
+ "MOVB", 0, MOVB, {EAREG, EAREG, 0, 0},
+ "MOVE", 0x4C00, MOVEK, {EXAREG,EAREG, OPTSPEC,0},
+ "MOVI", 0x09E0, IMMREG, {EXPR, REG, OPTSPEC,0},
+ "MOVK", 0x1800, K32REG, {EXPR, REG, 0, 0},
+ "MOVX", 0xEC00, TWOREG, {REG, REG, 0, 0},
+ "MOVY", 0xEE00, TWOREG, {REG, REG, 0, 0},
+ "MPYS", 0x5C00, TWOREG, {REG, REG, 0, 0},
+ "MPYU", 0x5E00, TWOREG, {REG, REG, 0, 0},
+ "NEG", 0x03A0, ONEREG, {REG, 0, 0, 0},
+ "NEGB", 0x03C0, ONEREG, {REG, 0, 0, 0},
+ "NOP", 0x0300, NOP, {0, 0, 0, 0},
+ "NOT", 0x03E0, ONEREG, {REG, 0, 0, 0},
+ "OR", 0x5400, OR, {EXREG, REG, 0, 0},
+ "ORI", 0x0BA0, LIMREG, {EXPR, REG, 0, 0},
+ "PIXBLT",0x0F00,PIXBLT, {SPEC, SPEC, 0, 0},
+ "PIXT", 0, PIXT, {EAREG, EAREG, 0, 0},
+ "POPST",0x01C0, NOP, {0, 0, 0, 0},
+ "PUSHST",0x01E0,NOP, {0, 0, 0, 0},
+ "PUTST",0x01A0, ONEREG, {REG, 0, 0, 0},
+ "RETI", 0x0940, NOP, {0, 0, 0, 0},
+ "RETS", 0x0960, RETS, {OPTEXPR,0, 0, 0},
+ "REV", 0x0020, ONEREG, {REG, 0, 0, 0},
+ "RL", 0x3000, KREG, {EXREG, REG, 0, 0},
+ "SETC", 0x0DE0, NOP, {0, 0, 0, 0},
+ "SETF", 0x0540, SETF, {EXPR, EXPR, OPTSPEC,0},
+ "SEXT", 0x0500, EXGF, {REG, OPTSPEC,0, 0},
+ "SLA", 0x2000, KREG, {EXREG, REG, 0, 0},
+ "SLL", 0x2400, KREG, {EXREG, REG, 0, 0},
+ "SRA", 0x2800, SRA, {EXREG, REG, 0, 0},
+ "SRL", 0x2C00, SRA, {EXREG, REG, 0, 0},
+ "SUB", 0x4400, SUB, {EXREG, REG, OPTSPEC,0},
+ "SUBB", 0x4600, TWOREG, {REG, REG, 0, 0},
+ "SUBI", 0x0D00, IMMREGC,{EXPR, REG, OPTSPEC,0},
+ "SUBK", 0x1400, K32REG, {EXPR, REG, 0, 0},
+ "SUBXY",0xE200, TWOREG, {REG, REG, 0, 0},
+ "TRAP", 0x0900, RETS, {EXPR, 0, 0, 0},
+ "XOR", 0x5600, OR, {EXREG, REG, 0, 0},
+ "XORI", 0x0BC0, LIMREG, {EXPR, REG, 0, 0},
+ "ZEXT", 0x0520, EXGF, {REG, OPTSPEC,0, 0},
+ NULL
+};
+
+
+void do_statement(char *opcode, operand operands);
+int encode_instr(struct inst *ip, operand ops,
+ int *spec, u_int16_t *iwords);
+
+void
+statement(char *opcode, operand operands)
+{
+ do_statement(opcode, operands);
+ free_operands(operands);
+}
+
+void
+do_statement(char *opcode, operand operands)
+{
+ register struct inst *ip;
+ register int i, nop, req;
+ register operand op;
+ int spec[3];
+ u_int16_t iwords[6];
+
+ ucasify(opcode);
+ i = 1;
+ for( ip = instructions; ip->opname != NULL; ++ip )
+ if( opcode[0] == ip->opname[0] ){
+ i = strcmp(opcode, ip->opname);
+ if( i <= 0 )
+ break;
+ }
+ if( i != 0 ){
+ perr("Unknown instruction code %s", opcode);
+ return;
+ }
+ if( ip->class == PSEUDO ){
+ pseudo(ip->opcode, operands);
+ return;
+ }
+
+ /* Check correspondence of operands with instruction requirements */
+ nop = 0;
+ spec[0] = spec[1] = spec[2] = 0;
+ for( op = operands; op != NULL; op = op->next ){
+ req = ip->optypes[MIN(nop, 3)];
+ if( req == 0 )
+ break;
+ if( (op->type & req) == 0 ){
+ perr("Inappropriate type for operand %d", nop+1);
+ return;
+ }
+ if( (req & ~OPTOPRN) == SPEC )
+ /* operand is a field/type/length specifier */
+ spec[nop] = specifier(op);
+ ++nop;
+ }
+ if( nop < 4 && ip->optypes[nop] != 0
+ && (ip->optypes[nop] & OPTOPRN) == 0 ){
+ perr("Insufficient operands");
+ return;
+ }
+ if( op != NULL )
+ perr("Extra operands ignored");
+
+ i = encode_instr(ip, operands, spec, iwords);
+
+ /* Pass 1 processing */
+ if( !pass2 ){
+ /* for pass 1, just work out the instruction size */
+/* printf("pc = %#x, size = %d\n", pc, i); */
+ pc += i << 4;
+ return;
+ }
+
+ /* Pass 2 processing */
+ if( i > 0 )
+ putcode(iwords, i);
+}
+
+char *specs[] = { "B", "L", "W", "XY", NULL };
+
+int
+specifier(operand op)
+{
+ register int i, k;
+ register char **sl;
+ register expr e;
+ char sp[4];
+
+ if( op->type != EXPR )
+ return '?';
+ e = op->op_u.value;
+ if( e->e_op == CONST ){
+ if( e->e_val == 0 || e->e_val == 1 )
+ return e->e_val + '0';
+ } else if( e->e_op == SYM ){
+ if( strlen(e->e_sym->name) > 2 )
+ return '?';
+ strcpy(sp, e->e_sym->name);
+ ucasify(sp);
+ for( sl = specs; *sl != NULL; ++sl )
+ if( strcmp(*sl, sp) == 0 )
+ return sp[0];
+ }
+ return '?';
+}
+
+int
+check_spec(int spec, char *valid, char *what)
+{
+ register char *p;
+
+ if( spec == 0 )
+ return 0;
+ p = strchr(valid, spec);
+ if( p == NULL ){
+ perr("Invalid %s specifier", what);
+ return 0;
+ }
+ return p - valid;
+}
+
+u_int16_t code_to_imm[] = {
+ 0x0B20, /* ADDI */
+ 0,
+ 0x0D00, /* SUBI */
+ 0,
+ 0x0B60, /* CMPI */
+ 0,
+ 0x09E0, /* MOVI */
+ 0,
+ 0x0B80, /* ANDI */
+ 0x0B80, /* ANDNI */
+ 0x0BA0, /* ORI */
+ 0x0BC0, /* XORI */
+};
+
+/* Opcodes for MOVE instruction */
+u_int16_t move_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0x4C00, 0x8400, 0x9400, 0xA400, 0, 0xB400, 0x05A0, /* R */
+ 0x8000, 0x8800, 0, 0, 0, 0, 0, /* *R */
+ 0x9000, 0, 0x9800, 0, 0, 0xD000, 0xD400, /* *R+ */
+ 0xA000, 0, 0, 0xA800, 0, 0, 0, /* *-R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R.XY */
+ 0xB000, 0, 0, 0, 0, 0xB800, 0, /* *R(n) */
+ 0x0580, 0, 0, 0, 0, 0, 0x05C0, /* @adr */
+};
+
+/* Opcodes for MOVB instruction */
+u_int16_t movb_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0, 0x8E00, 0, 0, 0, 0xAE00, 0x07E0, /* R */
+ 0x8C00, 0x9C00, 0, 0, 0, 0, 0, /* *R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R+ */
+ 0, 0, 0, 0, 0, 0, 0, /* *-R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R.XY */
+ 0xAC00, 0, 0, 0, 0, 0xBC00, 0, /* *R(n) */
+ 0x05E0, 0, 0, 0, 0, 0, 0x0340, /* @adr */
+};
+
+/* Opcodes for PIXT instruction */
+u_int16_t pixt_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0, 0xFA00, 0, 0, 0xF200, 0, 0, /* R */
+ 0xF800, 0xFC00, 0, 0, 0, 0, 0, /* *R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R+ */
+ 0, 0, 0, 0, 0, 0, 0, /* *-R */
+ 0xF000, 0, 0, 0, 0xF400, 0, 0, /* *R.XY */
+ 0, 0, 0, 0, 0, 0, 0, /* *R(n) */
+ 0, 0, 0, 0, 0, 0, 0, /* @adr */
+};
+
+#define USES_REG(op) ((op)->type == REG \
+ || (op)->type == EA && (op)->mode != M_ABSOLUTE)
+#define USES_EXPR(op) ((op)->type == EXPR \
+ || (op)->type == EA && (op)->mode >= M_INDEX)
+
+int
+encode_instr(struct inst *ip, operand ops, int *spec, u_int16_t *iwords)
+{
+ register int rs, rd;
+ int opc, nw, class, flags, ms, md, off;
+ int mask, file, bit, i;
+ register operand op0, op1;
+ unsigned line[2];
+ int32_t val[2];
+
+ opc = ip->opcode;
+ nw = 1;
+ op0 = ops;
+ if( op0 != NULL ){
+ if( spec[0] == 0 && USES_EXPR(op0) )
+ eval_expr(op0->op_u.value, &val[0], &line[0]);
+ op1 = ops->next;
+ if( op1 != NULL && spec[1] == 0 && USES_EXPR(op1) )
+ eval_expr(op1->op_u.value, &val[1], &line[1]);
+ } else
+ op1 = NULL;
+ class = ip->class & CLASS;
+ flags = ip->class & ~CLASS;
+ if( class == MOVE && op1->type == REG ){
+ if (op0->type == REG ){
+ class = DYADIC;
+ if( (op0->reg_no & op1->reg_no & REGFILE) == 0 ){
+ opc += 0x0200;
+ op1->reg_no ^= A0^B0;
+ }
+ } else if ( op0->type == EXPR )
+ class = DYADIC;
+ }
+ if( class == DYADIC ){
+ /* turn it into TWOREG, IMMREG or KREG */
+ if( op0->type == REG ){
+ class = TWOREG;
+ } else if( (flags & K32) != 0 && line[0] <= lineno
+ && spec[2] == 0
+ && 0 < val[0] && val[0] <= 32 ){
+ /* use 5-bit immediate */
+ class = KREG;
+ opc -= 0x3000;
+ if( opc == 0x1C00 )
+ opc = 0x1800;
+ flags &= ~IMMCOM;
+ } else {
+ class = IMMREG;
+ opc = code_to_imm[(opc - 0x4000) >> 9];
+ }
+ if( (class == TWOREG || class == KREG)
+ && spec[2] != 0 && op1->next->next == NULL )
+ perr("Extra operands ignored");
+ } else if( class == KREG ){
+ if( op0->type == REG ){
+ class = TWOREG;
+ if( opc < 0x2000 )
+ opc = 0x4A00; /* BTST */
+ else
+ opc = (opc >> 1) + 0x5000;
+ }
+ }
+
+ if( op0 != NULL )
+ rs = op0->reg_no;
+ if( op1 != NULL ){
+ rd = op1->reg_no;
+ if( USES_REG(op0) && USES_REG(op1) ){
+ if( (rs & rd & REGFILE) == 0 )
+ perr("Registers must be in the same register file");
+ /* force SP to the file of the other operand */
+ if( rs == SP )
+ rs |= rd;
+ if( rd == SP )
+ rd |= rs;
+ }
+ }
+
+ switch( class ){
+ case NOP: /* no operands */
+ break;
+ case ONEREG: /* reg */
+ opc |= rs & 0x1F;
+ break;
+ case TWOREG: /* reg, reg */
+ opc |= ((rs & 0x0F) << 5) | (rd & 0x1F);
+ break;
+ case IMMREG: /* immediate, reg */
+ opc |= rd & 0x1F;
+ if( (flags & IMMCOM) != 0 )
+ val[0] = ~ val[0];
+ i = check_spec(spec[2], " WL", "length");
+ if( i == 1
+ || i == 0 && (flags & NOIMM16) == 0 && line[0] <= lineno
+ && (int16_t)val[0] == val[0] ){
+ if( (int16_t) val[0] != val[0] )
+ perr("Value truncated to 16 bits");
+ opc -= 0x20;
+ if( opc == 0x0CE0 ) /* SUBI,W */
+ opc = 0x0BE0;
+ nw = 2;
+ } else {
+ iwords[2] = (val[0] >> 16);
+ nw = 3;
+ }
+ iwords[1] = val[0];
+ break;
+ case KREG: /* short immediate, reg */
+ opc |= rd & 0x1F;
+ if( val[0] < 0 || (flags & K32) == 0 && val[0] > 31
+ || (flags & K32) != 0 && val[0] <= 0 || val[0] > 32 )
+ perr("5-bit constant out of range");
+ rs = val[0];
+ if( (flags & IMMCOM) != 0 )
+ rs = ~rs;
+ else if( (flags & IMMNEG) != 0 )
+ rs = -rs;
+ opc |= (rs & 0x1F) << 5;
+ break;
+ case CALL: /* reg or address */
+ if( op0->type == REG ){
+ opc |= rs & 0x1F;
+ break;
+ }
+ off = (int)(val[0] - pc - 0x20) >> 4;
+ if( opc == 0x0920 ){ /* CALL */
+ if( line[0] <= lineno && (int16_t) off == off )
+ opc = 0x0D3F; /* CALLR */
+ else
+ opc = 0x0D5F; /* CALLA */
+ }
+ if( opc == 0x0D3F ){ /* CALLR */
+ if( (int16_t) off != off )
+ perr("Displacement too large");
+ iwords[1] = off;
+ nw = 2;
+ } else { /* CALLA */
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ nw = 3;
+ }
+ break;
+ case JUMP:
+ if( op0->type == REG ){
+ opc |= rs & 0x1F;
+ break;
+ }
+ off = (int)(val[0] - pc - 0x10) >> 4;
+ if( (opc & 0x80) != 0 ) /* JAcc */
+ i = 2;
+ else
+ i = check_spec(spec[1], " WL", "length");
+ if( opc == 0x0160 ){ /* JUMP */
+ opc = 0xC000; /* JRUC */
+ if( i == 0 )
+ i = 1; /* ,W is the default for JUMP */
+ }
+ switch( i ){
+ case 2: /* JAcc */
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ opc |= 0x80;
+ nw = 3;
+ break;
+ case 1:
+ --off;
+ if( (int16_t) off != off )
+ perr("Displacement too large (word)");
+ iwords[1] = off;
+ nw = 2;
+ break;
+ default:
+ if( off == 0 || off < -127 || off > 127 )
+ perr("Short displacement too large or 0");
+ opc |= off & 0xFF;
+ }
+ break;
+ case CLR: /* reg appears twice in encoding */
+ opc |= (rs & 0x1F) | ((rs & 0x0F) << 5);
+ break;
+ case DSJ:
+ off = (int)(val[1] - pc - 0x10) >> 4;
+ if( flags == 0 ){ /* DSJ */
+ if( off != 0 && off >= -31 && off <= 31 ){
+ flags = DSHORT;
+ opc = 0x3800; /* DSJS */
+ }
+ }
+ if( flags == DSHORT ){
+ if( off == 0 || off < -31 || off > 31 )
+ perr("DSJS displacement too large");
+ if( off > 0 )
+ opc |= (off & 0x1F) << 5;
+ else
+ opc |= 0x400 | ((-off & 0x1F) << 5);
+ } else {
+ --off;
+ if( (int16_t) off != off )
+ perr("Displacement too large (word)");
+ iwords[1] = off;
+ nw = 2;
+ }
+ opc |= rs & 0x1F;
+ break;
+ case EXGF:
+ opc |= rs & 0x1F;
+ opc |= check_spec(spec[1], "01", "field") << 9;
+ break;
+ case SETF:
+ rs = val[0];
+ rd = val[1];
+ if( rs <= 0 || rs > 32 )
+ perr("Field size must be 1..32");
+ if( rd != 0 && rd != 1 )
+ perr("Field extension must be 0 or 1");
+ opc |= (rs & 0x1F) | ((rd & 1) << 5);
+ opc |= check_spec(spec[2], "01", "field") << 9;
+ break;
+ case FILL:
+ opc |= check_spec(spec[0], "LX", "array type") << 5;
+ break;
+ case LINE:
+ opc |= check_spec(spec[0], "01", "algorithm") << 7;
+ break;
+ case PIXBLT:
+ rs = check_spec(spec[0], "LXB", "source array type");
+ rd = check_spec(spec[1], "LX", "destination array type");
+ opc |= (rs << 6) | (rd << 5);
+ break;
+ case MMFM:
+ opc |= rs & 0xF;
+ file = rs & REGFILE;
+ if( op1 == NULL )
+ mask = 0xFFFF;
+ else if( op1->type == REG ){
+ file &= rd;
+ mask = 0;
+ for( ; op1 != NULL; op1 = op1->next ){
+ rd = op1->reg_no;
+ bit = 1 << (~rd & 0xF);
+ if( file != 0 && (file &= rd) == 0 )
+ perr("Registers must all be in the same file");
+ if( file != 0 && (mask & bit) != 0 )
+ perr("Register name repeated");
+ mask |= bit;
+ }
+ } else {
+ if( val[1] < 0 || val[1] > 0xFFFFL )
+ perr("Mask value out of range");
+ mask = val[1];
+ if( op1->next != NULL )
+ perr("Extra operands ignored");
+ }
+ if( (file & A0 & REGFILE) == 0 )
+ opc |= 0x10;
+ if( (opc & 0x20) != 0 ){
+ /* mask reversed for MMFM */
+ rs = 0;
+ for( bit = 16; bit != 0; --bit ){
+ rs <<= 1;
+ rs |= mask & 1;
+ mask >>= 1;
+ }
+ mask = rs;
+ }
+ iwords[1] = mask;
+ nw = 2;
+ break;
+ case PIXT:
+ case MOVB:
+ case MOVE:
+ ms = op0->type == REG? M_REG: op0->mode;
+ md = op1->type == REG? M_REG: op1->mode;
+ opc = class == MOVE? move_opc[md][ms]:
+ class == MOVB? movb_opc[md][ms]: pixt_opc[md][ms];
+ if( opc == 0 ){
+ perr("Illegal combination of addressing modes");
+ nw = 0;
+ break;
+ }
+ if( ms == M_INDEX ){
+ if( (int16_t) val[0] != val[0] )
+ perr("Source displacement too large");
+ iwords[1] = val[0];
+ nw = 2;
+ } else if( ms == M_ABSOLUTE ){
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ nw = 3;
+ rs = 0;
+ }
+ if( md == M_INDEX ){
+ if( (int16_t) val[1] != val[1] )
+ perr("Destination displacement too large");
+ iwords[nw] = val[1];
+ ++nw;
+ } else if( md == M_ABSOLUTE ){
+ iwords[nw] = val[1];
+ iwords[nw+1] = val[1] >> 16;
+ nw += 2;
+ rd = rs;
+ rs = 0;
+ }
+ opc |= (rd & 0x1F) | ((rs & 0xF) << 5);
+ opc |= check_spec(spec[2], "01", "field") << 9;
+ break;
+ case RETS:
+ if( op0 == NULL )
+ val[0] = 0;
+ else if( val[0] < 0 || val[0] > 31 )
+ perr("%s out of range",
+ (opc > 0x900? "Pop count": "Trap number"));
+ opc |= val[0] & 0x1F;
+ break;
+ default:
+ perr("BUG: unknown instruction class %d\n", class);
+ }
+ iwords[0] = opc;
+ return nw;
+}
+
diff --git a/usr.sbin/gspa/gspa/gsp_lex.c b/usr.sbin/gspa/gspa/gsp_lex.c
new file mode 100644
index 00000000000..6327f281fdc
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_lex.c
@@ -0,0 +1,183 @@
+/*
+ * Lexical analyser for GSP assembler
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include "gsp_ass.h"
+#include "y.tab.h"
+#include <ctype.h>
+#include <stdlib.h>
+/*#include <string.h>*/
+
+char *lineptr;
+
+char idents[MAXLINE];
+char *idptr;
+
+extern YYSTYPE yylval;
+
+void ucasify(char *);
+int str_match(char *, char **);
+
+char *regnames[] = {
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "A8", "A9", "A10", "A11", "A12", "A13", "A14", "SP",
+ "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
+ "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15",
+ NULL
+};
+
+short regnumbers[] = {
+ A0+0, A0+1, A0+2, A0+3, A0+4, A0+5, A0+6, A0+7,
+ A0+8, A0+9, A0+10, A0+11, A0+12, A0+13, A0+14, SP,
+ B0+0, B0+1, B0+2, B0+3, B0+4, B0+5, B0+6, B0+7,
+ B0+8, B0+9, B0+10, B0+11, B0+12, B0+13, B0+14, B0+15,
+};
+
+void
+lex_init(char *line)
+{
+ lineptr = line;
+ idptr = idents;
+}
+
+int
+yylex()
+{
+ register int c, tok, x, len;
+ register char *lp, *ip;
+ char *end;
+
+ lp = lineptr;
+ c = *lp;
+ while( c == ' ' || c == '\t' )
+ c = *++lp;
+ if( isalpha(c) || c == '_' || c == '.' ){
+ /* an identifier or register name */
+ ip = lp;
+ do {
+ c = *++lp;
+ } while( isalnum(c) || c == '_' );
+ len = lp - ip;
+ if( len == 1 && *ip == '.' )
+ tok = '.';
+ else {
+ strncpy(idptr, ip, len);
+ idptr[len] = 0;
+ ucasify(idptr);
+ x = str_match(idptr, regnames);
+ if( x == -1 ){
+ strncpy(idptr, ip, len);
+ yylval.y_id = idptr;
+ idptr += len + 1;
+ tok = ID;
+ } else {
+ yylval.y_int = regnumbers[x];
+ tok = REGISTER;
+ }
+ }
+ } else if( c == '$' ){
+ /* a hex number */
+ ++lp;
+ yylval.y_int = strtoul(lp, &end, 16);
+ if( end == lp )
+ perr("Bad number syntax");
+ else
+ lp = end;
+ tok = NUMBER;
+ } else if( isdigit(c) ){
+ yylval.y_int = strtoul(lp, &end, 0);
+ ip = lp;
+ lp = end;
+ c = *lp;
+ if( (c == 'f' || c == 'F' || c == 'b' || c == 'B')
+ && !(isalnum(lp[1]) || lp[1] == '_') ){
+ /* reference to numeric label */
+ c = toupper(c);
+ sprintf(idptr, "%d%c", yylval.y_int, c);
+ yylval.y_id = idptr;
+ idptr += strlen(idptr) + 1;
+ ++lp;
+ tok = ID;
+ } else
+ tok = NUMBER;
+ } else if( c == '\n' ){
+ tok = 0; /* eof */
+ } else if( c == ';' ){
+ /* comment - skip to end of line */
+ while( *++lp != 0 )
+ ;
+ tok = 0;
+ } else if( c == '"' ){
+ /* string */
+ yylval.y_id = idptr;
+ while( (c = *++lp) != '"' && c != '\n' && c != 0 )
+ *idptr++ = c;
+ *idptr++ = 0;
+ if( c != '"' )
+ perr("Unterminated string");
+ else
+ ++lp;
+ tok = STRING;
+ } else if( c == '<' && lp[1] == '<' ){
+ lp += 2;
+ tok = LEFT_SHIFT;
+ } else if( c == '>' && lp[1] == '>' ){
+ lp += 2;
+ tok = RIGHT_SHIFT;
+ } else {
+ if( c != 0 )
+ ++lp;
+ tok = c;
+ }
+ lineptr = lp;
+ return tok;
+}
+
+void
+ucasify(register char *p)
+{
+ register int c;
+
+ for( ; (c = *p) != 0; p++ )
+ if( islower(c) )
+ *p = toupper(c);
+}
+
+int
+str_match(register char *id, char **names)
+{
+ register char **np;
+
+ for( np = names; *np != NULL; ++np )
+ if( strcmp(id, *np) == 0 )
+ return np - names;
+ return -1;
+}
diff --git a/usr.sbin/gspa/gspa/gsp_out.c b/usr.sbin/gspa/gspa/gsp_out.c
new file mode 100644
index 00000000000..4dcf7b39270
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_out.c
@@ -0,0 +1,182 @@
+/*
+ * GSP assembler - binary & listing output
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include "gsp_ass.h"
+
+u_int16_t codes[5];
+unsigned ncode;
+unsigned code_idx;
+short show_pc;
+short show_val;
+int32_t val_to_show;
+extern unsigned line_pc;
+
+unsigned obj_addr = 0;
+
+extern FILE *objfile, *listfile;
+extern char line[];
+
+struct error {
+ struct error *next;
+ char string[1];
+};
+
+struct error *error_list, *error_last;
+
+void put1code(u_int16_t);
+
+void
+putcode(u_int16_t *v, int n)
+{
+ for( ; n > 0; --n )
+ put1code(*v++);
+}
+
+void
+put1code(u_int16_t v)
+{
+ if( code_idx >= 3 )
+ listing_line();
+ codes[code_idx] = v;
+ if( objfile != NULL ){
+ if( pc != obj_addr ){
+ /* expect this only when ncode == 0 */
+ if( ncode % 8 != 0 )
+ fprintf(objfile, "\n");
+ fprintf(objfile, "@%x\n", pc);
+ obj_addr = pc;
+ } else {
+ if( ncode % 8 != 0 )
+ fprintf(objfile, " ");
+ }
+ fprintf(objfile, "%.4X", v & 0xFFFF);
+ obj_addr += 0x10;
+ if( ncode % 8 == 7 )
+ fprintf(objfile, "\n");
+ }
+ ++ncode;
+ ++code_idx;
+ pc += 0x10;
+ show_pc = TRUE;
+}
+
+start_at(int32_t val)
+{
+ if( objfile != NULL )
+ fprintf(objfile, ":%.lX\n", val);
+}
+
+do_list_pc()
+{
+ if( pass2 )
+ show_pc = TRUE;
+}
+
+do_show_val(int32_t v)
+{
+ if( ncode == 0 ){
+ val_to_show = v;
+ show_val = TRUE;
+ show_pc = FALSE;
+ }
+}
+
+list_error(char *string)
+{
+ struct error *p;
+ int l;
+
+ if( listfile == NULL )
+ return;
+ l = strlen(string);
+ p = (struct error *) alloc(sizeof(struct error) + l);
+ strcpy(p->string, string);
+ p->next = NULL;
+ if( error_list == NULL )
+ error_list = p;
+ else
+ error_last->next = p;
+ error_last = p;
+}
+
+show_errors()
+{
+ struct error *p, *q;
+
+ for( p = error_list; p != NULL; p = q ){
+ if( listfile != NULL )
+ fprintf(listfile, "\t\t\t%s\n", p->string);
+ q = p->next;
+ free(p);
+ }
+ error_list = error_last = NULL;
+}
+
+listing()
+{
+ if( objfile != NULL && ncode % 8 != 0 )
+ fprintf(objfile, "\n");
+ listing_line();
+ show_errors();
+ ncode = 0;
+ show_pc = FALSE;
+}
+
+listing_line()
+{
+ register int i;
+
+ if( listfile == NULL ){
+ code_idx = 0;
+ return;
+ }
+ if( show_pc )
+ fprintf(listfile, "%.8X", line_pc);
+ else
+ fprintf(listfile, " ");
+ if( show_val ){
+ fprintf(listfile, " %.8X", val_to_show);
+ i = 2;
+ } else {
+ for( i = 0; i < code_idx; ++i )
+ fprintf(listfile, " %.4X", codes[i]);
+ }
+ if( ncode <= 3 ){
+ for( ; i < 3; ++i )
+ fprintf(listfile, " ");
+ fprintf(listfile, " %s", line);
+ } else
+ fprintf(listfile, "\n");
+ line_pc += code_idx << 4;
+ code_idx = 0;
+ show_val = FALSE;
+}
diff --git a/usr.sbin/gspa/gspa/gsp_pseu.c b/usr.sbin/gspa/gspa/gsp_pseu.c
new file mode 100644
index 00000000000..2c80639374a
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_pseu.c
@@ -0,0 +1,148 @@
+/*
+ * GSP assembler - assembler directives
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "gsp_code.h"
+
+extern unsigned highest_pc, line_pc;
+
+void
+pseudo(int code, operand ops)
+{
+ operand o;
+ int32_t val;
+ unsigned ln;
+ u_int16_t words[2];
+
+ switch( code ){
+ case ORG:
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ if( !eval_expr(ops->op_u.value, &val, &ln) ){
+ p1err("ORG operand must be defined on pass 1");
+ break;
+ }
+ if( pc > highest_pc )
+ highest_pc = pc;
+ line_pc = pc = val;
+ do_list_pc();
+ break;
+#ifdef EQU
+ case EQU:
+ if( label == NULL ){
+ perr("Label required");
+ break;
+ }
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ do_asg(label, ops->op_u.value, 0);
+ break;
+#endif /* EQU */
+ case WORD:
+ case LONG:
+ if( ops == NULL )
+ break;
+ for( o = ops; o != NULL; o = o->next ){
+ if( o->type != EXPR ){
+ perr("Inappropriate operand");
+ continue;
+ }
+ if( pass2 ){
+ eval_expr(o->op_u.value, &val, &ln);
+ words[0] = val;
+ if( code == LONG ){
+ words[1] = val >> 16;
+ putcode(words, 2);
+ } else {
+ if( val < -32768 || val > 65535 )
+ perr("Word value too large");
+ putcode(words, 1);
+ }
+ } else
+ pc += code == LONG? 0x20: 0x10;
+ }
+ return;
+ case INCL:
+ if( ops == NULL )
+ break;
+ if( ops->type != STR_OPN ){
+ perr("Require filename string");
+ break;
+ }
+ push_input(ops->op_u.string);
+ break;
+ case BLKB:
+ case BLKW:
+ case BLKL:
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ if( !eval_expr(ops->op_u.value, &val, &ln) ){
+ p1err(".BLK%c operand must be defined on pass 1",
+ code==BLKB? 'B': code==BLKW? 'W': 'L');
+ break;
+ }
+ val *= 8;
+ if( code == BLKB )
+ val = (val + 8) & ~15; /* round to word */
+ else
+ val *= (code==BLKW? 2: 4);
+ pc += val;
+ do_list_pc();
+ break;
+ case START:
+ if( !pass2 || ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ eval_expr(ops->op_u.value, &val, &ln);
+ start_at(val);
+ do_show_val(val);
+ break;
+ }
+ if( ops == NULL )
+ perr("Insufficient operands");
+ else if( ops->next != NULL )
+ perr("Extra operands ignored");
+}
diff --git a/usr.sbin/gspa/gspa/gsp_sym.c b/usr.sbin/gspa/gspa/gsp_sym.c
new file mode 100644
index 00000000000..742348acb0e
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_sym.c
@@ -0,0 +1,192 @@
+/*
+ * GSP assembler - symbol table
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+
+#define NHASH 64 /* must be power of 2 */
+
+symbol symbol_hash[NHASH];
+
+symbol
+lookup(char *id, bool makeit)
+{
+ register symbol ptr, p, *pp;
+ register int h;
+ register char *ip;
+
+ h = 0;
+ for( ip = id; *ip != 0; )
+ h = (h << 1) + *ip++;
+ h &= NHASH-1;
+ for( pp = &symbol_hash[h]; (p = *pp) != NULL; pp = &p->next )
+ if( (h = strcmp(id, p->name)) == 0 )
+ return p;
+ else if( h < 0 )
+ break;
+ if( !makeit )
+ return NULL;
+ ptr = (symbol) alloc (sizeof(struct symbol) + strlen(id));
+ ptr->ndefn = 0;
+ ptr->flags = 0;
+ ptr->value = 0;
+ ptr->lineno = NOT_YET;
+ strcpy(ptr->name, id);
+ *pp = ptr;
+ ptr->next = p;
+ ptr->nlab = NULL;
+ return ptr;
+}
+
+void
+define_sym(char *id, unsigned val, unsigned lineno, int flags)
+{
+ register symbol ptr;
+
+ ptr = lookup(id, TRUE);
+ if( (ptr->flags & SET_LABEL) == 0 ){
+ if( ptr->ndefn >= 2 ){
+ perr("Multiply defined label %s", id);
+ if( (flags & SET_LABEL) != 0 )
+ return;
+ } else if( pass2 && ptr->value != val )
+ perr("Phase error on label %s (%#x -> %#x)",
+ id, ptr->value, val);
+ }
+ ptr->flags = flags;
+ ptr->ndefn += 1;
+ ptr->value = val;
+ ptr->lineno = lineno;
+}
+
+void
+set_label(char *id)
+{
+ if( id != NULL ){
+ define_sym(id, pc, lineno, DEFINED);
+ if( pass2 )
+ do_list_pc();
+ }
+}
+
+void
+do_asg(char *name, expr value, int flags)
+{
+ int32_t val;
+ unsigned line;
+
+ if( eval_expr(value, &val, &line) )
+ flags |= DEFINED;
+ if( line < lineno )
+ line = lineno;
+ define_sym(name, val, line, flags);
+ if( pass2 )
+ do_show_val(val);
+}
+
+void
+set_numeric_label(int lnum)
+{
+ register symbol bp, fp;
+ register struct numlab *nl;
+ char id[32];
+
+ /* define the backward reference symbol */
+ sprintf(id, "%dB", lnum);
+ bp = lookup(id, TRUE);
+ bp->flags = NUMERIC_LABEL | DEFINED;
+ bp->value = pc;
+ bp->lineno = lineno;
+
+ /* look up the forward reference symbol */
+ id[strlen(id) - 1] = 'F';
+ fp = lookup(id, TRUE);
+
+ if( !pass2 ){
+ /* Record a new numeric label and link it into the
+ chain. fp->nlab points to the head of the chain,
+ bp->nlab points to the tail. */
+ new(nl);
+ nl->value = pc;
+ nl->lineno = lineno;
+ nl->next = NULL;
+ if( bp->nlab == NULL )
+ fp->nlab = nl;
+ else
+ bp->nlab->next = nl;
+ bp->nlab = nl;
+ fp->flags = NUMERIC_LABEL;
+ } else {
+ /* Advance to the next numeric label entry in the chain
+ and update the value of the forward reference symbol. */
+ if( pc != fp->value )
+ perr("Phase error on numeric label %d (%#x -> %#x)",
+ lnum, fp->value, pc);
+ nl = fp->nlab;
+ nl = nl->next;
+ if( nl == NULL ){
+ /* no more labels of this number */
+ /* forward references are now undefined */
+ fp->flags &= ~DEFINED;
+ fp->lineno = NOT_YET;
+ fp->value = 0;
+ } else {
+ fp->lineno = nl->lineno;
+ fp->value = nl->value;
+ fp->nlab = nl;
+ }
+ do_list_pc();
+ }
+}
+
+/* At the beginning of pass 2, reset all of the numeric labels.
+ Backward references become undefined, forward references are defined
+ by the first instance of the label. */
+void
+reset_numeric_labels()
+{
+ register symbol p;
+ register struct numlab *nl;
+ register int h;
+
+ for( h = 0; h < NHASH; ++h )
+ for( p = symbol_hash[h]; p != NULL; p = p->next )
+ if( (p->flags & NUMERIC_LABEL) != 0 )
+ if( (p->flags & DEFINED) != 0 ){
+ /* a backward reference */
+ p->flags &= ~DEFINED;
+ } else {
+ /* a forward reference */
+ p->flags |= DEFINED;
+ nl = p->nlab;
+ p->value = nl->value;
+ p->lineno = nl->lineno;
+ }
+}
diff --git a/usr.sbin/gspa/gspa/gspa.c b/usr.sbin/gspa/gspa/gspa.c
new file mode 100644
index 00000000000..49c891175b0
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gspa.c
@@ -0,0 +1,273 @@
+/*
+ * GSP assembler main program
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * 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 Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+#include "gsp_ass.h"
+#include "y.tab.h"
+
+#define YYDEBUG_VALUE 0
+
+extern YYSTYPE yylval;
+int err_count;
+
+char line[MAXLINE];
+int lineno;
+
+extern int yydebug;
+short pass2;
+
+unsigned pc;
+unsigned highest_pc;
+unsigned line_pc;
+
+FILE *infile;
+FILE *current_infile;
+FILE *objfile;
+FILE *listfile;
+
+char in_name[PATH_MAX + 1];
+
+struct input {
+ FILE *fp;
+ struct input *next;
+ int lineno;
+ char name[128];
+} *pending_input;
+
+jmp_buf synerrjmp;
+
+main(int argc, char **argv)
+{
+ char *hex_name, *list_name;
+ short in_given, hex_given, list_given;
+ int i, v;
+ int c;
+ char *p;
+
+ hex_name = list_name = 0;
+
+ /* parse options */
+ while ((c = getopt(argc, argv, "o:l:")) != EOF) {
+ switch (c) {
+ case 'o':
+ if (hex_name)
+ usage();
+ hex_name = optarg;
+ break;
+ case 'l':
+ if (list_name)
+ usage();
+ list_name = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* get source file */
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ infile = stdin;
+ strcpy(in_name, "<stdin>");
+ } else if (argc == 1) {
+ strncpy(in_name, *argv, PATH_MAX);
+ in_name[PATH_MAX] = 0;
+ if ((infile = fopen(in_name, "r")) == NULL)
+ err(1, "fopen");
+ } else
+ usage();
+
+ /* Pass 1 */
+ pending_input = NULL;
+ current_infile = infile;
+
+ yydebug = YYDEBUG_VALUE;
+ pass2 = 0;
+ pc = 0;
+ lineno = 0;
+ while( get_line(line, MAXLINE) ){
+ if( !setjmp(synerrjmp) ){
+ lex_init(line);
+ yyparse();
+ }
+ }
+ if( err_count > 0 )
+ exit(1);
+
+ /* Open output files */
+ if (hex_name == 0)
+ objfile = stdout;
+ else if ((objfile = fopen(hex_name, "w")) == NULL)
+ err(1, "fopen");
+ if (list_name)
+ if ((listfile = fopen(list_name, "w")) == NULL)
+ err(1, "fopen");
+
+ /* Pass 2 */
+ pass2 = 1;
+ rewind(infile);
+ current_infile = infile;
+ pc = 0;
+ lineno = 0;
+ reset_numeric_labels();
+ while( get_line(line, MAXLINE) ){
+ line_pc = pc;
+ if( !setjmp(synerrjmp) ){
+ lex_init(line);
+ yyparse();
+ }
+ listing();
+ }
+
+ exit(err_count != 0);
+}
+
+setext(char *out, const char *in, const char *ext)
+{
+ const char *p;
+
+ p = strrchr(in, '.');
+ if( p != NULL ){
+ memcpy(out, in, p - in);
+ strcpy(out + (p - in), ext);
+ } else {
+ strcpy(out, in);
+ strcat(out, ext);
+ }
+}
+
+push_input(char *fn)
+{
+ FILE *f;
+ struct input *p;
+
+ f = fopen(fn, "r");
+ if( f == NULL ){
+ p1err("Can't open input file %s", fn);
+ return;
+ }
+ new(p);
+ p->fp = current_infile;
+ p->lineno = lineno;
+ strcpy(p->name, in_name);
+ p->next = pending_input;
+ current_infile = f;
+ lineno = 1;
+ strcpy(in_name, fn);
+ pending_input = p;
+}
+
+int
+get_line(char *lp, int maxlen)
+{
+ struct input *p;
+
+ while( fgets(lp, maxlen, current_infile) == NULL ){
+ if( (p = pending_input) == NULL )
+ return 0;
+ /* pop the input stack */
+ fclose(current_infile);
+ current_infile = p->fp;
+ strcpy(in_name, p->name);
+ lineno = p->lineno;
+ pending_input = p->next;
+ free(p);
+ }
+ ++lineno;
+ return 1;
+}
+
+void
+perr(char *fmt, ...)
+{
+ va_list ap;
+ char error_string[256];
+
+ if( !pass2 )
+ return;
+ fprintf(stderr, "Error in line %d: ", lineno);
+ va_start(ap, fmt);
+ vsprintf(error_string, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "%s\n", error_string);
+ list_error(error_string);
+ ++err_count;
+}
+
+void
+p1err(char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "Pass 1 error in line %d: ", lineno);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ ++err_count;
+}
+
+void
+yyerror(char *err)
+{
+ extern char *lineptr;
+
+ perr(err);
+ longjmp(synerrjmp, 1);
+}
+
+char *
+alloc(size_t nbytes)
+{
+ register char *p;
+
+ if( (p = malloc(nbytes)) == NULL ){
+ fprintf(stderr, "Insufficient memory at line %d\n", lineno);
+ exit(1);
+ }
+ return p;
+}
+
+usage()
+{
+ fprintf(stderr,
+ "Usage: gspa [infile] [+o|-o hex_file] [+l|-l list_file]\n");
+ exit(1);
+}
diff --git a/usr.sbin/gspa/gspahextoc/Makefile b/usr.sbin/gspa/gspahextoc/Makefile
new file mode 100644
index 00000000000..f0b26756dde
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/Makefile
@@ -0,0 +1,6 @@
+PROG= gspahextoc
+SRCS= gspahextoc.l
+NOMAN= noman
+LDADD= -ll
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gspa/gspahextoc/README b/usr.sbin/gspa/gspahextoc/README
new file mode 100644
index 00000000000..27077e7915f
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/README
@@ -0,0 +1,19 @@
+This is a small utility which is used to convert the hex output of Paul
+Mackerras' gspa to an initialized array of unsigned shorts.
+
+Input format:
+
+:hex -> start address
+@hex -> new load address
+hex -> load @load address & autoincrement
+
+Output format:
+
+Load blocks start with 16 bit count of the data without address, then
+high 16 bits of load address, then low 16 bits of load address, followed by
+count words of data. This sequence is repeated until count == 0.
+
+The start address is converted to two load blocks which set the
+NMI and the RESET vector.
+
+ Ignatios Souvatzis
diff --git a/usr.sbin/gspa/gspahextoc/gspahextoc.l b/usr.sbin/gspa/gspahextoc/gspahextoc.l
new file mode 100644
index 00000000000..dcd54bb165d
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/gspahextoc.l
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1995 Ignatios Souvatzis
+ * 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 Ignatios Souvatzis
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ int bufptr;
+ unsigned short buf[4096];
+
+ unsigned long binads;
+
+
+ void dumpstart __P((char *address));
+ void dumpbuf __P((void));
+ void initbuf __P((char *address));
+ void checkbuf __P((void));
+%%
+:[0-9A-Za-z]+ {if (bufptr>0) dumpbuf(); dumpstart(yytext+1);}
+@[0-9A-Za-z]+ {if (bufptr>0) dumpbuf(); initbuf(yytext+1);}
+[0-9A-Za-z]+ {checkbuf(); buf[bufptr++] = strtoul(yytext, 0, 16);}
+[ \t\n] ;
+%%
+
+void
+dumpbuf()
+{
+ int i;
+
+ printf("\n\n\t%d, 0x%04x, 0x%04x, /* new block */",
+ bufptr, binads >> 16, binads & 0xffff);
+ for (i=0; i<bufptr; ++i) {
+ if (i%8 == 0)
+ printf("\n\t");
+ printf("0x%04x, ", buf[i]);
+ }
+ binads += bufptr;
+ bufptr = 0;
+}
+
+void
+checkbuf()
+{
+ if (bufptr > (sizeof(buf)/sizeof(*buf)))
+ dumpbuf();
+}
+
+void
+initbuf(address)
+ char *address;
+{
+ binads = strtoul(address, 0, 16);
+ bufptr = 0;
+}
+
+void
+dumpstart(address)
+ char *address;
+{
+ u_int32_t startaddress;
+
+ startaddress = strtoul(address, 0, 16);
+
+ printf("\n\n\t2, 0xFFFF, 0xFEE0, 0x%04x, 0x%04x,\t/* start address */",
+ startaddress & 0xFFFF, startaddress >> 16);
+
+ printf("\n\t2, 0xFFFF, 0xFFE0, 0x%04x, 0x%04x,",
+ startaddress & 0xFFFF, startaddress >> 16);
+
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ++argv; --argc;
+ if (argc > 0) {
+ yyin = fopen(argv[0], "r");
+ printf("/*\n"
+ " * This file was automatically created from %s,\n"\
+ " * a TMS34010 assembler output file.\n", argv[0]);
+ } else {
+ yyin = stdin;
+ printf("/*\n"
+ " * This file was automatically created from\n"\
+ " * a TMS34010 assembler output file.\n");
+ }
+
+ printf(" * Do not edit manually..\n");
+ printf(" */\n");
+ printf("u_int16_t tmscode[] = {\n\t");
+ yylex();
+ if (bufptr>0)
+ dumpbuf();
+ printf("\n\t0\n};\n");
+
+ exit(0);
+}
diff --git a/usr.sbin/hilinfo/Makefile b/usr.sbin/hilinfo/Makefile
new file mode 100644
index 00000000000..2d90ba185b2
--- /dev/null
+++ b/usr.sbin/hilinfo/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:35 deraadt Exp $
+
+PROG= hilinfo
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../sys/arch/hp300
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/hilinfo/hilinfo.c b/usr.sbin/hilinfo/hilinfo.c
new file mode 100644
index 00000000000..672248fb7a3
--- /dev/null
+++ b/usr.sbin/hilinfo/hilinfo.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1987-1993, The University of Utah and
+ * the Center for Software Science at the University of Utah (CSS).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the Center
+ * for Software Science at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSS requests users of this software to return to css-dist@cs.utah.edu any
+ * improvements that they make and grant CSS redistribution rights.
+ *
+ * from: Utah $Hdr: hilinfo.c 1.3 94/04/04$
+ * $Id: hilinfo.c,v 1.1.1.1 1995/10/18 08:47:35 deraadt Exp $
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <dev/hilioctl.h>
+
+int aflg = 0;
+int tflg = 1;
+char *pname;
+char *dname, *tname();
+struct _hilbuf11 hi;
+struct _hilbuf16 sc;
+
+struct hil_info {
+ u_char hil_lo;
+ u_char hil_hi;
+ char *hil_name;
+} info[] = {
+ 0xA0, 0xFF, "keyboard",
+ 0x60, 0x6B, "mouse",
+ 0x90, 0x97, "tablet",
+ 0x34, 0x34, "id-module",
+ 0x30, 0x30, "button-box",
+ 0x00, 0x00, "unknown",
+};
+
+main(argc, argv)
+ char **argv;
+{
+ extern int optind, optopt;
+ extern char *optarg;
+ register int c;
+ int multi;
+
+ pname = argv[0];
+ while ((c = getopt(argc, argv, "at")) != EOF)
+ switch (c) {
+ /* everything */
+ case 'a':
+ aflg++;
+ tflg = 0;
+ break;
+ /* type */
+ case 't':
+ tflg++;
+ aflg = 0;
+ break;
+ /* bogon */
+ case '?':
+ usage();
+ }
+ if (optind == argc)
+ usage();
+ multi = (argc - optind) - 1;
+ while (optind < argc) {
+ dname = argv[optind];
+ if (multi)
+ printf("%s: ", dname);
+ if (getinfo()) {
+ if (aflg)
+ printall();
+ else if (tflg)
+ printf("%s\n", tname());
+ }
+ optind++;
+ }
+ exit(0);
+}
+
+getinfo()
+{
+ int f;
+ extern int errno;
+
+ f = open(dname, 0);
+ if (f < 0 || ioctl(f, HILIOCID, &hi) < 0) {
+ if (tflg)
+ printf(errno == EBUSY ? "busy\n" : "none\n");
+ else {
+ printf("error\n");
+ perror(dname);
+ }
+ close(f);
+ return(0);
+ }
+ (void) ioctl(f, HILIOCSC, &sc);
+ close(f);
+ return(1);
+}
+
+printall()
+{
+ register int i;
+
+ printf("%s: %s, info: ", dname, tname());
+ for (i = 0; i < 11; i++)
+ printf("%2.2x", hi.string[i]);
+ if (strcmp(tname(), "id-module") == 0) {
+ printf(", sc: ");
+ for (i = 0; i < 16; i++)
+ printf("%2.2x", sc.string[i]);
+ }
+ printf("\n");
+}
+
+char *
+tname()
+{
+ register struct hil_info *hp;
+
+ for (hp = info; hp->hil_lo; hp++)
+ if (hi.string[0] >= hp->hil_lo && hi.string[0] <= hp->hil_hi)
+ break;
+ if (hi.string[0] == 0x61 && hi.string[1] == 0x13)
+ return("knobs");
+ return(hp->hil_name);
+}
+
+usage()
+{
+ fprintf(stderr, "usage: %s [-at] device\n", pname);
+ exit(1);
+}
diff --git a/usr.sbin/htable/Makefile b/usr.sbin/htable/Makefile
new file mode 100644
index 00000000000..afdd4eaec7a
--- /dev/null
+++ b/usr.sbin/htable/Makefile
@@ -0,0 +1,14 @@
+# from: @(#)Makefile 5.12 (Berkeley) 7/1/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $
+
+PROG= htable
+SRCS= htable.c parse.c scan.c
+MAN= htable.8
+CFLAGS+=-I. -I${.CURDIR}
+LDADD+= -ll
+DPADD+= ${LIBL}
+CLEANFILES+=parse.c scan.c y.tab.h
+
+.include <bsd.prog.mk>
+
+${OBJS}: scan.c parse.c
diff --git a/usr.sbin/htable/htable.8 b/usr.sbin/htable/htable.8
new file mode 100644
index 00000000000..0675674e48e
--- /dev/null
+++ b/usr.sbin/htable/htable.8
@@ -0,0 +1,150 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\" from: @(#)htable.8 6.6 (Berkeley) 3/16/91
+.\" $Id: htable.8,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt HTABLE 8
+.Os BSD 4.2
+.Sh NAME
+.Nm htable
+.Nd convert
+.Tn NIC
+standard format host tables
+.Sh SYNOPSIS
+.Nm htable
+.Op Fl c Ar connected-nets
+.Op Fl l Ar local-nets
+.Ar file
+.Sh DESCRIPTION
+.Nm Htable
+is used to convert host files in the format specified
+in Internet
+.Tn RFC
+810 to the format used by the network
+library routines. Three files are created as a result
+of running
+.Nm htable :
+.Pa hosts ,
+.Pa networks ,
+and
+.Pa gateways .
+The
+.Xr hosts
+file may be used by the
+.Xr gethostbyname 3
+routines in mapping host names to addresses
+if the nameserver,
+.Xr named 8 ,
+is not used.
+The
+.Pa networks
+file is used by the
+.Xr getnetent 3
+routines in mapping network names to numbers.
+The
+.Pa gateways
+file may be used by the routing daemon
+in identifying
+.Dq passive
+Internet gateways;
+see
+.Xr routed 8
+for an explanation.
+.Pp
+Options available for
+.Nm htable :
+.Bl -tag -width Ds
+.It Fl c Ar connected-nets
+If the gateways file is to be used,
+.Ar connected-nets
+is a list of networks to which the host is directly connected.
+The networks, separated by commas,
+may be given by name or in Internet-standard dot notation,
+for example:
+.Bd -literal -offset indent
+\-c arpanet,128.32,local-ether-net.
+.Ed
+.Pp
+.Nm Htable
+only includes gateways
+which are directly connected to one of the networks specified,
+or which can be reached from another gateway on a connected net.
+.It Fl l Ar local-nets
+If the
+.Fl l
+option is given with a list of networks (in the same format as for
+.Fl c ) ,
+these networks will be treated as ``local,''
+and information about hosts on local networks is
+taken only from the localhosts file.
+Entries for local hosts from the main database will be omitted.
+This allows the localhosts file to completely override
+any entries in the input file.
+.El
+.Pp
+If any of the files
+.Pa localhosts ,
+.Pa localnetworks ,
+or
+.Pa localgateways
+are present in the current directory,
+the file's contents is prepended to the
+output file.
+Of these, only the gateways file is interpreted.
+This allows sites to maintain local aliases and
+entries which are not normally present in the
+master database.
+Only one gateway to each network will be placed in the gateways file;
+a gateway listed in the localgateways file will override any in the
+input file.
+.Pp
+.Nm Htable
+is best used in conjunction with the
+.Xr gettable 8
+program which retrieves the
+.Tn NIC
+database from a host.
+.Sh SEE ALSO
+.Xr netintro 4 ,
+.Xr gettable 8 ,
+.Xr named 8
+.Sh BUGS
+If the name-domain system provided network name mapping well as host
+name mapping,
+.Nm htable
+would no longer be needed.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/htable/htable.c b/usr.sbin/htable/htable.c
new file mode 100644
index 00000000000..77abae0a473
--- /dev/null
+++ b/usr.sbin/htable/htable.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)htable.c 5.10 (Berkeley) 2/6/91";*/
+static char rcsid[] = "$Id: htable.c,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * htable - convert NIC host table into a UNIX format.
+ * NIC format is described in RFC 810, 1 March 1982.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "htable.h" /* includes <sys/types.h> */
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#define DATELINES 3 /* these lines usually contain the date */
+#define MAXNETS 30 /* array size for local, connected nets */
+
+FILE *hf; /* hosts file */
+FILE *gf; /* gateways file */
+FILE *nf; /* networks file */
+struct gateway *savegateway(), *gatewayto();
+
+int connected_nets[MAXNETS];
+int nconnected;
+int local_nets[MAXNETS];
+int nlocal;
+char *myname;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int errs;
+
+ infile = "(stdin)";
+ myname = argv[0];
+ argc--;
+ argv++;
+ while (argc--) {
+ if (*argv[0] == '-') {
+ switch (argv[0][1]) {
+ case 'c':
+ nconnected = addlocal(argv[1], connected_nets);
+ argv++;
+ argc--;
+ break;
+ case 'l':
+ nlocal = addlocal(argv[1], local_nets);
+ argv++;
+ argc--;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ } else {
+ infile = argv[0];
+ if (freopen(infile, "r", stdin) == NULL) {
+ perror(infile);
+ exit(1);
+ }
+ }
+ argv++;
+ }
+ hf = fopen("hosts", "w");
+ if (hf == NULL) {
+ perror("hosts");
+ exit(1);
+ }
+ copylocal(hf, "localhosts");
+ gf = fopen("gateways", "w");
+ if (gf == NULL) {
+ perror("gateways");
+ exit(1);
+ }
+ copygateways("localgateways");
+ nf = fopen("networks", "w");
+ if (nf == NULL) {
+ perror("networks");
+ exit(1);
+ }
+ copylocal(nf, "localnetworks");
+ copycomments(stdin, hf, DATELINES);
+ errs = yyparse();
+ dogateways();
+ exit(errs);
+}
+
+usage()
+{
+ fprintf(stderr,
+ "usage: %s [ -c connected-nets ] [-l local-nets ] [ input-file ]\n",
+ myname);
+ exit(1);
+}
+
+/*
+ * Turn a comma-separated list of network names or numbers in dot notation
+ * (e.g. "arpanet, 128.32") into an array of net numbers.
+ */
+addlocal(arg, nets)
+ char *arg;
+ int *nets;
+{
+ register char *p, c;
+ register int nfound = 0;
+
+ do {
+ p = arg;
+ while (*p && *p != ',' && !isspace(*p))
+ p++;
+ c = *p;
+ *p = 0;
+ while (*arg && isspace(*arg))
+ arg++;
+ if (*arg == 0)
+ continue;
+ if (nfound == MAXNETS) {
+ fprintf(stderr, "%s: Too many networks in list\n",
+ myname);
+ return (nfound);
+ }
+ if (getnetaddr(arg, &nets[nfound]))
+ nfound++;
+ else {
+ fprintf(stderr, "%s: %s: unknown network\n",
+ myname, arg);
+ exit(1);
+ }
+ arg = p + 1;
+ } while (c);
+ return (nfound);
+}
+
+struct name *
+newname(str)
+ char *str;
+{
+ char *p;
+ struct name *nm;
+
+ p = malloc(strlen(str) + 1);
+ strcpy(p, str);
+ nm = (struct name *)malloc(sizeof (struct name));
+ nm->name_val = p;
+ nm->name_link = NONAME;
+ return (nm);
+}
+
+char *
+lower(str)
+ char *str;
+{
+ register char *cp = str;
+
+ while (*cp) {
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ cp++;
+ }
+ return (str);
+}
+
+do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
+ int keyword;
+ struct addr *addrlist;
+ struct name *namelist, *cputype, *opsys, *protos;
+{
+ register struct addr *al, *al2;
+ register struct name *nl;
+ struct addr *connect_addr;
+ char *cp;
+
+ switch (keyword) {
+
+ case KW_NET:
+ nl = namelist;
+ if (nl == NONAME) {
+ fprintf(stderr, "htable: net");
+ putnet(stderr, inet_netof(addrlist->addr_val));
+ fprintf(stderr, " missing names.\n");
+ break;
+ }
+ fprintf(nf, "%-16.16s", lower(nl->name_val));
+ al2 = addrlist;
+ while (al = al2) {
+ char *cp;
+
+ putnet(nf, inet_netof(al->addr_val));
+ cp = "\t%s";
+ while (nl = nl->name_link) {
+ fprintf(nf, cp, lower(nl->name_val));
+ cp = " %s";
+ }
+ putc('\n', nf);
+ al2 = al->addr_link;
+ free((char *)al);
+ }
+ break;
+
+ case KW_GATEWAY:
+ /* locate locally connected address, if one */
+ for (al = addrlist; al; al = al->addr_link)
+ if (connectedto(inet_netof(al->addr_val)))
+ break;
+ if (al == NULL) {
+ /*
+ * Not connected to known networks. Save for later.
+ */
+ struct gateway *gw, *firstgw = (struct gateway *) NULL;
+
+ for (al = addrlist; al; al = al->addr_link) {
+ register int net;
+
+ net = inet_netof(al->addr_val);
+ gw = savegateway(namelist, net,
+ al->addr_val, 0);
+ if (firstgw == (struct gateway *) NULL)
+ firstgw = gw;
+ gw->g_firstent = firstgw;
+ }
+ freeaddrs(addrlist);
+ goto dontfree;
+ }
+ /*
+ * Connected to a known network.
+ * Mark this as the gateway to all other networks
+ * that are on the addrlist (unless we already have
+ * gateways to them).
+ */
+ connect_addr = al;
+ for (al = addrlist; al; al = al->addr_link) {
+ register int net;
+
+ /* suppress duplicates -- not optimal */
+ net = inet_netof(al->addr_val);
+ if (connectedto(net) || gatewayto(net))
+ continue;
+ printgateway(net, namelist->name_val, 1);
+ (void) savegateway(namelist, net, al->addr_val, 1);
+ }
+ /*
+ * Put the gateway in the hosts file.
+ */
+ putaddr(hf, connect_addr->addr_val);
+ cp = "%s";
+ for (nl = namelist; nl; nl = nl->name_link) {
+ fprintf(hf, cp, lower(nl->name_val));
+ cp = " %s";
+ }
+ fprintf(hf, "\t# gateway\n");
+ freeaddrs(addrlist);
+ goto dontfree;
+
+ case KW_HOST:
+ al2 = addrlist;
+ while (al = al2) {
+ if (!local(inet_netof(al->addr_val))) {
+ char *cp;
+
+ putaddr(hf, al->addr_val);
+ cp = "%s";
+ for (nl = namelist; nl; nl = nl->name_link) {
+ fprintf(hf, cp, lower(nl->name_val));
+ cp = " %s";
+ }
+ putc('\n', hf);
+ }
+ al2 = al->addr_link;
+ free((char *)al);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unknown keyword: %d.\n", keyword);
+ }
+ freenames(namelist);
+dontfree:
+ freenames(protos);
+}
+
+printgateway(net, name, metric)
+ int net;
+ char *name;
+ int metric;
+{
+ struct netent *np;
+
+ fprintf(gf, "net ");
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ fprintf(gf, "%s", np->n_name);
+ else
+ putnet(gf, net);
+ fprintf(gf, " gateway %s metric %d passive\n",
+ lower(name), metric);
+}
+
+copylocal(f, filename)
+ FILE *f;
+ char *filename;
+{
+ register FILE *lhf;
+ register cc;
+ char buf[BUFSIZ];
+ extern int errno;
+
+ lhf = fopen(filename, "r");
+ if (lhf == NULL) {
+ if (errno != ENOENT) {
+ perror(filename);
+ exit(1);
+ }
+ fprintf(stderr, "Warning, no %s file.\n", filename);
+ return;
+ }
+ while (cc = fread(buf, 1, sizeof(buf), lhf))
+ fwrite(buf, 1, cc, f);
+ fclose(lhf);
+}
+
+copygateways(filename)
+ char *filename;
+{
+ register FILE *lhf;
+ struct name *nl;
+ char type[80];
+ char dname[80];
+ char gname[80];
+ char junk[80];
+ char buf[500];
+ struct in_addr addr;
+ int net, metric;
+ extern int errno;
+
+ lhf = fopen(filename, "r");
+ if (lhf == NULL) {
+ if (errno != ENOENT) {
+ perror(filename);
+ exit(1);
+ }
+ fprintf(stderr, "Warning, no %s file.\n", filename);
+ return;
+ }
+ /* format: {net | host} XX gateway XX metric DD [passive]\n */
+ for (;;) {
+ junk[0] = 0;
+ if (fgets(buf, sizeof(buf), lhf) == (char *)NULL)
+ break;
+ fputs(buf, gf);
+ if (buf[0] == '#' ||
+ sscanf(buf, "%s %s gateway %s metric %d %s",
+ type, dname, gname, &metric, junk) < 5)
+ continue;
+ if (strcmp(type, "net"))
+ continue;
+ if (!getnetaddr(dname, &net))
+ continue;
+ if (!gethostaddr(gname, &addr.s_addr))
+ continue;
+ nl = newname(gname);
+ (void) savegateway(nl, net, addr, metric);
+ }
+ fclose(lhf);
+}
+
+getnetaddr(name, addr)
+ char *name;
+ int *addr;
+{
+ struct netent *np = getnetbyname(name);
+
+ if (np == 0) {
+ *addr = inet_network(name);
+ return (*addr != -1);
+ } else {
+ if (np->n_addrtype != AF_INET)
+ return (0);
+ *addr = np->n_net;
+ return (1);
+ }
+}
+
+gethostaddr(name, addr)
+ char *name;
+ u_long *addr;
+{
+ struct hostent *hp;
+
+ hp = gethostbyname(name);
+ if (hp) {
+ *addr = *(u_long *)(hp->h_addr);
+ return (1);
+ }
+ *addr = inet_addr(name);
+ return (*addr != -1);
+}
+
+copycomments(in, out, ccount)
+ FILE *in, *out;
+ int ccount;
+{
+ int count;
+ char buf[BUFSIZ], *fgets();
+
+ for (count=0; count < ccount; count++) {
+ if ((fgets(buf, sizeof(buf), in) == NULL) || (buf[0] != ';'))
+ return;
+ buf[0] = '#';
+ fputs(buf, out);
+ }
+ return;
+}
+#define UC(b) (((int)(b))&0xff)
+
+/*
+ * Print network number in internet-standard dot notation;
+ * v is in host byte order.
+ */
+putnet(f, v)
+ FILE *f;
+ register int v;
+{
+ if (v < 128)
+ fprintf(f, "%d", v);
+ else if (v < 65536)
+ fprintf(f, "%d.%d", UC(v >> 8), UC(v));
+ else
+ fprintf(f, "%d.%d.%d", UC(v >> 16), UC(v >> 8), UC(v));
+}
+
+putaddr(f, v)
+ FILE *f;
+ struct in_addr v;
+{
+ fprintf(f, "%-16.16s", inet_ntoa(v));
+}
+
+freenames(list)
+ struct name *list;
+{
+ register struct name *nl, *nl2;
+
+ nl2 = list;
+ while (nl = nl2) {
+ nl2 = nl->name_link;
+ free(nl->name_val);
+ free((char *)nl);
+ }
+}
+
+freeaddrs(list)
+ struct addr *list;
+{
+ register struct addr *al, *al2;
+
+ al2 = list;
+ while (al = al2)
+ al2 = al->addr_link, free((char *)al);
+}
+
+struct gateway *gateways = 0;
+struct gateway *lastgateway = 0;
+
+struct gateway *
+gatewayto(net)
+ register int net;
+{
+ register struct gateway *gp;
+
+ for (gp = gateways; gp; gp = gp->g_link)
+ if ((gp->g_net == net) && (gp->g_metric > 0))
+ return (gp);
+ return ((struct gateway *) NULL);
+}
+
+struct gateway *
+savegateway(namelist, net, addr, metric)
+ struct name *namelist;
+ struct in_addr addr;
+ int net, metric;
+{
+ register struct gateway *gp;
+
+ gp = (struct gateway *)malloc(sizeof (struct gateway));
+ if (gp == 0) {
+ fprintf(stderr, "htable: out of memory\n");
+ exit(1);
+ }
+ gp->g_link = (struct gateway *) NULL;
+ if (lastgateway)
+ lastgateway->g_link = gp;
+ else
+ gateways = gp;
+ lastgateway = gp;
+ gp->g_name = namelist;
+ gp->g_net = net;
+ gp->g_addr = addr;
+ gp->g_metric = metric;
+ if (metric == 1)
+ gp->g_dst = gp;
+ return (gp);
+}
+
+connectedto(net)
+ u_long net;
+{
+ register i;
+
+ for (i = 0; i < nconnected; i++)
+ if (connected_nets[i] == net)
+ return(1);
+ return(0);
+}
+
+local(net)
+ u_long net;
+{
+ register i;
+
+ for (i = 0; i < nlocal; i++)
+ if (local_nets[i] == net)
+ return(1);
+ return(0);
+}
+
+#define MAXHOPS 10
+
+/*
+ * Go through list of gateways, finding connections for gateways
+ * that are not yet connected.
+ */
+dogateways()
+{
+ register struct gateway *gp, *gw, *ggp;
+ register int hops, changed = 1;
+ struct name *nl;
+ char *cp;
+
+ for (hops = 0; hops < MAXHOPS && changed; hops++, changed = 0) {
+ for (gp = gateways; gp; gp = gp->g_link)
+ if ((gp->g_metric == 0) && (gw = gatewayto(gp->g_net))) {
+ /*
+ * Found a new connection.
+ * For each other network that this gateway is on,
+ * add a new gateway to that network.
+ */
+ changed = 1;
+ gp->g_dst = gw->g_dst;
+ gp->g_metric = gw->g_metric + 1;
+ for (ggp = gp->g_firstent; ggp->g_name == gp->g_name;
+ ggp = ggp->g_link) {
+ if (ggp == gp)
+ continue;
+ if (gatewayto(ggp->g_net))
+ continue;
+ ggp->g_dst = gp->g_dst;
+ ggp->g_metric = gp->g_metric;
+ printgateway(ggp->g_net,
+ gw->g_dst->g_name->name_val, gp->g_metric);
+ }
+ /*
+ * Put the gateway in the hosts file,
+ * using the address for the connected net.
+ */
+ putaddr(hf, gp->g_addr);
+ cp = "%s";
+ for (nl = gp->g_name; nl; nl = nl->name_link) {
+ fprintf(hf, cp, lower(nl->name_val));
+ cp = " %s";
+ }
+ fprintf(hf, "\t# gateway\n");
+ }
+ }
+}
diff --git a/usr.sbin/htable/htable.h b/usr.sbin/htable/htable.h
new file mode 100644
index 00000000000..31d49862890
--- /dev/null
+++ b/usr.sbin/htable/htable.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * from: @(#)htable.h 5.5 (Berkeley) 2/6/91
+ * $Id: htable.h,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * common definitions for htable
+ */
+
+struct addr {
+ struct in_addr addr_val;
+ struct addr *addr_link;
+};
+
+struct name {
+ char *name_val;
+ struct name *name_link;
+};
+
+struct gateway {
+ struct gateway *g_link;
+ struct gateway *g_dst; /* connected gateway if metric > 0 */
+ struct gateway *g_firstent; /* first entry for this gateway */
+ struct name *g_name;
+ int g_net;
+ struct in_addr g_addr; /* address on g_net */
+ int g_metric; /* hops to this net */
+};
+
+#define NOADDR ((struct addr *)0)
+#define NONAME ((struct name *)0)
+
+#define KW_NET 1
+#define KW_GATEWAY 2
+#define KW_HOST 3
+
+struct name *newname();
+
+char *infile; /* Input file name */
diff --git a/usr.sbin/htable/parse.y b/usr.sbin/htable/parse.y
new file mode 100644
index 00000000000..5fc2ab6cf84
--- /dev/null
+++ b/usr.sbin/htable/parse.y
@@ -0,0 +1,166 @@
+%{
+
+/*
+ * Copyright (c) 1983 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[] = "from: @(#)parse.y 5.5 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: parse.y,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdlib.h>
+#include "htable.h"
+%}
+
+%union {
+ int number;
+ struct addr *addrlist;
+ struct name *namelist;
+}
+%start Table
+
+%token END
+%token <number> NUMBER KEYWORD
+%token <namelist> NAME
+
+%type <namelist> Names Cputype Opsys Protos Proto
+%type <addrlist> Addresses Address
+%%
+Table : Entry
+ | Table Entry
+ ;
+
+Entry : KEYWORD ':' Addresses ':' Names ':' END
+ = {
+ do_entry($1, $3, $5, NONAME, NONAME, NONAME);
+ }
+ | KEYWORD ':' Addresses ':' Names ':' Cputype ':' END
+ = {
+ do_entry($1, $3, $5, $7, NONAME, NONAME);
+ }
+ | KEYWORD ':' Addresses ':' Names ':' Cputype ':' Opsys ':' END
+ = {
+ do_entry($1, $3, $5, $7, $9, NONAME);
+ }
+ | KEYWORD ':' Addresses ':' Names ':' Cputype ':' Opsys ':' ':' END
+ = {
+ do_entry($1, $3, $5, $7, $9, NONAME);
+ }
+ | KEYWORD ':' Addresses ':' Names ':' Cputype ':' Opsys ':' Protos ':' END
+ = {
+ do_entry($1, $3, $5, $7, $9, $11);
+ }
+ | error END
+ | END /* blank line */
+ ;
+
+Addresses: Address
+ = {
+ $$ = $1;
+ }
+ | Address ',' Addresses
+ = {
+ $1->addr_link = $3;
+ $$ = $1;
+ }
+ ;
+
+Address : NUMBER '.' NUMBER '.' NUMBER '.' NUMBER
+ = {
+ char *a;
+
+ $$ = (struct addr *)malloc(sizeof (struct addr));
+ a = (char *)&($$->addr_val);
+ a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
+ $$->addr_link = NOADDR;
+ }
+ ;
+
+Names : NAME
+ = {
+ $$ = $1;
+ }
+ | NAME ',' Names
+ = {
+ $1->name_link = $3;
+ $$ = $1;
+ }
+ ;
+
+Cputype : /* empty */
+ = {
+ $$ = NONAME;
+ }
+ | NAME
+ = {
+ $$ = $1;
+ }
+ ;
+
+Opsys : /* empty */
+ = {
+ $$ = NONAME;
+ }
+ | NAME
+ = {
+ $$ = $1;
+ }
+ ;
+
+Protos : Proto
+ = {
+ $$ = $1;
+ }
+ | Proto ',' Protos
+ = {
+ $1->name_link = $3;
+ $$ = $1;
+ }
+ ;
+
+Proto : NAME
+ = {
+ $$ = $1;
+ }
+ ;
+%%
+
+#include <stdio.h>
+
+extern int yylineno;
+
+yyerror(msg)
+ char *msg;
+{
+ fprintf(stderr, "\"%s\", line %d: %s\n", infile, yylineno, msg);
+}
diff --git a/usr.sbin/htable/scan.l b/usr.sbin/htable/scan.l
new file mode 100644
index 00000000000..3b5c1759a75
--- /dev/null
+++ b/usr.sbin/htable/scan.l
@@ -0,0 +1,101 @@
+%{
+/*-
+ * Copyright (c) 1983 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[] = "from: @(#)scan.l 5.8 (Berkeley) 4/19/91";*/
+static char rcsid[] = "$Id: scan.l,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $";
+#endif /* not lint */
+
+extern int yylineno;
+int yylineno = 1;
+
+#include "y.tab.h"
+#include "htable.h"
+%}
+
+BLANK [ \t]
+DIGIT [0-9]
+ALPHA [A-Za-z]
+ANUM [0-9A-Za-z]
+NAMECHR [0-9A-Za-z./-]
+
+%%
+"NET" {
+ yylval.number = KW_NET;
+ return (KEYWORD);
+ }
+
+"GATEWAY" {
+ yylval.number = KW_GATEWAY;
+ return (KEYWORD);
+ }
+
+"HOST" {
+ yylval.number = KW_HOST;
+ return (KEYWORD);
+ }
+
+{ALPHA}{NAMECHR}*{ANUM} {
+ yylval.namelist = newname(yytext);
+ return (NAME);
+ }
+
+{ALPHA} {
+ yylval.namelist = newname(yytext);
+ return (NAME);
+ }
+
+{DIGIT}+{ALPHA}{NAMECHR}* {
+ fprintf(stderr, "Warning: nonstandard name \"%s\"\n",
+ yytext);
+ yylval.namelist = newname(yytext);
+ return (NAME);
+ }
+
+{DIGIT}+ {
+ yylval.number = atoi(yytext);
+ return (NUMBER);
+ }
+
+"." return ('.');
+":" return (':');
+"," return (',');
+"/" return ('/');
+";".* ;
+"\n"{BLANK}+ ++yylineno;
+{BLANK}+ ;
+"\n" ++yylineno; return (END);
+. fprintf(stderr, "Illegal char: '%s'\n", yytext);
+
+%%
diff --git a/usr.sbin/inetd/Makefile b/usr.sbin/inetd/Makefile
new file mode 100644
index 00000000000..9538f8be457
--- /dev/null
+++ b/usr.sbin/inetd/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.5 (Berkeley) 6/29/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $
+
+PROG= inetd
+MAN= inetd.8
+MLINKS= inetd.8 inetd.5
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8
new file mode 100644
index 00000000000..61e8fb60694
--- /dev/null
+++ b/usr.sbin/inetd/inetd.8
@@ -0,0 +1,280 @@
+.\" Copyright (c) 1985, 1991 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.
+.\"
+.\" from: @(#)inetd.8 6.7 (Berkeley) 3/16/91
+.\" $Id: inetd.8,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt INETD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm inetd
+.Nd internet
+.Dq super-server
+.Sh SYNOPSIS
+.Nm inetd
+.Op Fl d
+.Op Ar configuration file
+.Sh DESCRIPTION
+.Nm Inetd
+should be run at boot time by
+.Pa /etc/rc.local
+(see
+.Xr rc 8 ) .
+It then listens for connections on certain
+internet sockets. When a connection is found on one
+of its sockets, it decides what service the socket
+corresponds to, and invokes a program to service the request.
+After the program is
+finished, it continues to listen on the socket (except in some cases which
+will be described below). Essentially,
+.Nm inetd
+allows running one daemon to invoke several others,
+reducing load on the system.
+.Pp
+The option available for
+.Nm inetd:
+.Bl -tag -width Ds
+.It Fl d
+Turns on debugging.
+.El
+.Pp
+Upon execution,
+.Nm inetd
+reads its configuration information from a configuration
+file which, by default, is
+.Pa /etc/inetd.conf .
+There must be an entry for each field of the configuration
+file, with entries for each field separated by a tab or
+a space. Comments are denoted by a ``#'' at the beginning
+of a line. There must be an entry for each field. The
+fields of the configuration file are as follows:
+.Pp
+.Bd -unfilled -offset indent -compact
+service name
+socket type
+protocol
+wait/nowait[.max]
+user[.group]
+server program
+server program arguments
+.Ed
+.Pp
+To specify an
+.Em Sun-RPC
+based service, the entry would contain these fields.
+.Pp
+.Bd -unfilled -offset indent -compact
+service name/version
+socket type
+rpc/protocol
+wait/nowait[.max]
+user[.group]
+server program
+server program arguments
+.Ed
+.Pp
+The
+.Em service-name
+entry is the name of a valid service in
+the file
+.Pa /etc/services .
+For
+.Dq internal
+services (discussed below), the service
+name
+.Em must
+be the official name of the service (that is, the first entry in
+.Pa /etc/services ) .
+When used to specify a
+.Em Sun-RPC
+based service, this field is a valid RPC service name in
+the file
+.Pa /etc/rpc .
+The part on the right of the
+.Dq /
+is the RPC version number. This
+can simply be a single numeric argument or a range of versions.
+A range is bounded by the low version to the high version -
+.Dq rusers/1-3 .
+
+.Pp
+The
+.Em socket-type
+should be one of
+.Dq stream ,
+.Dq dgram ,
+.Dq raw ,
+.Dq rdm ,
+or
+.Dq seqpacket ,
+depending on whether the socket is a stream, datagram, raw,
+reliably delivered message, or sequenced packet socket.
+.Pp
+The
+.Em protocol
+must be a valid protocol as given in
+.Pa /etc/protocols .
+Examples might be
+.Dq tcp
+or
+.Dq udp .
+Rpc based services are specified with the
+.Dq rpc/tcp
+or
+.Dq rpc/udp
+service type.
+
+.Pp
+The
+.Em wait/nowait
+entry is applicable to datagram sockets only (other sockets should
+have a
+.Dq nowait
+entry in this space). If a datagram server connects
+to its peer, freeing the socket so
+.Nm inetd
+can received further messages on the socket, it is said to be
+a
+.Dq multi-threaded
+server, and should use the
+.Dq nowait
+entry. For datagram servers which process all incoming datagrams
+on a socket and eventually time out, the server is said to be
+.Dq single-threaded
+and should use a
+.Dq wait
+entry.
+.Xr Comsat 8
+.Pq Xr biff 1
+and
+.Xr talkd 8
+are both examples of the latter type of
+datagram server.
+.Xr Tftpd 8
+is an exception; it is a datagram server that establishes pseudo-connections.
+It must be listed as
+.Dq wait
+in order to avoid a race;
+the server reads the first packet, creates a new socket,
+and then forks and exits to allow
+.Nm inetd
+to check for new service requests to spawn new servers.
+The optional
+.Dq max
+suffix (separated from
+.Dq wait
+or
+.Dq nowait
+by a dot) specifies the maximum number of server instances that may be
+spawned from
+.Nm inetd
+within an interval of 60 seconds. When omitted,
+.Dq max
+defaults to 40.
+.Pp
+The
+.Em user
+entry should contain the user name of the user as whom the server
+should run. This allows for servers to be given less permission
+than root. An optional group name can be specified by appending a dot to
+the user name followed by the group name. This allows for servers to run with
+a different (primary) group id than specified in the password file. If a group
+is specified and user is not root, the supplementary groups associated with
+that user will still be set.
+.Pp
+The
+.Em server-program
+entry should contain the pathname of the program which is to be
+executed by
+.Nm inetd
+when a request is found on its socket. If
+.Nm inetd
+provides this service internally, this entry should
+be
+.Dq internal .
+.Pp
+The
+.Em server program arguments
+should be just as arguments
+normally are, starting with argv[0], which is the name of
+the program. If the service is provided internally, the
+word
+.Dq internal
+should take the place of this entry.
+.Pp
+.Nm Inetd
+provides several
+.Dq trivial
+services internally by use of
+routines within itself. These services are
+.Dq echo ,
+.Dq discard ,
+.Dq chargen
+(character generator),
+.Dq daytime
+(human readable time), and
+.Dq time
+(machine readable time,
+in the form of the number of seconds since midnight, January
+1, 1900). All of these services are tcp based. For
+details of these services, consult the appropriate
+.Tn RFC
+from the Network Information Center.
+.Pp
+.Nm Inetd
+rereads its configuration file when it receives a hangup signal,
+.Dv SIGHUP .
+Services may be added, deleted or modified when the configuration file
+is reread.
+.Nm Inetd
+creates a file
+.Em /var/run/inetd.pid
+that contains its process identifier.
+.Sh SEE ALSO
+.Xr comsat 8 ,
+.Xr fingerd 8 ,
+.Xr ftpd 8 ,
+.Xr rexecd 8 ,
+.Xr rlogind 8 ,
+.Xr rshd 8 ,
+.Xr telnetd 8 ,
+.Xr tftpd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+Support for
+.Em Sun-RPC
+based services is modeled after that
+provided by
+.Em Sun-OS 4.1 .
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
new file mode 100644
index 00000000000..0528607832c
--- /dev/null
+++ b/usr.sbin/inetd/inetd.c
@@ -0,0 +1,1607 @@
+/* $NetBSD: inetd.c,v 1.10 1995/06/02 15:02:18 pk Exp $ */
+/*
+ * Copyright (c) 1983,1991 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)inetd.c 5.30 (Berkeley) 6/3/91";*/
+static char rcsid[] = "$Id: inetd.c,v 1.1.1.1 1995/10/18 08:47:36 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Inetd - Internet super-server
+ *
+ * This program invokes all internet services as needed.
+ * connection-oriented services are invoked each time a
+ * connection is made, by creating a process. This process
+ * is passed the connection as file descriptor 0 and is
+ * expected to do a getpeername to find out the source host
+ * and port.
+ *
+ * Datagram oriented services are invoked when a datagram
+ * arrives; a process is created and passed a pending message
+ * on file descriptor 0. Datagram servers may either connect
+ * to their peer, freeing up the original socket for inetd
+ * to receive further messages on, or ``take over the socket'',
+ * processing all arriving datagrams and, eventually, timing
+ * out. The first type of server is said to be ``multi-threaded'';
+ * the second type of server ``single-threaded''.
+ *
+ * Inetd uses a configuration file which is read at startup
+ * and, possibly, at some later time in response to a hangup signal.
+ * The configuration file is ``free format'' with fields given in the
+ * order shown below. Continuation lines for an entry must being with
+ * a space or tab. All fields must be present in each entry.
+ *
+ * service name must be in /etc/services
+ * socket type stream/dgram/raw/rdm/seqpacket
+ * protocol must be in /etc/protocols
+ * wait/nowait[.max] single-threaded/multi-threaded, max #
+ * user[.group] user/group to run daemon as
+ * server program full path name
+ * server program arguments maximum of MAXARGS (20)
+ *
+ * For RPC services
+ * service name/version must be in /etc/rpc
+ * socket type stream/dgram/raw/rdm/seqpacket
+ * protocol must be in /etc/protocols
+ * wait/nowait[.max] single-threaded/multi-threaded
+ * user[.group] user to run daemon as
+ * server program full path name
+ * server program arguments maximum of MAXARGS (20)
+ *
+ * Comment lines are indicated by a `#' in column 1.
+ */
+
+/*
+ * Here's the scoop concerning the user.group feature:
+ *
+ * 1) set-group-option off.
+ *
+ * a) user = root: NO setuid() or setgid() is done
+ *
+ * b) other: setuid()
+ * setgid(primary group as found in passwd)
+ * initgroups(name, primary group)
+ *
+ * 2) set-group-option on.
+ *
+ * a) user = root: NO setuid()
+ * setgid(specified group)
+ * NO initgroups()
+ *
+ * b) other: setuid()
+ * setgid(specified group)
+ * initgroups(name, specified group)
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifndef RLIMIT_NOFILE
+#define RLIMIT_NOFILE RLIMIT_OFILE
+#endif
+
+#define RPC
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef RPC
+#include <rpc/rpc.h>
+#endif
+#include "pathnames.h"
+
+#define TOOMANY 40 /* don't start more than TOOMANY */
+#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
+#define RETRYTIME (60*10) /* retry after bind or server fail */
+
+#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
+
+extern int errno;
+
+void config(), reapchild(), retry(), goaway();
+char *index();
+
+int debug = 0;
+int nsock, maxsock;
+fd_set allsock;
+int options;
+int timingout;
+struct servent *sp;
+char *curdom;
+
+#ifndef OPEN_MAX
+#define OPEN_MAX 64
+#endif
+
+/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
+#define FD_MARGIN (8)
+typeof(((struct rlimit *)0)->rlim_cur) rlim_ofile_cur = OPEN_MAX;
+
+#ifdef RLIMIT_NOFILE
+struct rlimit rlim_ofile;
+#endif
+
+struct servtab {
+ char *se_service; /* name of service */
+ int se_socktype; /* type of socket to use */
+ int se_family; /* address family */
+ char *se_proto; /* protocol used */
+ int se_rpcprog; /* rpc program number */
+ int se_rpcversl; /* rpc program lowest version */
+ int se_rpcversh; /* rpc program highest version */
+#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
+ short se_wait; /* single threaded server */
+ short se_checked; /* looked at during merge */
+ char *se_user; /* user name to run as */
+ char *se_group; /* group name to run as */
+ struct biltin *se_bi; /* if built-in, description */
+ char *se_server; /* server program */
+#define MAXARGV 20
+ char *se_argv[MAXARGV+1]; /* program arguments */
+ int se_fd; /* open descriptor */
+ union {
+ struct sockaddr se_un_ctrladdr;
+ struct sockaddr_in se_un_ctrladdr_in;
+ struct sockaddr_un se_un_ctrladdr_un;
+ } se_un; /* bound address */
+#define se_ctrladdr se_un.se_un_ctrladdr
+#define se_ctrladdr_in se_un.se_un_ctrladdr_in
+#define se_ctrladdr_un se_un.se_un_ctrladdr_un
+ int se_ctrladdr_size;
+ int se_max; /* max # of instances of this service */
+ int se_count; /* number started since se_time */
+ struct timeval se_time; /* start of se_count */
+#ifdef MULOG
+ int se_log;
+#define MULOG_RFC931 0x40000000
+#endif
+ struct servtab *se_next;
+} *servtab;
+
+int echo_stream(), discard_stream(), machtime_stream();
+int daytime_stream(), chargen_stream();
+int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
+
+struct biltin {
+ char *bi_service; /* internally provided service name */
+ int bi_socktype; /* type of socket supported */
+ short bi_fork; /* 1 if should fork before call */
+ short bi_wait; /* 1 if should wait for child */
+ int (*bi_fn)(); /* function which performs it */
+} biltins[] = {
+ /* Echo received data */
+ "echo", SOCK_STREAM, 1, 0, echo_stream,
+ "echo", SOCK_DGRAM, 0, 0, echo_dg,
+
+ /* Internet /dev/null */
+ "discard", SOCK_STREAM, 1, 0, discard_stream,
+ "discard", SOCK_DGRAM, 0, 0, discard_dg,
+
+ /* Return 32 bit time since 1900 */
+ "time", SOCK_STREAM, 0, 0, machtime_stream,
+ "time", SOCK_DGRAM, 0, 0, machtime_dg,
+
+ /* Return human-readable time */
+ "daytime", SOCK_STREAM, 0, 0, daytime_stream,
+ "daytime", SOCK_DGRAM, 0, 0, daytime_dg,
+
+ /* Familiar character generator */
+ "chargen", SOCK_STREAM, 1, 0, chargen_stream,
+ "chargen", SOCK_DGRAM, 0, 0, chargen_dg,
+ 0
+};
+
+#define NUMINT (sizeof(intab) / sizeof(struct inent))
+char *CONFIG = _PATH_INETDCONF;
+char **Argv;
+char *LastArg;
+char *progname;
+
+#ifdef sun
+/*
+ * Sun's RPC library caches the result of `dtablesize()'
+ * This is incompatible with our "bumping" of file descriptors "on demand"
+ */
+int
+_rpc_dtablesize()
+{
+ return rlim_ofile_cur;
+}
+#endif
+
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ extern char *optarg;
+ extern int optind;
+ register struct servtab *sep;
+ register struct passwd *pwd;
+ register struct group *grp;
+ register int tmpint;
+ struct sigvec sv;
+ int ch, pid, dofork;
+ char buf[50];
+
+ Argv = argv;
+ if (envp == 0 || *envp == 0)
+ envp = argv;
+ while (*envp)
+ envp++;
+ LastArg = envp[-1] + strlen(envp[-1]);
+
+ progname = strrchr(argv[0], '/');
+ progname = progname ? progname + 1 : argv[0];
+
+ while ((ch = getopt(argc, argv, "d")) != EOF)
+ switch(ch) {
+ case 'd':
+ debug = 1;
+ options |= SO_DEBUG;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: %s [-d] [conf]", progname);
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ CONFIG = argv[0];
+
+ if (debug == 0)
+ daemon(0, 0);
+ openlog(progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+ logpid();
+
+#ifdef RLIMIT_NOFILE
+ if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
+ syslog(LOG_ERR, "getrlimit: %m");
+ } else {
+ rlim_ofile_cur = rlim_ofile.rlim_cur;
+ if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
+ rlim_ofile_cur = OPEN_MAX;
+ }
+#endif
+
+ bzero((char *)&sv, sizeof(sv));
+ sv.sv_mask = SIGBLOCK;
+ sv.sv_handler = retry;
+ sigvec(SIGALRM, &sv, (struct sigvec *)0);
+ config();
+ sv.sv_handler = config;
+ sigvec(SIGHUP, &sv, (struct sigvec *)0);
+ sv.sv_handler = reapchild;
+ sigvec(SIGCHLD, &sv, (struct sigvec *)0);
+ sv.sv_handler = goaway;
+ sigvec(SIGTERM, &sv, (struct sigvec *)0);
+ sv.sv_handler = goaway;
+ sigvec(SIGINT, &sv, (struct sigvec *)0);
+
+ {
+ /* space for daemons to overwrite environment for ps */
+#define DUMMYSIZE 100
+ char dummy[DUMMYSIZE];
+
+ (void)memset(dummy, 'x', DUMMYSIZE - 1);
+ dummy[DUMMYSIZE - 1] = '\0';
+
+ (void)setenv("inetd_dummy", dummy, 1);
+ }
+
+ for (;;) {
+ int n, ctrl;
+ fd_set readable;
+
+ if (nsock == 0) {
+ (void) sigblock(SIGBLOCK);
+ while (nsock == 0)
+ sigpause(0L);
+ (void) sigsetmask(0L);
+ }
+ readable = allsock;
+ if ((n = select(maxsock + 1, &readable, (fd_set *)0,
+ (fd_set *)0, (struct timeval *)0)) <= 0) {
+ if (n < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "select: %m\n");
+ sleep(1);
+ continue;
+ }
+ for (sep = servtab; n && sep; sep = sep->se_next)
+ if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
+ n--;
+ if (debug)
+ fprintf(stderr, "someone wants %s\n", sep->se_service);
+ if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
+ ctrl = accept(sep->se_fd, (struct sockaddr *)0,
+ (int *)0);
+ if (debug)
+ fprintf(stderr, "accept, ctrl %d\n", ctrl);
+ if (ctrl < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_WARNING, "accept (for %s): %m",
+ sep->se_service);
+ continue;
+ }
+ } else
+ ctrl = sep->se_fd;
+ (void) sigblock(SIGBLOCK);
+ pid = 0;
+ dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
+ if (dofork) {
+ if (sep->se_count++ == 0)
+ (void)gettimeofday(&sep->se_time,
+ (struct timezone *)0);
+ else if (sep->se_count >= sep->se_max) {
+ struct timeval now;
+
+ (void)gettimeofday(&now, (struct timezone *)0);
+ if (now.tv_sec - sep->se_time.tv_sec >
+ CNT_INTVL) {
+ sep->se_time = now;
+ sep->se_count = 1;
+ } else {
+ syslog(LOG_ERR,
+ "%s/%s server failing (looping), service terminated\n",
+ sep->se_service, sep->se_proto);
+ FD_CLR(sep->se_fd, &allsock);
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ sep->se_count = 0;
+ nsock--;
+ sigsetmask(0L);
+ if (!timingout) {
+ timingout = 1;
+ alarm(RETRYTIME);
+ }
+ continue;
+ }
+ }
+ pid = fork();
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ if (sep->se_socktype == SOCK_STREAM)
+ close(ctrl);
+ sigsetmask(0L);
+ sleep(1);
+ continue;
+ }
+ if (pid && sep->se_wait) {
+ sep->se_wait = pid;
+ FD_CLR(sep->se_fd, &allsock);
+ nsock--;
+ }
+ sigsetmask(0L);
+ if (pid == 0) {
+ if (debug && dofork)
+ setsid();
+ if (sep->se_bi)
+ (*sep->se_bi->bi_fn)(ctrl, sep);
+ else {
+ if ((pwd = getpwnam(sep->se_user)) == NULL) {
+ syslog(LOG_ERR,
+ "getpwnam: %s: No such user",
+ sep->se_user);
+ if (sep->se_socktype != SOCK_STREAM)
+ recv(0, buf, sizeof (buf), 0);
+ _exit(1);
+ }
+ if (sep->se_group &&
+ (grp = getgrnam(sep->se_group)) == NULL) {
+ syslog(LOG_ERR,
+ "getgrnam: %s: No such group",
+ sep->se_group);
+ if (sep->se_socktype != SOCK_STREAM)
+ recv(0, buf, sizeof (buf), 0);
+ _exit(1);
+ }
+ if (pwd->pw_uid) {
+ if (sep->se_group)
+ pwd->pw_gid = grp->gr_gid;
+ (void) setgid((gid_t)pwd->pw_gid);
+ initgroups(pwd->pw_name, pwd->pw_gid);
+ (void) setuid((uid_t)pwd->pw_uid);
+ } else if (sep->se_group) {
+ (void) setgid((gid_t)grp->gr_gid);
+ }
+ if (debug)
+ fprintf(stderr, "%d execl %s\n",
+ getpid(), sep->se_server);
+#ifdef MULOG
+ if (sep->se_log)
+ dolog(sep, ctrl);
+#endif
+ dup2(ctrl, 0);
+ close(ctrl);
+ dup2(0, 1);
+ dup2(0, 2);
+#ifdef RLIMIT_NOFILE
+ if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
+ if (setrlimit(RLIMIT_NOFILE,
+ &rlim_ofile) < 0)
+ syslog(LOG_ERR,"setrlimit: %m");
+ }
+#endif
+ for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
+ (void)close(tmpint);
+ execv(sep->se_server, sep->se_argv);
+ if (sep->se_socktype != SOCK_STREAM)
+ recv(0, buf, sizeof (buf), 0);
+ syslog(LOG_ERR, "execv %s: %m", sep->se_server);
+ _exit(1);
+ }
+ }
+ if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
+ close(ctrl);
+ }
+ }
+}
+
+void
+reapchild()
+{
+ int status;
+ int pid;
+ register struct servtab *sep;
+
+ for (;;) {
+ pid = wait3(&status, WNOHANG, (struct rusage *)0);
+ if (pid <= 0)
+ break;
+ if (debug)
+ fprintf(stderr, "%d reaped\n", pid);
+ for (sep = servtab; sep; sep = sep->se_next)
+ if (sep->se_wait == pid) {
+ if (WIFEXITED(status) && WEXITSTATUS(status))
+ syslog(LOG_WARNING,
+ "%s: exit status 0x%x",
+ sep->se_server, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ syslog(LOG_WARNING,
+ "%s: exit signal 0x%x",
+ sep->se_server, WTERMSIG(status));
+ sep->se_wait = 1;
+ FD_SET(sep->se_fd, &allsock);
+ nsock++;
+ if (debug)
+ fprintf(stderr, "restored %s, fd %d\n",
+ sep->se_service, sep->se_fd);
+ }
+ }
+}
+
+void
+config()
+{
+ register struct servtab *sep, *cp, **sepp;
+ struct servtab *getconfigent(), *enter();
+ long omask;
+ int n;
+
+ if (!setconfig()) {
+ syslog(LOG_ERR, "%s: %m", CONFIG);
+ return;
+ }
+ for (sep = servtab; sep; sep = sep->se_next)
+ sep->se_checked = 0;
+ while (cp = getconfigent()) {
+ for (sep = servtab; sep; sep = sep->se_next)
+ if (strcmp(sep->se_service, cp->se_service) == 0 &&
+ strcmp(sep->se_proto, cp->se_proto) == 0)
+ break;
+ if (sep != 0) {
+ int i;
+
+#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
+
+ omask = sigblock(SIGBLOCK);
+ /*
+ * sep->se_wait may be holding the pid of a daemon
+ * that we're waiting for. If so, don't overwrite
+ * it unless the config file explicitly says don't
+ * wait.
+ */
+ if (cp->se_bi == 0 &&
+ (sep->se_wait == 1 || cp->se_wait == 0))
+ sep->se_wait = cp->se_wait;
+ if (cp->se_max != sep->se_max)
+ SWAP(int, cp->se_max, sep->se_max);
+ if (cp->se_user)
+ SWAP(char *, sep->se_user, cp->se_user);
+ if (cp->se_group)
+ SWAP(char *, sep->se_group, cp->se_group);
+ if (cp->se_server)
+ SWAP(char *, sep->se_server, cp->se_server);
+ for (i = 0; i < MAXARGV; i++)
+ SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
+#undef SWAP
+ if (isrpcservice(sep))
+ unregister_rpc(sep);
+ sep->se_rpcversl = cp->se_rpcversl;
+ sep->se_rpcversh = cp->se_rpcversh;
+ sigsetmask(omask);
+ freeconfig(cp);
+ if (debug)
+ print_service("REDO", sep);
+ } else {
+ sep = enter(cp);
+ if (debug)
+ print_service("ADD ", sep);
+ }
+ sep->se_checked = 1;
+
+ switch (sep->se_family) {
+ case AF_UNIX:
+ if (sep->se_fd != -1)
+ break;
+ (void)unlink(sep->se_service);
+ n = strlen(sep->se_service);
+ if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
+ n = sizeof sep->se_ctrladdr_un.sun_path - 1;
+ strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
+ sep->se_ctrladdr_un.sun_family = AF_UNIX;
+ sep->se_ctrladdr_size = n +
+ sizeof sep->se_ctrladdr_un.sun_family;
+ setup(sep);
+ break;
+ case AF_INET:
+ sep->se_ctrladdr_in.sin_family = AF_INET;
+ sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
+ if (isrpcservice(sep)) {
+ struct rpcent *rp;
+
+ sep->se_rpcprog = atoi(sep->se_service);
+ if (sep->se_rpcprog == 0) {
+ rp = getrpcbyname(sep->se_service);
+ if (rp == 0) {
+ syslog(LOG_ERR,
+ "%s: unknown service",
+ sep->se_service);
+ continue;
+ }
+ sep->se_rpcprog = rp->r_number;
+ }
+ if (sep->se_fd == -1)
+ setup(sep);
+ if (sep->se_fd != -1)
+ register_rpc(sep);
+ } else {
+ u_short port = htons(atoi(sep->se_service));
+
+ if (!port) {
+ sp = getservbyname(sep->se_service,
+ sep->se_proto);
+ if (sp == 0) {
+ syslog(LOG_ERR,
+ "%s/%s: unknown service",
+ sep->se_service, sep->se_proto);
+ continue;
+ }
+ port = sp->s_port;
+ }
+ if (port != sep->se_ctrladdr_in.sin_port) {
+ sep->se_ctrladdr_in.sin_port = port;
+ if (sep->se_fd != -1) {
+ FD_CLR(sep->se_fd, &allsock);
+ nsock--;
+ (void) close(sep->se_fd);
+ }
+ sep->se_fd = -1;
+ }
+ if (sep->se_fd == -1)
+ setup(sep);
+ }
+ }
+ }
+ endconfig();
+ /*
+ * Purge anything not looked at above.
+ */
+ omask = sigblock(SIGBLOCK);
+ sepp = &servtab;
+ while (sep = *sepp) {
+ if (sep->se_checked) {
+ sepp = &sep->se_next;
+ continue;
+ }
+ *sepp = sep->se_next;
+ if (sep->se_fd != -1) {
+ FD_CLR(sep->se_fd, &allsock);
+ nsock--;
+ (void) close(sep->se_fd);
+ }
+ if (isrpcservice(sep))
+ unregister_rpc(sep);
+ if (sep->se_family == AF_UNIX)
+ (void)unlink(sep->se_service);
+ if (debug)
+ print_service("FREE", sep);
+ freeconfig(sep);
+ free((char *)sep);
+ }
+ (void) sigsetmask(omask);
+}
+
+void
+retry()
+{
+ register struct servtab *sep;
+
+ timingout = 0;
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (sep->se_fd == -1) {
+ switch (sep->se_family) {
+ case AF_UNIX:
+ case AF_INET:
+ setup(sep);
+ if (sep->se_fd != -1 && isrpcservice(sep))
+ register_rpc(sep);
+ break;
+ }
+ }
+ }
+}
+
+void
+goaway()
+{
+ register struct servtab *sep;
+
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (sep->se_fd == -1)
+ continue;
+
+ switch (sep->se_family) {
+ case AF_UNIX:
+ (void)unlink(sep->se_service);
+ break;
+ case AF_INET:
+ if (sep->se_wait == 1 && isrpcservice(sep))
+ unregister_rpc(sep);
+ break;
+ }
+ (void)close(sep->se_fd);
+ }
+ (void)unlink(_PATH_INETDPID);
+ exit(0);
+}
+
+
+setup(sep)
+ register struct servtab *sep;
+{
+ int on = 1;
+
+ if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
+ syslog(LOG_ERR, "%s/%s: socket: %m",
+ sep->se_service, sep->se_proto);
+ return;
+ }
+#define turnon(fd, opt) \
+setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
+ if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
+ turnon(sep->se_fd, SO_DEBUG) < 0)
+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+ if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
+ syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
+#undef turnon
+ if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
+ syslog(LOG_ERR, "%s/%s: bind: %m",
+ sep->se_service, sep->se_proto);
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ if (!timingout) {
+ timingout = 1;
+ alarm(RETRYTIME);
+ }
+ return;
+ }
+ if (sep->se_socktype == SOCK_STREAM)
+ listen(sep->se_fd, 10);
+
+ FD_SET(sep->se_fd, &allsock);
+ nsock++;
+ if (sep->se_fd > maxsock) {
+ maxsock = sep->se_fd;
+ if (maxsock > rlim_ofile_cur - FD_MARGIN)
+ bump_nofile();
+ }
+}
+
+register_rpc(sep)
+ register struct servtab *sep;
+{
+#ifdef RPC
+ int n;
+ struct sockaddr_in sin;
+ struct protoent *pp;
+
+ if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
+ syslog(LOG_ERR, "%s: getproto: %m",
+ sep->se_proto);
+ return;
+ }
+ n = sizeof sin;
+ if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
+ syslog(LOG_ERR, "%s/%s: getsockname: %m",
+ sep->se_service, sep->se_proto);
+ return;
+ }
+
+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
+ if (debug)
+ fprintf(stderr, "pmap_set: %u %u %u %u\n",
+ sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
+ (void)pmap_unset(sep->se_rpcprog, n);
+ if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
+ syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
+ sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
+ }
+#endif /* RPC */
+}
+
+unregister_rpc(sep)
+ register struct servtab *sep;
+{
+#ifdef RPC
+ int n;
+
+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
+ if (debug)
+ fprintf(stderr, "pmap_unset(%u, %u)\n",
+ sep->se_rpcprog, n);
+ if (!pmap_unset(sep->se_rpcprog, n))
+ syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
+ sep->se_rpcprog, n);
+ }
+#endif /* RPC */
+}
+
+
+struct servtab *
+enter(cp)
+ struct servtab *cp;
+{
+ register struct servtab *sep;
+ long omask;
+
+ sep = (struct servtab *)malloc(sizeof (*sep));
+ if (sep == (struct servtab *)0) {
+ syslog(LOG_ERR, "Out of memory.");
+ exit(-1);
+ }
+ *sep = *cp;
+ sep->se_fd = -1;
+ sep->se_rpcprog = -1;
+ omask = sigblock(SIGBLOCK);
+ sep->se_next = servtab;
+ servtab = sep;
+ sigsetmask(omask);
+ return (sep);
+}
+
+FILE *fconfig = NULL;
+struct servtab serv;
+char line[256];
+char *skip(), *nextline();
+
+setconfig()
+{
+
+ if (fconfig != NULL) {
+ fseek(fconfig, 0L, L_SET);
+ return (1);
+ }
+ fconfig = fopen(CONFIG, "r");
+ return (fconfig != NULL);
+}
+
+endconfig()
+{
+ if (fconfig) {
+ (void) fclose(fconfig);
+ fconfig = NULL;
+ }
+}
+
+struct servtab *
+getconfigent()
+{
+ register struct servtab *sep = &serv;
+ int argc;
+ char *cp, *arg, *newstr();
+
+more:
+#ifdef MULOG
+ while ((cp = nextline(fconfig)) && *cp == '#') {
+ /* Avoid use of `skip' if there is a danger of it looking
+ * at continuation lines.
+ */
+ do {
+ cp++;
+ } while (*cp == ' ' || *cp == '\t');
+ if (*cp == '\0')
+ continue;
+ if ((arg = skip(&cp)) == NULL)
+ continue;
+ if (strcmp(arg, "DOMAIN"))
+ continue;
+ if (curdom)
+ free(curdom);
+ curdom = NULL;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0')
+ continue;
+ arg = cp;
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+ curdom = newstr(arg);
+ }
+#else
+ while ((cp = nextline(fconfig)) && *cp == '#')
+ ;
+#endif
+ if (cp == NULL)
+ return ((struct servtab *)0);
+ bzero((char *)sep, sizeof *sep);
+ sep->se_service = newstr(skip(&cp));
+ arg = skip(&cp);
+ if (arg == NULL)
+ goto more;
+
+ if (strcmp(arg, "stream") == 0)
+ sep->se_socktype = SOCK_STREAM;
+ else if (strcmp(arg, "dgram") == 0)
+ sep->se_socktype = SOCK_DGRAM;
+ else if (strcmp(arg, "rdm") == 0)
+ sep->se_socktype = SOCK_RDM;
+ else if (strcmp(arg, "seqpacket") == 0)
+ sep->se_socktype = SOCK_SEQPACKET;
+ else if (strcmp(arg, "raw") == 0)
+ sep->se_socktype = SOCK_RAW;
+ else
+ sep->se_socktype = -1;
+
+ sep->se_proto = newstr(skip(&cp));
+ if (strcmp(sep->se_proto, "unix") == 0) {
+ sep->se_family = AF_UNIX;
+ } else {
+ sep->se_family = AF_INET;
+ if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
+#ifdef RPC
+ char *cp, *ccp;
+ cp = index(sep->se_service, '/');
+ if (cp == 0) {
+ syslog(LOG_ERR, "%s: no rpc version",
+ sep->se_service);
+ goto more;
+ }
+ *cp++ = '\0';
+ sep->se_rpcversl =
+ sep->se_rpcversh = strtol(cp, &ccp, 0);
+ if (ccp == cp) {
+ badafterall:
+ syslog(LOG_ERR, "%s/%s: bad rpc version",
+ sep->se_service, cp);
+ goto more;
+ }
+ if (*ccp == '-') {
+ cp = ccp + 1;
+ sep->se_rpcversh = strtol(cp, &ccp, 0);
+ if (ccp == cp)
+ goto badafterall;
+ }
+#else
+ syslog(LOG_ERR, "%s: rpc services not suported",
+ sep->se_service);
+ goto more;
+#endif /* RPC */
+ }
+ }
+ arg = skip(&cp);
+ if (arg == NULL)
+ goto more;
+ {
+ char *s = index(arg, '.');
+ if (s) {
+ *s++ = '\0';
+ sep->se_max = atoi(s);
+ } else
+ sep->se_max = TOOMANY;
+ }
+ sep->se_wait = strcmp(arg, "wait") == 0;
+ sep->se_user = newstr(skip(&cp));
+ if (sep->se_group = index(sep->se_user, '.')) {
+ *sep->se_group++ = '\0';
+ }
+ sep->se_server = newstr(skip(&cp));
+ if (strcmp(sep->se_server, "internal") == 0) {
+ register struct biltin *bi;
+
+ for (bi = biltins; bi->bi_service; bi++)
+ if (bi->bi_socktype == sep->se_socktype &&
+ strcmp(bi->bi_service, sep->se_service) == 0)
+ break;
+ if (bi->bi_service == 0) {
+ syslog(LOG_ERR, "internal service %s unknown\n",
+ sep->se_service);
+ goto more;
+ }
+ sep->se_bi = bi;
+ sep->se_wait = bi->bi_wait;
+ } else
+ sep->se_bi = NULL;
+ argc = 0;
+ for (arg = skip(&cp); cp; arg = skip(&cp)) {
+#if MULOG
+ char *colon, *rindex();
+
+ if (argc == 0 && (colon = rindex(arg, ':'))) {
+ while (arg < colon) {
+ int x;
+ char *ccp;
+
+ switch (*arg++) {
+ case 'l':
+ x = 1;
+ if (isdigit(*arg)) {
+ x = strtol(arg, &ccp, 0);
+ if (ccp == arg)
+ break;
+ arg = ccp;
+ }
+ sep->se_log &= ~MULOG_RFC931;
+ sep->se_log |= x;
+ break;
+ case 'a':
+ sep->se_log |= MULOG_RFC931;
+ break;
+ default:
+ break;
+ }
+ }
+ arg = colon + 1;
+ }
+#endif
+ if (argc < MAXARGV)
+ sep->se_argv[argc++] = newstr(arg);
+ }
+ while (argc <= MAXARGV)
+ sep->se_argv[argc++] = NULL;
+ return (sep);
+}
+
+freeconfig(cp)
+ register struct servtab *cp;
+{
+ int i;
+
+ if (cp->se_service)
+ free(cp->se_service);
+ if (cp->se_proto)
+ free(cp->se_proto);
+ if (cp->se_user)
+ free(cp->se_user);
+ /* Note: se_group is part of the newstr'ed se_user */
+ if (cp->se_server)
+ free(cp->se_server);
+ for (i = 0; i < MAXARGV; i++)
+ if (cp->se_argv[i])
+ free(cp->se_argv[i]);
+}
+
+char *
+skip(cpp)
+ char **cpp;
+{
+ register char *cp = *cpp;
+ char *start;
+
+ if (*cpp == NULL)
+ return ((char *)0);
+
+again:
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0') {
+ int c;
+
+ c = getc(fconfig);
+ (void) ungetc(c, fconfig);
+ if (c == ' ' || c == '\t')
+ if (cp = nextline(fconfig))
+ goto again;
+ *cpp = (char *)0;
+ return ((char *)0);
+ }
+ start = cp;
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ if (*cp != '\0')
+ *cp++ = '\0';
+ *cpp = cp;
+ return (start);
+}
+
+char *
+nextline(fd)
+ FILE *fd;
+{
+ char *cp;
+
+ if (fgets(line, sizeof (line), fd) == NULL)
+ return ((char *)0);
+ cp = index(line, '\n');
+ if (cp)
+ *cp = '\0';
+ return (line);
+}
+
+char *
+newstr(cp)
+ char *cp;
+{
+ if (cp = strdup(cp ? cp : ""))
+ return(cp);
+ syslog(LOG_ERR, "strdup: %m");
+ exit(-1);
+}
+
+inetd_setproctitle(a, s)
+ char *a;
+ int s;
+{
+ int size;
+ register char *cp;
+ struct sockaddr_in sin;
+ char buf[80];
+
+ cp = Argv[0];
+ size = sizeof(sin);
+ if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
+ (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
+ else
+ (void) sprintf(buf, "-%s", a);
+ strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = ' ';
+}
+
+logpid()
+{
+ FILE *fp;
+
+ if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
+ fprintf(fp, "%u\n", getpid());
+ (void)fclose(fp);
+ }
+}
+
+bump_nofile()
+{
+#ifdef RLIMIT_NOFILE
+
+#define FD_CHUNK 32
+
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
+ syslog(LOG_ERR, "getrlimit: %m");
+ return -1;
+ }
+ rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
+ if (rl.rlim_cur <= rlim_ofile_cur) {
+ syslog(LOG_ERR,
+ "bump_nofile: cannot extend file limit, max = %d",
+ rl.rlim_cur);
+ return -1;
+ }
+
+ if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
+ syslog(LOG_ERR, "setrlimit: %m");
+ return -1;
+ }
+
+ rlim_ofile_cur = rl.rlim_cur;
+ return 0;
+
+#else
+ syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
+ return -1;
+#endif
+}
+
+/*
+ * Internet services provided internally by inetd:
+ */
+#define BUFSIZE 4096
+
+/* ARGSUSED */
+echo_stream(s, sep) /* Echo service -- echo data back */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+ int i;
+
+ inetd_setproctitle(sep->se_service, s);
+ while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
+ write(s, buffer, i) > 0)
+ ;
+ exit(0);
+}
+
+/* ARGSUSED */
+echo_dg(s, sep) /* Echo service -- echo data back */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+ int i, size;
+ struct sockaddr sa;
+
+ size = sizeof(sa);
+ if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
+ return;
+ (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
+}
+
+/* ARGSUSED */
+discard_stream(s, sep) /* Discard service -- ignore data */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+
+ inetd_setproctitle(sep->se_service, s);
+ while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
+ errno == EINTR)
+ ;
+ exit(0);
+}
+
+/* ARGSUSED */
+discard_dg(s, sep) /* Discard service -- ignore data */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+
+ (void) read(s, buffer, sizeof(buffer));
+}
+
+#include <ctype.h>
+#define LINESIZ 72
+char ring[128];
+char *endring;
+
+initring()
+{
+ register int i;
+
+ endring = ring;
+
+ for (i = 0; i <= 128; ++i)
+ if (isprint(i))
+ *endring++ = i;
+}
+
+/* ARGSUSED */
+chargen_stream(s, sep) /* Character generator */
+ int s;
+ struct servtab *sep;
+{
+ register char *rs;
+ int len;
+ char text[LINESIZ+2];
+
+ inetd_setproctitle(sep->se_service, s);
+
+ if (!endring) {
+ initring();
+ rs = ring;
+ }
+
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+ for (rs = ring;;) {
+ if ((len = endring - rs) >= LINESIZ)
+ bcopy(rs, text, LINESIZ);
+ else {
+ bcopy(rs, text, len);
+ bcopy(ring, text + len, LINESIZ - len);
+ }
+ if (++rs == endring)
+ rs = ring;
+ if (write(s, text, sizeof(text)) != sizeof(text))
+ break;
+ }
+ exit(0);
+}
+
+/* ARGSUSED */
+chargen_dg(s, sep) /* Character generator */
+ int s;
+ struct servtab *sep;
+{
+ struct sockaddr sa;
+ static char *rs;
+ int len, size;
+ char text[LINESIZ+2];
+
+ if (endring == 0) {
+ initring();
+ rs = ring;
+ }
+
+ size = sizeof(sa);
+ if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
+ return;
+
+ if ((len = endring - rs) >= LINESIZ)
+ bcopy(rs, text, LINESIZ);
+ else {
+ bcopy(rs, text, len);
+ bcopy(ring, text + len, LINESIZ - len);
+ }
+ if (++rs == endring)
+ rs = ring;
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+ (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
+}
+
+/*
+ * Return a machine readable date and time, in the form of the
+ * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
+ * returns the number of seconds since midnight, Jan 1, 1970,
+ * we must add 2208988800 seconds to this figure to make up for
+ * some seventy years Bell Labs was asleep.
+ */
+
+long
+machtime()
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, (struct timezone *)0) < 0) {
+ fprintf(stderr, "Unable to get time of day\n");
+ return (0L);
+ }
+ return (htonl((long)tv.tv_sec + 2208988800UL));
+}
+
+/* ARGSUSED */
+machtime_stream(s, sep)
+ int s;
+ struct servtab *sep;
+{
+ long result;
+
+ result = machtime();
+ (void) write(s, (char *) &result, sizeof(result));
+}
+
+/* ARGSUSED */
+machtime_dg(s, sep)
+ int s;
+ struct servtab *sep;
+{
+ long result;
+ struct sockaddr sa;
+ int size;
+
+ size = sizeof(sa);
+ if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
+ return;
+ result = machtime();
+ (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
+}
+
+/* ARGSUSED */
+daytime_stream(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t time(), clock;
+
+ clock = time((time_t *) 0);
+
+ (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
+ (void) write(s, buffer, strlen(buffer));
+}
+
+/* ARGSUSED */
+daytime_dg(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t time(), clock;
+ struct sockaddr sa;
+ int size;
+
+ clock = time((time_t *) 0);
+
+ size = sizeof(sa);
+ if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
+ return;
+ (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
+ (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
+}
+
+/*
+ * print_service:
+ * Dump relevant information to stderr
+ */
+print_service(action, sep)
+ char *action;
+ struct servtab *sep;
+{
+ if (isrpcservice(sep))
+ fprintf(stderr,
+ "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
+ action, sep->se_service,
+ sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
+ sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
+ (long)sep->se_bi, sep->se_server);
+ else
+ fprintf(stderr,
+ "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
+ action, sep->se_service, sep->se_proto,
+ sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
+ (long)sep->se_bi, sep->se_server);
+}
+
+#ifdef MULOG
+dolog(sep, ctrl)
+ struct servtab *sep;
+ int ctrl;
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
+ int len = sizeof(sa);
+ struct hostent *hp;
+ char *host, *dp, buf[BUFSIZ], *rfc931_name();
+ int connected = 1;
+
+ if (sep->se_family != AF_INET)
+ return;
+
+ if (getpeername(ctrl, &sa, &len) < 0) {
+ if (errno != ENOTCONN) {
+ syslog(LOG_ERR, "getpeername: %m");
+ return;
+ }
+ if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ return;
+ }
+ connected = 0;
+ }
+ if (sa.sa_family != AF_INET) {
+ syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
+ return;
+ }
+
+ hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
+ sizeof (sin->sin_addr.s_addr), AF_INET);
+
+ host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
+
+ switch (sep->se_log & ~MULOG_RFC931) {
+ case 0:
+ return;
+ case 1:
+ if (curdom == NULL || *curdom == '\0')
+ break;
+ dp = host + strlen(host) - strlen(curdom);
+ if (dp < host)
+ break;
+ if (debug)
+ fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
+ host, curdom);
+ if (strcasecmp(dp, curdom) == 0)
+ return;
+ break;
+ case 2:
+ default:
+ break;
+ }
+
+ openlog("", LOG_NOWAIT, MULOG);
+
+ if (connected && (sep->se_log & MULOG_RFC931))
+ syslog(LOG_INFO, "%s@%s wants %s",
+ rfc931_name(sin, ctrl), host, sep->se_service);
+ else
+ syslog(LOG_INFO, "%s wants %s",
+ host, sep->se_service);
+}
+/*
+ * From tcp_log by
+ * Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+#if 0
+static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
+#endif
+
+#include <setjmp.h>
+
+#define RFC931_PORT 113 /* Semi-well-known port */
+#define TIMEOUT 4
+#define TIMEOUT2 10
+
+static jmp_buf timebuf;
+
+/* timeout - handle timeouts */
+
+static void timeout(sig)
+int sig;
+{
+ longjmp(timebuf, sig);
+}
+
+/* rfc931_name - return remote user name */
+
+char *
+rfc931_name(there, ctrl)
+struct sockaddr_in *there; /* remote link information */
+int ctrl;
+{
+ struct sockaddr_in here; /* local link information */
+ struct sockaddr_in sin; /* for talking to RFC931 daemon */
+ int length;
+ int s;
+ unsigned remote;
+ unsigned local;
+ static char user[256]; /* XXX */
+ char buf[256];
+ char *cp;
+ char *result = "USER_UNKNOWN";
+ int len;
+
+ /* Find out local port number of our stdin. */
+
+ length = sizeof(here);
+ if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
+ syslog(LOG_ERR, "getsockname: %m");
+ return (result);
+ }
+ /* Set up timer so we won't get stuck. */
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ syslog(LOG_ERR, "socket: %m");
+ return (result);
+ }
+
+ sin = here;
+ sin.sin_port = htons(0);
+ if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
+ syslog(LOG_ERR, "bind: %m");
+ return (result);
+ }
+
+ signal(SIGALRM, timeout);
+ if (setjmp(timebuf)) {
+ close(s); /* not: fclose(fp) */
+ return (result);
+ }
+ alarm(TIMEOUT);
+
+ /* Connect to the RFC931 daemon. */
+
+ sin = *there;
+ sin.sin_port = htons(RFC931_PORT);
+ if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
+ close(s);
+ alarm(0);
+ return (result);
+ }
+
+ /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
+ sprintf(buf, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port));
+
+
+ for (len = 0, cp = buf; len < strlen(buf); ) {
+ int n;
+ if ((n = write(s, cp, strlen(buf) - len)) == -1) {
+ close(s);
+ alarm(0);
+ return (result);
+ }
+ cp += n;
+ len += n;
+ }
+
+ /* Read response */
+ for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
+ char c;
+ if (read(s, &c, 1) != 1) {
+ close(s);
+ alarm(0);
+ return (result);
+ }
+ if (c == '\n')
+ break;
+ *cp++ = c;
+ }
+ *cp = '\0';
+
+ if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
+ && ntohs(there->sin_port) == remote
+ && ntohs(here.sin_port) == local) {
+
+ /* Strip trailing carriage return. */
+ if (cp = strchr(user, '\r'))
+ *cp = 0;
+ result = user;
+ }
+
+ alarm(0);
+ close(s);
+ return (result);
+}
+#endif
diff --git a/usr.sbin/inetd/pathnames.h b/usr.sbin/inetd/pathnames.h
new file mode 100644
index 00000000000..c6550548194
--- /dev/null
+++ b/usr.sbin/inetd/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989 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.
+ *
+ * from: @(#)pathnames.h 5.3 (Berkeley) 6/1/90
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:37 deraadt Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_INETDCONF "/etc/inetd.conf"
+#define _PATH_INETDPID "/var/run/inetd.pid"
diff --git a/usr.sbin/iostat/Makefile b/usr.sbin/iostat/Makefile
new file mode 100644
index 00000000000..20ebf133c8f
--- /dev/null
+++ b/usr.sbin/iostat/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= iostat
+.if (${MACHINE_ARCH} == "m68k")
+CFLAGS+=-D${MACHINE} -I${.CURDIR}/../../sys/arch
+.endif
+CFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat
+MAN= iostat.8
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/iostat/iostat.8 b/usr.sbin/iostat/iostat.8
new file mode 100644
index 00000000000..b2c56cc440f
--- /dev/null
+++ b/usr.sbin/iostat/iostat.8
@@ -0,0 +1,143 @@
+.\" Copyright (c) 1985, 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.
+.\"
+.\" from: @(#)iostat.8 8.1 (Berkeley) 6/6/93
+.\" $Id: iostat.8,v 1.1.1.1 1995/10/18 08:47:37 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt IOSTAT 8
+.Os BSD 4
+.Sh NAME
+.Nm iostat
+.Nd report
+.Tn I/O
+statistics
+.Sh SYNOPSIS
+.Nm iostat
+.Op Fl c Ar count
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl w Ar wait
+.Op Ar drives
+.Sh DESCRIPTION
+.Nm Iostat
+displays kernel
+.Tn I/O
+statistics on terminal, disk and cpu
+operations.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl c
+Repeat the display
+.Ar count
+times.
+The first display is for the time since a reboot and each subsequent
+report is for the time period since the last display.
+If no
+.Ar wait
+interval is specified, the default is 1 second.
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default
+.Dq Pa /dev/kmem .
+.It Fl N
+Extract the name list from the specified system instead of the default
+.Dq Pa /netbsd .
+.It Fl w
+Pause
+.Ar wait
+seconds between each display.
+If no repeat
+.Ar count
+is specified, the default is infinity.
+.El
+.Pp
+.Nm Iostat
+displays its information in the following format:
+.Bl -tag -width flag
+.It tty
+.Bl -tag -width indent -compact
+.It tin
+characters read from terminals
+.It tout
+characters written to terminals
+.El
+.It disks
+Disk operations (this field is system dependent).
+The header of the field is the disk name and unit number.
+If more than four disk drives are configured in the system,
+.Nm iostat
+displays only the first four drives.
+To force
+.Nm iostat
+to display specific drives, their names may be supplied on the command
+line.
+.Pp
+.Bl -tag -width indent -compact
+.It sps
+sectors transferred per second
+.It tps
+transfers per second
+.It msps
+milliseconds per average seek (including implied
+seeks and rotational latency)
+.El
+.It cpu
+.Bl -tag -width indent -compact
+.It \&us
+% of cpu time in user mode
+.It \&ni
+% of cpu time in user mode running niced processes
+.It \&sy
+% of cpu time in system mode
+.It \&id
+% of cpu time in idle mode
+.El
+.El
+.Sh FILES
+.Bl -tag -width /dev/kmem -compact
+.It Pa /netbsd
+Default kernel namelist.
+.It Pa /dev/kmem
+Default memory file.
+.El
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr netstat 1 ,
+.Xr nfsstat 1 ,
+.Xr \&ps 1 ,
+.Xr systat 1 ,
+.Xr pstat 8 ,
+.Xr vmstat 8
+.Pp
+The sections starting with ``Interpreting system activity'' in
+.%T "Installing and Operating 4.3BSD" .
diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c
new file mode 100644
index 00000000000..deaaaf600da
--- /dev/null
+++ b/usr.sbin/iostat/iostat.c
@@ -0,0 +1,392 @@
+/*-
+ * Copyright (c) 1986, 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1986, 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/* from: static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94"; */
+static char *rcsid = "$Id: iostat.c,v 1.1.1.1 1995/10/18 08:47:37 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/dkstat.h>
+
+#include <err.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct nlist namelist[] = {
+#define X_DK_TIME 0
+ { "_dk_time" },
+#define X_DK_XFER 1
+ { "_dk_xfer" },
+#define X_DK_WDS 2
+ { "_dk_wds" },
+#define X_TK_NIN 3
+ { "_tk_nin" },
+#define X_TK_NOUT 4
+ { "_tk_nout" },
+#define X_DK_SEEK 5
+ { "_dk_seek" },
+#define X_CP_TIME 6
+ { "_cp_time" },
+#define X_DK_WPMS 7
+ { "_dk_wpms" },
+#define X_HZ 8
+ { "_hz" },
+#define X_STATHZ 9
+ { "_stathz" },
+#define X_DK_NDRIVE 10
+ { "_dk_ndrive" },
+#define X_END 10
+#if defined(hp300) || defined(luna68k)
+#define X_HPDINIT (X_END+1)
+ { "_hp_dinit" },
+#endif
+#ifdef mips
+#define X_SCSI_DINIT (X_END+1)
+ { "_scsi_dinit" },
+#endif
+#ifdef tahoe
+#define X_VBDINIT (X_END+1)
+ { "_vbdinit" },
+#endif
+#ifdef vax
+ { "_mbdinit" },
+#define X_MBDINIT (X_END+1)
+ { "_ubdinit" },
+#define X_UBDINIT (X_END+2)
+#endif
+ { NULL },
+};
+
+struct _disk {
+ long cp_time[CPUSTATES];
+ long *dk_time;
+ long *dk_wds;
+ long *dk_seek;
+ long *dk_xfer;
+ long tk_nin;
+ long tk_nout;
+} cur, last;
+
+kvm_t *kd;
+double etime;
+long *dk_wpms;
+int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
+char **dr_name;
+
+#define nlread(x, v) \
+ kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
+
+#include "names.c" /* XXX */
+
+void cpustats __P((void));
+void dkstats __P((void));
+void phdr __P((int));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ long tmp;
+ int ch, hdrcnt, reps, interval, stathz, ndrives;
+ char **cp, *memf, *nlistf, buf[30];
+ char errbuf[_POSIX2_LINE_MAX];
+
+ interval = reps = 0;
+ nlistf = memf = NULL;
+ while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
+ switch(ch) {
+ case 'c':
+ if ((reps = atoi(optarg)) <= 0)
+ errx(1, "repetition count <= 0.");
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'w':
+ if ((interval = atoi(optarg)) <= 0)
+ errx(1, "interval <= 0.");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ setgid(getgid());
+
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "kvm_openfiles: %s", errbuf);
+ if (kvm_nlist(kd, namelist) == -1)
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+ if (namelist[X_DK_NDRIVE].n_type == 0)
+ errx(1, "dk_ndrive not found in namelist");
+ (void)nlread(X_DK_NDRIVE, dk_ndrive);
+ if (dk_ndrive <= 0)
+ errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
+
+ cur.dk_time = calloc(dk_ndrive, sizeof(long));
+ cur.dk_wds = calloc(dk_ndrive, sizeof(long));
+ cur.dk_seek = calloc(dk_ndrive, sizeof(long));
+ cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
+ last.dk_time = calloc(dk_ndrive, sizeof(long));
+ last.dk_wds = calloc(dk_ndrive, sizeof(long));
+ last.dk_seek = calloc(dk_ndrive, sizeof(long));
+ last.dk_xfer = calloc(dk_ndrive, sizeof(long));
+ dr_select = calloc(dk_ndrive, sizeof(int));
+ dr_name = calloc(dk_ndrive, sizeof(char *));
+ dk_wpms = calloc(dk_ndrive, sizeof(long));
+
+ for (i = 0; i < dk_ndrive; i++) {
+ (void)sprintf(buf, "dk%d", i);
+ dr_name[i] = strdup(buf);
+ }
+ if (!read_names())
+ exit(1);
+ (void)nlread(X_HZ, hz);
+ (void)nlread(X_STATHZ, stathz);
+ if (stathz)
+ hz = stathz;
+ (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
+ dk_ndrive * sizeof(dk_wpms));
+
+ /*
+ * Choose drives to be displayed. Priority goes to (in order) drives
+ * supplied as arguments and default drives. If everything isn't
+ * filled in and there are drives not taken care of, display the first
+ * few that fit.
+ *
+ * The backward compatibility #ifdefs permit the syntax:
+ * iostat [ drives ] [ interval [ count ] ]
+ */
+#define BACKWARD_COMPATIBILITY
+ for (ndrives = 0; *argv; ++argv) {
+#ifdef BACKWARD_COMPATIBILITY
+ if (isdigit(**argv))
+ break;
+#endif
+ for (i = 0; i < dk_ndrive; i++) {
+ if (strcmp(dr_name[i], *argv))
+ continue;
+ dr_select[i] = 1;
+ ++ndrives;
+ }
+ }
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ interval = atoi(*argv);
+ if (*++argv)
+ reps = atoi(*argv);
+ }
+#endif
+
+ if (interval) {
+ if (!reps)
+ reps = -1;
+ } else
+ if (reps)
+ interval = 1;
+
+ for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
+ if (dr_select[i] || dk_wpms[i] == 0)
+ continue;
+ for (cp = defdrives; *cp; cp++)
+ if (strcmp(dr_name[i], *cp) == 0) {
+ dr_select[i] = 1;
+ ++ndrives;
+ break;
+ }
+ }
+ for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
+ if (dr_select[i])
+ continue;
+ dr_select[i] = 1;
+ ++ndrives;
+ }
+
+ (void)signal(SIGCONT, phdr);
+
+ for (hdrcnt = 1;;) {
+ if (!--hdrcnt) {
+ phdr(0);
+ hdrcnt = 20;
+ }
+ (void)kvm_read(kd, namelist[X_DK_TIME].n_value,
+ cur.dk_time, dk_ndrive * sizeof(long));
+ (void)kvm_read(kd, namelist[X_DK_XFER].n_value,
+ cur.dk_xfer, dk_ndrive * sizeof(long));
+ (void)kvm_read(kd, namelist[X_DK_WDS].n_value,
+ cur.dk_wds, dk_ndrive * sizeof(long));
+ (void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
+ cur.dk_seek, dk_ndrive * sizeof(long));
+ (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
+ &cur.tk_nin, sizeof(cur.tk_nin));
+ (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
+ &cur.tk_nout, sizeof(cur.tk_nout));
+ (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
+ cur.cp_time, sizeof(cur.cp_time));
+ for (i = 0; i < dk_ndrive; i++) {
+ if (!dr_select[i])
+ continue;
+#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
+ X(dk_xfer);
+ X(dk_seek);
+ X(dk_wds);
+ X(dk_time);
+ }
+ tmp = cur.tk_nin;
+ cur.tk_nin -= last.tk_nin;
+ last.tk_nin = tmp;
+ tmp = cur.tk_nout;
+ cur.tk_nout -= last.tk_nout;
+ last.tk_nout = tmp;
+ etime = 0;
+ for (i = 0; i < CPUSTATES; i++) {
+ X(cp_time);
+ etime += cur.cp_time[i];
+ }
+ if (etime == 0.0)
+ etime = 1.0;
+ etime /= (float)hz;
+ (void)printf("%4.0f%5.0f",
+ cur.tk_nin / etime, cur.tk_nout / etime);
+ dkstats();
+ cpustats();
+ (void)printf("\n");
+ (void)fflush(stdout);
+
+ if (reps >= 0 && --reps <= 0)
+ break;
+ (void)sleep(interval);
+ }
+ exit(0);
+}
+
+/* ARGUSED */
+void
+phdr(signo)
+ int signo;
+{
+ register int i;
+
+ (void)printf(" tty");
+ for (i = 0; i < dk_ndrive; i++)
+ if (dr_select[i])
+ (void)printf(" %3.3s ", dr_name[i]);
+ (void)printf(" cpu\n tin tout");
+ for (i = 0; i < dk_ndrive; i++)
+ if (dr_select[i])
+ (void)printf(" sps tps msps ");
+ (void)printf(" us ni sy in id\n");
+}
+
+void
+dkstats()
+{
+ register int dn;
+ double atime, itime, msps, words, xtime;
+
+ for (dn = 0; dn < dk_ndrive; ++dn) {
+ if (!dr_select[dn])
+ continue;
+ words = cur.dk_wds[dn] * 32; /* words xfer'd */
+ (void)printf("%4.0f", /* sectors */
+ words / (DEV_BSIZE / 2) / etime);
+
+ (void)printf("%4.0f", cur.dk_xfer[dn] / etime);
+
+ if (dk_wpms[dn] && cur.dk_xfer[dn]) {
+ atime = cur.dk_time[dn]; /* ticks disk busy */
+ atime /= (float)hz; /* ticks to seconds */
+ xtime = words / dk_wpms[dn]; /* transfer time */
+ itime = atime - xtime; /* time not xfer'ing */
+ if (itime < 0)
+ msps = 0;
+ else
+ msps = itime * 1000 / cur.dk_xfer[dn];
+ } else
+ msps = 0;
+ (void)printf("%5.1f ", msps);
+ }
+}
+
+void
+cpustats()
+{
+ register int state;
+ double time;
+
+ time = 0;
+ for (state = 0; state < CPUSTATES; ++state)
+ time += cur.cp_time[state];
+ for (state = 0; state < CPUSTATES; ++state)
+ (void)printf("%3.0f",
+ 100. * cur.cp_time[state] / (time ? time : 1));
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
+ exit(1);
+}
diff --git a/usr.sbin/iteconfig/Makefile b/usr.sbin/iteconfig/Makefile
new file mode 100644
index 00000000000..51e194c90d9
--- /dev/null
+++ b/usr.sbin/iteconfig/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.3 1995/05/12 21:04:26 leo Exp $
+
+PROG=iteconfig
+MAN= iteconfig_${MACHINE}.8
+MLINKS= iteconfig_${MACHINE}.8 iteconfig.8
+CFLAGS+=-I${.CURDIR}/../../sys/arch -D${MACHINE}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/iteconfig/iteconfig.c b/usr.sbin/iteconfig/iteconfig.c
new file mode 100644
index 00000000000..1d5238e44ed
--- /dev/null
+++ b/usr.sbin/iteconfig/iteconfig.c
@@ -0,0 +1,286 @@
+/* $NetBSD: iteconfig.c,v 1.4 1995/05/12 21:04:29 leo Exp $ */
+/*
+ * Copyright (c) 1994 Christian E. Hopps
+ * 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 Christian E. Hopps
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+
+#if !defined(amiga) && !defined(atari)
+#error "This source is not suitable for this architecture!"
+#endif
+
+#if defined(amiga)
+#include <amiga/dev/grfabs_reg.h>
+#include <amiga/dev/viewioctl.h>
+#include <amiga/dev/iteioctl.h>
+#endif /* defined(amiga) */
+
+#if defined(atari)
+#include <atari/dev/grfabs_reg.h>
+#include <atari/dev/viewioctl.h>
+#include <atari/dev/iteioctl.h>
+#endif /* defined(atari) */
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+void printcmap __P((colormap_t *, int));
+void usage __P((void));
+void xioctl __P((int, int, void *));
+colormap_t *xgetcmap __P((int, int));
+long xstrtol __P((char *));
+int initialize __P((char *, struct itewinsize *, struct itebell *,
+ struct itewinsize *, struct itebell *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct itewinsize is, newis;
+ struct itebell ib, newib;
+ struct winsize ws;
+ colormap_t *cm;
+ char *file = _PATH_CONSOLE;
+ int ch, fd, i, iflag, max_colors, did_reset;
+ long val;
+
+ iflag = 0;
+ did_reset = 0;
+
+ fd = initialize(_PATH_CONSOLE, &is, &ib, &newis, &newib);
+
+ while ((ch = getopt(argc, argv, "D:H:P:T:V:W:X:Y:d:f:h:ip:t:v:w:x:y:"))
+ != EOF) {
+ switch (ch) {
+ case 'D': /* undocumented backward compat */
+ case 'd':
+ newis.depth = xstrtol(optarg);
+ break;
+ case 'f':
+ if (did_reset)
+ break;
+ if (fd != -1)
+ close(fd);
+ file = optarg;
+ fd = initialize(optarg, &is, &ib, &newis, &newib);
+ did_reset = optreset = optind = 1;
+ break;
+ case 'H': /* undocumented backward compat */
+ case 'h':
+ newis.height = xstrtol(optarg);
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'p':
+ newib.pitch = xstrtol(optarg);
+ break;
+ case 't':
+ newib.msec = xstrtol(optarg);
+ break;
+ case 'V': /* undocumented backward compat */
+ case 'v':
+ newib.volume = xstrtol(optarg);
+ break;
+ case 'W': /* undocumented backward compat */
+ case 'w':
+ newis.width = xstrtol(optarg);
+ break;
+ case 'X': /* undocumented backward compat */
+ case 'x':
+ newis.x = xstrtol(optarg);
+ break;
+ case 'Y': /* undocumented backward compat */
+ case 'y':
+ newis.y = xstrtol(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if(fd == -1)
+ err(1, "open \"%s\"", file);
+
+ if (memcmp(&newis, &is, sizeof(is))) {
+ xioctl(fd, ITEIOCSWINSZ, &newis);
+ xioctl(fd, ITEIOCGWINSZ, &is);
+ }
+ if (memcmp(&newib, &ib, sizeof(ib))) {
+ xioctl(fd, ITEIOCSBELL, &newib);
+ xioctl(fd, ITEIOCGBELL, &ib);
+ }
+
+ /*
+ * get, set and get colors again
+ */
+ i = 0;
+ max_colors = 1 << is.depth;
+ cm = xgetcmap(fd, max_colors);
+ while (argc--) {
+ val = xstrtol(*argv++);
+ if (i >= max_colors) {
+ warnx("warning: too many colors");
+ break;
+ }
+ cm->entry[i] = val;
+ i++;
+ }
+ xioctl(fd, VIOCSCMAP, cm);
+ free(cm);
+ cm = xgetcmap(fd, max_colors);
+
+ /* do tty stuff to get it to register the changes. */
+ xioctl(fd, TIOCGWINSZ, &ws);
+
+ if (iflag) {
+ printf("tty size: rows %d cols %d\n", ws.ws_row, ws.ws_col);
+ printf("ite size: w: %d h: %d d: %d [x: %d y: %d]\n",
+ is.width, is.height, is.depth, is.x, is.y);
+ printf("ite bell: vol: %d millisec: %d pitch: %d\n",
+ ib.volume, ib.msec, ib.pitch);
+ printcmap(cm, ws.ws_col);
+ }
+ close(fd);
+ exit(0);
+}
+
+void
+xioctl(fd, cmd, addr)
+ int fd, cmd;
+ void *addr;
+{
+ if (ioctl(fd, cmd, addr) == -1)
+ err(1, "ioctl");
+}
+
+long
+xstrtol(s)
+ char *s;
+{
+ long rv;
+
+ rv = strtol(s, NULL, 0);
+ if (errno == ERANGE && (rv == LONG_MIN || rv == LONG_MAX))
+ err(1, "bad format: \"%s\"", s);
+ return(rv);
+}
+
+colormap_t *
+xgetcmap(fd, ncolors)
+ int fd;
+ int ncolors;
+{
+ colormap_t *cm;
+
+ cm = malloc(sizeof(colormap_t) + ncolors * sizeof(u_long));
+ if (cm == NULL)
+ err(1, "malloc");
+ cm->first = 0;
+ cm->size = ncolors;
+ cm->entry = (u_long *) & cm[1];
+ xioctl(fd, VIOCGCMAP, cm);
+ return(cm);
+}
+
+void
+printcmap(cm, ncols)
+ colormap_t *cm;
+ int ncols;
+{
+ int i, nel;
+
+ switch (cm->type) {
+ case CM_MONO:
+ printf("monochrome");
+ return;
+ case CM_COLOR:
+ printf("color levels: red: %d green: %d blue: %d",
+ cm->red_mask + 1, cm->green_mask + 1, cm->blue_mask + 1);
+ break;
+ case CM_GREYSCALE:
+ printf("greyscale levels: %d", cm->grey_mask + 1);
+ break;
+ }
+ printf("\n");
+
+ nel = ncols / 11 - 1;
+ for (i = 0; i < cm->size; i++) {
+ printf("0x%08lx ", cm->entry[i]);
+ if ((i + 1) % nel == 0)
+ printf("\n");
+ }
+ if ((i + 1) % nel)
+ printf("\n");
+}
+
+int
+initialize(file, is, ib, newis, newib)
+ char *file;
+ struct itewinsize *is, *newis;
+ struct itebell *ib, *newib;
+{
+ int fd;
+
+ fd = open(file, O_RDONLY | O_NONBLOCK);
+ if (fd == -1)
+ return(-1);
+
+ xioctl(fd, ITEIOCGWINSZ, is);
+ xioctl(fd, ITEIOCGBELL, ib);
+
+ memcpy(newis, is, sizeof(*is));
+ memcpy(newib, ib, sizeof(*ib));
+ return(fd);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "%s\n\t\t%s\n",
+ "usage: iteconfig [-i] [-v volume] [-p period] [-t count]",
+ "[-w width] [-h height] [-d depth] [-x off] [-y off] [color ...]");
+ exit(1);
+}
diff --git a/usr.sbin/iteconfig/iteconfig_amiga.8 b/usr.sbin/iteconfig/iteconfig_amiga.8
new file mode 100644
index 00000000000..3e2375e7895
--- /dev/null
+++ b/usr.sbin/iteconfig/iteconfig_amiga.8
@@ -0,0 +1,160 @@
+.\" $NetBSD: iteconfig_amiga.8,v 1.1 1995/05/12 21:04:30 leo Exp $
+.\"
+.\" Copyright (c) 1994 Christian E. Hopps
+.\" 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 Christian E. Hopps.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.Dd February 3, 1994
+.Dt ITECONFIG 8 amiga
+.Os
+.Sh NAME
+.Nm iteconfig
+.Nd modify console attributes at run time
+.Sh SYNOPSIS
+.Nm iteconfig
+.Op Fl i
+.Op Fl f Ar file
+.Op Fl v Ar volume
+.Op Fl p Ar pitch
+.Op Fl t Ar msec
+.Op Fl w Ar width
+.Op Fl h Ar height
+.Op Fl d Ar depth
+.Op Fl x Ar offset
+.Op Fl y Ar offset
+.Op Ar color ...
+.Sh DESCRIPTION
+.Nm Iteconfig
+is used to modify or examine the attributes of the
+.Tn Amiga's
+console bell and bitmapped console display.
+The console bell's volume, pitch, and count may be
+specified, as well as
+the bitmapped display's width, height, horizontal and
+vertical offset, pixel depth, and color map.
+.Pp
+The following flags are interpreted by
+.Nm iteconfig :
+.Bl -tag -width indent
+.It Fl i
+After processing all other arguments,
+print information about the console's state.
+.It Fl f
+Open and use the terminal named by
+.Ar file
+rather than the default console
+.Nm "/dev/ttye0".
+.It Fl v
+Set the volume of the console bell to
+.Ar volume ,
+which must be between 0 and 63, inclusive.
+.It Fl p
+Set the pitch of the console bell to
+.Ar pitch ,
+which must be between 10 and 1399.
+.It Fl t
+Set the duration of the beep to
+.Ar msec
+milliseconds which must be between 1 and 5000 (5 seconds).
+.It Fl w
+Set the width of the console display to
+.Ar width
+pixel columns.
+.Ar Width
+must be a positive integer.
+.It Fl h
+Set the height of the console display to
+.Ar height
+pixel rows.
+.Ar Height
+must be a positive integer.
+.It Fl d
+Set the number of bitplanes the console view should use to
+.Ar depth .
+For example, if
+.Ar depth
+is 3 then 8 colors will be used.
+.It Fl x
+Set the horizontal offset of the console view on the monitor to
+.Ar offset
+pixel columns. The horizontal offset may be a positive or a
+negative integer, positive being an offset to the right, negative
+to the left.
+.It Fl y
+Set the vertical offset of the console view on the monitor to
+.Ar offset
+pixel rows. The vertical offset may be a positive or a negative
+integer, positive being an offset down, negative up.
+.El
+.Pp
+Any additional arguments will be interpreted as colors and will
+be used to supply the color values for the console view's
+color map, starting with the first entry in the map. (See the
+.Sx COLOR SPECIFICATION
+section of this manual page for information on how to specify
+colors.)
+If more colors are supplied than are usable by the console
+view, a warning is printed and the extra colors are ignored.
+.Sh COLOR SPECIFICATION
+Colors are hexidecimal numbers which have one of the following
+formats:
+.Bl -tag -width "0xRRGGBB"
+.It Ar 0xRRGGBB
+.Ar RR ,
+.Ar GG ,
+and
+.Ar BB
+are taken to be eight-bit values specifying the
+intensities of the red, green and blue components, respectively,
+of the color to be used. For example,
+.Li 0xff0000
+is bright red,
+.Li 0xffffff
+is white, and
+.Li 0x008080
+is dark cyan.
+.It Ar 0xGG
+.Ar GG
+is taken to be an eight-bit value specifying the intensity
+of grey to be used. A value of
+.Li 0x00
+is black, a value of
+.Li 0xff
+is white, and a value of
+.Li 0x80
+is a grey
+approximately half way in between.
+.It Ar 0xM
+.Ar M
+is taken to be the one-bit monochrome value to be used.
+A value of
+.Li 0x1
+is black, and a value of
+.Li 0x0
+is white.
+.El
diff --git a/usr.sbin/iteconfig/iteconfig_atari.8 b/usr.sbin/iteconfig/iteconfig_atari.8
new file mode 100644
index 00000000000..196c48aa6de
--- /dev/null
+++ b/usr.sbin/iteconfig/iteconfig_atari.8
@@ -0,0 +1,160 @@
+.\" $NetBSD: iteconfig_atari.8,v 1.1 1995/05/12 21:04:31 leo Exp $
+.\"
+.\" Copyright (c) 1994 Christian E. Hopps
+.\" 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 Christian E. Hopps.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.Dd April 15, 1995
+.Dt ITECONFIG 8 atari
+.Os
+.Sh NAME
+.Nm iteconfig
+.Nd modify console attributes at run time
+.Sh SYNOPSIS
+.Nm iteconfig
+.Op Fl i
+.Op Fl f Ar file
+.Op Fl v Ar volume
+.Op Fl p Ar pitch
+.Op Fl t Ar msec
+.Op Fl w Ar width
+.Op Fl h Ar height
+.Op Fl d Ar depth
+.Op Fl x Ar offset
+.Op Fl y Ar offset
+.Op Ar color ...
+.Sh DESCRIPTION
+.Nm Iteconfig
+is used to modify or examine the attributes of the
+.Tn Atari's
+console bell and bitmapped console display.
+The console bell's volume, pitch, and count may be
+specified, as well as
+the bitmapped display's width, height, horizontal and
+vertical offset, pixel depth, and color map.
+.Pp
+The following flags are interpreted by
+.Nm iteconfig :
+.Bl -tag -width indent
+.It Fl i
+After processing all other arguments,
+print information about the console's state.
+.It Fl f
+Open and use the terminal named by
+.Ar file
+rather than the default console
+.Nm "/dev/ttye0".
+.It Fl v
+Set the volume of the console bell to
+.Ar volume ,
+which must be between 0 and 63, inclusive.
+.It Fl p
+Set the pitch of the console bell to
+.Ar pitch ,
+which must be between 10 and 1399.
+.It Fl t
+Set the duration of the beep to
+.Ar msec
+milliseconds which must be between 1 and 5000 (5 seconds).
+.It Fl w
+Set the width of the console display to
+.Ar width
+pixel columns.
+.Ar Width
+must be a positive integer.
+.It Fl h
+Set the height of the console display to
+.Ar height
+pixel rows.
+.Ar Height
+must be a positive integer.
+.It Fl d
+Set the number of bitplanes the console view should use to
+.Ar depth .
+For example, if
+.Ar depth
+is 3 then 8 colors will be used.
+.It Fl x
+Set the horizontal offset of the console view on the monitor to
+.Ar offset
+pixel columns. The horizontal offset may be a positive or a
+negative integer, positive being an offset to the right, negative
+to the left.
+.It Fl y
+Set the vertical offset of the console view on the monitor to
+.Ar offset
+pixel rows. The vertical offset may be a positive or a negative
+integer, positive being an offset down, negative up.
+.El
+.Pp
+Any additional arguments will be interpreted as colors and will
+be used to supply the color values for the console view's
+color map, starting with the first entry in the map. (See the
+.Sx COLOR SPECIFICATION
+section of this manual page for information on how to specify
+colors.)
+If more colors are supplied than are usable by the console
+view, a warning is printed and the extra colors are ignored.
+.Sh COLOR SPECIFICATION
+Colors are hexidecimal numbers which have one of the following
+formats:
+.Bl -tag -width "0xRRGGBB"
+.It Ar 0xRRGGBB
+.Ar RR ,
+.Ar GG ,
+and
+.Ar BB
+are taken to be eight-bit values specifying the
+intensities of the red, green and blue components, respectively,
+of the color to be used. For example,
+.Li 0xff0000
+is bright red,
+.Li 0xffffff
+is white, and
+.Li 0x008080
+is dark cyan.
+.It Ar 0xGG
+.Ar GG
+is taken to be an eight-bit value specifying the intensity
+of grey to be used. A value of
+.Li 0x00
+is black, a value of
+.Li 0xff
+is white, and a value of
+.Li 0x80
+is a grey
+approximately half way in between.
+.It Ar 0xM
+.Ar M
+is taken to be the one-bit monochrome value to be used.
+A value of
+.Li 0x1
+is black, and a value of
+.Li 0x0
+is white.
+.El
diff --git a/usr.sbin/iteconfig/pathnames.h b/usr.sbin/iteconfig/pathnames.h
new file mode 100644
index 00000000000..bbea95190dd
--- /dev/null
+++ b/usr.sbin/iteconfig/pathnames.h
@@ -0,0 +1,35 @@
+/* $NetBSD: pathnames.h,v 1.3 1995/05/12 21:04:32 leo Exp $ */
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#if defined(amiga) || defined(atari)
+#define _PATH_CONSOLE "/dev/ttye0"
+#endif
diff --git a/usr.sbin/kgmon/Makefile b/usr.sbin/kgmon/Makefile
new file mode 100644
index 00000000000..93c5e9322f5
--- /dev/null
+++ b/usr.sbin/kgmon/Makefile
@@ -0,0 +1,15 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:38 deraadt Exp $
+
+PROG= kgmon
+MAN= kgmon.8
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+#
+# This program may safely be run setuid-root to allow non-root
+# users to start, stop, and reset profiling buffers.
+#
+#BINOWN=root
+#BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/kgmon/kgmon.8 b/usr.sbin/kgmon/kgmon.8
new file mode 100644
index 00000000000..e1596d9e435
--- /dev/null
+++ b/usr.sbin/kgmon/kgmon.8
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" from: @(#)kgmon.8 8.1 (Berkeley) 6/6/93
+.\" $Id: kgmon.8,v 1.1.1.1 1995/10/18 08:47:38 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt KGMON 8
+.Os BSD 4.2
+.Sh NAME
+.Nm kgmon
+.Nd generate a dump of the operating system's profile buffers
+.Sh SYNOPSIS
+.Nm kgmon
+.Op Fl bhpr
+.Op Fl M core
+.Op Fl N system
+.Sh DESCRIPTION
+.Nm Kgmon
+is a tool used when profiling the operating system.
+When no arguments are supplied,
+.Nm kgmon
+indicates the state of operating system profiling as running,
+off, or not configured.
+(see
+.Xr config 8 )
+If the
+.Fl p
+flag is specified,
+.Nm kgmon
+extracts profile data from the operating system and produces a
+.Pa gmon.out
+file suitable for later analysis by
+.Xr gprof 1 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b
+Resume the collection of profile data.
+.It Fl h
+Stop the collection of profile data.
+.It Fl p
+Dump the contents of the profile buffers into a
+.Pa gmon.out
+file.
+.It Fl r
+Reset all the profile buffers.
+If the
+.Fl p
+flag is also specified, the
+.Pa gmon.out
+file is generated before the buffers are reset.
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default ``/dev/kmem''.
+.It Fl N
+Extract the name list from the specified system instead of the
+default ``/netbsd''.
+.El
+.Pp
+If neither
+.Fl b
+nor
+.Fl h
+is specified, the state of profiling collection remains unchanged.
+For example, if the
+.Fl p
+flag is specified and profile data is being collected,
+profiling will be momentarily suspended,
+the operating system profile buffers will be dumped,
+and profiling will be immediately resumed.
+.Sh FILES
+.Bl -tag -width /dev/kmemx -compact
+.It Pa /netbsd
+the default system
+.It Pa /dev/kmem
+the default memory
+.El
+.Sh SEE ALSO
+.Xr gprof 1 ,
+.Xr config 8
+.Sh DIAGNOSTICS
+Users with only read permission on
+.Pa /dev/kmem
+cannot change the state
+of profiling collection.
+They can get a
+.Pa gmon.out
+file with the warning that the data may be
+inconsistent if profiling is in progress.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/kgmon/kgmon.c b/usr.sbin/kgmon/kgmon.c
new file mode 100644
index 00000000000..a7e08d790a6
--- /dev/null
+++ b/usr.sbin/kgmon/kgmon.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 1983, 1992, 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) 1983, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)kgmon.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: kgmon.c,v 1.1.1.1 1995/10/18 08:47:38 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/sysctl.h>
+#include <sys/gmon.h>
+#include <errno.h>
+#include <kvm.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <nlist.h>
+#include <ctype.h>
+#include <paths.h>
+
+struct nlist nl[] = {
+#define N_GMONPARAM 0
+ { "__gmonparam" },
+#define N_PROFHZ 1
+ { "_profhz" },
+ 0,
+};
+
+struct kvmvars {
+ kvm_t *kd;
+ struct gmonparam gpm;
+};
+
+int bflag, hflag, kflag, rflag, pflag;
+int debug = 0;
+void setprof __P((struct kvmvars *kvp, int state));
+void dumpstate __P((struct kvmvars *kvp));
+void reset __P((struct kvmvars *kvp));
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, mode, disp, accessmode;
+ struct kvmvars kvmvars;
+ char *system, *kmemf;
+
+ seteuid(getuid());
+ kmemf = NULL;
+ system = NULL;
+ while ((ch = getopt(argc, argv, "M:N:bhpr")) != EOF) {
+ switch((char)ch) {
+
+ case 'M':
+ kmemf = optarg;
+ kflag = 1;
+ break;
+
+ case 'N':
+ system = optarg;
+ break;
+
+ case 'b':
+ bflag = 1;
+ break;
+
+ case 'h':
+ hflag = 1;
+ break;
+
+ case 'p':
+ pflag = 1;
+ break;
+
+ case 'r':
+ rflag = 1;
+ break;
+
+ default:
+ (void)fprintf(stderr,
+ "usage: kgmon [-bhrp] [-M core] [-N system]\n");
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ system = *argv;
+ if (*++argv) {
+ kmemf = *argv;
+ ++kflag;
+ }
+ }
+#endif
+ if (system == NULL)
+ system = _PATH_UNIX;
+ accessmode = openfiles(system, kmemf, &kvmvars);
+ mode = getprof(&kvmvars);
+ if (hflag)
+ disp = GMON_PROF_OFF;
+ else if (bflag)
+ disp = GMON_PROF_ON;
+ else
+ disp = mode;
+ if (pflag)
+ dumpstate(&kvmvars);
+ if (rflag)
+ reset(&kvmvars);
+ if (accessmode == O_RDWR)
+ setprof(&kvmvars, disp);
+ (void)fprintf(stdout, "kgmon: kernel profiling is %s.\n",
+ disp == GMON_PROF_OFF ? "off" : "running");
+ return (0);
+}
+
+/*
+ * Check that profiling is enabled and open any ncessary files.
+ */
+openfiles(system, kmemf, kvp)
+ char *system;
+ char *kmemf;
+ struct kvmvars *kvp;
+{
+ int mib[3], state, openmode;
+ size_t size;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ if (!kflag) {
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ mib[2] = GPROF_STATE;
+ size = sizeof state;
+ if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
+ (void)fprintf(stderr,
+ "kgmon: profiling not defined in kernel.\n");
+ exit(20);
+ }
+ if (!(bflag || hflag || rflag ||
+ (pflag && state == GMON_PROF_ON)))
+ return (O_RDONLY);
+ (void)seteuid(0);
+ if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0)
+ return (O_RDWR);
+ (void)seteuid(getuid());
+ kern_readonly(state);
+ return (O_RDONLY);
+ }
+ openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY;
+ kvp->kd = kvm_openfiles(system, kmemf, NULL, openmode, errbuf);
+ if (kvp->kd == NULL) {
+ if (openmode == O_RDWR) {
+ openmode = O_RDONLY;
+ kvp->kd = kvm_openfiles(system, kmemf, NULL, O_RDONLY,
+ errbuf);
+ }
+ if (kvp->kd == NULL) {
+ (void)fprintf(stderr, "kgmon: kvm_openfiles: %s\n",
+ errbuf);
+ exit(2);
+ }
+ kern_readonly(GMON_PROF_ON);
+ }
+ if (kvm_nlist(kvp->kd, nl) < 0) {
+ (void)fprintf(stderr, "kgmon: %s: no namelist\n", system);
+ exit(3);
+ }
+ if (!nl[N_GMONPARAM].n_value) {
+ (void)fprintf(stderr,
+ "kgmon: profiling not defined in kernel.\n");
+ exit(20);
+ }
+ return (openmode);
+}
+
+/*
+ * Suppress options that require a writable kernel.
+ */
+kern_readonly(mode)
+ int mode;
+{
+
+ (void)fprintf(stderr, "kgmon: kernel read-only: ");
+ if (pflag && mode == GMON_PROF_ON)
+ (void)fprintf(stderr, "data may be inconsistent\n");
+ if (rflag)
+ (void)fprintf(stderr, "-r supressed\n");
+ if (bflag)
+ (void)fprintf(stderr, "-b supressed\n");
+ if (hflag)
+ (void)fprintf(stderr, "-h supressed\n");
+ rflag = bflag = hflag = 0;
+}
+
+/*
+ * Get the state of kernel profiling.
+ */
+getprof(kvp)
+ struct kvmvars *kvp;
+{
+ int mib[3];
+ size_t size;
+
+ if (kflag) {
+ size = kvm_read(kvp->kd, nl[N_GMONPARAM].n_value, &kvp->gpm,
+ sizeof kvp->gpm);
+ } else {
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ mib[2] = GPROF_GMONPARAM;
+ size = sizeof kvp->gpm;
+ if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0)
+ size = 0;
+ }
+ if (size != sizeof kvp->gpm) {
+ (void)fprintf(stderr, "kgmon: cannot get gmonparam: %s\n",
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ exit (4);
+ }
+ return (kvp->gpm.state);
+}
+
+/*
+ * Enable or disable kernel profiling according to the state variable.
+ */
+void
+setprof(kvp, state)
+ struct kvmvars *kvp;
+ int state;
+{
+ struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value;
+ int mib[3], oldstate;
+ size_t sz;
+
+ sz = sizeof(state);
+ if (!kflag) {
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ mib[2] = GPROF_STATE;
+ if (sysctl(mib, 3, &oldstate, &sz, NULL, 0) < 0)
+ goto bad;
+ if (oldstate == state)
+ return;
+ (void)seteuid(0);
+ if (sysctl(mib, 3, NULL, NULL, &state, sz) >= 0) {
+ (void)seteuid(getuid());
+ return;
+ }
+ (void)seteuid(getuid());
+ } else if (kvm_write(kvp->kd, (u_long)&p->state, (void *)&state, sz)
+ == sz)
+ return;
+bad:
+ (void)fprintf(stderr, "kgmon: warning: cannot turn profiling %s\n",
+ state == GMON_PROF_OFF ? "off" : "on");
+}
+
+/*
+ * Build the gmon.out file.
+ */
+void
+dumpstate(kvp)
+ struct kvmvars *kvp;
+{
+ register FILE *fp;
+ struct rawarc rawarc;
+ struct tostruct *tos;
+ u_long frompc, addr;
+ u_short *froms, *tickbuf;
+ int mib[3];
+ size_t i;
+ struct gmonhdr h;
+ int fromindex, endfrom, toindex;
+
+ setprof(kvp, GMON_PROF_OFF);
+ fp = fopen("gmon.out", "w");
+ if (fp == 0) {
+ perror("gmon.out");
+ return;
+ }
+
+ /*
+ * Build the gmon header and write it to a file.
+ */
+ bzero(&h, sizeof(h));
+ h.lpc = kvp->gpm.lowpc;
+ h.hpc = kvp->gpm.highpc;
+ h.ncnt = kvp->gpm.kcountsize + sizeof(h);
+ h.version = GMONVERSION;
+ h.profrate = getprofhz(kvp);
+ fwrite((char *)&h, sizeof(h), 1, fp);
+
+ /*
+ * Write out the tick buffer.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ if ((tickbuf = (u_short *)malloc(kvp->gpm.kcountsize)) == NULL) {
+ fprintf(stderr, "kgmon: cannot allocate kcount space\n");
+ exit (5);
+ }
+ if (kflag) {
+ i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, (void *)tickbuf,
+ kvp->gpm.kcountsize);
+ } else {
+ mib[2] = GPROF_COUNT;
+ i = kvp->gpm.kcountsize;
+ if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0)
+ i = 0;
+ }
+ if (i != kvp->gpm.kcountsize) {
+ (void)fprintf(stderr, "kgmon: read ticks: read %u, got %d: %s",
+ kvp->gpm.kcountsize, i,
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ exit(6);
+ }
+ if ((fwrite(tickbuf, kvp->gpm.kcountsize, 1, fp)) != 1) {
+ perror("kgmon: writing tocks to gmon.out");
+ exit(7);
+ }
+ free(tickbuf);
+
+ /*
+ * Write out the arc info.
+ */
+ if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL) {
+ fprintf(stderr, "kgmon: cannot allocate froms space\n");
+ exit (8);
+ }
+ if (kflag) {
+ i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms,
+ kvp->gpm.fromssize);
+ } else {
+ mib[2] = GPROF_FROMS;
+ i = kvp->gpm.fromssize;
+ if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
+ i = 0;
+ }
+ if (i != kvp->gpm.fromssize) {
+ (void)fprintf(stderr, "kgmon: read froms: read %u, got %d: %s",
+ kvp->gpm.fromssize, i,
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ exit(9);
+ }
+ if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) == NULL) {
+ fprintf(stderr, "kgmon: cannot allocate tos space\n");
+ exit(10);
+ }
+ if (kflag) {
+ i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
+ kvp->gpm.tossize);
+ } else {
+ mib[2] = GPROF_TOS;
+ i = kvp->gpm.tossize;
+ if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
+ i = 0;
+ }
+ if (i != kvp->gpm.tossize) {
+ (void)fprintf(stderr, "kgmon: read tos: read %u, got %d: %s",
+ kvp->gpm.tossize, i,
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ exit(11);
+ }
+ if (debug)
+ (void)fprintf(stderr, "kgmon: lowpc 0x%x, textsize 0x%x\n",
+ kvp->gpm.lowpc, kvp->gpm.textsize);
+ endfrom = kvp->gpm.fromssize / sizeof(*froms);
+ for (fromindex = 0; fromindex < endfrom; ++fromindex) {
+ if (froms[fromindex] == 0)
+ continue;
+ frompc = (u_long)kvp->gpm.lowpc +
+ (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
+ for (toindex = froms[fromindex]; toindex != 0;
+ toindex = tos[toindex].link) {
+ if (debug)
+ (void)fprintf(stderr,
+ "%s: [mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
+ "kgmon", frompc, tos[toindex].selfpc,
+ tos[toindex].count);
+ rawarc.raw_frompc = frompc;
+ rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
+ rawarc.raw_count = tos[toindex].count;
+ fwrite((char *)&rawarc, sizeof(rawarc), 1, fp);
+ }
+ }
+ fclose(fp);
+}
+
+/*
+ * Get the profiling rate.
+ */
+int
+getprofhz(kvp)
+ struct kvmvars *kvp;
+{
+ int mib[2], profrate;
+ size_t size;
+ struct clockinfo clockrate;
+
+ if (kflag) {
+ profrate = 1;
+ if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
+ sizeof profrate) != sizeof profrate)
+ (void)fprintf(stderr, "kgmon: get clockrate: %s\n",
+ kvm_geterr(kvp->kd));
+ return (profrate);
+ }
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ clockrate.profhz = 1;
+ size = sizeof clockrate;
+ if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
+ (void)fprintf(stderr, "kgmon: get clockrate: %s\n",
+ strerror(errno));
+ return (clockrate.profhz);
+}
+
+/*
+ * Reset the kernel profiling date structures.
+ */
+void
+reset(kvp)
+ struct kvmvars *kvp;
+{
+ char *zbuf;
+ u_long biggest;
+ int mib[3];
+
+ setprof(kvp, GMON_PROF_OFF);
+
+ biggest = kvp->gpm.kcountsize;
+ if (kvp->gpm.fromssize > biggest)
+ biggest = kvp->gpm.fromssize;
+ if (kvp->gpm.tossize > biggest)
+ biggest = kvp->gpm.tossize;
+ if ((zbuf = (char *)malloc(biggest)) == NULL) {
+ fprintf(stderr, "kgmon: cannot allocate zbuf space\n");
+ exit(12);
+ }
+ bzero(zbuf, biggest);
+ if (kflag) {
+ if (kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
+ kvp->gpm.kcountsize) != kvp->gpm.kcountsize) {
+ (void)fprintf(stderr, "kgmon: tickbuf zero: %s\n",
+ kvm_geterr(kvp->kd));
+ exit(13);
+ }
+ if (kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
+ kvp->gpm.fromssize) != kvp->gpm.fromssize) {
+ (void)fprintf(stderr, "kgmon: froms zero: %s\n",
+ kvm_geterr(kvp->kd));
+ exit(14);
+ }
+ if (kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
+ kvp->gpm.tossize) != kvp->gpm.tossize) {
+ (void)fprintf(stderr, "kgmon: tos zero: %s\n",
+ kvm_geterr(kvp->kd));
+ exit(15);
+ }
+ return;
+ }
+ (void)seteuid(0);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ mib[2] = GPROF_COUNT;
+ if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0) {
+ (void)fprintf(stderr, "kgmon: tickbuf zero: %s\n",
+ strerror(errno));
+ exit(13);
+ }
+ mib[2] = GPROF_FROMS;
+ if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0) {
+ (void)fprintf(stderr, "kgmon: froms zero: %s\n",
+ strerror(errno));
+ exit(14);
+ }
+ mib[2] = GPROF_TOS;
+ if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0) {
+ (void)fprintf(stderr, "kgmon: tos zero: %s\n",
+ strerror(errno));
+ exit(15);
+ }
+ (void)seteuid(getuid());
+ free(zbuf);
+}
diff --git a/usr.sbin/kvm_mkdb/Makefile b/usr.sbin/kvm_mkdb/Makefile
new file mode 100644
index 00000000000..59e82da1c05
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:38 deraadt Exp $
+
+PROG= kvm_mkdb
+SRCS= kvm_mkdb.c nlist.c testdb.c
+MAN= kvm_mkdb.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/kvm_mkdb/extern.h b/usr.sbin/kvm_mkdb/extern.h
new file mode 100644
index 00000000000..dd88a591f90
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/extern.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1992, 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.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $Id: extern.h,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $
+ */
+
+void create_knlist __P((char *, DB *));
+void error __P((char *));
+int testdb __P(());
diff --git a/usr.sbin/kvm_mkdb/kvm_mkdb.8 b/usr.sbin/kvm_mkdb/kvm_mkdb.8
new file mode 100644
index 00000000000..49402c32586
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/kvm_mkdb.8
@@ -0,0 +1,70 @@
+.\" Copyright (c) 1989, 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.
+.\"
+.\" from: @(#)kvm_mkdb.8 8.1 (Berkeley) 6/9/93
+.\" $Id: kvm_mkdb.8,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $
+.\"
+.Dd June 9, 1993
+.Dt KVM_MKDB 8
+.Os
+.Sh NAME
+.Nm kvm_mkdb
+.Nd create kernel database
+.Sh SYNOPSIS
+.Nm kvm_mkdb
+.Op file
+.Sh DESCRIPTION
+.Nm Kvm_mkdb
+creates a database in
+.Pa /var/db
+containing information about the specified file.
+If no file is specified,
+.Pa /netbsd
+is used by default.
+The file is named ``kvm_filename.db'', where ``filename'' is the
+name of the file read.
+Various library routines consult this database.
+The only information currently stored is the kernel namelist, which is
+used by the
+.Xr kvm_nlist 3
+function, however, in the future the database may contain other static
+information about the current system.
+.Sh FILES
+.Bl -tag -width /var/db/kvm_netbsd.db -compact
+.It Pa /netbsd
+.It Pa /var/db/kvm_netbsd.db
+.El
+.Sh SEE ALSO
+.Xr kvm_nlist 3
+.Sh HISTORY
+The
+.Nm kvm_mkdb
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/kvm_mkdb/kvm_mkdb.c b/usr.sbin/kvm_mkdb/kvm_mkdb.c
new file mode 100644
index 00000000000..9a2c7589cd9
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/kvm_mkdb.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1990, 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) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)kvm_mkdb.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: kvm_mkdb.c,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extern.h"
+
+static void usage __P((void));
+
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 128, /* ffactor */
+ 1024, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ DB *db;
+ int ch;
+ char *p, *nlistpath, *nlistname, dbtemp[MAXPATHLEN], dbname[MAXPATHLEN];
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ /* If the existing db file matches the currently running kernel, exit */
+ if (testdb())
+ exit(0);
+
+#define basename(cp) ((p = rindex((cp), '/')) != NULL ? p + 1 : (cp))
+ nlistpath = argc > 0 ? argv[0] : _PATH_UNIX;
+ nlistname = basename(nlistpath);
+
+ (void)snprintf(dbtemp, sizeof(dbtemp), "%skvm_%s.tmp",
+ _PATH_VARDB, nlistname);
+ (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db",
+ _PATH_VARDB, nlistname);
+ (void)umask(0);
+ db = dbopen(dbtemp, O_CREAT | O_EXLOCK | O_TRUNC | O_RDWR,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, DB_HASH, &openinfo);
+ if (db == NULL)
+ err(1, "%s", dbtemp);
+ create_knlist(nlistpath, db);
+ if (db->close(db))
+ err(1, "%s", dbtemp);
+ if (rename(dbtemp, dbname))
+ err(1, "rename %s to %s", dbtemp, dbname);
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: kvm_mkdb [file]\n");
+ exit(1);
+}
diff --git a/usr.sbin/kvm_mkdb/nlist.c b/usr.sbin/kvm_mkdb/nlist.c
new file mode 100644
index 00000000000..a6738940fae
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/nlist.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 1990, 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 sccsid[] = "from: @(#)nlist.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: nlist.c,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <a.out.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+typedef struct nlist NLIST;
+#define _strx n_un.n_strx
+#define _name n_un.n_name
+
+#define badfmt(str) errx(1, "%s: %s: %s", kfile, str, strerror(EFTYPE))
+
+static void badread __P((int, char *));
+
+static char *kfile;
+
+void
+create_knlist(name, db)
+ char *name;
+ DB *db;
+{
+ register int nsyms;
+ struct exec ebuf;
+ FILE *fp;
+ NLIST nbuf;
+ DBT data, key;
+ int fd, nr, strsize;
+ char *strtab, buf[1024];
+
+ kfile = name;
+ if ((fd = open(name, O_RDONLY, 0)) < 0)
+ err(1, "%s", name);
+
+ /* Read in exec structure. */
+ nr = read(fd, &ebuf, sizeof(struct exec));
+ if (nr != sizeof(struct exec))
+ badfmt("no exec header");
+
+ /* Check magic number and symbol count. */
+ if (N_BADMAG(ebuf))
+ badfmt("bad magic number");
+ if (!ebuf.a_syms)
+ badfmt("stripped");
+
+ /* Seek to string table. */
+ if (lseek(fd, N_STROFF(ebuf), SEEK_SET) == -1)
+ badfmt("corrupted string table");
+
+ /* Read in the size of the symbol table. */
+ nr = read(fd, (char *)&strsize, sizeof(strsize));
+ if (nr != sizeof(strsize))
+ badread(nr, "no symbol table");
+
+ /* Read in the string table. */
+ strsize -= sizeof(strsize);
+ if (!(strtab = malloc(strsize)))
+ err(1, NULL);
+ if ((nr = read(fd, strtab, strsize)) != strsize)
+ badread(nr, "corrupted symbol table");
+
+ /* Seek to symbol table. */
+ if (!(fp = fdopen(fd, "r")))
+ err(1, "%s", name);
+ if (fseek(fp, N_SYMOFF(ebuf), SEEK_SET) == -1)
+ err(1, "%s", name);
+
+ data.data = (u_char *)&nbuf;
+ data.size = sizeof(NLIST);
+
+ /* Read each symbol and enter it into the database. */
+ nsyms = ebuf.a_syms / sizeof(struct nlist);
+ while (nsyms--) {
+ if (fread((char *)&nbuf, sizeof (NLIST), 1, fp) != 1) {
+ if (feof(fp))
+ badfmt("corrupted symbol table");
+ err(1, "%s", name);
+ }
+ if (!nbuf._strx || nbuf.n_type&N_STAB)
+ continue;
+
+ key.data = (u_char *)strtab + nbuf._strx - sizeof(long);
+ key.size = strlen((char *)key.data);
+ if (db->put(db, &key, &data, 0))
+ err(1, "record enter");
+
+ if (strcmp((char *)key.data, VRS_SYM) == 0) {
+ long cur_off, voff;
+#ifndef KERNTEXTOFF
+#define KERNTEXTOFF KERNBASE
+#endif
+ /*
+ * Calculate offset relative to a normal (non-kernel)
+ * a.out. KERNTEXTOFF is where the kernel is really
+ * loaded; N_TXTADDR is where a normal file is loaded.
+ * From there, locate file offset in text or data.
+ */
+ voff = nbuf.n_value - KERNTEXTOFF + N_TXTADDR(ebuf);
+ if ((nbuf.n_type & N_TYPE) == N_TEXT)
+ voff += N_TXTOFF(ebuf) - N_TXTADDR(ebuf);
+ else
+ voff += N_DATOFF(ebuf) - N_DATADDR(ebuf);
+ cur_off = ftell(fp);
+ if (fseek(fp, voff, SEEK_SET) == -1)
+ badfmt("corrupted string table");
+
+ /*
+ * Read version string up to, and including newline.
+ * This code assumes that a newline terminates the
+ * version line.
+ */
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ badfmt("corrupted string table");
+
+ key.data = (u_char *)VRS_KEY;
+ key.size = sizeof(VRS_KEY) - 1;
+ data.data = (u_char *)buf;
+ data.size = strlen(buf);
+ if (db->put(db, &key, &data, 0))
+ err(1, "record enter");
+
+ /* Restore to original values. */
+ data.data = (u_char *)&nbuf;
+ data.size = sizeof(NLIST);
+ if (fseek(fp, cur_off, SEEK_SET) == -1)
+ badfmt("corrupted string table");
+ }
+ }
+ (void)fclose(fp);
+}
+
+static void
+badread(nr, p)
+ int nr;
+ char *p;
+{
+ if (nr < 0)
+ err(1, "%s", kfile);
+ badfmt(p);
+}
diff --git a/usr.sbin/kvm_mkdb/testdb.c b/usr.sbin/kvm_mkdb/testdb.c
new file mode 100644
index 00000000000..a754bcd0be6
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/testdb.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1992, 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 sccsid[] = "from: @(#)testdb.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: testdb.c,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <limits.h>
+#include <kvm.h>
+#include <db.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <paths.h>
+
+#include "extern.h"
+
+/* Return true if the db file is valid, else false */
+int
+testdb()
+{
+ register DB *db;
+ register int cc, kd, ret, dbversionlen;
+ register char *cp, *uf;
+ DBT rec;
+ struct nlist nitem;
+ char dbname[MAXPATHLEN], dbversion[_POSIX2_LINE_MAX];
+ char kversion[_POSIX2_LINE_MAX];
+
+ ret = 0;
+ db = NULL;
+
+ if ((kd = open(_PATH_KMEM, O_RDONLY, 0)) < 0)
+ goto close;
+
+ uf = _PATH_UNIX;
+ if ((cp = rindex(uf, '/')) != 0)
+ uf = cp + 1;
+ (void) snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
+ if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
+ goto close;
+
+ /* Read the version out of the database */
+ rec.data = VRS_KEY;
+ rec.size = sizeof(VRS_KEY) - 1;
+ if ((db->get)(db, &rec, &rec, 0))
+ goto close;
+ if (rec.data == 0 || rec.size > sizeof(dbversion))
+ goto close;
+ bcopy(rec.data, dbversion, rec.size);
+ dbversionlen = rec.size;
+
+ /* Read version string from kernel memory */
+ rec.data = VRS_SYM;
+ rec.size = sizeof(VRS_SYM) - 1;
+ if ((db->get)(db, &rec, &rec, 0))
+ goto close;
+ if (rec.data == 0 || rec.size != sizeof(struct nlist))
+ goto close;
+ bcopy(rec.data, &nitem, sizeof(nitem));
+ /*
+ * Theoretically possible for lseek to be seeking to -1. Not
+ * that it's something to lie awake nights about, however.
+ */
+ errno = 0;
+ if (lseek(kd, (off_t)nitem.n_value, SEEK_SET) == -1 && errno != 0)
+ goto close;
+ cc = read(kd, kversion, sizeof(kversion));
+ if (cc < 0 || cc != sizeof(kversion))
+ goto close;
+
+ /* If they match, we win */
+ ret = bcmp(dbversion, kversion, dbversionlen) == 0;
+
+close: if (kd >= 0)
+ (void)close(kd);
+ if (db)
+ (void)(db->close)(db);
+ return (ret);
+}
diff --git a/usr.sbin/lpr/Makefile b/usr.sbin/lpr/Makefile
new file mode 100644
index 00000000000..2955f06ea81
--- /dev/null
+++ b/usr.sbin/lpr/Makefile
@@ -0,0 +1,10 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $
+
+SUBDIR= lpc lpd lpq lpr lprm lptest pac filters
+
+.if make(install)
+SUBDIR+= SMM.doc
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/lpr/SMM.doc/0.t b/usr.sbin/lpr/SMM.doc/0.t
new file mode 100644
index 00000000000..65ecd4e44aa
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/0.t
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)0.t 8.1 (Berkeley) 6/8/93
+.\"
+.if n .ND
+.TL
+4.3BSD Line Printer Spooler Manual
+.EH 'SMM:7-%''4.3BSD Line Printer Spooler Manual'
+.OH '4.3BSD Line Printer Spooler Manual''SMM:7-%'
+.AU
+Ralph Campbell
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.AB
+.FS
+* UNIX is a trademark of Bell Laboratories.
+.FE
+This document describes the structure and installation procedure
+for the line printer spooling system
+developed for the 4.3BSD version
+of the UNIX* operating system.
+.de D?
+.ie \\n(.$>1 Revised \\$1 \\$2 \\$3
+.el DRAFT of \n(mo/\n(dy/\n(yr
+..
+.sp 2
+.LP
+.D? June 8, 1993
+.AE
+.de IR
+\fI\\$1\fP\\$2
+..
+.de DT
+.TA 8 16 24 32 40 48 56 64 72 80
+..
diff --git a/usr.sbin/lpr/SMM.doc/1.t b/usr.sbin/lpr/SMM.doc/1.t
new file mode 100644
index 00000000000..1d34e9ea86c
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/1.t
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)1.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Overview
+.PP
+The line printer system supports:
+.IP \(bu 3
+multiple printers,
+.IP \(bu 3
+multiple spooling queues,
+.IP \(bu 3
+both local and remote
+printers, and
+.IP \(bu 3
+printers attached via serial lines that require
+line initialization such as the baud rate.
+.LP
+Raster output devices
+such as a Varian or Versatec, and laser printers such as an Imagen,
+are also supported by the line printer system.
+.PP
+The line printer system consists mainly of the
+following files and commands:
+.DS
+.TS
+l l.
+/etc/printcap printer configuration and capability data base
+/usr/lib/lpd line printer daemon, does all the real work
+/usr/ucb/lpr program to enter a job in a printer queue
+/usr/ucb/lpq spooling queue examination program
+/usr/ucb/lprm program to delete jobs from a queue
+/etc/lpc program to administer printers and spooling queues
+/dev/printer socket on which lpd listens
+.TE
+.DE
+The file /etc/printcap is a master data base describing line
+printers directly attached to a machine and, also, printers
+accessible across a network. The manual page entry
+.IR printcap (5)
+provides the authoritative definition of
+the format of this data base, as well as
+specifying default values for important items
+such as the directory in which spooling is performed.
+This document introduces some of the
+information that may be placed
+.IR printcap .
diff --git a/usr.sbin/lpr/SMM.doc/2.t b/usr.sbin/lpr/SMM.doc/2.t
new file mode 100644
index 00000000000..9da2ae231cc
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/2.t
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)2.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Commands
+.NH 2
+lpd \- line printer daemon
+.PP
+The program
+.IR lpd (8),
+usually invoked at boot time from the /etc/rc file, acts as
+a master server for coordinating and controlling
+the spooling queues configured in the printcap file.
+When
+.I lpd
+is started it makes a single pass through the
+.I printcap
+database restarting any printers that have jobs.
+In normal operation
+.I lpd
+listens for service requests on multiple sockets,
+one in the UNIX domain (named ``/dev/printer'') for
+local requests, and one in the Internet domain
+(under the ``printer'' service specification)
+for requests for printer access from off machine;
+see \fIsocket\fP\|(2) and \fIservices\fP\|(5)
+for more information on sockets and service
+specifications, respectively.
+.I Lpd
+spawns a copy of itself to process the request; the master daemon
+continues to listen for new requests.
+.PP
+Clients communicate with
+.I lpd
+using a simple transaction oriented protocol.
+Authentication of remote clients is done based
+on the ``privilege port'' scheme employed by
+\fIrshd\fP\|(8C) and \fIrcmd\fP\|(3X).
+The following table shows the requests
+understood by
+.IR lpd .
+In each request the first byte indicates the
+``meaning'' of the request, followed by the name
+of the printer to which it should be applied. Additional
+qualifiers may follow, depending on the request.
+.DS
+.TS
+l l.
+Request Interpretation
+_
+^Aprinter\en check the queue for jobs and print any found
+^Bprinter\en receive and queue a job from another machine
+^Cprinter [users ...] [jobs ...]\en return short list of current queue state
+^Dprinter [users ...] [jobs ...]\en return long list of current queue state
+^Eprinter person [users ...] [jobs ...]\en remove jobs from a queue
+.TE
+.DE
+.PP
+The \fIlpr\fP\|(1) command
+is used by users to enter a print job in a local queue and to notify
+the local
+.I lpd
+that there are new jobs in the spooling area.
+.I Lpd
+either schedules the job to be printed locally, or if
+printing remotely, attempts to forward
+the job to the appropriate machine.
+If the printer cannot be opened or the destination
+machine is unreachable, the job will remain queued until it is
+possible to complete the work.
+.NH 2
+lpq \- show line printer queue
+.PP
+The \fIlpq\fP\|(1)
+program works recursively backwards displaying the queue of the machine with
+the printer and then the queue(s) of the machine(s) that lead to it.
+.I Lpq
+has two forms of output: in the default, short, format it
+gives a single line of output per queued job; in the long
+format it shows the list of files, and their sizes, that
+comprise a job.
+.NH 2
+lprm \- remove jobs from a queue
+.PP
+The \fIlprm\fP\|(1) command deletes jobs from a spooling
+queue. If necessary, \fIlprm\fP will first kill off a
+running daemon that is servicing the queue and restart
+it after the required files are removed. When removing
+jobs destined for a remote printer, \fIlprm\fP acts
+similarly to \fIlpq\fP except it first checks locally
+for jobs to remove and then
+tries to remove files in queues off-machine.
+.NH 2
+lpc \- line printer control program
+.PP
+The
+.IR lpc (8)
+program is used by the system administrator to control the
+operation of the line printer system.
+For each line printer configured in /etc/printcap,
+.I lpc
+may be used to:
+.IP \(bu
+disable or enable a printer,
+.IP \(bu
+disable or enable a printer's spooling queue,
+.IP \(bu
+rearrange the order of jobs in a spooling queue,
+.IP \(bu
+find the status of printers, and their associated
+spooling queues and printer daemons.
diff --git a/usr.sbin/lpr/SMM.doc/3.t b/usr.sbin/lpr/SMM.doc/3.t
new file mode 100644
index 00000000000..8c950a961c8
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/3.t
@@ -0,0 +1,73 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)3.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Access control
+.PP
+The printer system maintains protected spooling areas so that
+users cannot circumvent printer accounting or
+remove files other than their own.
+The strategy used to maintain protected
+spooling areas is as follows:
+.IP \(bu 3
+The spooling area is writable only by a \fIdaemon\fP user
+and \fIdaemon\fP group.
+.IP \(bu 3
+The \fIlpr\fP program runs set-user-id to \fIroot\fP and
+set-group-id to group \fIdaemon\fP. The \fIroot\fP access permits
+reading any file required. Accessibility is verified
+with an \fIaccess\fP\|(2) call. The group ID
+is used in setting up proper ownership of files
+in the spooling area for \fIlprm\fP.
+.IP \(bu 3
+Control files in a spooling area are made with \fIdaemon\fP
+ownership and group ownership \fIdaemon\fP. Their mode is 0660.
+This insures control files are not modified by a user
+and that no user can remove files except through \fIlprm\fP.
+.IP \(bu 3
+The spooling programs,
+\fIlpd\fP, \fIlpq\fP, and \fIlprm\fP run set-user-id to \fIroot\fP
+and set-group-id to group \fIdaemon\fP to access spool files and printers.
+.IP \(bu 3
+The printer server, \fIlpd\fP,
+uses the same verification procedures as \fIrshd\fP\|(8C)
+in authenticating remote clients. The host on which a client
+resides must be present in the file /etc/hosts.equiv or /etc/hosts.lpd and
+the request message must come from a reserved port number.
+.PP
+In practice, none of \fIlpd\fP, \fIlpq\fP, or
+\fIlprm\fP would have to run as user \fIroot\fP if remote
+spooling were not supported. In previous incarnations of
+the printer system \fIlpd\fP ran set-user-id to \fIdaemon\fP,
+set-group-id to group \fIspooling\fP, and \fIlpq\fP and \fIlprm\fP ran
+set-group-id to group \fIspooling\fP.
diff --git a/usr.sbin/lpr/SMM.doc/4.t b/usr.sbin/lpr/SMM.doc/4.t
new file mode 100644
index 00000000000..8800bc0d51c
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/4.t
@@ -0,0 +1,206 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)4.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Setting up
+.PP
+The 4.3BSD release comes with the necessary programs
+installed and with the default line printer queue
+created. If the system must be modified, the
+makefile in the directory /usr/src/usr.lib/lpr
+should be used in recompiling and reinstalling
+the necessary programs.
+.PP
+The real work in setting up is to create the
+.I printcap
+file and any printer filters for printers not supported
+in the distribution system.
+.NH 2
+Creating a printcap file
+.PP
+The
+.I printcap
+database contains one or more entries per printer.
+A printer should have a separate spooling directory;
+otherwise, jobs will be printed on
+different printers depending on which printer daemon starts first.
+This section describes how to create entries for printers that do not
+conform to the default printer description (an LP-11 style interface to a
+standard, band printer).
+.NH 3
+Printers on serial lines
+.PP
+When a printer is connected via a serial communication line
+it must have the proper baud rate and terminal modes set.
+The following example is for a DecWriter III printer connected
+locally via a 1200 baud serial line.
+.DS
+.DT
+lp|LA-180 DecWriter III:\e
+ :lp=/dev/lp:br#1200:fs#06320:\e
+ :tr=\ef:of=/usr/lib/lpf:lf=/usr/adm/lpd-errs:
+.DE
+The
+.B lp
+entry specifies the file name to open for output. Here it could
+be left out since ``/dev/lp'' is the default.
+The
+.B br
+entry sets the baud rate for the tty line and the
+.B fs
+entry sets CRMOD, no parity, and XTABS (see \fItty\fP\|(4)).
+The
+.B tr
+entry indicates that a form-feed should be printed when the queue
+empties so the paper can be torn off without turning the printer off-line and
+pressing form feed.
+The
+.B of
+entry specifies the filter program
+.I lpf
+should be used for printing the files;
+more will be said about filters later.
+The last entry causes errors
+to be written to the file ``/usr/adm/lpd-errs''
+instead of the console. Most errors from \fIlpd\fP are logged using
+\fIsyslogd\fP\|(8) and will not be logged in the specified file. The
+filters should use \fIsyslogd\fP to report errors; only those that
+write to standard error output will end up with errors in the \fBlf\fP file.
+(Occasionally errors sent to standard error output have not appeared
+in the log file; the use of \fIsyslogd\fP is highly recommended.)
+.NH 3
+Remote printers
+.PP
+Printers that reside on remote hosts should have an empty
+.B lp
+entry.
+For example, the following printcap entry would send output to the printer
+named ``lp'' on the machine ``ucbvax''.
+.DS
+.DT
+lp|default line printer:\e
+ :lp=:rm=ucbvax:rp=lp:sd=/usr/spool/vaxlpd:
+.DE
+The
+.B rm
+entry is the name of the remote machine to connect to; this name must
+be a known host name for a machine on the network.
+The
+.B rp
+capability indicates
+the name of the printer on the remote machine is ``lp'';
+here it could be left out since this is the default value.
+The
+.B sd
+entry specifies ``/usr/spool/vaxlpd''
+as the spooling directory instead of the
+default value of ``/usr/spool/lpd''.
+.NH 2
+Output filters
+.PP
+Filters are used to handle device dependencies and to
+do accounting functions. The output filtering of
+.B of
+is used when accounting is
+not being done or when all text data must be passed through a filter.
+It is not intended to do accounting since it is started only once,
+all text files are filtered through it, and no provision is made for passing
+owners' login name, identifying the beginning and ending of jobs, etc.
+The other filters (if specified) are started for each file
+printed and do accounting if there is an
+.B af
+entry.
+If entries for both
+.B of
+and other filters are specified,
+the output filter is used only to print the banner page;
+it is then stopped to allow other filters access to the printer.
+An example of a printer that requires output filters
+is the Benson-Varian.
+.DS
+.DT
+va|varian|Benson-Varian:\e
+ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e
+ :tf=/usr/lib/rvcat:mx#2000:pl#58:px=2112:py=1700:tr=\ef:
+.DE
+The
+.B tf
+entry specifies ``/usr/lib/rvcat'' as the filter to be
+used in printing \fItroff\fP\|(1) output.
+This filter is needed to set the device into print mode
+for text, and plot mode for printing
+.I troff
+files and raster images (see \fIva\fP\|(4V)).
+Note that the page length is set to 58 lines by the
+.B pl
+entry for 8.5" by 11" fan-fold paper.
+To enable accounting, the varian entry would be
+augmented with an
+.B af
+filter as shown below.
+.DS
+.DT
+va|varian|Benson-Varian:\e
+ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e
+ :if=/usr/lib/vpf:tf=/usr/lib/rvcat:af=/usr/adm/vaacct:\e
+ :mx#2000:pl#58:px=2112:py=1700:tr=\ef:
+.DE
+.NH 2
+Access Control
+.PP
+Local access to printer queues is controlled with the
+.B rg
+printcap entry.
+.DS
+ :rg=lprgroup:
+.DE
+Users must be in the group
+.I lprgroup
+to submit jobs to the specified printer.
+The default is to allow all users access.
+Note that once the files are in the local queue, they can be printed
+locally or forwarded to another host depending on the configuration.
+.PP
+Remote access is controlled by listing the hosts in either the file
+/etc/hosts.equiv or /etc/hosts.lpd, one host per line. Note that
+.IR rsh (1)
+and
+.IR rlogin (1)
+use /etc/hosts.equiv to determine which hosts are equivalent for allowing logins
+without passwords. The file /etc/hosts.lpd is only used to control
+which hosts have line printer access.
+Remote access can be further restricted to only allow remote users with accounts
+on the local host to print jobs by using the \fBrs\fP printcap entry.
+.DS
+ :rs:
+.DE
diff --git a/usr.sbin/lpr/SMM.doc/5.t b/usr.sbin/lpr/SMM.doc/5.t
new file mode 100644
index 00000000000..137a342640b
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/5.t
@@ -0,0 +1,116 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)5.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Output filter specifications
+.PP
+The filters supplied with 4.3BSD
+handle printing and accounting for most common
+line printers, the Benson-Varian, the wide (36") and
+narrow (11") Versatec printer/plotters. For other devices or accounting
+methods, it may be necessary to create a new filter.
+.PP
+Filters are spawned by \fIlpd\fP
+with their standard input the data to be printed, and standard output
+the printer. The standard error is attached to the
+.B lf
+file for logging errors or \fIsyslogd\fP may be used for logging errors.
+A filter must return a 0 exit
+code if there were no errors, 1 if the job should be reprinted,
+and 2 if the job should be thrown away.
+When \fIlprm\fP
+sends a kill signal to the \fIlpd\fP process controlling
+printing, it sends a SIGINT signal
+to all filters and descendents of filters.
+This signal can be trapped by filters that need
+to do cleanup operations such as
+deleting temporary files.
+.PP
+Arguments passed to a filter depend on its type.
+The
+.B of
+filter is called with the following arguments.
+.DS
+\fIfilter\fP \fB\-w\fPwidth \fB\-l\fPlength
+.DE
+The \fIwidth\fP and \fIlength\fP values come from the
+.B pw
+and
+.B pl
+entries in the printcap database.
+The
+.B if
+filter is passed the following parameters.
+.DS
+\fIfilter\fP [\|\fB\-c\fP\|] \fB\-w\fPwidth \fB\-l\fPlength \fB\-i\fPindent \fB\-n\fP login \fB\-h\fP host accounting_file
+.DE
+The
+.B \-c
+flag is optional, and only supplied when control characters
+are to be passed uninterpreted to the printer (when using the
+.B \-l
+option of
+.I lpr
+to print the file).
+The
+.B \-w
+and
+.B \-l
+parameters are the same as for the
+.B of
+filter.
+The
+.B \-n
+and
+.B \-h
+parameters specify the login name and host name of the job owner.
+The last argument is the name of the accounting file from
+.IR printcap .
+.PP
+All other filters are called with the following arguments:
+.DS
+\fIfilter\fP \fB\-x\fPwidth \fB\-y\fPlength \fB\-n\fP login \fB\-h\fP host accounting_file
+.DE
+The
+.B \-x
+and
+.B \-y
+options specify the horizontal and vertical page
+size in pixels (from the
+.B px
+and
+.B py
+entries in the printcap file).
+The rest of the arguments are the same as for the
+.B if
+filter.
diff --git a/usr.sbin/lpr/SMM.doc/6.t b/usr.sbin/lpr/SMM.doc/6.t
new file mode 100644
index 00000000000..708779055f7
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/6.t
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)6.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Line printer Administration
+.PP
+The
+.I lpc
+program provides local control over line printer activity.
+The major commands and their intended use will be described.
+The command format and remaining commands are described in
+.IR lpc (8).
+.LP
+\fBabort\fP and \fBstart\fP
+.IP
+.I Abort
+terminates an active spooling daemon on the local host immediately and
+then disables printing (preventing new daemons from being started by
+.IR lpr ).
+This is normally used to forcibly restart a hung line printer daemon
+(i.e., \fIlpq\fP reports that there is a daemon present but nothing is
+happening). It does not remove any jobs from the queue
+(use the \fIlprm\fP command instead).
+.I Start
+enables printing and requests \fIlpd\fP to start printing jobs.
+.LP
+\fBenable\fP and \fBdisable\fP
+.IP
+\fIEnable\fP and \fIdisable\fP allow spooling in the local queue to be
+turned on/off.
+This will allow/prevent
+.I lpr
+from putting new jobs in the spool queue. It is frequently convenient
+to turn spooling off while testing new line printer filters since the
+.I root
+user can still use
+.I lpr
+to put jobs in the queue but no one else can.
+The other main use is to prevent users from putting jobs in the queue
+when the printer is expected to be unavailable for a long time.
+.LP
+\fBrestart\fP
+.IP
+.I Restart
+allows ordinary users to restart printer daemons when
+.I lpq
+reports that there is no daemon present.
+.LP
+\fBstop\fP
+.IP
+.I Stop
+halts a spooling daemon after the current job completes;
+this also disables printing. This is a clean way to shutdown a
+printer to do maintenance, etc. Note that users can still enter jobs in a
+spool queue while a printer is
+.IR stopped .
+.LP
+\fBtopq\fP
+.IP
+.I Topq
+places jobs at the top of a printer queue. This can be used
+to reorder high priority jobs since
+.I lpr
+only provides first-come-first-serve ordering of jobs.
diff --git a/usr.sbin/lpr/SMM.doc/7.t b/usr.sbin/lpr/SMM.doc/7.t
new file mode 100644
index 00000000000..a6f6bea5032
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/7.t
@@ -0,0 +1,226 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)7.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Troubleshooting
+.PP
+There are several messages that may be generated by the
+the line printer system. This section
+categorizes the most common and explains the cause
+for their generation. Where the message implies a failure,
+directions are given to remedy the problem.
+.PP
+In the examples below, the name
+.I printer
+is the name of the printer from the
+.I printcap
+database.
+.NH 2
+LPR
+.SH
+lpr: \fIprinter\fP\|: unknown printer
+.IP
+The
+.I printer
+was not found in the
+.I printcap
+database. Usually this is a typing mistake; however, it may indicate
+a missing or incorrect entry in the /etc/printcap file.
+.SH
+lpr: \fIprinter\fP\|: jobs queued, but cannot start daemon.
+.IP
+The connection to
+.I lpd
+on the local machine failed.
+This usually means the printer server started at
+boot time has died or is hung. Check the local socket
+/dev/printer to be sure it still exists (if it does not exist,
+there is no
+.I lpd
+process running).
+Usually it is enough to get a super-user to type the following to
+restart
+.IR lpd .
+.DS
+% /usr/lib/lpd
+.DE
+You can also check the state of the master printer daemon with the following.
+.DS
+% ps l`cat /usr/spool/lpd.lock`
+.DE
+.IP
+Another possibility is that the
+.I lpr
+program is not set-user-id to \fIroot\fP, set-group-id to group \fIdaemon\fP.
+This can be checked with
+.DS
+% ls \-lg /usr/ucb/lpr
+.DE
+.SH
+lpr: \fIprinter\fP\|: printer queue is disabled
+.IP
+This means the queue was turned off with
+.DS
+% lpc disable \fIprinter\fP
+.DE
+to prevent
+.I lpr
+from putting files in the queue. This is normally
+done by the system manager when a printer is
+going to be down for a long time. The
+printer can be turned back on by a super-user with
+.IR lpc .
+.NH 2
+LPQ
+.SH
+waiting for \fIprinter\fP to become ready (offline ?)
+.IP
+The printer device could not be opened by the daemon.
+This can happen for several reasons,
+the most common is that the printer is turned off-line.
+This message can also be generated if the printer is out
+of paper, the paper is jammed, etc.
+The actual reason is dependent on the meaning
+of error codes returned by system device driver.
+Not all printers supply enough information
+to distinguish when a printer is off-line or having
+trouble (e.g. a printer connected through a serial line).
+Another possible cause of this message is
+some other process, such as an output filter,
+has an exclusive open on the device. Your only recourse
+here is to kill off the offending program(s) and
+restart the printer with
+.IR lpc .
+.SH
+\fIprinter\fP is ready and printing
+.IP
+The
+.I lpq
+program checks to see if a daemon process exists for
+.I printer
+and prints the file \fIstatus\fP located in the spooling directory.
+If the daemon is hung, a super user can use
+.I lpc
+to abort the current daemon and start a new one.
+.SH
+waiting for \fIhost\fP to come up
+.IP
+This implies there is a daemon trying to connect to the remote
+machine named
+.I host
+to send the files in the local queue.
+If the remote machine is up,
+.I lpd
+on the remote machine is probably dead or
+hung and should be restarted as mentioned for
+.IR lpr .
+.SH
+sending to \fIhost\fP
+.IP
+The files should be in the process of being transferred to the remote
+.IR host .
+If not, the local daemon should be aborted and started with
+.IR lpc .
+.SH
+Warning: \fIprinter\fP is down
+.IP
+The printer has been marked as being unavailable with
+.IR lpc .
+.SH
+Warning: no daemon present
+.IP
+The \fIlpd\fP process overseeing
+the spooling queue, as specified in the ``lock'' file
+in that directory, does not exist. This normally occurs
+only when the daemon has unexpectedly died.
+The error log file for the printer and the \fIsyslogd\fP logs
+should be checked for a
+diagnostic from the deceased process.
+To restart an \fIlpd\fP, use
+.DS
+% lpc restart \fIprinter\fP
+.DE
+.SH
+no space on remote; waiting for queue to drain
+.IP
+This implies that there is insufficient disk space on the remote.
+If the file is large enough, there will never be enough space on
+the remote (even after the queue on the remote is empty). The solution here
+is to move the spooling queue or make more free space on the remote.
+.NH 2
+LPRM
+.SH
+lprm: \fIprinter\fP\|: cannot restart printer daemon
+.IP
+This case is the same as when
+.I lpr
+prints that the daemon cannot be started.
+.NH 2
+LPD
+.PP
+The
+.I lpd
+program can log many different messages using \fIsyslogd\fP\|(8).
+Most of these messages are about files that can not
+be opened and usually imply that the
+.I printcap
+file or the protection modes of the files are
+incorrect. Files may also be inaccessible if people
+manually manipulate the line printer system (i.e. they
+bypass the
+.I lpr
+program).
+.PP
+In addition to messages generated by
+.IR lpd ,
+any of the filters that
+.I lpd
+spawns may log messages using \fIsyslogd\fP or to the error log file
+(the file specified in the \fBlf\fP entry in \fIprintcap\fP\|).
+.NH 2
+LPC
+.PP
+.SH
+couldn't start printer
+.IP
+This case is the same as when
+.I lpr
+reports that the daemon cannot be started.
+.SH
+cannot examine spool directory
+.IP
+Error messages beginning with ``cannot ...'' are usually because of
+incorrect ownership or protection mode of the lock file, spooling
+directory or the
+.I lpc
+program.
diff --git a/usr.sbin/lpr/SMM.doc/Makefile b/usr.sbin/lpr/SMM.doc/Makefile
new file mode 100644
index 00000000000..1701c865d63
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/07.lpd
+SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t 7.t
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/lpr/SMM.doc/spell.ok b/usr.sbin/lpr/SMM.doc/spell.ok
new file mode 100644
index 00000000000..bf31319943d
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/spell.ok
@@ -0,0 +1,70 @@
+Aprinter
+Bprinter
+CRMOD
+Cprinter
+DecWriter
+Dprinter
+Eprinter
+LPC
+LPD
+Lpd
+Manual''SMM:5
+SIGINT
+SMM:5
+Topq
+XTABS
+adm
+af
+br
+daemon
+daemons
+dev
+f:of
+fs
+hosts.equiv
+hosts.lpd
+lf
+lg
+lib
+lp:br
+lp:sd
+lpc
+lpd
+lpd.lock
+lpf
+lpf:lf
+lprgroup
+makefile
+mx
+offline
+pl
+printcap
+pw
+py
+rc
+rcmd
+rg
+rlogin
+rp
+rs
+rsh
+rshd
+rvcat
+rvcat:af
+rvcat:mx
+sd
+src
+syslogd
+tf
+topq
+ucb
+ucbvax
+ucbvax:rp
+usr.lib
+va0:sd
+vaacct
+vad:of
+varian
+vaxlpd
+vpf
+vpf:tf
diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c
new file mode 100644
index 00000000000..7d3394be6fe
--- /dev/null
+++ b/usr.sbin/lpr/common_source/common.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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[] = "@(#)common.c 8.2 (Berkeley) 1/21/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+/*
+ * Routines and data common to all the line printer functions.
+ */
+
+char *AF; /* accounting file */
+long BR; /* baud rate if lp is a tty */
+char *CF; /* name of cifplot filter (per job) */
+char *DF; /* name of tex filter (per job) */
+long DU; /* daeomon user-id */
+long FC; /* flags to clear if lp is a tty */
+char *FF; /* form feed string */
+long FS; /* flags to set if lp is a tty */
+char *GF; /* name of graph(1G) filter (per job) */
+long HL; /* print header last */
+char *IF; /* name of input filter (created per job) */
+char *LF; /* log file for error messages */
+char *LO; /* lock file name */
+char *LP; /* line printer device name */
+long MC; /* maximum number of copies allowed */
+char *MS; /* stty flags to set if lp is a tty */
+long MX; /* maximum number of blocks to copy */
+char *NF; /* name of ditroff filter (per job) */
+char *OF; /* name of output filter (created once) */
+char *PF; /* name of vrast filter (per job) */
+long PL; /* page length */
+long PW; /* page width */
+long PX; /* page width in pixels */
+long PY; /* page length in pixels */
+char *RF; /* name of fortran text filter (per job) */
+char *RG; /* resricted group */
+char *RM; /* remote machine name */
+char *RP; /* remote printer name */
+long RS; /* restricted to those with local accounts */
+long RW; /* open LP for reading and writing */
+long SB; /* short banner instead of normal header */
+long SC; /* suppress multiple copies */
+char *SD; /* spool directory */
+long SF; /* suppress FF on each print job */
+long SH; /* suppress header page */
+char *ST; /* status file name */
+char *TF; /* name of troff filter (per job) */
+char *TR; /* trailer string to be output when Q empties */
+char *VF; /* name of vplot filter (per job) */
+long XC; /* flags to clear for local mode */
+long XS; /* flags to set for local mode */
+
+char line[BUFSIZ];
+char *bp; /* pointer into printcap buffer. */
+char *name; /* program name */
+char *printer; /* printer name */
+ /* host machine name */
+char host[MAXHOSTNAMELEN];
+char *from = host; /* client's machine name */
+int sendtorem; /* are we sending to a remote? */
+char *printcapdb[2] = { _PATH_PRINTCAP, 0 };
+
+extern uid_t uid, euid;
+
+static int compar __P((const void *, const void *));
+
+/*
+ * Create a connection to the remote printer server.
+ * Most of this code comes from rcmd.c.
+ */
+int
+getport(rhost)
+ char *rhost;
+{
+ struct hostent *hp;
+ struct servent *sp;
+ struct sockaddr_in sin;
+ int s, timo = 1, lport = IPPORT_RESERVED - 1;
+ int err;
+
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (rhost == NULL)
+ fatal("no remote host to connect to");
+ hp = gethostbyname(rhost);
+ if (hp == NULL)
+ fatal("unknown host %s", rhost);
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL)
+ fatal("printer/tcp: unknown service");
+ bzero((char *)&sin, sizeof(sin));
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+ sin.sin_family = hp->h_addrtype;
+ sin.sin_port = sp->s_port;
+
+ /*
+ * Try connecting to the server.
+ */
+retry:
+ seteuid(euid);
+ s = rresvport(&lport);
+ seteuid(uid);
+ if (s < 0)
+ return(-1);
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ err = errno;
+ (void) close(s);
+ errno = err;
+ if (errno == EADDRINUSE) {
+ lport--;
+ goto retry;
+ }
+ if (errno == ECONNREFUSED && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ return(-1);
+ }
+ return(s);
+}
+
+/*
+ * Getline reads a line from the control file cfp, removes tabs, converts
+ * new-line to null and leaves it in line.
+ * Returns 0 at EOF or the number of characters read.
+ */
+int
+getline(cfp)
+ FILE *cfp;
+{
+ register int linel = 0;
+ register char *lp = line;
+ register c;
+
+ while ((c = getc(cfp)) != '\n') {
+ if (c == EOF)
+ return(0);
+ if (c == '\t') {
+ do {
+ *lp++ = ' ';
+ linel++;
+ } while ((linel & 07) != 0);
+ continue;
+ }
+ *lp++ = c;
+ linel++;
+ }
+ *lp++ = '\0';
+ return(linel);
+}
+
+/*
+ * Scan the current directory and make a list of daemon files sorted by
+ * creation time.
+ * Return the number of entries and a pointer to the list.
+ */
+int
+getq(namelist)
+ struct queue *(*namelist[]);
+{
+ register struct dirent *d;
+ register struct queue *q, **queue;
+ register int nitems;
+ struct stat stbuf;
+ DIR *dirp;
+ int arraysz;
+
+ seteuid(euid);
+ if ((dirp = opendir(SD)) == NULL)
+ return(-1);
+ if (fstat(dirp->dd_fd, &stbuf) < 0)
+ goto errdone;
+ seteuid(uid);
+
+ /*
+ * Estimate the array size by taking the size of the directory file
+ * and dividing it by a multiple of the minimum size entry.
+ */
+ arraysz = (stbuf.st_size / 24);
+ queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
+ if (queue == NULL)
+ goto errdone;
+
+ nitems = 0;
+ while ((d = readdir(dirp)) != NULL) {
+ if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
+ continue; /* daemon control files only */
+ seteuid(euid);
+ if (stat(d->d_name, &stbuf) < 0)
+ continue; /* Doesn't exist */
+ seteuid(uid);
+ q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
+ if (q == NULL)
+ goto errdone;
+ q->q_time = stbuf.st_mtime;
+ strcpy(q->q_name, d->d_name);
+ /*
+ * Check to make sure the array has space left and
+ * realloc the maximum size.
+ */
+ if (++nitems > arraysz) {
+ queue = (struct queue **)realloc((char *)queue,
+ (stbuf.st_size/12) * sizeof(struct queue *));
+ if (queue == NULL)
+ goto errdone;
+ }
+ queue[nitems-1] = q;
+ }
+ closedir(dirp);
+ if (nitems)
+ qsort(queue, nitems, sizeof(struct queue *), compar);
+ *namelist = queue;
+ return(nitems);
+
+errdone:
+ closedir(dirp);
+ return(-1);
+}
+
+/*
+ * Compare modification times.
+ */
+static int
+compar(p1, p2)
+ const void *p1, *p2;
+{
+ if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
+ return(-1);
+ if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
+ return(1);
+ return(0);
+}
+
+/*
+ * Figure out whether the local machine is the same
+ * as the remote machine (RM) entry (if it exists).
+ */
+char *
+checkremote()
+{
+ char name[MAXHOSTNAMELEN];
+ register struct hostent *hp;
+ static char errbuf[128];
+
+ sendtorem = 0; /* assume printer is local */
+ if (RM != (char *)NULL) {
+ /* get the official name of the local host */
+ gethostname(name, sizeof(name));
+ name[sizeof(name)-1] = '\0';
+ hp = gethostbyname(name);
+ if (hp == (struct hostent *) NULL) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "unable to get official name for local machine %s",
+ name);
+ return errbuf;
+ } else (void) strcpy(name, hp->h_name);
+
+ /* get the official name of RM */
+ hp = gethostbyname(RM);
+ if (hp == (struct hostent *) NULL) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "unable to get official name for remote machine %s",
+ RM);
+ return errbuf;
+ }
+
+ /*
+ * if the two hosts are not the same,
+ * then the printer must be remote.
+ */
+ if (strcmp(name, hp->h_name) != 0)
+ sendtorem = 1;
+ }
+ return (char *)0;
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+fatal(const char *msg, ...)
+#else
+fatal(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ if (from != host)
+ (void)printf("%s: ", host);
+ (void)printf("%s: ", name);
+ if (printer)
+ (void)printf("%s: ", printer);
+ (void)vprintf(msg, ap);
+ va_end(ap);
+ (void)putchar('\n');
+ exit(1);
+}
diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c
new file mode 100644
index 00000000000..37b26bf7316
--- /dev/null
+++ b/usr.sbin/lpr/common_source/displayq.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 1983, 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 sccsid[] = "@(#)displayq.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * Routines to display the state of the queue.
+ */
+#define JOBCOL 40 /* column for job # in -l format */
+#define OWNCOL 7 /* start of Owner column in normal */
+#define SIZCOL 62 /* start of Size column in normal */
+
+/*
+ * Stuff for handling job specifications
+ */
+extern int requ[]; /* job number of spool entries */
+extern int requests; /* # of spool requests */
+extern char *user[]; /* users to process */
+extern int users; /* # of users in user array */
+
+extern uid_t uid, euid;
+
+static int col; /* column on screen */
+static char current[40]; /* current file being printed */
+static char file[132]; /* print file name */
+static int first; /* first file in ``files'' column? */
+static int garbage; /* # of garbage cf files */
+static int lflag; /* long output option */
+static int rank; /* order to be printed (-1=none, 0=active) */
+static long totsize; /* total print job size in bytes */
+
+static char *head0 = "Rank Owner Job Files";
+static char *head1 = "Total Size\n";
+
+/*
+ * Display the current state of the queue. Format = 1 if long format.
+ */
+void
+displayq(format)
+ int format;
+{
+ register struct queue *q;
+ register int i, nitems, fd, ret;
+ register char *cp;
+ struct queue **queue;
+ struct stat statb;
+ FILE *fp;
+
+ lflag = format;
+ totsize = 0;
+ rank = -1;
+ if ((i = cgetent(&bp, printcapdb, printer)) == -2)
+ fatal("can't open printer description file");
+ else if (i == -1)
+ fatal("unknown printer");
+ else if (i == -3)
+ fatal("potential reference loop detected in printcap file");
+ if (cgetstr(bp, "lp", &LP) < 0)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) < 0)
+ RP = DEFLP;
+ if (cgetstr(bp, "sd", &SD) < 0)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp,"lo", &LO) < 0)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) < 0)
+ ST = DEFSTAT;
+ cgetstr(bp, "rm", &RM);
+ if (cp = checkremote())
+ printf("Warning: %s\n", cp);
+
+ /*
+ * Print out local queue
+ * Find all the control files in the spooling directory
+ */
+ seteuid(euid);
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spooling directory");
+ seteuid(uid);
+ if ((nitems = getq(&queue)) < 0)
+ fatal("cannot examine spooling area\n");
+ seteuid(euid);
+ ret = stat(LO, &statb);
+ seteuid(uid);
+ if (ret >= 0) {
+ if (statb.st_mode & 0100) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s is down: ", printer);
+ seteuid(euid);
+ fd = open(ST, O_RDONLY);
+ seteuid(uid);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd); /* unlocks as well */
+ } else
+ putchar('\n');
+ }
+ if (statb.st_mode & 010) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s queue is turned off\n", printer);
+ }
+ }
+
+ if (nitems) {
+ seteuid(euid);
+ fp = fopen(LO, "r");
+ seteuid(uid);
+ if (fp == NULL)
+ warn();
+ else {
+ /* get daemon pid */
+ cp = current;
+ while ((*cp = getc(fp)) != EOF && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ i = atoi(current);
+ if (i <= 0) {
+ seteuid(euid);
+ ret = kill(i, 0);
+ seteuid(uid);
+ }
+ ret = -1;
+ if (ret < 0) {
+ /* read current file name */
+ cp = current;
+ while ((*cp = getc(fp)) != EOF && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ /*
+ * Print the status file.
+ */
+ if (sendtorem)
+ printf("%s: ", host);
+ seteuid(euid);
+ fd = open(ST, O_RDONLY);
+ seteuid(uid);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd); /* unlocks as well */
+ } else
+ putchar('\n');
+ }
+ (void) fclose(fp);
+ }
+ /*
+ * Now, examine the control files and print out the jobs to
+ * be done for each user.
+ */
+ if (!lflag)
+ header();
+ for (i = 0; i < nitems; i++) {
+ q = queue[i];
+ inform(q->q_name);
+ free(q);
+ }
+ free(queue);
+ }
+ if (!sendtorem) {
+ if (nitems == 0)
+ puts("no entries");
+ return;
+ }
+
+ /*
+ * Print foreign queue
+ * Note that a file in transit may show up in either queue.
+ */
+ if (nitems)
+ putchar('\n');
+ (void) sprintf(line, "%c%s", format + '\3', RP);
+ cp = line;
+ for (i = 0; i < requests; i++) {
+ cp += strlen(cp);
+ (void) sprintf(cp, " %d", requ[i]);
+ }
+ for (i = 0; i < users; i++) {
+ cp += strlen(cp);
+ *cp++ = ' ';
+ (void) strcpy(cp, user[i]);
+ }
+ strcat(line, "\n");
+ fd = getport(RM);
+ if (fd < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", RM);
+ }
+ else {
+ i = strlen(line);
+ if (write(fd, line, i) != i)
+ fatal("Lost connection");
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd);
+ }
+}
+
+/*
+ * Print a warning message if there is no daemon present.
+ */
+void
+warn()
+{
+ if (sendtorem)
+ printf("\n%s: ", host);
+ puts("Warning: no daemon present");
+ current[0] = '\0';
+}
+
+/*
+ * Print the header for the short listing format
+ */
+void
+header()
+{
+ printf(head0);
+ col = strlen(head0)+1;
+ blankfill(SIZCOL);
+ printf(head1);
+}
+
+void
+inform(cf)
+ char *cf;
+{
+ register int j;
+ FILE *cfp;
+
+ /*
+ * There's a chance the control file has gone away
+ * in the meantime; if this is the case just keep going
+ */
+ seteuid(euid);
+ if ((cfp = fopen(cf, "r")) == NULL)
+ return;
+ seteuid(uid);
+
+ if (rank < 0)
+ rank = 0;
+ if (sendtorem || garbage || strcmp(cf, current))
+ rank++;
+ j = 0;
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'P': /* Was this file specified in the user's list? */
+ if (!inlist(line+1, cf)) {
+ fclose(cfp);
+ return;
+ }
+ if (lflag) {
+ printf("\n%s: ", line+1);
+ col = strlen(line+1) + 2;
+ prank(rank);
+ blankfill(JOBCOL);
+ printf(" [job %s]\n", cf+3);
+ } else {
+ col = 0;
+ prank(rank);
+ blankfill(OWNCOL);
+ printf("%-10s %-3d ", line+1, atoi(cf+3));
+ col += 16;
+ first = 1;
+ }
+ continue;
+ default: /* some format specifer and file name? */
+ if (line[0] < 'a' || line[0] > 'z')
+ continue;
+ if (j == 0 || strcmp(file, line+1) != 0)
+ (void) strcpy(file, line+1);
+ j++;
+ continue;
+ case 'N':
+ show(line+1, file, j);
+ file[0] = '\0';
+ j = 0;
+ }
+ }
+ fclose(cfp);
+ if (!lflag) {
+ blankfill(SIZCOL);
+ printf("%ld bytes\n", totsize);
+ totsize = 0;
+ }
+}
+
+int
+inlist(name, file)
+ char *name, *file;
+{
+ register int *r, n;
+ register char **u, *cp;
+
+ if (users == 0 && requests == 0)
+ return(1);
+ /*
+ * Check to see if it's in the user list
+ */
+ for (u = user; u < &user[users]; u++)
+ if (!strcmp(*u, name))
+ return(1);
+ /*
+ * Check the request list
+ */
+ for (n = 0, cp = file+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ for (r = requ; r < &requ[requests]; r++)
+ if (*r == n && !strcmp(cp, from))
+ return(1);
+ return(0);
+}
+
+void
+show(nfile, file, copies)
+ register char *nfile, *file;
+ int copies;
+{
+ if (strcmp(nfile, " ") == 0)
+ nfile = "(standard input)";
+ if (lflag)
+ ldump(nfile, file, copies);
+ else
+ dump(nfile, file, copies);
+}
+
+/*
+ * Fill the line with blanks to the specified column
+ */
+void
+blankfill(n)
+ register int n;
+{
+ while (col++ < n)
+ putchar(' ');
+}
+
+/*
+ * Give the abbreviated dump of the file names
+ */
+void
+dump(nfile, file, copies)
+ char *nfile, *file;
+ int copies;
+{
+ register short n, fill;
+ struct stat lbuf;
+
+ /*
+ * Print as many files as will fit
+ * (leaving room for the total size)
+ */
+ fill = first ? 0 : 2; /* fill space for ``, '' */
+ if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
+ if (col < SIZCOL) {
+ printf(" ..."), col += 4;
+ blankfill(SIZCOL);
+ }
+ } else {
+ if (first)
+ first = 0;
+ else
+ printf(", ");
+ printf("%s", nfile);
+ col += n+fill;
+ }
+ seteuid(euid);
+ if (*file && !stat(file, &lbuf))
+ totsize += copies * lbuf.st_size;
+ seteuid(uid);
+}
+
+/*
+ * Print the long info about the file
+ */
+void
+ldump(nfile, file, copies)
+ char *nfile, *file;
+ int copies;
+{
+ struct stat lbuf;
+
+ putchar('\t');
+ if (copies > 1)
+ printf("%-2d copies of %-19s", copies, nfile);
+ else
+ printf("%-32s", nfile);
+ if (*file && !stat(file, &lbuf))
+ printf(" %qd bytes", lbuf.st_size);
+ else
+ printf(" ??? bytes");
+ putchar('\n');
+}
+
+/*
+ * Print the job's rank in the queue,
+ * update col for screen management
+ */
+void
+prank(n)
+ int n;
+{
+ char rline[100];
+ static char *r[] = {
+ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+ };
+
+ if (n == 0) {
+ printf("active");
+ col += 6;
+ return;
+ }
+ if ((n/10)%10 == 1)
+ (void)snprintf(rline, sizeof(rline), "%dth", n);
+ else
+ (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
+ col += strlen(rline);
+ printf("%s", rline);
+}
diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h
new file mode 100644
index 00000000000..8829f64b457
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)lp.h 8.1 (Berkeley) 6/6/93
+ */
+
+
+/*
+ * Global definitions for the line printer system.
+ */
+
+extern char *AF; /* accounting file */
+extern long BR; /* baud rate if lp is a tty */
+extern char *CF; /* name of cifplot filter (per job) */
+extern char *DF; /* name of tex filter (per job) */
+extern long DU; /* daeomon user-id */
+extern long FC; /* flags to clear if lp is a tty */
+extern char *FF; /* form feed string */
+extern long FS; /* flags to set if lp is a tty */
+extern char *GF; /* name of graph(1G) filter (per job) */
+extern long HL; /* print header last */
+extern char *IF; /* name of input filter (created per job) */
+extern char *LF; /* log file for error messages */
+extern char *LO; /* lock file name */
+extern char *LP; /* line printer device name */
+extern long MC; /* maximum number of copies allowed */
+extern char *MS; /* stty flags to set if lp is a tty */
+extern long MX; /* maximum number of blocks to copy */
+extern char *NF; /* name of ditroff(1) filter (per job) */
+extern char *OF; /* name of output filter (created once) */
+extern long PL; /* page length */
+extern long PW; /* page width */
+extern long PX; /* page width in pixels */
+extern long PY; /* page length in pixels */
+extern char *RF; /* name of fortran text filter (per job) */
+extern char *RG; /* restricted group */
+extern char *RM; /* remote machine name */
+extern char *RP; /* remote printer name */
+extern long RS; /* restricted to those with local accounts */
+extern long RW; /* open LP for reading and writing */
+extern long SB; /* short banner instead of normal header */
+extern long SC; /* suppress multiple copies */
+extern char *SD; /* spool directory */
+extern long SF; /* suppress FF on each print job */
+extern long SH; /* suppress header page */
+extern char *ST; /* status file name */
+extern char *TF; /* name of troff(1) filter (per job) */
+extern char *TR; /* trailer string to be output when Q empties */
+extern char *VF; /* name of raster filter (per job) */
+extern long XC; /* flags to clear for local mode */
+extern long XS; /* flags to set for local mode */
+
+extern char line[BUFSIZ];
+extern char *bp; /* pointer into printcap buffer */
+extern char *name; /* program name */
+extern char *printer; /* printer name */
+ /* host machine name */
+extern char host[MAXHOSTNAMELEN];
+extern char *from; /* client's machine name */
+extern int sendtorem; /* are we sending to a remote? */
+extern char *printcapdb[]; /* printcap database array */
+/*
+ * Structure used for building a sorted list of control files.
+ */
+struct queue {
+ time_t q_time; /* modification time */
+ char q_name[MAXNAMLEN+1]; /* control file name */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct dirent;
+
+void blankfill __P((int));
+char *checkremote __P((void));
+int chk __P((char *));
+void displayq __P((int));
+void dump __P((char *, char *, int));
+void fatal __P((const char *, ...));
+int getline __P((FILE *));
+int getport __P((char *));
+int getq __P((struct queue *(*[])));
+void header __P((void));
+void inform __P((char *));
+int inlist __P((char *, char *));
+int iscf __P((struct dirent *));
+int isowner __P((char *, char *));
+void ldump __P((char *, char *, int));
+int lockchk __P((char *));
+void prank __P((int));
+void process __P((char *));
+void rmjob __P((void));
+void rmremote __P((void));
+void show __P((char *, char *, int));
+int startdaemon __P((char *));
+void warn __P((void));
+__END_DECLS
diff --git a/usr.sbin/lpr/common_source/lp.local.h b/usr.sbin/lpr/common_source/lp.local.h
new file mode 100644
index 00000000000..837fd2fcb53
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.local.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)lp.local.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Possibly, local parameters to the spooling system
+ */
+
+/*
+ * Defaults for line printer capabilities data base
+ */
+#define DEFLP "lp"
+#define DEFLOCK "lock"
+#define DEFSTAT "status"
+#define DEFMX 1000
+#define DEFMAXCOPIES 0
+#define DEFFF "\f"
+#define DEFWIDTH 132
+#define DEFLENGTH 66
+#define DEFUID 1
+
+/*
+ * When files are created in the spooling area, they are normally
+ * readable only by their owner and the spooling group. If you
+ * want otherwise, change this mode.
+ */
+#define FILMOD 0660
+
+/*
+ * Printer is assumed to support LINELEN (for block chars)
+ * and background character (blank) is a space
+ */
+#define LINELEN 132
+#define BACKGND ' '
+
+#define HEIGHT 9 /* height of characters */
+#define WIDTH 8 /* width of characters */
+#define DROP 3 /* offset to drop characters with descenders */
+
+/*
+ * Define TERMCAP if the terminal capabilites are to be used for lpq.
+ */
+#define TERMCAP
+
+/*
+ * Maximum number of user and job requests for lpq and lprm.
+ */
+#define MAXUSERS 50
+#define MAXREQUESTS 50
diff --git a/usr.sbin/lpr/common_source/pathnames.h b/usr.sbin/lpr/common_source/pathnames.h
new file mode 100644
index 00000000000..5c07cdb820a
--- /dev/null
+++ b/usr.sbin/lpr/common_source/pathnames.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#define _PATH_DEFDEVLP "/dev/lp"
+#define _PATH_DEFSPOOL "/var/spool/output/lpd"
+#define _PATH_HOSTSEQUIV "/etc/hosts.equiv"
+#define _PATH_HOSTSLPD "/etc/hosts.lpd"
+#define _PATH_MASTERLOCK "/var/spool/output/lpd.lock"
+#define _PATH_PR "/usr/bin/pr"
+#define _PATH_PRINTCAP "/etc/printcap"
+#define _PATH_SOCKETNAME "/var/run/printer"
+#define _PATH_VFONT "/usr/libdata/vfont/"
+#define _PATH_VFONTB "/usr/libdata/vfont/B"
+#define _PATH_VFONTI "/usr/libdata/vfont/I"
+#define _PATH_VFONTR "/usr/libdata/vfont/R"
+#define _PATH_VFONTS "/usr/libdata/vfont/S"
diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c
new file mode 100644
index 00000000000..dbf688d1539
--- /dev/null
+++ b/usr.sbin/lpr/common_source/printcap.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 1983, 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 sccsid[] = "@(#)printcap.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+#define PRINTCAP
+
+#ifdef PRINTCAP
+#define tgetent pgetent
+#define tskip pskip
+#define tgetstr pgetstr
+#define tdecode pdecode
+#define tgetnum pgetnum
+#define tgetflag pgetflag
+#define tdecode pdecode
+#define tnchktc pnchktc
+#define tnamatch pnamatch
+#define V6
+#endif
+
+static FILE *pfp = NULL; /* printcap data base file pointer */
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+
+static char *tskip __P((char *));
+static char *tskip __P((char *bp));
+static char *tdecode __P((char *, char **));
+
+/*
+ * Similar to tgetent except it returns the next enrty instead of
+ * doing a lookup.
+ */
+int
+getprent(bp)
+ register char *bp;
+{
+ register int c, skip = 0;
+
+ if (pfp == NULL) {
+ seteuid(euid);
+ pfp = fopen(_PATH_PRINTCAP, "r");
+ seteuid(uid);
+ if (pfp == NULL)
+ return(-1);
+ }
+
+ tbuf = bp;
+ for (;;) {
+ switch (c = getc(pfp)) {
+ case EOF:
+ fclose(pfp);
+ pfp = NULL;
+ return(0);
+ case '\n':
+ if (bp == tbuf) {
+ skip = 0;
+ continue;
+ }
+ if (bp[-1] == '\\') {
+ bp--;
+ continue;
+ }
+ *bp = '\0';
+ return(1);
+ case '#':
+ if (bp == tbuf)
+ skip++;
+ default:
+ if (skip)
+ continue;
+ if (bp >= tbuf+BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ *bp = '\0';
+ return(1);
+ }
+ *bp++ = c;
+ }
+ }
+}
+
+void
+endprent()
+{
+ if (pfp != NULL)
+ fclose(pfp);
+}
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int
+tgetent(bp, name)
+ char *bp, *name;
+{
+ register char *cp;
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+#ifndef V6
+ cp = getenv("TERMCAP");
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ if (*cp!='/') {
+ cp2 = getenv("TERM");
+ if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
+ strcpy(bp,cp);
+ return(tnchktc());
+ } else {
+ seteuid(euid);
+ tf = open(_PATH_PRINTCAP, 0);
+ seteuid(uid);
+ }
+ } else
+ /*
+ * don't seteuid here incase TERMCAP is set to
+ * some file we don't have access to.
+ */
+ tf = open(cp, 0);
+ }
+ if (tf == 0) {
+ seteuid(euid);
+ tf = open(_PATH_PRINTCAP, 0);
+ seteuid(uid);
+ }
+#else
+ seteuid(euid);
+ tf = open(_PATH_PRINTCAP, 0);
+ seteuid(uid);
+#endif
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\'){
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Termcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return(tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+int
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p<tbuf) {
+ write(2, "Bad termcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return(1);
+ strcpy(tcname,p+3);
+ q = tcname;
+ while (q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (tgetent(tcbuf, tcname) != 1)
+ return(0);
+ for (q=tcbuf; *q != ':'; q++)
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ q[BUFSIZ - (p-tbuf)] = 0;
+ }
+ strcpy(p, q+1);
+ tbuf = holdtbuf;
+ return(1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+int
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return(0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+int
+tgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return(0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c
new file mode 100644
index 00000000000..eaf82779bd2
--- /dev/null
+++ b/usr.sbin/lpr/common_source/rmjob.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 1983, 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 sccsid[] = "@(#)rmjob.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * rmjob - remove the specified jobs from the queue.
+ */
+
+/*
+ * Stuff for handling lprm specifications
+ */
+extern char *user[]; /* users to process */
+extern int users; /* # of users in user array */
+extern int requ[]; /* job number of spool entries */
+extern int requests; /* # of spool requests */
+extern char *person; /* name of person doing lprm */
+
+static char root[] = "root";
+static int all = 0; /* eliminate all files (root only) */
+static int cur_daemon; /* daemon's pid */
+static char current[40]; /* active control file name */
+
+extern uid_t uid, euid; /* real and effective user id's */
+
+static void do_unlink __P((char *));
+
+void
+rmjob()
+{
+ register int i, nitems;
+ int assasinated = 0;
+ struct dirent **files;
+ char *cp;
+
+ if ((i = cgetent(&bp, printcapdb, printer)) == -2)
+ fatal("can't open printer description file");
+ else if (i == -1)
+ fatal("unknown printer");
+ else if (i == -3)
+ fatal("potential reference loop detected in printcap file");
+ if (cgetstr(bp, "lp", &LP) < 0)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) < 0)
+ RP = DEFLP;
+ if (cgetstr(bp, "sd", &SD) < 0)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp,"lo", &LO) < 0)
+ LO = DEFLOCK;
+ cgetstr(bp, "rm", &RM);
+ if (cp = checkremote())
+ printf("Warning: %s\n", cp);
+
+ /*
+ * If the format was `lprm -' and the user isn't the super-user,
+ * then fake things to look like he said `lprm user'.
+ */
+ if (users < 0) {
+ if (getuid() == 0)
+ all = 1; /* all files in local queue */
+ else {
+ user[0] = person;
+ users = 1;
+ }
+ }
+ if (!strcmp(person, "-all")) {
+ if (from == host)
+ fatal("The login name \"-all\" is reserved");
+ all = 1; /* all those from 'from' */
+ person = root;
+ }
+
+ seteuid(euid);
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spool directory");
+ if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
+ fatal("cannot access spool directory");
+ seteuid(uid);
+
+ if (nitems) {
+ /*
+ * Check for an active printer daemon (in which case we
+ * kill it if it is reading our file) then remove stuff
+ * (after which we have to restart the daemon).
+ */
+ if (lockchk(LO) && chk(current)) {
+ seteuid(euid);
+ assasinated = kill(cur_daemon, SIGINT) == 0;
+ seteuid(uid);
+ if (!assasinated)
+ fatal("cannot kill printer daemon");
+ }
+ /*
+ * process the files
+ */
+ for (i = 0; i < nitems; i++)
+ process(files[i]->d_name);
+ }
+ rmremote();
+ /*
+ * Restart the printer daemon if it was killed
+ */
+ if (assasinated && !startdaemon(printer))
+ fatal("cannot restart printer daemon\n");
+ exit(0);
+}
+
+/*
+ * Process a lock file: collect the pid of the active
+ * daemon and the file name of the active spool entry.
+ * Return boolean indicating existence of a lock file.
+ */
+int
+lockchk(s)
+ char *s;
+{
+ register FILE *fp;
+ register int i, n;
+
+ seteuid(euid);
+ if ((fp = fopen(s, "r")) == NULL) {
+ if (errno == EACCES)
+ fatal("can't access lock file");
+ else
+ return(0);
+ }
+ seteuid(uid);
+ if (!getline(fp)) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ cur_daemon = atoi(line);
+ if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
+ if (i > 5) {
+ n = 1;
+ break;
+ }
+ sleep(i);
+ }
+ current[n-1] = '\0';
+ (void) fclose(fp);
+ return(1);
+}
+
+/*
+ * Process a control file.
+ */
+void
+process(file)
+ char *file;
+{
+ FILE *cfp;
+
+ if (!chk(file))
+ return;
+ seteuid(euid);
+ if ((cfp = fopen(file, "r")) == NULL)
+ fatal("cannot open %s", file);
+ seteuid(uid);
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'U': /* unlink associated files */
+ do_unlink(file);
+ }
+ }
+ (void) fclose(cfp);
+ do_unlink(file);
+}
+
+static void
+do_unlink(file)
+ char *file;
+{
+ int ret;
+
+ if (from != host)
+ printf("%s: ", host);
+ seteuid(euid);
+ ret = unlink(file);
+ seteuid(uid);
+ printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
+}
+
+/*
+ * Do the dirty work in checking
+ */
+int
+chk(file)
+ char *file;
+{
+ register int *r, n;
+ register char **u, *cp;
+ FILE *cfp;
+
+ /*
+ * Check for valid cf file name (mostly checking current).
+ */
+ if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
+ return(0);
+
+ if (all && (from == host || !strcmp(from, file+6)))
+ return(1);
+
+ /*
+ * get the owner's name from the control file.
+ */
+ seteuid(euid);
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(0);
+ seteuid(uid);
+ while (getline(cfp)) {
+ if (line[0] == 'P')
+ break;
+ }
+ (void) fclose(cfp);
+ if (line[0] != 'P')
+ return(0);
+
+ if (users == 0 && requests == 0)
+ return(!strcmp(file, current) && isowner(line+1, file));
+ /*
+ * Check the request list
+ */
+ for (n = 0, cp = file+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ for (r = requ; r < &requ[requests]; r++)
+ if (*r == n && isowner(line+1, file))
+ return(1);
+ /*
+ * Check to see if it's in the user list
+ */
+ for (u = user; u < &user[users]; u++)
+ if (!strcmp(*u, line+1) && isowner(line+1, file))
+ return(1);
+ return(0);
+}
+
+/*
+ * If root is removing a file on the local machine, allow it.
+ * If root is removing a file from a remote machine, only allow
+ * files sent from the remote machine to be removed.
+ * Normal users can only remove the file from where it was sent.
+ */
+int
+isowner(owner, file)
+ char *owner, *file;
+{
+ if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
+ return(1);
+ if (!strcmp(person, owner) && !strcmp(from, file+6))
+ return(1);
+ if (from != host)
+ printf("%s: ", host);
+ printf("%s: Permission denied\n", file);
+ return(0);
+}
+
+/*
+ * Check to see if we are sending files to a remote machine. If we are,
+ * then try removing files on the remote machine.
+ */
+void
+rmremote()
+{
+ register char *cp;
+ register int i, rem;
+ char buf[BUFSIZ];
+
+ if (!sendtorem)
+ return; /* not sending to a remote machine */
+
+ /*
+ * Flush stdout so the user can see what has been deleted
+ * while we wait (possibly) for the connection.
+ */
+ fflush(stdout);
+
+ (void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person);
+ cp = buf;
+ for (i = 0; i < users; i++) {
+ cp += strlen(cp);
+ *cp++ = ' ';
+ strcpy(cp, user[i]);
+ }
+ for (i = 0; i < requests; i++) {
+ cp += strlen(cp);
+ (void) sprintf(cp, " %d", requ[i]);
+ }
+ strcat(cp, "\n");
+ rem = getport(RM);
+ if (rem < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", RM);
+ } else {
+ i = strlen(buf);
+ if (write(rem, buf, i) != i)
+ fatal("Lost connection");
+ while ((i = read(rem, buf, sizeof(buf))) > 0)
+ (void) fwrite(buf, 1, i, stdout);
+ (void) close(rem);
+ }
+}
+
+/*
+ * Return 1 if the filename begins with 'cf'
+ */
+int
+iscf(d)
+ struct dirent *d;
+{
+ return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
+}
diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c
new file mode 100644
index 00000000000..930afc341de
--- /dev/null
+++ b/usr.sbin/lpr/common_source/startdaemon.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94";
+#endif /* not lint */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+extern uid_t uid, euid;
+
+static void perr __P((char *));
+
+/*
+ * Tell the printer daemon that there are new files in the spool directory.
+ */
+
+int
+startdaemon(printer)
+ char *printer;
+{
+ struct sockaddr_un un;
+ register int s, n;
+ char buf[BUFSIZ];
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ perr("socket");
+ return(0);
+ }
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, _PATH_SOCKETNAME);
+#ifndef SUN_LEN
+#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
+#endif
+ seteuid(euid);
+ if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ seteuid(uid);
+ perr("connect");
+ (void) close(s);
+ return(0);
+ }
+ seteuid(uid);
+ (void) sprintf(buf, "\1%s\n", printer);
+ n = strlen(buf);
+ if (write(s, buf, n) != n) {
+ perr("write");
+ (void) close(s);
+ return(0);
+ }
+ if (read(s, buf, 1) == 1) {
+ if (buf[0] == '\0') { /* everything is OK */
+ (void) close(s);
+ return(1);
+ }
+ putchar(buf[0]);
+ }
+ while ((n = read(s, buf, sizeof(buf))) > 0)
+ fwrite(buf, 1, n, stdout);
+ (void) close(s);
+ return(0);
+}
+
+static void
+perr(msg)
+ char *msg;
+{
+ extern char *name;
+
+ (void)printf("%s: %s: %s\n", name, msg, strerror(errno));
+}
diff --git a/usr.sbin/lpr/filters/Makefile b/usr.sbin/lpr/filters/Makefile
new file mode 100644
index 00000000000..c9d5c4f0215
--- /dev/null
+++ b/usr.sbin/lpr/filters/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpf
+NOMAN= noman
+BINDIR= /usr/libexec/lpr
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/filters/lpf.c b/usr.sbin/lpr/filters/lpf.c
new file mode 100644
index 00000000000..5335f316c56
--- /dev/null
+++ b/usr.sbin/lpr/filters/lpf.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * filter which reads the output of nroff and converts lines
+ * with ^H's to overwritten lines. Thus this works like 'ul'
+ * but is much better: it can handle more than 2 overwrites
+ * and it is written with some style.
+ * modified by kls to use register references instead of arrays
+ * to try to gain a little speed.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define MAXWIDTH 132
+#define MAXREP 10
+
+char buf[MAXREP][MAXWIDTH];
+int maxcol[MAXREP] = {-1};
+int lineno;
+int width = 132; /* default line length */
+int length = 66; /* page length */
+int indent; /* indentation length */
+int npages = 1;
+int literal; /* print control characters */
+char *name; /* user's login name */
+char *host; /* user's machine name */
+char *acctfile; /* accounting information file */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register FILE *p = stdin, *o = stdout;
+ register int i, col;
+ register char *cp;
+ int done, linedone, maxrep;
+ char ch, *limit;
+
+ while (--argc) {
+ if (*(cp = *++argv) == '-') {
+ switch (cp[1]) {
+ case 'n':
+ argc--;
+ name = *++argv;
+ break;
+
+ case 'h':
+ argc--;
+ host = *++argv;
+ break;
+
+ case 'w':
+ if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH)
+ width = i;
+ break;
+
+ case 'l':
+ length = atoi(&cp[2]);
+ break;
+
+ case 'i':
+ indent = atoi(&cp[2]);
+ break;
+
+ case 'c': /* Print control chars */
+ literal++;
+ break;
+ }
+ } else
+ acctfile = cp;
+ }
+
+ for (cp = buf[0], limit = buf[MAXREP]; cp < limit; *cp++ = ' ');
+ done = 0;
+
+ while (!done) {
+ col = indent;
+ maxrep = -1;
+ linedone = 0;
+ while (!linedone) {
+ switch (ch = getc(p)) {
+ case EOF:
+ linedone = done = 1;
+ ch = '\n';
+ break;
+
+ case '\f':
+ lineno = length;
+ case '\n':
+ if (maxrep < 0)
+ maxrep = 0;
+ linedone = 1;
+ break;
+
+ case '\b':
+ if (--col < indent)
+ col = indent;
+ break;
+
+ case '\r':
+ col = indent;
+ break;
+
+ case '\t':
+ col = ((col - indent) | 07) + indent + 1;
+ break;
+
+ case '\031':
+ /*
+ * lpd needs to use a different filter to
+ * print data so stop what we are doing and
+ * wait for lpd to restart us.
+ */
+ if ((ch = getchar()) == '\1') {
+ fflush(stdout);
+ kill(getpid(), SIGSTOP);
+ break;
+ } else {
+ ungetc(ch, stdin);
+ ch = '\031';
+ }
+
+ default:
+ if (col >= width || !literal && ch < ' ') {
+ col++;
+ break;
+ }
+ cp = &buf[0][col];
+ for (i = 0; i < MAXREP; i++) {
+ if (i > maxrep)
+ maxrep = i;
+ if (*cp == ' ') {
+ *cp = ch;
+ if (col > maxcol[i])
+ maxcol[i] = col;
+ break;
+ }
+ cp += MAXWIDTH;
+ }
+ col++;
+ break;
+ }
+ }
+
+ /* print out lines */
+ for (i = 0; i <= maxrep; i++) {
+ for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
+ putc(*cp, o);
+ *cp++ = ' ';
+ }
+ if (i < maxrep)
+ putc('\r', o);
+ else
+ putc(ch, o);
+ if (++lineno >= length) {
+ fflush(o);
+ npages++;
+ lineno = 0;
+ }
+ maxcol[i] = -1;
+ }
+ }
+ if (lineno) { /* be sure to end on a page boundary */
+ putchar('\f');
+ npages++;
+ }
+ if (name && acctfile && access(acctfile, 02) >= 0 &&
+ freopen(acctfile, "a", stdout) != NULL) {
+ printf("%7.2f\t%s:%s\n", (float)npages, host, name);
+ }
+ exit(0);
+}
diff --git a/usr.sbin/lpr/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile
new file mode 100644
index 00000000000..c6cefebe698
--- /dev/null
+++ b/usr.sbin/lpr/lpc/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpc
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN= lpc.8
+SRCS= lpc.c cmds.c cmdtab.c startdaemon.c common.c
+BINGRP= daemon
+BINMODE=2555
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c
new file mode 100644
index 00000000000..094672e2d8c
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmds.c
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program -- commands:
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "lpc.h"
+#include "extern.h"
+#include "pathnames.h"
+
+extern uid_t uid, euid;
+
+static void abortpr __P((int));
+static void cleanpr __P((void));
+static void disablepr __P((void));
+static int doarg __P((char *));
+static int doselect __P((struct dirent *));
+static void enablepr __P((void));
+static void prstat __P((void));
+static void putmsg __P((int, char **));
+static int sortq __P((const void *, const void *));
+static void startpr __P((int));
+static void stoppr __P((void));
+static int touch __P((struct queue *));
+static void unlinkf __P((char *));
+static void upstat __P((char *));
+
+/*
+ * kill an existing daemon and disable printing.
+ */
+void
+doabort(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: abort {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+ abortpr(1);
+ }
+}
+
+static void
+abortpr(dis)
+ int dis;
+{
+ register FILE *fp;
+ struct stat stbuf;
+ int pid, fd, ret;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (dis) {
+ seteuid(euid);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ printf("\tno daemon to abort\n");
+ }
+ goto out;
+ } else {
+ printf("\tcannot stat lock file\n");
+ goto out;
+ }
+ }
+ /*
+ * Kill the current daemon to stop printing now.
+ */
+ if ((fp = fopen(line, "r")) == NULL) {
+ printf("\tcannot open lock file\n");
+ goto out;
+ }
+ if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+ (void) fclose(fp); /* unlocks as well */
+ printf("\tno daemon to abort\n");
+ goto out;
+ }
+ (void) fclose(fp);
+ if (kill(pid = atoi(line), SIGTERM) < 0)
+ printf("\tWarning: daemon (pid %d) not killed\n", pid);
+ else
+ printf("\tdaemon (pid %d) killed\n", pid);
+out:
+ seteuid(uid);
+}
+
+/*
+ * Write a message into the status file.
+ */
+static void
+upstat(msg)
+ char *msg;
+{
+ register int fd;
+ char statfile[BUFSIZ];
+
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ (void) sprintf(statfile, "%s/%s", SD, ST);
+ umask(0);
+ fd = open(statfile, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ return;
+ }
+ (void) ftruncate(fd, 0);
+ if (msg == (char *)NULL)
+ (void) write(fd, "\n", 1);
+ else
+ (void) write(fd, msg, strlen(msg));
+ (void) close(fd);
+}
+
+/*
+ * Remove all spool files and temporaries from the spooling area.
+ */
+void
+clean(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: clean {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ cleanpr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ cleanpr();
+ }
+}
+
+static int
+doselect(d)
+ struct dirent *d;
+{
+ int c = d->d_name[0];
+
+ if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
+ return(1);
+ return(0);
+}
+
+/*
+ * Comparison routine for scandir. Sort by job number and machine, then
+ * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
+ */
+static int
+sortq(a, b)
+ const void *a, *b;
+{
+ struct dirent **d1, **d2;
+ int c1, c2;
+
+ d1 = (struct dirent **)a;
+ d2 = (struct dirent **)b;
+ if (c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))
+ return(c1);
+ c1 = (*d1)->d_name[0];
+ c2 = (*d2)->d_name[0];
+ if (c1 == c2)
+ return((*d1)->d_name[2] - (*d2)->d_name[2]);
+ if (c1 == 'c')
+ return(-1);
+ if (c1 == 'd' || c2 == 'c')
+ return(1);
+ return(-1);
+}
+
+/*
+ * Remove incomplete jobs from spooling area.
+ */
+static void
+cleanpr()
+{
+ register int i, n;
+ register char *cp, *cp1, *lp;
+ struct dirent **queue;
+ int nitems;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ printf("%s:\n", printer);
+
+ for (lp = line, cp = SD; *lp++ = *cp++; )
+ ;
+ lp[-1] = '/';
+
+ seteuid(euid);
+ nitems = scandir(SD, &queue, doselect, sortq);
+ seteuid(uid);
+ if (nitems < 0) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ if (nitems == 0)
+ return;
+ i = 0;
+ do {
+ cp = queue[i]->d_name;
+ if (*cp == 'c') {
+ n = 0;
+ while (i + 1 < nitems) {
+ cp1 = queue[i + 1]->d_name;
+ if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
+ break;
+ i++;
+ n++;
+ }
+ if (n == 0) {
+ strcpy(lp, cp);
+ unlinkf(line);
+ }
+ } else {
+ /*
+ * Must be a df with no cf (otherwise, it would have
+ * been skipped above) or a tf file (which can always
+ * be removed).
+ */
+ strcpy(lp, cp);
+ unlinkf(line);
+ }
+ } while (++i < nitems);
+}
+
+static void
+unlinkf(name)
+ char *name;
+{
+ seteuid(euid);
+ if (unlink(name) < 0)
+ printf("\tcannot remove %s\n", name);
+ else
+ printf("\tremoved %s\n", name);
+ seteuid(uid);
+}
+
+/*
+ * Enable queuing to the printer (allow lpr's).
+ */
+void
+enable(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: enable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ enablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ enablepr();
+ }
+}
+
+static void
+enablepr()
+{
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the group execute bit of the lock file to enable queuing.
+ */
+ seteuid(euid);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & 0767) < 0)
+ printf("\tcannot enable queuing\n");
+ else
+ printf("\tqueuing enabled\n");
+ }
+ seteuid(uid);
+}
+
+/*
+ * Disable queuing.
+ */
+void
+disable(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: disable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ disablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ disablepr();
+ }
+}
+
+static void
+disablepr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing.
+ */
+ seteuid(euid);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tqueuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tqueuing disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+ seteuid(uid);
+}
+
+/*
+ * Disable queuing and printing and put a message into the status file
+ * (reason for being down).
+ */
+void
+down(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: down {all | printer} [message ...]\n");
+ return;
+ }
+ if (!strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ putmsg(argc - 2, argv + 2);
+ }
+ return;
+ }
+ printer = argv[1];
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ return;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ putmsg(argc - 2, argv + 2);
+}
+
+static void
+putmsg(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int fd;
+ register char *cp1, *cp2;
+ char buf[1024];
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing and
+ * turn on the owner execute bit of the lock file to disable printing.
+ */
+ (void) sprintf(line, "%s/%s", SD, LO);
+ seteuid(euid);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tprinter and queuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tprinter and queuing disabled\n");
+ }
+ seteuid(uid);
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+ /*
+ * Write the message into the status file.
+ */
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ seteuid(uid);
+ return;
+ }
+ seteuid(uid);
+ (void) ftruncate(fd, 0);
+ if (argc <= 0) {
+ (void) write(fd, "\n", 1);
+ (void) close(fd);
+ return;
+ }
+ cp1 = buf;
+ while (--argc >= 0) {
+ cp2 = *argv++;
+ while (*cp1++ = *cp2++)
+ ;
+ cp1[-1] = ' ';
+ }
+ cp1[-1] = '\n';
+ *cp1 = '\0';
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}
+
+/*
+ * Exit lpc
+ */
+void
+quit(argc, argv)
+ int argc;
+ char *argv[];
+{
+ exit(0);
+}
+
+/*
+ * Kill and restart the daemon.
+ */
+void
+restart(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: restart {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(0);
+ startpr(0);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ abortpr(0);
+ startpr(0);
+ }
+}
+
+/*
+ * Enable printing on the specified printer and startup the daemon.
+ */
+void
+startcmd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: start {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ startpr(1);
+ }
+}
+
+static void
+startpr(enable)
+ int enable;
+{
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the owner execute bit of the lock file to enable printing.
+ */
+ seteuid(euid);
+ if (enable && stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0)
+ printf("\tcannot enable printing\n");
+ else
+ printf("\tprinting enabled\n");
+ }
+ if (!startdaemon(printer))
+ printf("\tcouldn't start daemon\n");
+ else
+ printf("\tdaemon started\n");
+ seteuid(uid);
+}
+
+/*
+ * Print the status of each queue listed or all the queues.
+ */
+void
+status(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ prstat();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ prstat();
+ }
+}
+
+/*
+ * Print the status of the printer queue.
+ */
+static void
+prstat()
+{
+ struct stat stbuf;
+ register int fd, i;
+ register struct dirent *dp;
+ DIR *dirp;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ (void) sprintf(line, "%s/%s", SD, LO);
+ if (stat(line, &stbuf) >= 0) {
+ printf("\tqueuing is %s\n",
+ (stbuf.st_mode & 010) ? "disabled" : "enabled");
+ printf("\tprinting is %s\n",
+ (stbuf.st_mode & 0100) ? "disabled" : "enabled");
+ } else {
+ printf("\tqueuing is enabled\n");
+ printf("\tprinting is enabled\n");
+ }
+ if ((dirp = opendir(SD)) == NULL) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ i = 0;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
+ i++;
+ }
+ closedir(dirp);
+ if (i == 0)
+ printf("\tno entries\n");
+ else if (i == 1)
+ printf("\t1 entry in spool area\n");
+ else
+ printf("\t%d entries in spool area\n", i);
+ fd = open(line, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
+ (void) close(fd); /* unlocks as well */
+ printf("\tno daemon present\n");
+ return;
+ }
+ (void) close(fd);
+ putchar('\t');
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_RDONLY);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd); /* unlocks as well */
+ }
+}
+
+/*
+ * Stop the specified daemon after completing the current job and disable
+ * printing.
+ */
+void
+stop(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: stop {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ stoppr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ stoppr();
+ }
+}
+
+static void
+stoppr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ seteuid(euid);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+ seteuid(uid);
+}
+
+struct queue **queue;
+int nitems;
+time_t mtime;
+
+/*
+ * Put the specified jobs at the top of printer queue.
+ */
+void
+topq(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ struct stat stbuf;
+ int status, changed;
+
+ if (argc < 3) {
+ printf("Usage: topq printer [jobnum ...] [user ...]\n");
+ return;
+ }
+
+ --argc;
+ printer = *++argv;
+ status = cgetent(&bp, printcapdb, printer);
+ if (status == -2) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == -1) {
+ printf("%s: unknown printer\n", printer);
+ return;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ printf("%s:\n", printer);
+
+ seteuid(euid);
+ if (chdir(SD) < 0) {
+ printf("\tcannot chdir to %s\n", SD);
+ goto out;
+ }
+ seteuid(uid);
+ nitems = getq(&queue);
+ if (nitems == 0)
+ return;
+ changed = 0;
+ mtime = queue[0]->q_time;
+ for (i = argc; --i; ) {
+ if (doarg(argv[i]) == 0) {
+ printf("\tjob %s is not in the queue\n", argv[i]);
+ continue;
+ } else
+ changed++;
+ }
+ for (i = 0; i < nitems; i++)
+ free(queue[i]);
+ free(queue);
+ if (!changed) {
+ printf("\tqueue order unchanged\n");
+ return;
+ }
+ /*
+ * Turn on the public execute bit of the lock file to
+ * get lpd to rebuild the queue after the current job.
+ */
+ seteuid(euid);
+ if (changed && stat(LO, &stbuf) >= 0)
+ (void) chmod(LO, (stbuf.st_mode & 0777) | 01);
+
+out:
+ seteuid(uid);
+}
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+static int
+touch(q)
+ struct queue *q;
+{
+ struct timeval tvp[2];
+ int ret;
+
+ tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ seteuid(euid);
+ ret = utimes(q->q_name, tvp);
+ seteuid(uid);
+ return (ret);
+}
+
+/*
+ * Checks if specified job name is in the printer's queue.
+ * Returns: negative (-1) if argument name is not in the queue.
+ */
+static int
+doarg(job)
+ char *job;
+{
+ register struct queue **qq;
+ register int jobnum, n;
+ register char *cp, *machine;
+ int cnt = 0;
+ FILE *fp;
+
+ /*
+ * Look for a job item consisting of system name, colon, number
+ * (example: ucbarpa:114)
+ */
+ if ((cp = index(job, ':')) != NULL) {
+ machine = job;
+ *cp++ = '\0';
+ job = cp;
+ } else
+ machine = NULL;
+
+ /*
+ * Check for job specified by number (example: 112 or 235ucbarpa).
+ */
+ if (isdigit(*job)) {
+ jobnum = 0;
+ do
+ jobnum = jobnum * 10 + (*job++ - '0');
+ while (isdigit(*job));
+ for (qq = queue + nitems; --qq >= queue; ) {
+ n = 0;
+ for (cp = (*qq)->q_name+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ if (jobnum != n)
+ continue;
+ if (*job && strcmp(job, cp) != 0)
+ continue;
+ if (machine != NULL && strcmp(machine, cp) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+ }
+ /*
+ * Process item consisting of owner's name (example: henry).
+ */
+ for (qq = queue + nitems; --qq >= queue; ) {
+ seteuid(euid);
+ fp = fopen((*qq)->q_name, "r");
+ seteuid(uid);
+ if (fp == NULL)
+ continue;
+ while (getline(fp) > 0)
+ if (line[0] == 'P')
+ break;
+ (void) fclose(fp);
+ if (line[0] != 'P' || strcmp(job, line+1) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+}
+
+/*
+ * Enable everything and start printer (undo `down').
+ */
+void
+up(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: up {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(2);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ startpr(2);
+ }
+}
diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c
new file mode 100644
index 00000000000..7619791cdca
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmdtab.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1983, 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 sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "lpc.h"
+#include "extern.h"
+
+/*
+ * lpc -- command tables
+ */
+char aborthelp[] = "terminate a spooling daemon immediately and disable printing";
+char cleanhelp[] = "remove cruft files from a queue";
+char enablehelp[] = "turn a spooling queue on";
+char disablehelp[] = "turn a spooling queue off";
+char downhelp[] = "do a 'stop' followed by 'disable' and put a message in status";
+char helphelp[] = "get help on commands";
+char quithelp[] = "exit lpc";
+char restarthelp[] = "kill (if possible) and restart a spooling daemon";
+char starthelp[] = "enable printing and start a spooling daemon";
+char statushelp[] = "show status of daemon and queue";
+char stophelp[] = "stop a spooling daemon after current job completes and disable printing";
+char topqhelp[] = "put job at top of printer queue";
+char uphelp[] = "enable everything and restart spooling daemon";
+
+struct cmd cmdtab[] = {
+ { "abort", aborthelp, doabort, 1 },
+ { "clean", cleanhelp, clean, 1 },
+ { "enable", enablehelp, enable, 1 },
+ { "exit", quithelp, quit, 0 },
+ { "disable", disablehelp, disable, 1 },
+ { "down", downhelp, down, 1 },
+ { "help", helphelp, help, 0 },
+ { "quit", quithelp, quit, 0 },
+ { "restart", restarthelp, restart, 0 },
+ { "start", starthelp, startcmd, 1 },
+ { "status", statushelp, status, 0 },
+ { "stop", stophelp, stop, 1 },
+ { "topq", topqhelp, topq, 1 },
+ { "up", uphelp, up, 1 },
+ { "?", helphelp, help, 0 },
+ { 0 },
+};
+
+int NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
diff --git a/usr.sbin/lpr/lpc/extern.h b/usr.sbin/lpr/lpc/extern.h
new file mode 100644
index 00000000000..1b807b132df
--- /dev/null
+++ b/usr.sbin/lpr/lpc/extern.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+
+#include <sys/cdefs.h>
+
+
+__BEGIN_DECLS
+void clean __P((int, char **));
+void disable __P((int, char **));
+void doabort __P((int, char **));
+void down __P((int, char **));
+void enable __P((int, char **));
+void help __P((int, char **));
+void quit __P((int, char **));
+void restart __P((int, char **));
+void startcmd __P((int, char **));
+void status __P((int, char **));
+void stop __P((int, char **));
+void topq __P((int, char **));
+void up __P((int, char **));
+__END_DECLS
+
+extern int NCMDS;
+extern struct cmd cmdtab[];
diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8
new file mode 100644
index 00000000000..a786adcad94
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.8
@@ -0,0 +1,174 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)lpc.8 8.3 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt LPC 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpc
+.Nd line printer control program
+.Sh SYNOPSIS
+.Nm lpc
+.Oo
+.Ar command
+.Op Ar argument ...
+.Oc
+.Sh DESCRIPTION
+.Nm Lpc
+is used by the system administrator to control the
+operation of the line printer system.
+For each line printer configured in
+.Pa /etc/printcap ,
+.Nm lpc
+may be used to:
+.Bl -bullet -offset indent
+.It
+disable or enable a printer,
+.It
+disable or enable a printer's spooling queue,
+.It
+rearrange the order of jobs in a spooling queue,
+.It
+find the status of printers, and their associated
+spooling queues and printer daemons.
+.El
+.Pp
+Without any arguments,
+.Nm lpc
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm lpc
+interprets the first argument as a command and the remaining
+arguments as parameters to the command. The standard input
+may be redirected causing
+.Nm lpc
+to read commands from file.
+Commands may be abbreviated;
+the following is the list of recognized commands.
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic \&? No [ command ... ]
+.It Ic help No [ command ... ]
+Print a short description of each command specified in the argument list,
+or, if no argument is given, a list of the recognized commands.
+.Pp
+.It Ic abort No {\ all\ |\ printer\ }
+Terminate an active spooling daemon on the local host immediately and
+then disable printing (preventing new daemons from being started by
+.Xr lpr )
+for the specified printers.
+.Pp
+.It Ic clean No {\ all\ |\ printer\ }
+Remove any temporary files, data files, and control files that cannot
+be printed (i.e., do not form a complete printer job)
+from the specified printer queue(s) on the local machine.
+.Pp
+.It Ic disable No {\ all\ |\ printer\ }
+Turn the specified printer queues off. This prevents new
+printer jobs from being entered into the queue by
+.Xr lpr .
+.Pp
+.It Ic down No {\ all\ |\ printer\ } message ...
+Turn the specified printer queue off, disable printing and put
+.Em message
+in the printer status file. The message doesn't need to be quoted, the
+remaining arguments are treated like
+.Xr echo 1 .
+This is normally used to take a printer down and let others know why
+.Xr lpq 1
+will indicate the printer is down and print the status message).
+.Pp
+.It Ic enable No {\ all\ |\ printer\ }
+Enable spooling on the local queue for the listed printers.
+This will allow
+.Xr lpr 1
+to put new jobs in the spool queue.
+.Pp
+.It Ic exit
+.It Ic quit
+Exit from lpc.
+.Pp
+.It Ic restart No {\ all\ |\ printer\ }
+Attempt to start a new printer daemon.
+This is useful when some abnormal condition causes the daemon to
+die unexpectedly, leaving jobs in the queue.
+.Xr Lpq
+will report that there is no daemon present when this condition occurs.
+If the user is the super-user,
+try to abort the current daemon first (i.e., kill and restart a stuck daemon).
+.Pp
+.It Ic start No {\ all\ |\ printer\ }
+Enable printing and start a spooling daemon for the listed printers.
+.Pp
+.It Ic status No {\ all\ |\ printer\ }
+Display the status of daemons and queues on the local machine.
+.Pp
+.It Ic stop No {\ all\ |\ printer\ }
+Stop a spooling daemon after the current job completes and disable
+printing.
+.Pp
+.It Ic topq No printer\ [\ jobnum\ ...\ ]\ [\ user\ ...\ ]
+Place the jobs in the order listed at the top of the printer queue.
+.Pp
+.It Ic up No {\ all\ |\ printer\ }
+Enable everything and start a new printer daemon. Undoes the effects of
+.Ic down .
+.Sh FILES
+.Bl -tag -width /var/spool/*/lockx -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/lock
+lock file for queue control
+.El
+.Sh SEE ALSO
+.Xr lpd 8 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr printcap 5
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds
+.It Sy "?Ambiguous command"
+abbreviation matches more than one command
+.It Sy "?Invalid command"
+no match was found
+.It Sy "?Privileged command"
+command can be executed by root only
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/lpr/lpc/lpc.c b/usr.sbin/lpr/lpc/lpc.c
new file mode 100644
index 00000000000..b26728c3f62
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lpc.h"
+#include "extern.h"
+
+/*
+ * lpc -- line printer control program
+ */
+
+#define MAX_CMDLINE 200
+#define MAX_MARGV 20
+int fromatty;
+
+char cmdline[MAX_CMDLINE];
+int margc;
+char *margv[MAX_MARGV];
+int top;
+uid_t uid, euid;
+
+jmp_buf toplevel;
+
+static void cmdscanner __P((int));
+static struct cmd *getcmd __P((char *));
+static void intr __P((int));
+static void makeargv __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ name = argv[0];
+ openlog("lpd", 0, LOG_LPR);
+
+ if (--argc > 0) {
+ c = getcmd(*++argv);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ exit(1);
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ exit(1);
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+ fromatty = isatty(fileno(stdin));
+ top = setjmp(toplevel) == 0;
+ if (top)
+ signal(SIGINT, intr);
+ for (;;) {
+ cmdscanner(top);
+ top = 1;
+ }
+}
+
+static void
+intr(signo)
+ int signo;
+{
+ if (!fromatty)
+ exit(0);
+ longjmp(toplevel, 1);
+}
+
+/*
+ * Command parser.
+ */
+static void
+cmdscanner(top)
+ int top;
+{
+ register struct cmd *c;
+
+ if (!top)
+ putchar('\n');
+ for (;;) {
+ if (fromatty) {
+ printf("lpc> ");
+ fflush(stdout);
+ }
+ if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
+ quit(0, NULL);
+ if (cmdline[0] == 0 || cmdline[0] == '\n')
+ break;
+ makeargv();
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ }
+ longjmp(toplevel, 0);
+}
+
+struct cmd *
+getcmd(name)
+ register char *name;
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; p = c->c_name; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return(c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return((struct cmd *)-1);
+ return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+static void
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+ register int n = 0;
+
+ margc = 0;
+ for (cp = cmdline; *cp && n < MAX_MARGV; n++) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ if (argc == 1) {
+ register int i, j, w;
+ int columns, width = 0, lines;
+ extern int NCMDS;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->c_name; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ if (c->c_name)
+ printf("%s", c->c_name);
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
diff --git a/usr.sbin/lpr/lpc/lpc.h b/usr.sbin/lpr/lpc/lpc.h
new file mode 100644
index 00000000000..5e7120315f5
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)lpc.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Line printer control program.
+ */
+struct cmd {
+ char *c_name; /* command name */
+ char *c_help; /* help message */
+ /* routine to do the work */
+ void (*c_handler) __P((int, char *[]));
+ int c_priv; /* privileged command */
+};
diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile
new file mode 100644
index 00000000000..58c4a679b50
--- /dev/null
+++ b/usr.sbin/lpr/lpd/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpd
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN= lpd.8
+SRCS= lpd.c printjob.c recvjob.c displayq.c rmjob.c startdaemon.c \
+ lpdchar.c common.c key.c modes.c ttcompat.c
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpd/extern.h b/usr.sbin/lpr/lpd/extern.h
new file mode 100644
index 00000000000..cabc92d2296
--- /dev/null
+++ b/usr.sbin/lpr/lpd/extern.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/cdefs.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+/*
+ * from stty.h
+ */
+struct info {
+ int fd; /* file descriptor */
+ int ldisc; /* line discipline */
+ int off; /* turn off */
+ int set; /* need set */
+ int wset; /* need window set */
+ char *arg; /* argument */
+ struct termios t; /* terminal info */
+ struct winsize win; /* window info */
+};
+
+void printjob __P((void));
+void recvjob __P((void));
+void sttyclearflags __P((struct termios *tp, int flags));
+void sttysetflags __P((struct termios *tp, int flags));
+void sttyclearlflags __P((struct termios *tp, int flags));
+void sttysetlflags __P((struct termios *tp, int flags));
diff --git a/usr.sbin/lpr/lpd/key.c b/usr.sbin/lpr/lpd/key.c
new file mode 100644
index 00000000000..b6ac5c419b1
--- /dev/null
+++ b/usr.sbin/lpr/lpd/key.c
@@ -0,0 +1,270 @@
+/* $NetBSD: key.c,v 1.1 1995/10/03 15:02:41 hpeyerl Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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
+#if 0
+static char sccsid[] = "@(#)key.c 8.3 (Berkeley) 4/2/94";
+#else
+static char rcsid[] = "$NetBSD: key.c,v 1.1 1995/10/03 15:02:41 hpeyerl Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <termios.h>
+
+#include "lp.h"
+#include "extern.h"
+
+__BEGIN_DECLS
+void f_cbreak __P((struct info *));
+void f_columns __P((struct info *));
+void f_dec __P((struct info *));
+void f_extproc __P((struct info *));
+void f_ispeed __P((struct info *));
+void f_nl __P((struct info *));
+void f_ospeed __P((struct info *));
+void f_raw __P((struct info *));
+void f_rows __P((struct info *));
+void f_sane __P((struct info *));
+void f_tty __P((struct info *));
+__END_DECLS
+
+static struct key {
+ char *name; /* name */
+ void (*f) __P((struct info *)); /* function */
+#define F_NEEDARG 0x01 /* needs an argument */
+#define F_OFFOK 0x02 /* can turn off */
+ int flags;
+} keys[] = {
+ { "cbreak", f_cbreak, F_OFFOK },
+ { "cols", f_columns, F_NEEDARG },
+ { "columns", f_columns, F_NEEDARG },
+ { "cooked", f_sane, 0 },
+ { "dec", f_dec, 0 },
+ { "extproc", f_extproc, F_OFFOK },
+ { "ispeed", f_ispeed, F_NEEDARG },
+ { "new", f_tty, 0 },
+ { "nl", f_nl, F_OFFOK },
+ { "old", f_tty, 0 },
+ { "ospeed", f_ospeed, F_NEEDARG },
+ { "raw", f_raw, F_OFFOK },
+ { "rows", f_rows, F_NEEDARG },
+ { "sane", f_sane, 0 },
+ { "tty", f_tty, 0 },
+};
+
+static int
+c_key(a, b)
+ const void *a, *b;
+{
+
+ return (strcmp(((struct key *)a)->name, ((struct key *)b)->name));
+}
+
+int
+ksearch(argvp, ip)
+ char ***argvp;
+ struct info *ip;
+{
+ char *name;
+ struct key *kp, tmp;
+
+ name = **argvp;
+ if (*name == '-') {
+ ip->off = 1;
+ ++name;
+ } else
+ ip->off = 0;
+
+ tmp.name = name;
+ if (!(kp = (struct key *)bsearch(&tmp, keys,
+ sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
+ return (0);
+ if (!(kp->flags & F_OFFOK) && ip->off) {
+ syslog(LOG_INFO, "%s: illegal option: %s", printer, name);
+ return (1);
+ }
+ if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) {
+ syslog(LOG_INFO, "%s: option requires an argument: %s",
+ printer, name);
+ return (1);
+ }
+ kp->f(ip);
+ return (1);
+}
+
+void
+f_cbreak(ip)
+ struct info *ip;
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ ip->t.c_iflag |= BRKINT|IXON|IMAXBEL;
+ ip->t.c_oflag |= OPOST;
+ ip->t.c_lflag |= ISIG|IEXTEN;
+ ip->t.c_lflag &= ~ICANON;
+ ip->set = 1;
+ }
+}
+
+void
+f_columns(ip)
+ struct info *ip;
+{
+
+ ip->win.ws_col = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_dec(ip)
+ struct info *ip;
+{
+
+ ip->t.c_cc[VERASE] = (u_char)0177;
+ ip->t.c_cc[VKILL] = CTRL('u');
+ ip->t.c_cc[VINTR] = CTRL('c');
+ ip->t.c_lflag &= ~ECHOPRT;
+ ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
+ ip->t.c_iflag &= ~IXANY;
+ ip->set = 1;
+}
+
+void
+f_extproc(ip)
+ struct info *ip;
+{
+
+ if (ip->set) {
+ int tmp = 1;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ } else {
+ int tmp = 0;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ }
+}
+
+void
+f_ispeed(ip)
+ struct info *ip;
+{
+
+ cfsetispeed(&ip->t, atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_nl(ip)
+ struct info *ip;
+{
+
+ if (ip->off) {
+ ip->t.c_iflag |= ICRNL;
+ ip->t.c_oflag |= ONLCR;
+ } else {
+ ip->t.c_iflag &= ~ICRNL;
+ ip->t.c_oflag &= ~ONLCR;
+ }
+ ip->set = 1;
+}
+
+void
+f_ospeed(ip)
+ struct info *ip;
+{
+
+ cfsetospeed(&ip->t, atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_raw(ip)
+ struct info *ip;
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ cfmakeraw(&ip->t);
+ ip->t.c_cflag &= ~(CSIZE|PARENB);
+ ip->t.c_cflag |= CS8;
+ ip->set = 1;
+ }
+}
+
+void
+f_rows(ip)
+ struct info *ip;
+{
+
+ ip->win.ws_row = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_sane(ip)
+ struct info *ip;
+{
+
+ ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & (CLOCAL|CRTSCTS));
+ ip->t.c_iflag = TTYDEF_IFLAG;
+ ip->t.c_iflag |= ICRNL;
+ /* preserve user-preference flags in lflag */
+#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
+ ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP);
+ ip->t.c_oflag = TTYDEF_OFLAG;
+ ip->set = 1;
+}
+
+void
+f_tty(ip)
+ struct info *ip;
+{
+ int tmp;
+
+ tmp = TTYDISC;
+ if (ioctl(0, TIOCSETD, &tmp) < 0)
+ syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
+}
diff --git a/usr.sbin/lpr/lpd/lpd.8 b/usr.sbin/lpr/lpd/lpd.8
new file mode 100644
index 00000000000..1e4677ff91e
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.8
@@ -0,0 +1,249 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)lpd.8 8.3 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt LPD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpd
+.Nd line printer spooler daemon
+.Sh SYNOPSIS
+.Nm lpd
+.Op Fl l
+.Op Ar port#
+.Sh DESCRIPTION
+.Nm Lpd
+is the line printer daemon (spool area handler) and is normally invoked
+at boot time from the
+.Xr rc 8
+file. It makes a single pass through the
+.Xr printcap 5
+file to find out about the existing printers and
+prints any files left after a crash. It then uses the system calls
+.Xr listen 2
+and
+.Xr accept 2
+to receive requests to print files in the queue,
+transfer files to the spooling area, display the queue,
+or remove jobs from the queue. In each case, it forks a child to handle
+the request so the parent can continue to listen for more requests.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl l
+The
+.Fl l
+flag causes
+.Nm lpd
+to log valid requests received from the network. This can be useful
+for debugging purposes.
+.It Ar "port#"
+The Internet port number used to rendezvous
+with other processes is normally obtained with
+.Xr getservbyname 3
+but can be changed with the
+.Ar port#
+argument.
+.El
+.Pp
+Access control is provided by two means. First, all requests must come from
+one of the machines listed in the file
+.Pa /etc/hosts.equiv
+or
+.Pa /etc/hosts.lpd .
+Second, if the
+.Li rs
+capability is specified in the
+.Xr printcap
+entry for the printer being accessed,
+.Em lpr
+requests will only be honored for those users with accounts on the
+machine with the printer.
+.Pp
+The file
+.Em minfree
+in each spool directory contains the number of disk blocks to leave free
+so that the line printer queue won't completely fill the disk.
+The
+.Em minfree
+file can be edited with your favorite text editor.
+.Pp
+The daemon begins processing files
+after it has successfully set the lock for exclusive
+access (described a bit later),
+and scans the spool directory
+for files beginning with
+.Em cf .
+Lines in each
+.Em cf
+file specify files to be printed or non-printing actions to be
+performed. Each such line begins with a key character
+to specify what to do with the remainder of the line.
+.Bl -tag -width Ds
+.It J
+Job Name. String to be used for the job name on the burst page.
+.It C
+Classification. String to be used for the classification line
+on the burst page.
+.It L
+Literal. The line contains identification info from
+the password file and causes the banner page to be printed.
+.It T
+Title. String to be used as the title for
+.Xr pr 1 .
+.It H
+Host Name. Name of the machine where
+.Xr lpr
+was invoked.
+.It P
+Person. Login name of the person who invoked
+.Xr lpr .
+This is used to verify ownership by
+.Xr lprm .
+.It M
+Send mail to the specified user when the current print job completes.
+.It f
+Formatted File. Name of a file to print which is already formatted.
+.It l
+Like ``f'' but passes control characters and does not make page breaks.
+.It p
+Name of a file to print using
+.Xr pr 1
+as a filter.
+.It t
+Troff File. The file contains
+.Xr troff 1
+output (cat phototypesetter commands).
+.It n
+Ditroff File. The file contains device independent troff
+output.
+.It r
+DVI File. The file contains
+.Tn Tex l
+output
+DVI format from Standford.
+.It g
+Graph File. The file contains data produced by
+.Xr plot 3 .
+.It c
+Cifplot File. The file contains data produced by
+.Em cifplot .
+.It v
+The file contains a raster image.
+.It r
+The file contains text data with
+FORTRAN carriage control characters.
+.It \&1
+Troff Font R. Name of the font file to use instead of the default.
+.It \&2
+Troff Font I. Name of the font file to use instead of the default.
+.It \&3
+Troff Font B. Name of the font file to use instead of the default.
+.It \&4
+Troff Font S. Name of the font file to use instead of the default.
+.It W
+Width. Changes the page width (in characters) used by
+.Xr pr 1
+and the text filters.
+.It I
+Indent. The number of characters to indent the output by (in ascii).
+.It U
+Unlink. Name of file to remove upon completion of printing.
+.It N
+File name. The name of the file which is being printed, or a blank
+for the standard input (when
+.Xr lpr
+is invoked in a pipeline).
+.El
+.Pp
+If a file cannot be opened, a message will be logged via
+.Xr syslog 3
+using the
+.Em LOG_LPR
+facility.
+.Nm Lpd
+will try up to 20 times
+to reopen a file it expects to be there, after which it will
+skip the file to be printed.
+.Pp
+.Nm Lpd
+uses
+.Xr flock 2
+to provide exclusive access to the lock file and to prevent multiple
+daemons from becoming active simultaneously. If the daemon should be killed
+or die unexpectedly, the lock file need not be removed.
+The lock file is kept in a readable
+.Tn ASCII
+form
+and contains two lines.
+The first is the process id of the daemon and the second is the control
+file name of the current job being printed. The second line is updated to
+reflect the current status of
+.Nm lpd
+for the programs
+.Xr lpq 1
+and
+.Xr lprm 1 .
+.Sh FILES
+.Bl -tag -width "/var/spool/*/minfree" -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/minfree
+minimum free space to leave
+.It Pa /dev/lp*
+line printer devices
+.It Pa /dev/printer
+socket for local requests
+.It Pa /etc/hosts.equiv
+lists machine names allowed printer access
+.It Pa /etc/hosts.lpd
+lists machine names allowed printer access,
+but not under same administrative control.
+.El
+.Sh SEE ALSO
+.Xr lpc 8 ,
+.Xr pac 1 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr syslog 3 ,
+.Xr printcap 5
+.Rs
+.%T "4.2 BSD Line Printer Spooler Manual"
+.Re
+.Sh HISTORY
+An
+.Nm
+daemon appeared in Version 6 AT&T UNIX.
diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c
new file mode 100644
index 00000000000..f06efdce8d9
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 1983, 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 copyright[] =
+"@(#) Copyright (c) 1983, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpd.c 8.4 (Berkeley) 4/17/94";
+#endif /* not lint */
+
+/*
+ * lpd -- line printer daemon.
+ *
+ * Listen for a connection and perform the requested operation.
+ * Operations are:
+ * \1printer\n
+ * check the queue for jobs and print any found.
+ * \2printer\n
+ * receive a job from another machine and queue it.
+ * \3printer [users ...] [jobs ...]\n
+ * return the current state of the queue (short form).
+ * \4printer [users ...] [jobs ...]\n
+ * return the current state of the queue (long form).
+ * \5printer person [users ...] [jobs ...]\n
+ * remove jobs from the queue.
+ *
+ * Strategy to maintain protected spooling area:
+ * 1. Spooling area is writable only by daemon and spooling group
+ * 2. lpr runs setuid root and setgrp spooling group; it uses
+ * root to access any file it wants (verifying things before
+ * with an access call) and group id to know how it should
+ * set up ownership of files in the spooling area.
+ * 3. Files in spooling area are owned by root, group spooling
+ * group, with mode 660.
+ * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
+ * access files and printer. Users can't get to anything
+ * w/o help of lpq and lprm programs.
+ */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
+
+int lflag; /* log requests flag */
+int from_remote; /* from remote socket */
+
+static void reapchild __P((int));
+static void mcleanup __P((int));
+static void doit __P((void));
+static void startup __P((void));
+static void chkhost __P((struct sockaddr_in *));
+
+uid_t uid, euid;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int f, funix, finet, options, fromlen;
+ fd_set defreadfds;
+ struct sockaddr_un un, fromunix;
+ struct sockaddr_in sin, frominet;
+ int omask, lfd;
+
+ euid = geteuid(); /* these shouldn't be different */
+ uid = getuid();
+ options = 0;
+ gethostname(host, sizeof(host));
+ name = argv[0];
+
+ while (--argc > 0) {
+ argv++;
+ if (argv[0][0] == '-')
+ switch (argv[0][1]) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ }
+ }
+
+#ifndef DEBUG
+ /*
+ * Set up standard environment by detaching from the parent.
+ */
+ daemon(0, 0);
+#endif
+
+ openlog("lpd", LOG_PID, LOG_LPR);
+ syslog(LOG_INFO, "restarted");
+ (void) umask(0);
+ lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
+ if (lfd < 0) {
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ ftruncate(lfd, 0);
+ /*
+ * write process id for others to know
+ */
+ sprintf(line, "%u\n", getpid());
+ f = strlen(line);
+ if (write(lfd, line, f) != f) {
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ signal(SIGCHLD, reapchild);
+ /*
+ * Restart all the printers.
+ */
+ startup();
+ (void) unlink(_PATH_SOCKETNAME);
+ funix = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (funix < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+#define mask(s) (1 << ((s) - 1))
+ omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+ signal(SIGHUP, mcleanup);
+ signal(SIGINT, mcleanup);
+ signal(SIGQUIT, mcleanup);
+ signal(SIGTERM, mcleanup);
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, _PATH_SOCKETNAME);
+#ifndef SUN_LEN
+#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
+#endif
+ if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ syslog(LOG_ERR, "ubind: %m");
+ exit(1);
+ }
+ sigsetmask(omask);
+ FD_ZERO(&defreadfds);
+ FD_SET(funix, &defreadfds);
+ listen(funix, 5);
+ finet = socket(AF_INET, SOCK_STREAM, 0);
+ if (finet >= 0) {
+ struct servent *sp;
+
+ if (options & SO_DEBUG)
+ if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+ mcleanup(0);
+ }
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL) {
+ syslog(LOG_ERR, "printer/tcp: unknown service");
+ mcleanup(0);
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = sp->s_port;
+ if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ mcleanup(0);
+ }
+ FD_SET(finet, &defreadfds);
+ listen(finet, 5);
+ }
+ /*
+ * Main loop: accept, do a request, continue.
+ */
+ memset(&frominet, 0, sizeof(frominet));
+ memset(&fromunix, 0, sizeof(fromunix));
+ for (;;) {
+ int domain, nfds, s;
+ fd_set readfds;
+
+ FD_COPY(&defreadfds, &readfds);
+ nfds = select(20, &readfds, 0, 0, 0);
+ if (nfds <= 0) {
+ if (nfds < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "select: %m");
+ continue;
+ }
+ if (FD_ISSET(funix, &readfds)) {
+ domain = AF_UNIX, fromlen = sizeof(fromunix);
+ s = accept(funix,
+ (struct sockaddr *)&fromunix, &fromlen);
+ } else /* if (FD_ISSET(finet, &readfds)) */ {
+ domain = AF_INET, fromlen = sizeof(frominet);
+ s = accept(finet,
+ (struct sockaddr *)&frominet, &fromlen);
+ }
+ if (s < 0) {
+ if (errno != EINTR)
+ syslog(LOG_WARNING, "accept: %m");
+ continue;
+ }
+ if (fork() == 0) {
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ (void) close(funix);
+ (void) close(finet);
+ dup2(s, 1);
+ (void) close(s);
+ if (domain == AF_INET) {
+ from_remote = 1;
+ chkhost(&frominet);
+ } else
+ from_remote = 0;
+ doit();
+ exit(0);
+ }
+ (void) close(s);
+ }
+}
+
+static void
+reapchild(signo)
+ int signo;
+{
+ union wait status;
+
+ while (wait3((int *)&status, WNOHANG, 0) > 0)
+ ;
+}
+
+static void
+mcleanup(signo)
+ int signo;
+{
+ if (lflag)
+ syslog(LOG_INFO, "exiting");
+ unlink(_PATH_SOCKETNAME);
+ exit(0);
+}
+
+/*
+ * Stuff for handling job specifications
+ */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *person; /* name of person doing lprm */
+
+char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */
+char cbuf[BUFSIZ]; /* command line buffer */
+char *cmdnames[] = {
+ "null",
+ "printjob",
+ "recvjob",
+ "displayq short",
+ "displayq long",
+ "rmjob"
+};
+
+static void
+doit()
+{
+ register char *cp;
+ register int n;
+
+ for (;;) {
+ cp = cbuf;
+ do {
+ if (cp >= &cbuf[sizeof(cbuf) - 1])
+ fatal("Command line too long");
+ if ((n = read(1, cp, 1)) != 1) {
+ if (n < 0)
+ fatal("Lost connection");
+ return;
+ }
+ } while (*cp++ != '\n');
+ *--cp = '\0';
+ cp = cbuf;
+ if (lflag) {
+ if (*cp >= '\1' && *cp <= '\5')
+ syslog(LOG_INFO, "%s requests %s %s",
+ from, cmdnames[*cp], cp+1);
+ else
+ syslog(LOG_INFO, "bad request (%d) from %s",
+ *cp, from);
+ }
+ switch (*cp++) {
+ case '\1': /* check the queue and print any jobs there */
+ printer = cp;
+ printjob();
+ break;
+ case '\2': /* receive files to be queued */
+ if (!from_remote) {
+ syslog(LOG_INFO, "illegal request (%d)", *cp);
+ exit(1);
+ }
+ printer = cp;
+ recvjob();
+ break;
+ case '\3': /* display the queue (short form) */
+ case '\4': /* display the queue (long form) */
+ printer = cp;
+ while (*cp) {
+ if (*cp != ' ') {
+ cp++;
+ continue;
+ }
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ if (isdigit(*cp)) {
+ if (requests >= MAXREQUESTS)
+ fatal("Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = cp;
+ }
+ }
+ displayq(cbuf[0] - '\3');
+ exit(0);
+ case '\5': /* remove a job from the queue */
+ if (!from_remote) {
+ syslog(LOG_INFO, "illegal request (%d)", *cp);
+ exit(1);
+ }
+ printer = cp;
+ while (*cp && *cp != ' ')
+ cp++;
+ if (!*cp)
+ break;
+ *cp++ = '\0';
+ person = cp;
+ while (*cp) {
+ if (*cp != ' ') {
+ cp++;
+ continue;
+ }
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ if (isdigit(*cp)) {
+ if (requests >= MAXREQUESTS)
+ fatal("Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = cp;
+ }
+ }
+ rmjob();
+ break;
+ }
+ fatal("Illegal service request");
+ }
+}
+
+/*
+ * Make a pass through the printcap database and start printing any
+ * files left from the last time the machine went down.
+ */
+static void
+startup()
+{
+ char *buf;
+ register char *cp;
+ int pid;
+
+ /*
+ * Restart the daemons.
+ */
+ while (cgetnext(&buf, printcapdb) > 0) {
+ for (cp = buf; *cp; cp++)
+ if (*cp == '|' || *cp == ':') {
+ *cp = '\0';
+ break;
+ }
+ if ((pid = fork()) < 0) {
+ syslog(LOG_WARNING, "startup: cannot fork");
+ mcleanup(0);
+ }
+ if (!pid) {
+ printer = buf;
+ cgetclose();
+ printjob();
+ }
+ }
+}
+
+#define DUMMY ":nobody::"
+
+/*
+ * Check to see if the from host has access to the line printer.
+ */
+static void
+chkhost(f)
+ struct sockaddr_in *f;
+{
+ register struct hostent *hp;
+ register FILE *hostf;
+ int first = 1;
+ extern char *inet_ntoa();
+
+ f->sin_port = ntohs(f->sin_port);
+ if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
+ fatal("Malformed from address");
+
+ /* Need real hostname for temporary filenames */
+ hp = gethostbyaddr((char *)&f->sin_addr,
+ sizeof(struct in_addr), f->sin_family);
+ if (hp == NULL)
+ fatal("Host name for your address (%s) unknown",
+ inet_ntoa(f->sin_addr));
+
+ (void) strncpy(fromb, hp->h_name, sizeof(fromb));
+ from[sizeof(fromb) - 1] = '\0';
+ from = fromb;
+
+ hostf = fopen(_PATH_HOSTSEQUIV, "r");
+again:
+ if (hostf) {
+ if (__ivaliduser(hostf, f->sin_addr.s_addr,
+ DUMMY, DUMMY) == 0) {
+ (void) fclose(hostf);
+ return;
+ }
+ (void) fclose(hostf);
+ }
+ if (first == 1) {
+ first = 0;
+ hostf = fopen(_PATH_HOSTSLPD, "r");
+ goto again;
+ }
+ fatal("Your host does not have line printer access");
+ /*NOTREACHED*/
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr.sbin/lpr/lpd/lpdchar.c b/usr.sbin/lpr/lpd/lpdchar.c
new file mode 100644
index 00000000000..4a4f5da1ccb
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpdchar.c
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 1983, 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 sccsid[] = "@(#)lpdchar.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Character set for line printer daemon
+ */
+#include "lp.local.h"
+
+#define c_______ 0
+#define c______1 01
+#define c_____1_ 02
+#define c____1__ 04
+#define c____11_ 06
+#define c___1___ 010
+#define c___1__1 011
+#define c___1_1_ 012
+#define c___11__ 014
+#define c__1____ 020
+#define c__1__1_ 022
+#define c__1_1__ 024
+#define c__11___ 030
+#define c__111__ 034
+#define c__111_1 035
+#define c__1111_ 036
+#define c__11111 037
+#define c_1_____ 040
+#define c_1____1 041
+#define c_1___1_ 042
+#define c_1__1__ 044
+#define c_1_1___ 050
+#define c_1_1__1 051
+#define c_1_1_1_ 052
+#define c_11____ 060
+#define c_11_11_ 066
+#define c_111___ 070
+#define c_111__1 071
+#define c_111_1_ 072
+#define c_1111__ 074
+#define c_1111_1 075
+#define c_11111_ 076
+#define c_111111 077
+#define c1______ 0100
+#define c1_____1 0101
+#define c1____1_ 0102
+#define c1____11 0103
+#define c1___1__ 0104
+#define c1___1_1 0105
+#define c1___11_ 0106
+#define c1__1___ 0110
+#define c1__1__1 0111
+#define c1__11_1 0115
+#define c1__1111 0117
+#define c1_1____ 0120
+#define c1_1___1 0121
+#define c1_1_1_1 0125
+#define c1_1_11_ 0126
+#define c1_111__ 0134
+#define c1_1111_ 0136
+#define c11____1 0141
+#define c11___1_ 0142
+#define c11___11 0143
+#define c11_1___ 0150
+#define c11_1__1 0151
+#define c111_11_ 0166
+#define c1111___ 0170
+#define c11111__ 0174
+#define c111111_ 0176
+#define c1111111 0177
+
+char scnkey[][HEIGHT] = /* this is relatively easy to modify */
+ /* just look: */
+{
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* */
+
+ { c__11___,
+ c__11___,
+ c__11___,
+ c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* ! */
+
+ { c_1__1__,
+ c_1__1__,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* " */
+
+ { c_______,
+ c__1_1__,
+ c__1_1__,
+ c1111111,
+ c__1_1__,
+ c1111111,
+ c__1_1__,
+ c__1_1__,
+ c_______ }, /* # */
+
+ { c___1___,
+ c_11111_,
+ c1__1__1,
+ c1__1___,
+ c_11111_,
+ c___1__1,
+ c1__1__1,
+ c_11111_,
+ c___1___ }, /* $ */
+
+ { c_1_____,
+ c1_1___1,
+ c_1___1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1___1_,
+ c1___1_1,
+ c_____1_ }, /* % */
+
+ { c_11____,
+ c1__1___,
+ c1___1__,
+ c_1_1___,
+ c__1____,
+ c_1_1__1,
+ c1___11_,
+ c1___11_,
+ c_111__1 }, /* & */
+
+ { c___11__,
+ c___11__,
+ c___1___,
+ c__1____,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ' */
+
+ { c____1__,
+ c___1___,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c___1___,
+ c____1__ }, /* ( */
+
+ { c__1____,
+ c___1___,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c___1___,
+ c__1____ }, /* ) */
+
+ { c_______,
+ c___1___,
+ c1__1__1,
+ c_1_1_1_,
+ c__111__,
+ c_1_1_1_,
+ c1__1__1,
+ c___1___,
+ c_______ }, /* * */
+
+ { c_______,
+ c___1___,
+ c___1___,
+ c___1___,
+ c1111111,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_______ }, /* + */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c__1____,
+ c_1_____,
+ c_______ }, /* , */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* - */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* . */
+
+ { c_______,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c_______ }, /* / */
+
+ { c_11111_,
+ c1_____1,
+ c1____11,
+ c1___1_1,
+ c1__1__1,
+ c1_1___1,
+ c11____1,
+ c1_____1,
+ c_11111_ }, /* 0 */
+
+ { c___1___,
+ c__11___,
+ c_1_1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_11111_ }, /* 1 */
+
+ { c_11111_,
+ c1_____1,
+ c______1,
+ c_____1_,
+ c__111__,
+ c_1_____,
+ c1______,
+ c1______,
+ c1111111 }, /* 2 */
+
+ { c_11111_,
+ c1_____1,
+ c______1,
+ c______1,
+ c__1111_,
+ c______1,
+ c______1,
+ c1_____1,
+ c_11111_ }, /* 3 */
+
+ { c_____1_,
+ c____11_,
+ c___1_1_,
+ c__1__1_,
+ c_1___1_,
+ c1____1_,
+ c1111111,
+ c_____1_,
+ c_____1_ }, /* 4 */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c11111__,
+ c_____1_,
+ c______1,
+ c______1,
+ c1____1_,
+ c_1111__ }, /* 5 */
+
+ { c__1111_,
+ c_1_____,
+ c1______,
+ c1______,
+ c1_1111_,
+ c11____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* 6 */
+
+ { c1111111,
+ c1_____1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____ }, /* 7 */
+
+ { c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* 8 */
+
+ { c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_111111,
+ c______1,
+ c______1,
+ c1_____1,
+ c_1111__ }, /* 9 */
+
+ { c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* : */
+
+
+ { c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c__1____,
+ c_1_____,
+ c_______ }, /* ; */
+
+ { c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c_1_____,
+ c__1____,
+ c___1___,
+ c____1__ }, /* < */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______,
+ c1111111,
+ c_______,
+ c_______,
+ c_______ }, /* = */
+
+ { c__1____,
+ c___1___,
+ c____1__,
+ c_____1_,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____ }, /* > */
+
+ { c__1111_,
+ c_1____1,
+ c_1____1,
+ c______1,
+ c____11_,
+ c___1___,
+ c___1___,
+ c_______,
+ c___1___ }, /* ? */
+
+ { c__1111_,
+ c_1____1,
+ c1__11_1,
+ c1_1_1_1,
+ c1_1_1_1,
+ c1_1111_,
+ c1______,
+ c_1____1,
+ c__1111_ }, /* @ */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1111111,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* A */
+
+ { c111111_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_11111_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c111111_ }, /* B */
+
+ { c__1111_,
+ c_1____1,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c_1____1,
+ c__1111_ }, /* C */
+
+ { c11111__,
+ c_1___1_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1___1_,
+ c11111__ }, /* D */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c1______,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1111111 }, /* E */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c1______,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* F */
+
+ { c__1111_,
+ c_1____1,
+ c1______,
+ c1______,
+ c1______,
+ c1__1111,
+ c1_____1,
+ c_1____1,
+ c__1111_ }, /* G */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1111111,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* H */
+
+ { c_11111_,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_11111_ }, /* I */
+
+ { c__11111,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c1___1__,
+ c_111___ }, /* J */
+
+ { c1_____1,
+ c1____1_,
+ c1___1__,
+ c1__1___,
+ c1_1____,
+ c11_1___,
+ c1___1__,
+ c1____1_,
+ c1_____1 }, /* K */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1111111 }, /* L */
+
+ { c1_____1,
+ c11___11,
+ c1_1_1_1,
+ c1__1__1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* M */
+
+ { c1_____1,
+ c11____1,
+ c1_1___1,
+ c1__1__1,
+ c1___1_1,
+ c1____11,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* N */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__111__ }, /* O */
+
+ { c111111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* P */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1__1__1,
+ c1___1_1,
+ c_1___1_,
+ c__111_1 }, /* Q */
+
+ { c111111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c111111_,
+ c1__1___,
+ c1___1__,
+ c1____1_,
+ c1_____1 }, /* R */
+
+ { c_11111_,
+ c1_____1,
+ c1______,
+ c1______,
+ c_11111_,
+ c______1,
+ c______1,
+ c1_____1,
+ c_11111_ }, /* S */
+
+ { c1111111,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* T */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* U */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c_1___1_,
+ c__1_1__,
+ c__1_1__,
+ c___1___,
+ c___1___ }, /* V */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1__1__1,
+ c1__1__1,
+ c1_1_1_1,
+ c11___11,
+ c1_____1 }, /* W */
+
+ { c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___,
+ c__1_1__,
+ c_1___1_,
+ c1_____1,
+ c1_____1 }, /* X */
+
+ { c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* Y */
+
+ { c1111111,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c1111111 }, /* Z */
+
+ { c_1111__,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1111__ }, /* [ */
+
+ { c_______,
+ c1______,
+ c_1_____,
+ c__1____,
+ c___1___,
+ c____1__,
+ c_____1_,
+ c______1,
+ c_______ }, /* \ */
+
+ { c__1111_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c__1111_ }, /* ] */
+
+ { c___1___,
+ c__1_1__,
+ c_1___1_,
+ c1_____1,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ^ */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______ }, /* _ */
+
+ { c__11___,
+ c__11___,
+ c___1___,
+ c____1__,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ` */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c_____1_,
+ c_11111_,
+ c1_____1,
+ c1____11,
+ c_1111_1 }, /* a */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1_111__,
+ c11___1_,
+ c1_____1,
+ c1_____1,
+ c11___1_,
+ c1_111__ }, /* b */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c1______,
+ c1______,
+ c1____1_,
+ c_1111__ }, /* c */
+
+ { c_____1_,
+ c_____1_,
+ c_____1_,
+ c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_ }, /* d */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c111111_,
+ c1______,
+ c1____1_,
+ c_1111__ }, /* e */
+
+ { c___11__,
+ c__1__1_,
+ c__1____,
+ c__1____,
+ c11111__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____ }, /* f */
+
+ { c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c1____1_,
+ c_1111__ }, /* g */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_ }, /* h */
+
+ { c_______,
+ c___1___,
+ c_______,
+ c__11___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c__111__ }, /* i */
+
+ { c____11_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_1___1_,
+ c__111__ }, /* j */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1___1__,
+ c1__1___,
+ c1_1____,
+ c11_1___,
+ c1___1__,
+ c1____1_ }, /* k */
+
+ { c__11___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c__111__ }, /* l */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_1_11_,
+ c11_1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1 }, /* m */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_ }, /* n */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c_1111__ }, /* o */
+
+ { c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c11___1_,
+ c1_111__,
+ c1______,
+ c1______,
+ c1______ }, /* p */
+
+ { c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c_____1_,
+ c_____1_ }, /* q */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_111__,
+ c11___1_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* r */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c_11____,
+ c___11__,
+ c1____1_,
+ c_1111__ }, /* s */
+
+ { c_______,
+ c__1____,
+ c__1____,
+ c11111__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1__1_,
+ c___11__ }, /* t */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_ }, /* u */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___ }, /* v */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_____1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c_11_11_ }, /* w */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1____1_,
+ c_1__1__,
+ c__11___,
+ c__11___,
+ c_1__1__,
+ c1____1_ }, /* x */
+
+ { c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c1____1_,
+ c_1111__ }, /* y */
+
+ { c_______,
+ c_______,
+ c_______,
+ c111111_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c111111_ }, /* z */
+
+ { c___11__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c_1_____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c___11__ }, /* } */
+
+ { c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* | */
+
+ { c__11___,
+ c____1__,
+ c____1__,
+ c____1__,
+ c_____1_,
+ c____1__,
+ c____1__,
+ c____1__,
+ c__11___ }, /* } */
+
+ { c_11____,
+ c1__1__1,
+ c____11_,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ~ */
+
+ { c_1__1__,
+ c1__1__1,
+ c__1__1_,
+ c_1__1__,
+ c1__1__1,
+ c__1__1_,
+ c_1__1__,
+ c1__1__1,
+ c__1__1_ } /* rub-out */
+};
diff --git a/usr.sbin/lpr/lpd/modes.c b/usr.sbin/lpr/lpd/modes.c
new file mode 100644
index 00000000000..7436a9f3335
--- /dev/null
+++ b/usr.sbin/lpr/lpd/modes.c
@@ -0,0 +1,238 @@
+/* $NetBSD: modes.c,v 1.1 1995/10/03 15:02:45 hpeyerl Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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
+#if 0
+static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
+#else
+static char rcsid[] = "$NetBSD: modes.c,v 1.1 1995/10/03 15:02:45 hpeyerl Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <string.h>
+#include <termios.h>
+#include "extern.h"
+
+struct modes {
+ char *name;
+ long set;
+ long unset;
+};
+
+/*
+ * The code in optlist() depends on minus options following regular
+ * options, i.e. "foo" must immediately precede "-foo".
+ */
+struct modes cmodes[] = {
+ { "cs5", CS5, CSIZE },
+ { "cs6", CS6, CSIZE },
+ { "cs7", CS7, CSIZE },
+ { "cs8", CS8, CSIZE },
+ { "cstopb", CSTOPB, 0 },
+ { "-cstopb", 0, CSTOPB },
+ { "cread", CREAD, 0 },
+ { "-cread", 0, CREAD },
+ { "parenb", PARENB, 0 },
+ { "-parenb", 0, PARENB },
+ { "parodd", PARODD, 0 },
+ { "-parodd", 0, PARODD },
+ { "parity", PARENB | CS7, PARODD | CSIZE },
+ { "-parity", CS8, PARODD | PARENB | CSIZE },
+ { "evenp", PARENB | CS7, PARODD | CSIZE },
+ { "-evenp", CS8, PARODD | PARENB | CSIZE },
+ { "oddp", PARENB | CS7 | PARODD, CSIZE },
+ { "-oddp", CS8, PARODD | PARENB | CSIZE },
+ { "pass8", CS8, PARODD | PARENB | CSIZE },
+ { "-pass8", PARENB | CS7, PARODD | CSIZE },
+ { "hupcl", HUPCL, 0 },
+ { "-hupcl", 0, HUPCL },
+ { "hup", HUPCL, 0 },
+ { "-hup", 0, HUPCL },
+ { "clocal", CLOCAL, 0 },
+ { "-clocal", 0, CLOCAL },
+ { "crtscts", CRTSCTS, 0 },
+ { "-crtscts", 0, CRTSCTS },
+ { "mdmbuf", MDMBUF, 0 },
+ { "-mdmbuf", 0, MDMBUF },
+ { NULL },
+};
+
+struct modes imodes[] = {
+ { "ignbrk", IGNBRK, 0 },
+ { "-ignbrk", 0, IGNBRK },
+ { "brkint", BRKINT, 0 },
+ { "-brkint", 0, BRKINT },
+ { "ignpar", IGNPAR, 0 },
+ { "-ignpar", 0, IGNPAR },
+ { "parmrk", PARMRK, 0 },
+ { "-parmrk", 0, PARMRK },
+ { "inpck", INPCK, 0 },
+ { "-inpck", 0, INPCK },
+ { "istrip", ISTRIP, 0 },
+ { "-istrip", 0, ISTRIP },
+ { "inlcr", INLCR, 0 },
+ { "-inlcr", 0, INLCR },
+ { "igncr", IGNCR, 0 },
+ { "-igncr", 0, IGNCR },
+ { "icrnl", ICRNL, 0 },
+ { "-icrnl", 0, ICRNL },
+ { "ixon", IXON, 0 },
+ { "-ixon", 0, IXON },
+ { "flow", IXON, 0 },
+ { "-flow", 0, IXON },
+ { "ixoff", IXOFF, 0 },
+ { "-ixoff", 0, IXOFF },
+ { "tandem", IXOFF, 0 },
+ { "-tandem", 0, IXOFF },
+ { "ixany", IXANY, 0 },
+ { "-ixany", 0, IXANY },
+ { "decctlq", 0, IXANY },
+ { "-decctlq", IXANY, 0 },
+ { "imaxbel", IMAXBEL, 0 },
+ { "-imaxbel", 0, IMAXBEL },
+ { NULL },
+};
+
+struct modes lmodes[] = {
+ { "echo", ECHO, 0 },
+ { "-echo", 0, ECHO },
+ { "echoe", ECHOE, 0 },
+ { "-echoe", 0, ECHOE },
+ { "crterase", ECHOE, 0 },
+ { "-crterase", 0, ECHOE },
+ { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */
+ { "-crtbs", 0, ECHOE },
+ { "echok", ECHOK, 0 },
+ { "-echok", 0, ECHOK },
+ { "echoke", ECHOKE, 0 },
+ { "-echoke", 0, ECHOKE },
+ { "crtkill", ECHOKE, 0 },
+ { "-crtkill", 0, ECHOKE },
+ { "altwerase", ALTWERASE, 0 },
+ { "-altwerase", 0, ALTWERASE },
+ { "iexten", IEXTEN, 0 },
+ { "-iexten", 0, IEXTEN },
+ { "echonl", ECHONL, 0 },
+ { "-echonl", 0, ECHONL },
+ { "echoctl", ECHOCTL, 0 },
+ { "-echoctl", 0, ECHOCTL },
+ { "ctlecho", ECHOCTL, 0 },
+ { "-ctlecho", 0, ECHOCTL },
+ { "echoprt", ECHOPRT, 0 },
+ { "-echoprt", 0, ECHOPRT },
+ { "prterase", ECHOPRT, 0 },
+ { "-prterase", 0, ECHOPRT },
+ { "isig", ISIG, 0 },
+ { "-isig", 0, ISIG },
+ { "icanon", ICANON, 0 },
+ { "-icanon", 0, ICANON },
+ { "noflsh", NOFLSH, 0 },
+ { "-noflsh", 0, NOFLSH },
+ { "tostop", TOSTOP, 0 },
+ { "-tostop", 0, TOSTOP },
+ { "flusho", FLUSHO, 0 },
+ { "-flusho", 0, FLUSHO },
+ { "pendin", PENDIN, 0 },
+ { "-pendin", 0, PENDIN },
+ { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "nokerninfo", NOKERNINFO, 0 },
+ { "-nokerninfo",0, NOKERNINFO },
+ { "kerninfo", 0, NOKERNINFO },
+ { "-kerninfo", NOKERNINFO, 0 },
+ { NULL },
+};
+
+struct modes omodes[] = {
+ { "opost", OPOST, 0 },
+ { "-opost", 0, OPOST },
+ { "litout", 0, OPOST },
+ { "-litout", OPOST, 0 },
+ { "onlcr", ONLCR, 0 },
+ { "-onlcr", 0, ONLCR },
+ { "tabs", 0, OXTABS }, /* "preserve" tabs */
+ { "-tabs", OXTABS, 0 },
+ { "oxtabs", OXTABS, 0 },
+ { "-oxtabs", 0, OXTABS },
+ { NULL },
+};
+
+#define CHK(s) (*name == s[0] && !strcmp(name, s))
+
+int
+msearch(argvp, ip)
+ char ***argvp;
+ struct info *ip;
+{
+ struct modes *mp;
+ char *name;
+
+ name = **argvp;
+
+ for (mp = cmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_cflag &= ~mp->unset;
+ ip->t.c_cflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = imodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_iflag &= ~mp->unset;
+ ip->t.c_iflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = lmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_lflag &= ~mp->unset;
+ ip->t.c_lflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = omodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_oflag &= ~mp->unset;
+ ip->t.c_oflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c
new file mode 100644
index 00000000000..9e7e334b969
--- /dev/null
+++ b/usr.sbin/lpr/lpd/printjob.c
@@ -0,0 +1,1429 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94";
+#endif /* not lint */
+
+
+/*
+ * printjob -- print jobs in the queue.
+ *
+ * NOTE: the lock file is used to pass information to lpq and lprm.
+ * it does not need to be removed because file locks are dynamic.
+ */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <signal.h>
+#include <termios.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
+
+#define DORETURN 0 /* absorb fork error */
+#define DOABORT 1 /* abort if dofork fails */
+
+/*
+ * Error tokens
+ */
+#define REPRINT -2
+#define ERROR -1
+#define OK 0
+#define FATALERR 1
+#define NOACCT 2
+#define FILTERERR 3
+#define ACCESS 4
+
+static dev_t fdev; /* device of file pointed to by symlink */
+static ino_t fino; /* inode of file pointed to by symlink */
+static FILE *cfp; /* control file */
+static int child; /* id of any filters */
+static int lfd; /* lock file descriptor */
+static int ofd; /* output filter file descriptor */
+static int ofilter; /* id of output filter, if any */
+static int pfd; /* prstatic inter file descriptor */
+static int pid; /* pid of lpd process */
+static int prchild; /* id of pr process */
+static int remote; /* true if sending files to remote */
+static char title[80]; /* ``pr'' title */
+static int tof; /* true if at top of form */
+
+static char class[32]; /* classification field */
+static char fromhost[32]; /* user's host machine */
+ /* indentation size in static characters */
+static char indent[10] = "-i0";
+static char jobname[100]; /* job or file name */
+static char length[10] = "-l"; /* page length in lines */
+static char logname[32]; /* user's login name */
+static char pxlength[10] = "-y"; /* page length in pixels */
+static char pxwidth[10] = "-x"; /* page width in pixels */
+static char tempfile[] = "errsXXXXXX"; /* file name for filter output */
+static char width[10] = "-w"; /* page width in static characters */
+
+static void abortpr __P((int));
+static void banner __P((char *, char *));
+static int dofork __P((int));
+static int dropit __P((int));
+static void init __P((void));
+static void openpr __P((void));
+static int print __P((int, char *));
+static int printit __P((char *));
+static void pstatus __P((const char *, ...));
+static char response __P((void));
+static void scan_out __P((int, char *, int));
+static char *scnline __P((int, char *, int));
+static int sendfile __P((int, char *));
+static int sendit __P((char *));
+static void sendmail __P((char *, int));
+static void set_ttyflags __P((struct termios *));
+static void setty __P((void));
+
+void
+printjob()
+{
+ struct stat stb;
+ register struct queue *q, **qp;
+ struct queue **queue;
+ register int i, nitems;
+ long pidoff;
+ int count = 0;
+
+ init(); /* set up capabilities */
+ (void) write(1, "", 1); /* ack that daemon is started */
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+ setgid(getegid());
+ pid = getpid(); /* for use with lprm */
+ setpgrp(0, pid);
+ signal(SIGHUP, abortpr);
+ signal(SIGINT, abortpr);
+ signal(SIGQUIT, abortpr);
+ signal(SIGTERM, abortpr);
+
+ (void) mktemp(tempfile);
+
+ /*
+ * uses short form file names
+ */
+ if (chdir(SD) < 0) {
+ syslog(LOG_ERR, "%s: %m", SD);
+ exit(1);
+ }
+ if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
+ exit(0); /* printing disabled */
+ lfd = open(LO, O_WRONLY|O_CREAT, 0644);
+ if (lfd < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ exit(1);
+ }
+ if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ exit(1);
+ }
+ ftruncate(lfd, 0);
+ /*
+ * write process id for others to know
+ */
+ sprintf(line, "%u\n", pid);
+ pidoff = i = strlen(line);
+ if (write(lfd, line, i) != i) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ exit(1);
+ }
+ /*
+ * search the spool directory for work and sort by queue order.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) /* no work to do */
+ exit(0);
+ if (stb.st_mode & 01) { /* reset queue flag */
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ }
+ openpr(); /* open printer or remote */
+again:
+ /*
+ * we found something to do now do it --
+ * write the name of the current control file into the lock file
+ * so the spool queue program can tell what we're working on
+ */
+ for (qp = queue; nitems--; free((char *) q)) {
+ q = *qp++;
+ if (stat(q->q_name, &stb) < 0)
+ continue;
+ restart:
+ (void) lseek(lfd, (off_t)pidoff, 0);
+ (void) sprintf(line, "%s\n", q->q_name);
+ i = strlen(line);
+ if (write(lfd, line, i) != i)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ if (!remote)
+ i = printit(q->q_name);
+ else
+ i = sendit(q->q_name);
+ /*
+ * Check to see if we are supposed to stop printing or
+ * if we are to rebuild the queue.
+ */
+ if (fstat(lfd, &stb) == 0) {
+ /* stop printing before starting next job? */
+ if (stb.st_mode & 0100)
+ goto done;
+ /* rebuild queue (after lpc topq) */
+ if (stb.st_mode & 01) {
+ for (free((char *) q); nitems--; free((char *) q))
+ q = *qp++;
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m",
+ printer, LO);
+ break;
+ }
+ }
+ if (i == OK) /* file ok and printed */
+ count++;
+ else if (i == REPRINT) { /* try reprinting the job */
+ syslog(LOG_INFO, "restarting %s", printer);
+ if (ofilter > 0) {
+ kill(ofilter, SIGCONT); /* to be sure */
+ (void) close(ofd);
+ while ((i = wait(0)) > 0 && i != ofilter)
+ ;
+ ofilter = 0;
+ }
+ (void) close(pfd); /* close printer */
+ if (ftruncate(lfd, pidoff) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
+ openpr(); /* try to reopen printer */
+ goto restart;
+ }
+ }
+ free((char *) queue);
+ /*
+ * search the spool directory for more work.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) { /* no more work to do */
+ done:
+ if (count > 0) { /* Files actually printed */
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (TR != NULL) /* output trailer */
+ (void) write(ofd, TR, strlen(TR));
+ }
+ (void) unlink(tempfile);
+ exit(0);
+ }
+ goto again;
+}
+
+char fonts[4][50]; /* fonts for troff */
+
+char ifonts[4][40] = {
+ _PATH_VFONTR,
+ _PATH_VFONTI,
+ _PATH_VFONTB,
+ _PATH_VFONTS,
+};
+
+/*
+ * The remaining part is the reading of the control file (cf)
+ * and performing the various actions.
+ */
+static int
+printit(file)
+ char *file;
+{
+ register int i;
+ char *cp;
+ int bombed = OK;
+
+ /*
+ * open control file; ignore if no longer there.
+ */
+ if ((cfp = fopen(file, "r")) == NULL) {
+ syslog(LOG_INFO, "%s: %s: %m", printer, file);
+ return(OK);
+ }
+ /*
+ * Reset troff fonts.
+ */
+ for (i = 0; i < 4; i++)
+ strcpy(fonts[i], ifonts[i]);
+ sprintf(&width[2], "%d", PW);
+ strcpy(indent+2, "0");
+
+ /*
+ * read the control file for work to do
+ *
+ * file format -- first character in the line is a command
+ * rest of the line is the argument.
+ * valid commands are:
+ *
+ * S -- "stat info" for symbolic link protection
+ * J -- "job name" on banner page
+ * C -- "class name" on banner page
+ * L -- "literal" user's name to print on banner
+ * T -- "title" for pr
+ * H -- "host name" of machine where lpr was done
+ * P -- "person" user's login name
+ * I -- "indent" amount to indent output
+ * f -- "file name" name of text file to print
+ * l -- "file name" text file with control chars
+ * p -- "file name" text file to print with pr(1)
+ * t -- "file name" troff(1) file to print
+ * n -- "file name" ditroff(1) file to print
+ * d -- "file name" dvi file to print
+ * g -- "file name" plot(1G) file to print
+ * v -- "file name" plain raster file to print
+ * c -- "file name" cifplot file to print
+ * 1 -- "R font file" for troff
+ * 2 -- "I font file" for troff
+ * 3 -- "B font file" for troff
+ * 4 -- "S font file" for troff
+ * N -- "name" of file (used by lpq)
+ * U -- "unlink" name of file to remove
+ * (after we print it. (Pass 2 only)).
+ * M -- "mail" to user when done printing
+ *
+ * getline reads a line and expands tabs to blanks
+ */
+
+ /* pass 1 */
+
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'H':
+ strcpy(fromhost, line+1);
+ if (class[0] == '\0')
+ strncpy(class, line+1, sizeof(class)-1);
+ continue;
+
+ case 'P':
+ strncpy(logname, line+1, sizeof(logname)-1);
+ if (RS) { /* restricted */
+ if (getpwnam(logname) == NULL) {
+ bombed = NOACCT;
+ sendmail(line+1, bombed);
+ goto pass2;
+ }
+ }
+ continue;
+
+ case 'S':
+ cp = line+1;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fdev = i;
+ cp++;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fino = i;
+ continue;
+
+ case 'J':
+ if (line[1] != '\0')
+ strncpy(jobname, line+1, sizeof(jobname)-1);
+ else
+ strcpy(jobname, " ");
+ continue;
+
+ case 'C':
+ if (line[1] != '\0')
+ strncpy(class, line+1, sizeof(class)-1);
+ else if (class[0] == '\0')
+ gethostname(class, sizeof(class));
+ continue;
+
+ case 'T': /* header title for pr */
+ strncpy(title, line+1, sizeof(title)-1);
+ continue;
+
+ case 'L': /* identification line */
+ if (!SH && !HL)
+ banner(line+1, jobname);
+ continue;
+
+ case '1': /* troff fonts */
+ case '2':
+ case '3':
+ case '4':
+ if (line[1] != '\0')
+ strcpy(fonts[line[0]-'1'], line+1);
+ continue;
+
+ case 'W': /* page width */
+ strncpy(width+2, line+1, sizeof(width)-3);
+ continue;
+
+ case 'I': /* indent amount */
+ strncpy(indent+2, line+1, sizeof(indent)-3);
+ continue;
+
+ default: /* some file to print */
+ switch (i = print(line[0], line+1)) {
+ case ERROR:
+ if (bombed == OK)
+ bombed = FATALERR;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case FILTERERR:
+ case ACCESS:
+ bombed = i;
+ sendmail(logname, bombed);
+ }
+ title[0] = '\0';
+ continue;
+
+ case 'N':
+ case 'U':
+ case 'M':
+ continue;
+ }
+
+ /* pass 2 */
+
+pass2:
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'L': /* identification line */
+ if (!SH && HL)
+ banner(line+1, jobname);
+ continue;
+
+ case 'M':
+ if (bombed < NOACCT) /* already sent if >= NOACCT */
+ sendmail(line+1, bombed);
+ continue;
+
+ case 'U':
+ (void) unlink(line+1);
+ }
+ /*
+ * clean-up in case another control file exists
+ */
+ (void) fclose(cfp);
+ (void) unlink(file);
+ return(bombed == OK ? OK : ERROR);
+}
+
+/*
+ * Print a file.
+ * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
+ * Return -1 if a non-recoverable error occured,
+ * 2 if the filter detected some errors (but printed the job anyway),
+ * 1 if we should try to reprint this job and
+ * 0 if all is well.
+ * Note: all filters take stdin as the file, stdout as the printer,
+ * stderr as the log file, and must not ignore SIGINT.
+ */
+static int
+print(format, file)
+ int format;
+ char *file;
+{
+ register int n;
+ register char *prog;
+ int fi, fo;
+ FILE *fp;
+ char *av[15], buf[BUFSIZ];
+ int pid, p[2], stopped = 0;
+ union wait status;
+ struct stat stb;
+
+ if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
+ return(ERROR);
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print
+ * something he shouldn't.
+ */
+ if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
+ if (!SF && !tof) { /* start on a fresh page */
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+ }
+ if (IF == NULL && (format == 'f' || format == 'l')) {
+ tof = 0;
+ while ((n = read(fi, buf, BUFSIZ)) > 0)
+ if (write(ofd, buf, n) != n) {
+ (void) close(fi);
+ return(REPRINT);
+ }
+ (void) close(fi);
+ return(OK);
+ }
+ switch (format) {
+ case 'p': /* print file using 'pr' */
+ if (IF == NULL) { /* use output filter */
+ prog = _PATH_PR;
+ av[0] = "pr";
+ av[1] = width;
+ av[2] = length;
+ av[3] = "-h";
+ av[4] = *title ? title : " ";
+ av[5] = 0;
+ fo = ofd;
+ goto start;
+ }
+ pipe(p);
+ if ((prchild = dofork(DORETURN)) == 0) { /* child */
+ dup2(fi, 0); /* file is stdin */
+ dup2(p[1], 1); /* pipe is stdout */
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ execl(_PATH_PR, "pr", width, length,
+ "-h", *title ? title : " ", 0);
+ syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
+ exit(2);
+ }
+ (void) close(p[1]); /* close output side */
+ (void) close(fi);
+ if (prchild < 0) {
+ prchild = 0;
+ (void) close(p[0]);
+ return(ERROR);
+ }
+ fi = p[0]; /* use pipe for input */
+ case 'f': /* print plain text file */
+ prog = IF;
+ av[1] = width;
+ av[2] = length;
+ av[3] = indent;
+ n = 4;
+ break;
+ case 'l': /* like 'f' but pass control characters */
+ prog = IF;
+ av[1] = "-c";
+ av[2] = width;
+ av[3] = length;
+ av[4] = indent;
+ n = 5;
+ break;
+ case 'r': /* print a fortran text file */
+ prog = RF;
+ av[1] = width;
+ av[2] = length;
+ n = 3;
+ break;
+ case 't': /* print troff output */
+ case 'n': /* print ditroff output */
+ case 'd': /* print tex output */
+ (void) unlink(".railmag");
+ if ((fo = creat(".railmag", FILMOD)) < 0) {
+ syslog(LOG_ERR, "%s: cannot create .railmag", printer);
+ (void) unlink(".railmag");
+ } else {
+ for (n = 0; n < 4; n++) {
+ if (fonts[n][0] != '/')
+ (void) write(fo, _PATH_VFONT,
+ sizeof(_PATH_VFONT) - 1);
+ (void) write(fo, fonts[n], strlen(fonts[n]));
+ (void) write(fo, "\n", 1);
+ }
+ (void) close(fo);
+ }
+ prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'c': /* print cifplot output */
+ prog = CF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'g': /* print plot(1G) output */
+ prog = GF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'v': /* print raster output */
+ prog = VF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ default:
+ (void) close(fi);
+ syslog(LOG_ERR, "%s: illegal format character '%c'",
+ printer, format);
+ return(ERROR);
+ }
+ if ((av[0] = rindex(prog, '/')) != NULL)
+ av[0]++;
+ else
+ av[0] = prog;
+ av[n++] = "-n";
+ av[n++] = logname;
+ av[n++] = "-h";
+ av[n++] = fromhost;
+ av[n++] = AF;
+ av[n] = 0;
+ fo = pfd;
+ if (ofilter > 0) { /* stop output filter */
+ write(ofd, "\031\1", 2);
+ while ((pid =
+ wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
+ ;
+ if (status.w_stopval != WSTOPPED) {
+ (void) close(fi);
+ syslog(LOG_WARNING, "%s: output filter died (%d)",
+ printer, status.w_retcode);
+ return(REPRINT);
+ }
+ stopped++;
+ }
+start:
+ if ((child = dofork(DORETURN)) == 0) { /* child */
+ dup2(fi, 0);
+ dup2(fo, 1);
+ n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
+ if (n >= 0)
+ dup2(n, 2);
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ execv(prog, av);
+ syslog(LOG_ERR, "cannot execv %s", prog);
+ exit(2);
+ }
+ (void) close(fi);
+ if (child < 0)
+ status.w_retcode = 100;
+ else
+ while ((pid = wait((int *)&status)) > 0 && pid != child)
+ ;
+ child = 0;
+ prchild = 0;
+ if (stopped) { /* restart output filter */
+ if (kill(ofilter, SIGCONT) < 0) {
+ syslog(LOG_ERR, "cannot restart output filter");
+ exit(1);
+ }
+ }
+ tof = 0;
+
+ /* Copy filter output to "lf" logfile */
+ if (fp = fopen(tempfile, "r")) {
+ while (fgets(buf, sizeof(buf), fp))
+ fputs(buf, stderr);
+ fclose(fp);
+ }
+
+ if (!WIFEXITED(status)) {
+ syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
+ printer, format, status.w_termsig);
+ return(ERROR);
+ }
+ switch (status.w_retcode) {
+ case 0:
+ tof = 1;
+ return(OK);
+ case 1:
+ return(REPRINT);
+ default:
+ syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
+ printer, format, status.w_retcode);
+ case 2:
+ return(ERROR);
+ }
+}
+
+/*
+ * Send the daemon control file (cf) and any data files.
+ * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
+ * 0 if all is well.
+ */
+static int
+sendit(file)
+ char *file;
+{
+ register int i, err = OK;
+ char *cp, last[BUFSIZ];
+
+ /*
+ * open control file
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(OK);
+ /*
+ * read the control file for work to do
+ *
+ * file format -- first character in the line is a command
+ * rest of the line is the argument.
+ * commands of interest are:
+ *
+ * a-z -- "file name" name of file to print
+ * U -- "unlink" name of file to remove
+ * (after we print it. (Pass 2 only)).
+ */
+
+ /*
+ * pass 1
+ */
+ while (getline(cfp)) {
+ again:
+ if (line[0] == 'S') {
+ cp = line+1;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fdev = i;
+ cp++;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fino = i;
+ continue;
+ }
+ if (line[0] >= 'a' && line[0] <= 'z') {
+ strcpy(last, line);
+ while (i = getline(cfp))
+ if (strcmp(last, line))
+ break;
+ switch (sendfile('\3', last+1)) {
+ case OK:
+ if (i)
+ goto again;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case ACCESS:
+ sendmail(logname, ACCESS);
+ case ERROR:
+ err = ERROR;
+ }
+ break;
+ }
+ }
+ if (err == OK && sendfile('\2', file) > 0) {
+ (void) fclose(cfp);
+ return(REPRINT);
+ }
+ /*
+ * pass 2
+ */
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ if (line[0] == 'U')
+ (void) unlink(line+1);
+ /*
+ * clean-up in case another control file exists
+ */
+ (void) fclose(cfp);
+ (void) unlink(file);
+ return(err);
+}
+
+/*
+ * Send a data file to the remote machine and spool it.
+ * Return positive if we should try resending.
+ */
+static int
+sendfile(type, file)
+ int type;
+ char *file;
+{
+ register int f, i, amt;
+ struct stat stb;
+ char buf[BUFSIZ];
+ int sizerr, resp;
+
+ if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
+ return(ERROR);
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print something
+ * he shouldn't.
+ */
+ if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
+ (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
+ amt = strlen(buf);
+ for (i = 0; ; i++) {
+ if (write(pfd, buf, amt) != amt ||
+ (resp = response()) < 0 || resp == '\1') {
+ (void) close(f);
+ return(REPRINT);
+ } else if (resp == '\0')
+ break;
+ if (i == 0)
+ pstatus("no space on remote; waiting for queue to drain");
+ if (i == 10)
+ syslog(LOG_ALERT, "%s: can't send to %s; queue full",
+ printer, RM);
+ sleep(5 * 60);
+ }
+ if (i)
+ pstatus("sending to %s", RM);
+ sizerr = 0;
+ for (i = 0; i < stb.st_size; i += BUFSIZ) {
+ amt = BUFSIZ;
+ if (i + amt > stb.st_size)
+ amt = stb.st_size - i;
+ if (sizerr == 0 && read(f, buf, amt) != amt)
+ sizerr = 1;
+ if (write(pfd, buf, amt) != amt) {
+ (void) close(f);
+ return(REPRINT);
+ }
+ }
+
+
+
+
+ (void) close(f);
+ if (sizerr) {
+ syslog(LOG_INFO, "%s: %s: changed size", printer, file);
+ /* tell recvjob to ignore this file */
+ (void) write(pfd, "\1", 1);
+ return(ERROR);
+ }
+ if (write(pfd, "", 1) != 1 || response())
+ return(REPRINT);
+ return(OK);
+}
+
+/*
+ * Check to make sure there have been no errors and that both programs
+ * are in sync with eachother.
+ * Return non-zero if the connection was lost.
+ */
+static char
+response()
+{
+ char resp;
+
+ if (read(pfd, &resp, 1) != 1) {
+ syslog(LOG_INFO, "%s: lost connection", printer);
+ return(-1);
+ }
+ return(resp);
+}
+
+/*
+ * Banner printing stuff
+ */
+static void
+banner(name1, name2)
+ char *name1, *name2;
+{
+ time_t tvec;
+ extern char *ctime();
+
+ time(&tvec);
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (SB) { /* short banner only */
+ if (class[0]) {
+ (void) write(ofd, class, strlen(class));
+ (void) write(ofd, ":", 1);
+ }
+ (void) write(ofd, name1, strlen(name1));
+ (void) write(ofd, " Job: ", 7);
+ (void) write(ofd, name2, strlen(name2));
+ (void) write(ofd, " Date: ", 8);
+ (void) write(ofd, ctime(&tvec), 24);
+ (void) write(ofd, "\n", 1);
+ } else { /* normal banner */
+ (void) write(ofd, "\n\n\n", 3);
+ scan_out(ofd, name1, '\0');
+ (void) write(ofd, "\n\n", 2);
+ scan_out(ofd, name2, '\0');
+ if (class[0]) {
+ (void) write(ofd,"\n\n\n",3);
+ scan_out(ofd, class, '\0');
+ }
+ (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
+ (void) write(ofd, name2, strlen(name2));
+ (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
+ (void) write(ofd, ctime(&tvec), 24);
+ (void) write(ofd, "\n", 1);
+ }
+ if (!SF)
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+}
+
+static char *
+scnline(key, p, c)
+ register int key;
+ register char *p;
+ int c;
+{
+ register scnwidth;
+
+ for (scnwidth = WIDTH; --scnwidth;) {
+ key <<= 1;
+ *p++ = key & 0200 ? c : BACKGND;
+ }
+ return (p);
+}
+
+#define TRC(q) (((q)-' ')&0177)
+
+static void
+scan_out(scfd, scsp, dlm)
+ int scfd, dlm;
+ char *scsp;
+{
+ register char *strp;
+ register nchrs, j;
+ char outbuf[LINELEN+1], *sp, c, cc;
+ int d, scnhgt;
+ extern char scnkey[][HEIGHT]; /* in lpdchar.c */
+
+ for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
+ strp = &outbuf[0];
+ sp = scsp;
+ for (nchrs = 0; ; ) {
+ d = dropit(c = TRC(cc = *sp++));
+ if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
+ for (j = WIDTH; --j;)
+ *strp++ = BACKGND;
+ else
+ strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
+ if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
+ break;
+ *strp++ = BACKGND;
+ *strp++ = BACKGND;
+ }
+ while (*--strp == BACKGND && strp >= outbuf)
+ ;
+ strp++;
+ *strp++ = '\n';
+ (void) write(scfd, outbuf, strp-outbuf);
+ }
+}
+
+static int
+dropit(c)
+ int c;
+{
+ switch(c) {
+
+ case TRC('_'):
+ case TRC(';'):
+ case TRC(','):
+ case TRC('g'):
+ case TRC('j'):
+ case TRC('p'):
+ case TRC('q'):
+ case TRC('y'):
+ return (DROP);
+
+ default:
+ return (0);
+ }
+}
+
+/*
+ * sendmail ---
+ * tell people about job completion
+ */
+static void
+sendmail(user, bombed)
+ char *user;
+ int bombed;
+{
+ register int i;
+ int p[2], s;
+ register char *cp;
+ char buf[100];
+ struct stat stb;
+ FILE *fp;
+
+ pipe(p);
+ if ((s = dofork(DORETURN)) == 0) { /* child */
+ dup2(p[0], 0);
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
+ cp++;
+ else
+ cp = _PATH_SENDMAIL;
+ sprintf(buf, "%s@%s", user, fromhost);
+ execl(_PATH_SENDMAIL, cp, buf, 0);
+ exit(0);
+ } else if (s > 0) { /* parent */
+ dup2(p[1], 1);
+ printf("To: %s@%s\n", user, fromhost);
+ printf("Subject: printer job\n\n");
+ printf("Your printer job ");
+ if (*jobname)
+ printf("(%s) ", jobname);
+ switch (bombed) {
+ case OK:
+ printf("\ncompleted successfully\n");
+ break;
+ default:
+ case FATALERR:
+ printf("\ncould not be printed\n");
+ break;
+ case NOACCT:
+ printf("\ncould not be printed without an account on %s\n", host);
+ break;
+ case FILTERERR:
+ if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
+ (fp = fopen(tempfile, "r")) == NULL) {
+ printf("\nwas printed but had some errors\n");
+ break;
+ }
+ printf("\nwas printed but had the following errors:\n");
+ while ((i = getc(fp)) != EOF)
+ putchar(i);
+ (void) fclose(fp);
+ break;
+ case ACCESS:
+ printf("\nwas not printed because it was not linked to the original file\n");
+ }
+ fflush(stdout);
+ (void) close(1);
+ }
+ (void) close(p[0]);
+ (void) close(p[1]);
+ wait(&s);
+}
+
+/*
+ * dofork - fork with retries on failure
+ */
+static int
+dofork(action)
+ int action;
+{
+ register int i, pid;
+ struct passwd *pw;
+
+ for (i = 0; i < 20; i++) {
+ if ((pid = fork()) < 0) {
+ sleep((unsigned)(i*i));
+ continue;
+ }
+ /*
+ * Child should run as daemon instead of root
+ */
+ if (pid == 0) {
+ pw = getpwuid(DU);
+ if (pw == 0) {
+ syslog(LOG_ERR, "uid %d not in password file",
+ DU);
+ break;
+ }
+ initgroups(pw->pw_name, pw->pw_gid);
+ setgid(pw->pw_gid);
+ setuid(DU);
+ }
+ return (pid);
+ }
+ syslog(LOG_ERR, "can't fork");
+
+ switch (action) {
+ case DORETURN:
+ return (-1);
+ default:
+ syslog(LOG_ERR, "bad action (%d) to dofork", action);
+ /*FALL THRU*/
+ case DOABORT:
+ exit(1);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * Kill child processes to abort current job.
+ */
+static void
+abortpr(signo)
+ int signo;
+{
+ (void) unlink(tempfile);
+ kill(0, SIGINT);
+ if (ofilter > 0)
+ kill(ofilter, SIGCONT);
+ while (wait(NULL) > 0)
+ ;
+ exit(0);
+}
+
+static void
+init()
+{
+ int status;
+ char *s;
+
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ syslog(LOG_ERR, "can't open printer description file");
+ exit(1);
+ } else if (status == -1) {
+ syslog(LOG_ERR, "unknown printer: %s", printer);
+ exit(1);
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lp", &LP) == -1)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) == -1)
+ RP = DEFLP;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetnum(bp, "du", &DU) < 0)
+ DU = DEFUID;
+ if (cgetstr(bp,"ff", &FF) == -1)
+ FF = DEFFF;
+ if (cgetnum(bp, "pw", &PW) < 0)
+ PW = DEFWIDTH;
+ sprintf(&width[2], "%d", PW);
+ if (cgetnum(bp, "pl", &PL) < 0)
+ PL = DEFLENGTH;
+ sprintf(&length[2], "%d", PL);
+ if (cgetnum(bp,"px", &PX) < 0)
+ PX = 0;
+ sprintf(&pxwidth[2], "%d", PX);
+ if (cgetnum(bp, "py", &PY) < 0)
+ PY = 0;
+ sprintf(&pxlength[2], "%d", PY);
+ cgetstr(bp, "rm", &RM);
+ if (s = checkremote())
+ syslog(LOG_WARNING, s);
+
+ cgetstr(bp, "af", &AF);
+ cgetstr(bp, "of", &OF);
+ cgetstr(bp, "if", &IF);
+ cgetstr(bp, "rf", &RF);
+ cgetstr(bp, "tf", &TF);
+ cgetstr(bp, "nf", &NF);
+ cgetstr(bp, "df", &DF);
+ cgetstr(bp, "gf", &GF);
+ cgetstr(bp, "vf", &VF);
+ cgetstr(bp, "cf", &CF);
+ cgetstr(bp, "tr", &TR);
+
+ RS = (cgetcap(bp, "rs", ':') != NULL);
+ SF = (cgetcap(bp, "sf", ':') != NULL);
+ SH = (cgetcap(bp, "sh", ':') != NULL);
+ SB = (cgetcap(bp, "sb", ':') != NULL);
+ HL = (cgetcap(bp, "hl", ':') != NULL);
+ RW = (cgetcap(bp, "rw", ':') != NULL);
+
+ cgetnum(bp, "br", &BR);
+ if (cgetnum(bp, "fc", &FC) < 0)
+ FC = 0;
+ if (cgetnum(bp, "fs", &FS) < 0)
+ FS = 0;
+ if (cgetnum(bp, "xc", &XC) < 0)
+ XC = 0;
+ if (cgetnum(bp, "xs", &XS) < 0)
+ XS = 0;
+ cgetstr(bp, "ms", &MS);
+
+ tof = (cgetcap(bp, "fo", ':') == NULL);
+}
+
+/*
+ * Acquire line printer or remote connection.
+ */
+static void
+openpr()
+{
+ register int i, n;
+ int resp;
+
+ if (!sendtorem && *LP) {
+ for (i = 1; ; i = i < 32 ? i << 1 : i) {
+ pfd = open(LP, RW ? O_RDWR : O_WRONLY);
+ if (pfd >= 0)
+ break;
+ if (errno == ENOENT) {
+ syslog(LOG_ERR, "%s: %m", LP);
+ exit(1);
+ }
+ if (i == 1)
+ pstatus("waiting for %s to become ready (offline ?)", printer);
+ sleep(i);
+ }
+ if (isatty(pfd))
+ setty();
+ pstatus("%s is ready and printing", printer);
+ } else if (RM != NULL) {
+ for (i = 1; ; i = i < 256 ? i << 1 : i) {
+ resp = -1;
+ pfd = getport(RM);
+ if (pfd >= 0) {
+ (void) sprintf(line, "\2%s\n", RP);
+ n = strlen(line);
+ if (write(pfd, line, n) == n &&
+ (resp = response()) == '\0')
+ break;
+ (void) close(pfd);
+ }
+ if (i == 1) {
+ if (resp < 0)
+ pstatus("waiting for %s to come up", RM);
+ else {
+ pstatus("waiting for queue to be enabled on %s", RM);
+ i = 256;
+ }
+ }
+ sleep(i);
+ }
+ pstatus("sending to %s", RM);
+ remote = 1;
+ } else {
+ syslog(LOG_ERR, "%s: no line printer device or host name",
+ printer);
+ exit(1);
+ }
+ /*
+ * Start up an output filter, if needed.
+ */
+ if (!remote && OF) {
+ int p[2];
+ char *cp;
+
+ pipe(p);
+ if ((ofilter = dofork(DOABORT)) == 0) { /* child */
+ dup2(p[0], 0); /* pipe is std in */
+ dup2(pfd, 1); /* printer is std out */
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(OF, '/')) == NULL)
+ cp = OF;
+ else
+ cp++;
+ execl(OF, cp, width, length, 0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, OF);
+ exit(1);
+ }
+ (void) close(p[0]); /* close input side */
+ ofd = p[1]; /* use pipe for output */
+ } else {
+ ofd = pfd;
+ ofilter = 0;
+ }
+}
+
+struct bauds {
+ int baud;
+ int speed;
+} bauds[] = {
+ 50, B50,
+ 75, B75,
+ 110, B110,
+ 134, B134,
+ 150, B150,
+ 200, B200,
+ 300, B300,
+ 600, B600,
+ 1200, B1200,
+ 1800, B1800,
+ 2400, B2400,
+ 4800, B4800,
+ 9600, B9600,
+ 19200, B19200,
+ 38400, B38400,
+ 0, 0
+};
+
+/*
+ * setup tty lines.
+ */
+static void
+setty()
+{
+ register struct bauds *bp;
+ struct info i;
+ char **argv, **ap, *p, *val;
+
+ i.fd = pfd;
+ i.set = i.wset = 0;
+ if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
+ exit(1);
+ }
+ if (tcgetattr(i.fd, &i.t) < 0) {
+ syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
+ exit(1);
+ }
+ if (BR > 0) {
+ for (bp = bauds; bp->baud; bp++)
+ if (BR == bp->baud)
+ break;
+ if (!bp->baud) {
+ syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
+ exit(1);
+ }
+ cfsetspeed(&i.t, bp->speed);
+ i.set = 1;
+ }
+ if (MS) {
+ if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
+ exit(1);
+ }
+ if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
+ syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
+ printer);
+
+ argv = (char **)calloc(256, sizeof(char *));
+ if (argv == NULL) {
+ syslog(LOG_ERR, "%s: calloc: %m", printer);
+ exit(1);
+ }
+ p = strdup(MS);
+ ap = argv;
+ while ((val = strsep(&p, " \t,")) != NULL) {
+ *ap++ = strdup(val);
+ }
+
+ for (; *argv; ++argv) {
+ if (ksearch(&argv, &i))
+ continue;
+ if (msearch(&argv, &i))
+ continue;
+ syslog(LOG_INFO, "%s: unknown stty flag: %s",
+ printer, *argv);
+ }
+ } else {
+ if (FC) {
+ sttyclearflags(&i.t, FC);
+ i.set = 1;
+ }
+ if (FS) {
+ sttysetflags(&i.t, FS);
+ i.set = 1;
+ }
+ if (XC) {
+ sttyclearlflags(&i.t, XC);
+ i.set = 1;
+ }
+ if (XS) {
+ sttysetlflags(&i.t, XC);
+ i.set = 1;
+ }
+ }
+
+ if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
+ syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
+ exit(1);
+ }
+ if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
+ syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
+ return;
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+pstatus(const char *msg, ...)
+#else
+pstatus(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ register int fd;
+ char buf[BUFSIZ];
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+
+ umask(0);
+ fd = open(ST, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, ST);
+ exit(1);
+ }
+ ftruncate(fd, 0);
+ (void)vsnprintf(buf, sizeof(buf), msg, ap);
+ va_end(ap);
+ strcat(buf, "\n");
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}
diff --git a/usr.sbin/lpr/lpd/recvjob.c b/usr.sbin/lpr/lpd/recvjob.c
new file mode 100644
index 00000000000..8c51723cd8b
--- /dev/null
+++ b/usr.sbin/lpr/lpd/recvjob.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)recvjob.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Receive printer jobs from the network, queue them and
+ * start the printer daemon.
+ */
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "extern.h"
+#include "pathnames.h"
+
+#define ack() (void) write(1, sp, 1);
+
+static char dfname[40]; /* data files */
+static int minfree; /* keep at least minfree blocks available */
+static char *sp = "";
+static char tfname[40]; /* tmp copy of cf before linking */
+
+static int chksize __P((int));
+static void frecverr __P((const char *, ...));
+static int noresponse __P((void));
+static void rcleanup __P((int));
+static int read_number __P((char *));
+static int readfile __P((char *, int));
+static int readjob __P((void));
+
+
+void
+recvjob()
+{
+ struct stat stb;
+ int status;
+
+ /*
+ * Perform lookup for printer name or abbreviation
+ */
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2)
+ frecverr("cannot open printer description file");
+ else if (status == -1)
+ frecverr("unknown printer %s", printer);
+ else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+
+ if (chdir(SD) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ if (stat(LO, &stb) == 0) {
+ if (stb.st_mode & 010) {
+ /* queue is disabled */
+ putchar('\1'); /* return error code */
+ exit(1);
+ }
+ } else if (stat(SD, &stb) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
+ signal(SIGTERM, rcleanup);
+ signal(SIGPIPE, rcleanup);
+
+ if (readjob())
+ printjob();
+}
+
+/*
+ * Read printer jobs sent by lpd and copy them to the spooling directory.
+ * Return the number of jobs successfully transfered.
+ */
+static int
+readjob()
+{
+ register int size, nfiles;
+ register char *cp;
+
+ ack();
+ nfiles = 0;
+ for (;;) {
+ /*
+ * Read a command to tell us what to do
+ */
+ cp = line;
+ do {
+ if ((size = read(1, cp, 1)) != 1) {
+ if (size < 0)
+ frecverr("%s: Lost connection",printer);
+ return(nfiles);
+ }
+ } while (*cp++ != '\n');
+ *--cp = '\0';
+ cp = line;
+ switch (*cp++) {
+ case '\1': /* cleanup because data sent was bad */
+ rcleanup(0);
+ continue;
+
+ case '\2': /* read cf file */
+ size = 0;
+ while (*cp >= '0' && *cp <= '9')
+ size = size * 10 + (*cp++ - '0');
+ if (*cp++ != ' ')
+ break;
+ /*
+ * host name has been authenticated, we use our
+ * view of the host name since we may be passed
+ * something different than what gethostbyaddr()
+ * returns
+ */
+ strcpy(cp + 6, from);
+ strcpy(tfname, cp);
+ tfname[0] = 't';
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ if (!readfile(tfname, size)) {
+ rcleanup(0);
+ continue;
+ }
+ if (link(tfname, cp) < 0)
+ frecverr("%s: %m", tfname);
+ (void) unlink(tfname);
+ tfname[0] = '\0';
+ nfiles++;
+ continue;
+
+ case '\3': /* read df file */
+ size = 0;
+ while (*cp >= '0' && *cp <= '9')
+ size = size * 10 + (*cp++ - '0');
+ if (*cp++ != ' ')
+ break;
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ (void) strcpy(dfname, cp);
+ if (index(dfname, '/'))
+ frecverr("readjob: %s: illegal path name",
+ dfname);
+ (void) readfile(dfname, size);
+ continue;
+ }
+ frecverr("protocol screwup: %s", line);
+ }
+}
+
+/*
+ * Read files send by lpd and copy them to the spooling directory.
+ */
+static int
+readfile(file, size)
+ char *file;
+ int size;
+{
+ register char *cp;
+ char buf[BUFSIZ];
+ register int i, j, amt;
+ int fd, err;
+
+ fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
+ if (fd < 0)
+ frecverr("readfile: %s: illegal path name: %m", file);
+ ack();
+ err = 0;
+ for (i = 0; i < size; i += BUFSIZ) {
+ amt = BUFSIZ;
+ cp = buf;
+ if (i + amt > size)
+ amt = size - i;
+ do {
+ j = read(1, cp, amt);
+ if (j <= 0)
+ frecverr("Lost connection");
+ amt -= j;
+ cp += j;
+ } while (amt > 0);
+ amt = BUFSIZ;
+ if (i + amt > size)
+ amt = size - i;
+ if (write(fd, buf, amt) != amt) {
+ err++;
+ break;
+ }
+ }
+ (void) close(fd);
+ if (err)
+ frecverr("%s: write error", file);
+ if (noresponse()) { /* file sent had bad data in it */
+ (void) unlink(file);
+ return(0);
+ }
+ ack();
+ return(1);
+}
+
+static int
+noresponse()
+{
+ char resp;
+
+ if (read(1, &resp, 1) != 1)
+ frecverr("Lost connection");
+ if (resp == '\0')
+ return(0);
+ return(1);
+}
+
+/*
+ * Check to see if there is enough space on the disk for size bytes.
+ * 1 == OK, 0 == Not OK.
+ */
+static int
+chksize(size)
+ int size;
+{
+ int spacefree;
+ struct statfs sfb;
+
+ if (statfs(".", &sfb) < 0) {
+ syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
+ return (1);
+ }
+ spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
+ size = (size + 511) / 512;
+ if (minfree + size > spacefree)
+ return(0);
+ return(1);
+}
+
+static int
+read_number(fn)
+ char *fn;
+{
+ char lin[80];
+ register FILE *fp;
+
+ if ((fp = fopen(fn, "r")) == NULL)
+ return (0);
+ if (fgets(lin, 80, fp) == NULL) {
+ fclose(fp);
+ return (0);
+ }
+ fclose(fp);
+ return (atoi(lin));
+}
+
+/*
+ * Remove all the files associated with the current job being transfered.
+ */
+static void
+rcleanup(signo)
+ int signo;
+{
+ if (tfname[0])
+ (void) unlink(tfname);
+ if (dfname[0])
+ do {
+ do
+ (void) unlink(dfname);
+ while (dfname[2]-- != 'A');
+ dfname[2] = 'z';
+ } while (dfname[0]-- != 'd');
+ dfname[0] = '\0';
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+frecverr(const char *msg, ...)
+#else
+frecverr(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ extern char fromb[];
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ rcleanup(0);
+ syslog(LOG_ERR, "%s", fromb);
+ vsyslog(LOG_ERR, msg, ap);
+ va_end(ap);
+ putchar('\1'); /* return error code */
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lpd/ttcompat.c b/usr.sbin/lpr/lpd/ttcompat.c
new file mode 100644
index 00000000000..a31a0dbb594
--- /dev/null
+++ b/usr.sbin/lpr/lpd/ttcompat.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * ttcompat.c -- convert sgtty flags to termios
+ * originally from /sys/kern/tty_compat.c
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <sys/ioctl_compat.h>
+#include <termios.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "extern.h"
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+static int
+sttygetoflags(tp)
+ struct termios *tp;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t cflag = tp->c_cflag;
+ register int flags = 0;
+
+ if (ISSET(cflag, PARENB)) {
+ if (ISSET(iflag, INPCK)) {
+ if (ISSET(cflag, PARODD))
+ SET(flags, ODDP);
+ else
+ SET(flags, EVENP);
+ } else
+ SET(flags, EVENP|ODDP);
+ }
+ if (ISSET(cflag, CSIZE) == CS8) {
+ if (!ISSET(iflag, ISTRIP))
+ SET(flags, PASS8);
+ if (!ISSET(oflag, OPOST))
+ SET(flags, LITOUT);
+ }
+
+ if (!ISSET(lflag, ICANON)) {
+ /* fudge */
+ if (ISSET(iflag, IXON) || ISSET(lflag, ISIG|IEXTEN) ||
+ ISSET(cflag, PARENB))
+ SET(flags, CBREAK);
+ else
+ SET(flags, RAW);
+ }
+
+ return (flags);
+}
+
+static void
+sttysetoflags(tp, flags)
+ struct termios *tp;
+ int flags;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t cflag = tp->c_cflag;
+
+ if (ISSET(flags, RAW)) {
+ iflag &= IXOFF;
+ CLR(lflag, ISIG|ICANON|IEXTEN);
+ CLR(cflag, PARENB);
+ } else {
+ SET(iflag, BRKINT|IXON|IMAXBEL);
+ SET(lflag, ISIG|IEXTEN);
+ if (ISSET(flags, CBREAK))
+ CLR(lflag, ICANON);
+ else
+ SET(lflag, ICANON);
+ switch (ISSET(flags, ANYP)) {
+ case 0:
+ CLR(cflag, PARENB);
+ break;
+ case ANYP:
+ SET(cflag, PARENB);
+ CLR(iflag, INPCK);
+ break;
+ case EVENP:
+ SET(cflag, PARENB);
+ SET(iflag, INPCK);
+ CLR(cflag, PARODD);
+ break;
+ case ODDP:
+ SET(cflag, PARENB);
+ SET(iflag, INPCK);
+ SET(cflag, PARODD);
+ break;
+ }
+ }
+
+ if (ISSET(flags, RAW|LITOUT|PASS8)) {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS8);
+ if (!ISSET(flags, RAW|PASS8))
+ SET(iflag, ISTRIP);
+ else
+ CLR(iflag, ISTRIP);
+ if (!ISSET(flags, RAW|LITOUT))
+ SET(oflag, OPOST);
+ else
+ CLR(oflag, OPOST);
+ } else {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS7);
+ SET(iflag, ISTRIP);
+ SET(oflag, OPOST);
+ }
+
+ tp->c_iflag = iflag;
+ tp->c_oflag = oflag;
+ tp->c_lflag = lflag;
+ tp->c_cflag = cflag;
+}
+
+void
+sttyclearflags(tp, flags)
+ struct termios *tp;
+ int flags;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t cflag = tp->c_cflag;
+ register int oflags = sttygetoflags(tp) & ~flags;
+
+ if (ISSET(flags, TANDEM))
+ CLR(iflag, IXOFF);
+ if (ISSET(flags, ECHO))
+ CLR(lflag, ECHO);
+ if (ISSET(flags, CRMOD)) {
+ CLR(iflag, ICRNL);
+ CLR(oflag, ONLCR);
+ }
+ if (ISSET(flags, XTABS))
+ CLR(oflag, OXTABS);
+
+
+ tp->c_iflag = iflag;
+ tp->c_oflag = oflag;
+ tp->c_lflag = lflag;
+ tp->c_cflag = cflag;
+
+ sttysetoflags(tp, oflags);
+}
+
+void
+sttysetflags(tp, flags)
+ struct termios *tp;
+ int flags;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t cflag = tp->c_cflag;
+ register int oflags = sttygetoflags(tp) | flags;
+
+ if (ISSET(flags, TANDEM))
+ SET(iflag, IXOFF);
+ if (ISSET(flags, ECHO))
+ SET(lflag, ECHO);
+ if (ISSET(flags, CRMOD)) {
+ SET(iflag, ICRNL);
+ SET(oflag, ONLCR);
+ }
+ if (ISSET(flags, XTABS))
+ SET(oflag, OXTABS);
+
+ tp->c_iflag = iflag;
+ tp->c_oflag = oflag;
+ tp->c_lflag = lflag;
+ tp->c_cflag = cflag;
+
+ sttysetoflags(tp, oflags);
+}
+
+void
+sttyclearlflags(tp, flags)
+ struct termios *tp;
+ int flags;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t cflag = tp->c_cflag;
+ register int oflags = sttygetoflags(tp) & ~flags;
+
+ /* Nothing we can do with CRTBS. */
+ if (ISSET(flags, PRTERA))
+ CLR(lflag, ECHOPRT);
+ if (ISSET(flags, CRTERA))
+ CLR(lflag, ECHOE);
+ /* Nothing we can do with TILDE. */
+ if (ISSET(flags, MDMBUF))
+ CLR(cflag, MDMBUF);
+ if (ISSET(flags, NOHANG))
+ SET(cflag, HUPCL);
+ if (ISSET(flags, CRTKIL))
+ CLR(lflag, ECHOKE);
+ if (ISSET(flags, CTLECH))
+ CLR(lflag, ECHOCTL);
+ if (ISSET(flags, DECCTQ))
+ SET(iflag, IXANY);
+ CLR(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
+
+ tp->c_iflag = iflag;
+ tp->c_oflag = oflag;
+ tp->c_lflag = lflag;
+ tp->c_cflag = cflag;
+
+ sttysetoflags(tp, oflags);
+}
+
+void
+sttysetlflags(tp, flags)
+ struct termios *tp;
+ int flags;
+{
+ register tcflag_t iflag = tp->c_iflag;
+ register tcflag_t oflag = tp->c_oflag;
+ register tcflag_t lflag = tp->c_lflag;
+ register tcflag_t cflag = tp->c_cflag;
+ register int oflags = sttygetoflags(tp) | flags;
+
+ /* Nothing we can do with CRTBS. */
+ if (ISSET(flags, PRTERA))
+ SET(lflag, ECHOPRT);
+ if (ISSET(flags, CRTERA))
+ SET(lflag, ECHOE);
+ /* Nothing we can do with TILDE. */
+ if (ISSET(flags, MDMBUF))
+ SET(cflag, MDMBUF);
+ if (ISSET(flags, NOHANG))
+ CLR(cflag, HUPCL);
+ if (ISSET(flags, CRTKIL))
+ SET(lflag, ECHOKE);
+ if (ISSET(flags, CTLECH))
+ SET(lflag, ECHOCTL);
+ if (ISSET(flags, DECCTQ))
+ CLR(iflag, IXANY);
+ SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
+
+ tp->c_iflag = iflag;
+ tp->c_oflag = oflag;
+ tp->c_lflag = lflag;
+ tp->c_cflag = cflag;
+
+ sttysetoflags(tp, oflags);
+}
diff --git a/usr.sbin/lpr/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile
new file mode 100644
index 00000000000..1c730c1a4b8
--- /dev/null
+++ b/usr.sbin/lpr/lpq/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpq
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lpq.c displayq.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpq/lpq.1 b/usr.sbin/lpr/lpq/lpq.1
new file mode 100644
index 00000000000..50e1474121e
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.1
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1983, 1990, 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.
+.\"
+.\" @(#)lpq.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LPQ 1
+.Os BSD 4.2
+.Sh NAME
+.Nm lpq
+.Nd spool queue examination program
+.Sh SYNOPSIS
+.Nm lpq
+.Op Fl l
+.Op Fl P Ns Ar printer
+.Op job # ...
+.Op user ...
+.Sh DESCRIPTION
+.Nm Lpq
+examines the spooling area used by
+.Xr lpd 8
+for printing files on the line printer, and reports the status of the
+specified jobs or all jobs associated with a user.
+.Nm Lpq
+invoked
+without any arguments reports on any jobs currently in the queue.
+.Pp
+Options:
+.Pp
+.Bl -tag -width indent
+.It Fl P
+Specify a particular printer, otherwise the default
+line printer is used (or the value of the
+.Ev PRINTER
+variable in the
+environment). All other arguments supplied are interpreted as user
+names or job numbers to filter out only those jobs of interest.
+.It Fl l
+Information about each of the files comprising the job entry
+is printed.
+Normally, only as much information as will fit on one line is displayed.
+.El
+.Pp
+For each job submitted (i.e. invocation of
+.Xr lpr 1 )
+.Nm lpq
+reports the user's name, current rank in the queue, the
+names of files comprising the job, the job identifier (a number which
+may be supplied to
+.Xr lprm 1
+for removing a specific job), and the total size in bytes.
+Job ordering is dependent on
+the algorithm used to scan the spooling directory and is supposed
+to be
+.Tn FIFO
+(First in First Out).
+File names comprising a job may be unavailable
+(when
+.Xr lpr 1
+is used as a sink in a pipeline) in which case the file
+is indicated as ``(standard input)''.
+.Pp
+If
+.Nm lpq
+warns that there is no daemon present (i.e. due to some malfunction),
+the
+.Xr lpc 8
+command can be used to restart the printer daemon.
+.Sh ENVIRONMENT
+If the following environment variable exists, it is used by
+.Nm lpq :
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+Specifies an alternate default printer.
+.El
+.Sh FILES
+.Bl -tag -width /usr/share/misc/termcap -compact
+.It Pa /etc/printcap
+To determine printer characteristics.
+.It Pa /var/spool/*
+The spooling directory, as determined from printcap.
+.It Pa /var/spool/*/cf*
+Control files specifying jobs.
+.It Pa /var/spool/*/lock
+The lock file to obtain the currently active job.
+.It Pa /usr/share/misc/termcap
+For manipulating the screen for repeated display.
+.El
+.Sh SEE ALSO
+.Xr lpr 1 ,
+.Xr lprm 1 ,
+.Xr lpc 8 ,
+.Xr lpd 8
+.Sh HISTORY
+.Nm Lpq
+appeared in
+.Bx 3 .
+.Sh BUGS
+Due to the dynamic nature of the information in the spooling directory
+.Nm lpq
+may report unreliably.
+Output formatting is sensitive to the line length of the terminal;
+this can results in widely spaced columns.
+.Sh DIAGNOSTICS
+Unable to open various files. The lock file being malformed. Garbage
+files when there is no daemon active, but files in the spooling directory.
diff --git a/usr.sbin/lpr/lpq/lpq.c b/usr.sbin/lpr/lpq/lpq.c
new file mode 100644
index 00000000000..e9026bf8e5d
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpq.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Spool Queue examination program
+ *
+ * lpq [-l] [-Pprinter] [user...] [job...]
+ *
+ * -l long output
+ * -P used to identify printer as per lpr/lprm
+ */
+
+#include <sys/param.h>
+
+#include <syslog.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+
+uid_t uid, euid;
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ register int argc;
+ register char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, lflag; /* long output option */
+
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ name = *argv;
+ if (gethostname(host, sizeof(host))) {
+ perror("lpq: gethostname");
+ exit(1);
+ }
+ openlog("lpd", 0, LOG_LPR);
+
+ lflag = 0;
+ while ((ch = getopt(argc, argv, "lP:")) != EOF)
+ switch((char)ch) {
+ case 'l': /* long output */
+ ++lflag;
+ break;
+ case 'P': /* printer name */
+ printer = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+
+ for (argc -= optind, argv += optind; argc; --argc, ++argv)
+ if (isdigit(argv[0][0])) {
+ if (requests >= MAXREQUESTS)
+ fatal("too many requests");
+ requ[requests++] = atoi(*argv);
+ }
+ else {
+ if (users >= MAXUSERS)
+ fatal("too many users");
+ user[users++] = *argv;
+ }
+
+ displayq(lflag);
+ exit(0);
+}
+
+void
+usage()
+{
+ puts("usage: lpq [-l] [-Pprinter] [user ...] [job ...]");
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile
new file mode 100644
index 00000000000..9a3cbfd591e
--- /dev/null
+++ b/usr.sbin/lpr/lpr/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpr
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lpr.c startdaemon.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpr/lpr.1 b/usr.sbin/lpr/lpr/lpr.1
new file mode 100644
index 00000000000..382d50886a9
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.1
@@ -0,0 +1,256 @@
+.\" Copyright (c) 1980, 1990, 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.
+.\"
+.\" @(#)lpr.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LPR 1
+.Os BSD 4
+.Sh NAME
+.Nm lpr
+.Nd off line print
+.Sh SYNOPSIS
+.Nm lpr
+.Op Fl P Ns Ar printer
+.Op Fl \&# Ns Ar num
+.Op Fl C Ar class
+.Op Fl J Ar job
+.Op Fl T Ar title
+.Op Fl U Ar user
+.Op Fl i Op Ar numcols
+.Op Fl 1234 Ar font
+.Op Fl w Ns Ar num
+.Op Fl cdfghlnmprstv
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm Lpr
+uses a spooling daemon to print the named files when facilities
+become available. If no names appear, the standard input is assumed.
+.Pp
+The following single letter options are used to notify the line printer
+spooler that the files are not standard text files. The spooling daemon will
+use the appropriate filters to print the data accordingly.
+.Bl -tag -width indent
+.It Fl c
+The files are assumed to contain data produced by
+.Xr cifplot 1
+.It Fl d
+The files are assumed to contain data from
+.Em tex
+.Pf ( Tn DVI
+format from Stanford).
+.It Fl f
+Use a filter which interprets the first character of each line as a
+standard
+.Tn FORTRAN
+carriage control character.
+.It Fl g
+The files are assumed to contain standard plot data as produced by the
+.Xr plot
+routines (see also
+.Xr plot
+for the filters used by the printer spooler).
+.It Fl l
+Use a filter which allows control characters to be printed and suppresses
+page breaks.
+.It Fl n
+The files are assumed to contain data from
+.Em ditroff
+(device independent troff).
+.It Fl p
+Use
+.Xr pr 1
+to format the files (equivalent to
+.Xr print ) .
+.It Fl t
+The files are assumed to contain data from
+.Xr troff 1
+(cat phototypesetter commands).
+.It Fl v
+The files are assumed to contain a raster image for devices like the
+Benson Varian.
+.El
+.Pp
+These options apply to the handling of
+the print job:
+.Bl -tag -width indent
+.It Fl P
+Force output to a specific printer. Normally,
+the default printer is used (site dependent), or the value of the
+environment variable
+.Ev PRINTER
+is used.
+.It Fl h
+Suppress the printing of the burst page.
+.It Fl m
+Send mail upon completion.
+.It Fl r
+Remove the file upon completion of spooling or upon completion of
+printing (with the
+.Fl s
+option).
+.It Fl s
+Use symbolic links. Usually files are copied to the spool directory.
+The
+.Fl s
+option will use
+.Xr symlink 2
+to link data files rather than trying to copy them so large files can be
+printed. This means the files should
+not be modified or removed until they have been printed.
+.El
+.Pp
+The remaining options apply to copies, the page display, and headers:
+.Bl -tag -width indent
+.It Fl \&# Ns Ar num
+The quantity
+.Ar num
+is the number of copies desired of each file named. For example,
+.Bd -literal -offset indent
+lpr \-#3 foo.c bar.c more.c
+.Ed
+would result in 3 copies of the file foo.c, followed by 3 copies
+of the file bar.c, etc. On the other hand,
+.Bd -literal -offset indent
+cat foo.c bar.c more.c \&| lpr \-#3
+.Ed
+.Pp
+will give three copies of the concatenation of the files. Often
+a site will disable this feature to encourage use of a photocopier
+instead.
+.It Xo
+.Fl Ns Oo Cm 1234 Oc Ar font
+.Xc
+Specifies a
+.Ar font
+to be mounted on font position
+.Ar i .
+The daemon
+will construct a
+.Li .railmag
+file referencing
+the font pathname.
+.It Fl C Ar class
+Job classification
+to use on the burst page. For example,
+.Bd -literal -offset indent
+lpr \-C EECS foo.c
+.Ed
+.Pp
+causes the system name (the name returned by
+.Xr hostname 1 )
+to be replaced on the burst page by
+.Tn EECS ,
+and the file foo.c to be printed.
+.It Fl J Ar job
+Job name to print on the burst page.
+Normally, the first file's name is used.
+.It Fl T Ar title
+Title name for
+.Xr pr 1 ,
+instead of the file name.
+.It Fl U Ar user
+User name to print on the burst page,
+also for accounting purposes.
+This option is only honored if the real user-id is daemon
+(or that specified in the printcap file instead of daemon),
+and is intended for those instances where print filters wish to requeue jobs.
+.It Fl i Op numcols
+The output is indented. If the next argument
+is numeric
+.Pq Ar numcols ,
+it is used as the number of blanks to be printed before each
+line; otherwise, 8 characters are printed.
+.It Fl w Ns Ar num
+Uses
+.Ar num
+as the page width for
+.Xr pr 1 .
+.El
+.Sh ENVIRONMENT
+If the following environment variable exists, it is used by
+.Nm lpr :
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+Specifies an alternate default printer.
+.El
+.Sh FILES
+.Bl -tag -width /var/spool/output/*/tf* -compact
+.It Pa /etc/passwd
+Personal identification.
+.It Pa /etc/printcap
+Printer capabilities data base.
+.It Pa /usr/sbin/lpd*
+Line printer daemons.
+.It Pa /var/spool/output/*
+Directories used for spooling.
+.It Pa /var/spool/output/*/cf*
+Daemon control files.
+.It Pa /var/spool/output/*/df*
+Data files specified in "cf" files.
+.It Pa /var/spool/output/*/tf*
+Temporary copies of "cf" files.
+.El
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr pr 1 ,
+.Xr symlink 2 ,
+.Xr printcap 5 ,
+.Xr lpc 8 ,
+.Xr lpd 8
+.Sh HISTORY
+The
+.Nm lpr
+command appeared in
+.Bx 3 .
+.Sh DIAGNOSTICS
+If you try to spool too large a file, it will be truncated.
+.Nm Lpr
+will object to printing binary files.
+If a user other than root prints a file and spooling is disabled,
+.Nm lpr
+will print a message saying so and will not put jobs in the queue.
+If a connection to
+.Xr lpd 1
+on the local machine cannot be made,
+.Nm lpr
+will say that the daemon cannot be started.
+Diagnostics may be printed in the daemon's log file
+regarding missing spool files by
+.Xr lpd 1 .
+.Sh BUGS
+Fonts for
+.Xr troff 1
+and
+.Xr tex
+reside on the host with the printer. It is currently not possible to
+use local font libraries.
diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c
new file mode 100644
index 00000000000..734871cc68e
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ *
+ * 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) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpr.c 8.3 (Berkeley) 3/30/94";
+#endif /* not lint */
+
+/*
+ * lpr -- off line print
+ *
+ * Allows multiple printers and printers on remote machines by
+ * using information from a printer data base.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <signal.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+static char *cfname; /* daemon control files, linked from tf's */
+static char *class = host; /* class title on header page */
+static char *dfname; /* data files */
+static char *fonts[4]; /* troff font names */
+static char format = 'f'; /* format char for printing files */
+static int hdr = 1; /* print header or not (default is yes) */
+static int iflag; /* indentation wanted */
+static int inchar; /* location to increment char in file names */
+static int indent; /* amount to indent */
+static char *jobname; /* job name on header page */
+static int mailflg; /* send mail */
+static int nact; /* number of jobs to act on */
+static int ncopies = 1; /* # of copies to make */
+static char *person; /* user name */
+static int qflag; /* q job, but don't exec daemon */
+static int rflag; /* remove files upon completion */
+static int sflag; /* symbolic link flag */
+static int tfd; /* control file descriptor */
+static char *tfname; /* tmp copy of cf before linking */
+static char *title; /* pr'ing title */
+static int userid; /* user id */
+static char *width; /* width for versatec printing */
+
+static struct stat statb;
+
+static void card __P((int, char *));
+static void chkprinter __P((char *));
+static void cleanup __P((int));
+static void copy __P((int, char []));
+static void fatal2 __P((const char *, ...));
+static char *itoa __P((int));
+static char *linked __P((char *));
+static char *lmktemp __P((char *, int, int));
+static void mktemps __P((void));
+static int nfile __P((char *));
+static int test __P((char *));
+
+uid_t uid, euid;
+
+void
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct passwd *pw;
+ struct group *gptr;
+ extern char *itoa();
+ register char *arg, *cp;
+ char buf[BUFSIZ];
+ int i, f;
+ struct stat stb;
+
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, cleanup);
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, cleanup);
+ if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+ signal(SIGQUIT, cleanup);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, cleanup);
+
+ name = argv[0];
+ gethostname(host, sizeof (host));
+ openlog("lpd", 0, LOG_LPR);
+
+ while (argc > 1 && argv[1][0] == '-') {
+ argc--;
+ arg = *++argv;
+ switch (arg[1]) {
+
+ case 'P': /* specifiy printer name */
+ if (arg[2])
+ printer = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ printer = *++argv;
+ }
+ break;
+
+ case 'C': /* classification spec */
+ hdr++;
+ if (arg[2])
+ class = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ class = *++argv;
+ }
+ break;
+
+ case 'U': /* user name */
+ hdr++;
+ if (arg[2])
+ person = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ person = *++argv;
+ }
+ break;
+
+ case 'J': /* job name */
+ hdr++;
+ if (arg[2])
+ jobname = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ jobname = *++argv;
+ }
+ break;
+
+ case 'T': /* pr's title line */
+ if (arg[2])
+ title = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ title = *++argv;
+ }
+ break;
+
+ case 'l': /* literal output */
+ case 'p': /* print using ``pr'' */
+ case 't': /* print troff output (cat files) */
+ case 'n': /* print ditroff output */
+ case 'd': /* print tex output (dvi files) */
+ case 'g': /* print graph(1G) output */
+ case 'c': /* print cifplot output */
+ case 'v': /* print vplot output */
+ format = arg[1];
+ break;
+
+ case 'f': /* print fortran output */
+ format = 'r';
+ break;
+
+ case '4': /* troff fonts */
+ case '3':
+ case '2':
+ case '1':
+ if (argc > 1) {
+ argc--;
+ fonts[arg[1] - '1'] = *++argv;
+ }
+ break;
+
+ case 'w': /* versatec page width */
+ width = arg+2;
+ break;
+
+ case 'r': /* remove file when done */
+ rflag++;
+ break;
+
+ case 'm': /* send mail when done */
+ mailflg++;
+ break;
+
+ case 'h': /* toggle want of header page */
+ hdr = !hdr;
+ break;
+
+ case 's': /* try to link files */
+ sflag++;
+ break;
+
+ case 'q': /* just q job */
+ qflag++;
+ break;
+
+ case 'i': /* indent output */
+ iflag++;
+ indent = arg[2] ? atoi(&arg[2]) : 8;
+ break;
+
+ case '#': /* n copies */
+ if (isdigit(arg[2])) {
+ i = atoi(&arg[2]);
+ if (i > 0)
+ ncopies = i;
+ }
+ }
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+ chkprinter(printer);
+ if (SC && ncopies > 1)
+ fatal2("multiple copies are not allowed");
+ if (MC > 0 && ncopies > MC)
+ fatal2("only %d copies are allowed", MC);
+ /*
+ * Get the identity of the person doing the lpr using the same
+ * algorithm as lprm.
+ */
+ userid = getuid();
+ if (userid != DU || person == 0) {
+ if ((pw = getpwuid(userid)) == NULL)
+ fatal2("Who are you?");
+ person = pw->pw_name;
+ }
+ /*
+ * Check for restricted group access.
+ */
+ if (RG != NULL && userid != DU) {
+ if ((gptr = getgrnam(RG)) == NULL)
+ fatal2("Restricted group specified incorrectly");
+ if (gptr->gr_gid != getgid()) {
+ while (*gptr->gr_mem != NULL) {
+ if ((strcmp(person, *gptr->gr_mem)) == 0)
+ break;
+ gptr->gr_mem++;
+ }
+ if (*gptr->gr_mem == NULL)
+ fatal2("Not a member of the restricted group");
+ }
+ }
+ /*
+ * Check to make sure queuing is enabled if userid is not root.
+ */
+ (void) sprintf(buf, "%s/%s", SD, LO);
+ if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
+ fatal2("Printer queue is disabled");
+ /*
+ * Initialize the control file.
+ */
+ mktemps();
+ tfd = nfile(tfname);
+ seteuid(euid);
+ (void) fchown(tfd, DU, -1); /* owned by daemon for protection */
+ seteuid(uid);
+ card('H', host);
+ card('P', person);
+ if (hdr) {
+ if (jobname == NULL) {
+ if (argc == 1)
+ jobname = "stdin";
+ else
+ jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
+ }
+ card('J', jobname);
+ card('C', class);
+ card('L', person);
+ }
+ if (iflag)
+ card('I', itoa(indent));
+ if (mailflg)
+ card('M', person);
+ if (format == 't' || format == 'n' || format == 'd')
+ for (i = 0; i < 4; i++)
+ if (fonts[i] != NULL)
+ card('1'+i, fonts[i]);
+ if (width != NULL)
+ card('W', width);
+
+ /*
+ * Read the files and spool them.
+ */
+ if (argc == 1)
+ copy(0, " ");
+ else while (--argc) {
+ if ((f = test(arg = *++argv)) < 0)
+ continue; /* file unreasonable */
+
+ if (sflag && (cp = linked(arg)) != NULL) {
+ (void) sprintf(buf, "%d %d", statb.st_dev, statb.st_ino);
+ card('S', buf);
+ if (format == 'p')
+ card('T', title ? title : arg);
+ for (i = 0; i < ncopies; i++)
+ card(format, &dfname[inchar-2]);
+ card('U', &dfname[inchar-2]);
+ if (f)
+ card('U', cp);
+ card('N', arg);
+ dfname[inchar]++;
+ nact++;
+ continue;
+ }
+ if (sflag)
+ printf("%s: %s: not linked, copying instead\n", name, arg);
+ seteuid(euid);
+ if ((i = open(arg, O_RDONLY)) < 0) {
+ seteuid(uid);
+ printf("%s: cannot open %s\n", name, arg);
+ continue;
+ }
+ copy(i, arg);
+ (void) close(i);
+ if (f && unlink(arg) < 0)
+ printf("%s: %s: not removed\n", name, arg);
+ seteuid(uid);
+ }
+
+ if (nact) {
+ (void) close(tfd);
+ tfname[inchar]--;
+ /*
+ * Touch the control file to fix position in the queue.
+ */
+ seteuid(euid);
+ if ((tfd = open(tfname, O_RDWR)) >= 0) {
+ char c;
+
+ if (read(tfd, &c, 1) == 1 &&
+ lseek(tfd, (off_t)0, 0) == 0 &&
+ write(tfd, &c, 1) != 1) {
+ printf("%s: cannot touch %s\n", name, tfname);
+ tfname[inchar]++;
+ cleanup(0);
+ }
+ (void) close(tfd);
+ }
+ if (link(tfname, cfname) < 0) {
+ printf("%s: cannot rename %s\n", name, cfname);
+ tfname[inchar]++;
+ cleanup(0);
+ }
+ unlink(tfname);
+ seteuid(uid);
+ if (qflag) /* just q things up */
+ exit(0);
+ if (!startdaemon(printer))
+ printf("jobs queued, but cannot start daemon.\n");
+ exit(0);
+ }
+ cleanup(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Create the file n and copy from file descriptor f.
+ */
+static void
+copy(f, n)
+ int f;
+ char n[];
+{
+ register int fd, i, nr, nc;
+ char buf[BUFSIZ];
+
+ if (format == 'p')
+ card('T', title ? title : n);
+ for (i = 0; i < ncopies; i++)
+ card(format, &dfname[inchar-2]);
+ card('U', &dfname[inchar-2]);
+ card('N', n);
+ fd = nfile(dfname);
+ nr = nc = 0;
+ while ((i = read(f, buf, BUFSIZ)) > 0) {
+ if (write(fd, buf, i) != i) {
+ printf("%s: %s: temp file write error\n", name, n);
+ break;
+ }
+ nc += i;
+ if (nc >= BUFSIZ) {
+ nc -= BUFSIZ;
+ nr++;
+ if (MX > 0 && nr > MX) {
+ printf("%s: %s: copy file is too large\n", name, n);
+ break;
+ }
+ }
+ }
+ (void) close(fd);
+ if (nc==0 && nr==0)
+ printf("%s: %s: empty input file\n", name, f ? n : "stdin");
+ else
+ nact++;
+}
+
+/*
+ * Try and link the file to dfname. Return a pointer to the full
+ * path name if successful.
+ */
+static char *
+linked(file)
+ register char *file;
+{
+ register char *cp;
+ static char buf[BUFSIZ];
+ register int ret;
+
+ if (*file != '/') {
+ seteuid(euid);
+ if (getcwd(buf, BUFSIZ) == NULL) {
+ seteuid(uid);
+ return(NULL);
+ }
+ while (file[0] == '.') {
+ switch (file[1]) {
+ case '/':
+ file += 2;
+ continue;
+ case '.':
+ if (file[2] == '/') {
+ if ((cp = rindex(buf, '/')) != NULL)
+ *cp = '\0';
+ file += 3;
+ continue;
+ }
+ }
+ break;
+ }
+ strcat(buf, "/");
+ strcat(buf, file);
+ file = buf;
+ }
+ seteuid(euid);
+ ret = symlink(file, dfname);
+ seteuid(uid);
+ return(ret ? NULL : file);
+}
+
+/*
+ * Put a line into the control file.
+ */
+static void
+card(c, p2)
+ register int c;
+ register char *p2;
+{
+ char buf[BUFSIZ];
+ register char *p1 = buf;
+ register int len = 2;
+
+ *p1++ = c;
+ while ((c = *p2++) != '\0') {
+ *p1++ = (c == '\n') ? ' ' : c;
+ len++;
+ }
+ *p1++ = '\n';
+ write(tfd, buf, len);
+}
+
+/*
+ * Create a new file in the spool directory.
+ */
+static int
+nfile(n)
+ char *n;
+{
+ register int f;
+ int oldumask = umask(0); /* should block signals */
+
+ seteuid(euid);
+ f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
+ (void) umask(oldumask);
+ if (f < 0) {
+ printf("%s: cannot create %s\n", name, n);
+ cleanup(0);
+ }
+ if (fchown(f, userid, -1) < 0) {
+ printf("%s: cannot chown %s\n", name, n);
+ cleanup(0); /* cleanup does exit */
+ }
+ seteuid(uid);
+ if (++n[inchar] > 'z') {
+ if (++n[inchar-2] == 't') {
+ printf("too many files - break up the job\n");
+ cleanup(0);
+ }
+ n[inchar] = 'A';
+ } else if (n[inchar] == '[')
+ n[inchar] = 'a';
+ return(f);
+}
+
+/*
+ * Cleanup after interrupts and errors.
+ */
+static void
+cleanup(signo)
+ int signo;
+{
+ register i;
+
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ i = inchar;
+ seteuid(euid);
+ if (tfname)
+ do
+ unlink(tfname);
+ while (tfname[i]-- != 'A');
+ if (cfname)
+ do
+ unlink(cfname);
+ while (cfname[i]-- != 'A');
+ if (dfname)
+ do {
+ do
+ unlink(dfname);
+ while (dfname[i]-- != 'A');
+ dfname[i] = 'z';
+ } while (dfname[i-2]-- != 'd');
+ exit(1);
+}
+
+/*
+ * Test to see if this is a printable file.
+ * Return -1 if it is not, 0 if its printable, and 1 if
+ * we should remove it after printing.
+ */
+static int
+test(file)
+ char *file;
+{
+ struct exec execb;
+ register int fd;
+ register char *cp;
+
+ seteuid(euid);
+ if (access(file, 4) < 0) {
+ printf("%s: cannot access %s\n", name, file);
+ goto bad;
+ }
+ if (stat(file, &statb) < 0) {
+ printf("%s: cannot stat %s\n", name, file);
+ goto bad;
+ }
+ if ((statb.st_mode & S_IFMT) == S_IFDIR) {
+ printf("%s: %s is a directory\n", name, file);
+ goto bad;
+ }
+ if (statb.st_size == 0) {
+ printf("%s: %s is an empty file\n", name, file);
+ goto bad;
+ }
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ printf("%s: cannot open %s\n", name, file);
+ goto bad;
+ }
+ if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
+ !N_BADMAG(execb)) {
+ printf("%s: %s is an executable program and is unprintable",
+ name, file);
+ (void) close(fd);
+ goto bad;
+ }
+ (void) close(fd);
+ if (rflag) {
+ if ((cp = rindex(file, '/')) == NULL) {
+ if (access(".", 2) == 0)
+ return(1);
+ } else {
+ if (cp == file) {
+ fd = access("/", 2);
+ } else {
+ *cp = '\0';
+ fd = access(file, 2);
+ *cp = '/';
+ }
+ if (fd == 0)
+ return(1);
+ }
+ printf("%s: %s: is not removable by you\n", name, file);
+ }
+ return(0);
+bad:
+ seteuid(uid);
+ return(-1);
+}
+
+/*
+ * itoa - integer to string conversion
+ */
+static char *
+itoa(i)
+ register int i;
+{
+ static char b[10] = "########";
+ register char *p;
+
+ p = &b[8];
+ do
+ *p-- = i%10 + '0';
+ while (i /= 10);
+ return(++p);
+}
+
+/*
+ * Perform lookup for printer name or abbreviation --
+ */
+static void
+chkprinter(s)
+ char *s;
+{
+ int status;
+
+ if ((status = cgetent(&bp, printcapdb, s)) == -2)
+ fatal2("cannot open printer description file");
+ else if (status == -1)
+ fatal2("%s: unknown printer", s);
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ cgetstr(bp, "rg", &RG);
+ if (cgetnum(bp, "mx", &MX) < 0)
+ MX = DEFMX;
+ if (cgetnum(bp,"mc", &MC) < 0)
+ MC = DEFMAXCOPIES;
+ if (cgetnum(bp, "du", &DU) < 0)
+ DU = DEFUID;
+ SC = (cgetcap(bp, "sc", ':') != NULL);
+}
+
+/*
+ * Make the temp files.
+ */
+static void
+mktemps()
+{
+ register int len, fd, n;
+ register char *cp;
+ char buf[BUFSIZ];
+ char *lmktemp();
+
+ (void) sprintf(buf, "%s/.seq", SD);
+ seteuid(euid);
+ if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
+ printf("%s: cannot create %s\n", name, buf);
+ exit(1);
+ }
+ if (flock(fd, LOCK_EX)) {
+ printf("%s: cannot lock %s\n", name, buf);
+ exit(1);
+ }
+ seteuid(uid);
+ n = 0;
+ if ((len = read(fd, buf, sizeof(buf))) > 0) {
+ for (cp = buf; len--; ) {
+ if (*cp < '0' || *cp > '9')
+ break;
+ n = n * 10 + (*cp++ - '0');
+ }
+ }
+ len = strlen(SD) + strlen(host) + 8;
+ tfname = lmktemp("tf", n, len);
+ cfname = lmktemp("cf", n, len);
+ dfname = lmktemp("df", n, len);
+ inchar = strlen(SD) + 3;
+ n = (n + 1) % 1000;
+ (void) lseek(fd, (off_t)0, 0);
+ sprintf(buf, "%03d\n", n);
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd); /* unlocks as well */
+}
+
+/*
+ * Make a temp file name.
+ */
+static char *
+lmktemp(id, num, len)
+ char *id;
+ int num, len;
+{
+ register char *s;
+
+ if ((s = malloc(len)) == NULL)
+ fatal2("out of memory");
+ (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
+ return(s);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+fatal2(const char *msg, ...)
+#else
+fatal2(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ printf("%s: ", name);
+ vprintf(msg, ap);
+ putchar('\n');
+ va_end(ap);
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile
new file mode 100644
index 00000000000..d1362f5cdce
--- /dev/null
+++ b/usr.sbin/lpr/lprm/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lprm
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lprm.c rmjob.c startdaemon.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lprm/lprm.1 b/usr.sbin/lpr/lprm/lprm.1
new file mode 100644
index 00000000000..88a1c1075f0
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.1
@@ -0,0 +1,145 @@
+.\" Copyright (c) 1983, 1990, 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.
+.\"
+.\" @(#)lprm.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LPRM 1
+.Os BSD 4.2
+.Sh NAME
+.Nm lprm
+.Nd remove jobs from the line printer spooling queue
+.Sh SYNOPSIS
+.Nm lprm
+.Op Fl P Ns Ar printer
+.Op Fl
+.Op job # ...
+.Op Ar user ...
+.Sh DESCRIPTION
+.Nm Lprm
+will remove a job, or jobs, from a printer's spool queue.
+Since the spooling directory is protected from users, using
+.Nm lprm
+is normally the only method by which a user may remove a job.
+The owner of a job is determined by the user's login name
+and host name on the machine where the
+.Xr lpr 1
+command was invoked.
+.Pp
+Options and arguments:
+.Bl -tag -width indent
+.It Fl P Ns Ar printer
+Specify the queue associated with a specific
+.Ar printer
+(otherwise the default printer is used).
+.It Fl
+If a single
+.Sq Fl
+is given,
+.Nm lprm
+will remove all jobs which a user
+owns. If the super-user employs this flag, the spool queue will
+be emptied entirely.
+.It Ar user
+Causes
+.Nm lprm
+to attempt to remove any jobs queued belonging to that user
+(or users). This form of invoking
+.Nm lprm
+is useful only to the super-user.
+.It Ar job\ \&#
+A user may dequeue an individual job by specifying its job number.
+This number may be obtained from the
+.Xr lpq 1
+program, e.g.
+.Pp
+.Bd -literal -offset indent
+\&% lpq \-l
+
+1st:ken [job #013ucbarpa]
+ (standard input) 100 bytes
+% lprm 13
+.Ed
+.El
+.Pp
+If neither arguments or options are given,
+.Nm Lprm
+will delete the currently active job if it is
+owned by the user who invoked
+.Nm lprm .
+.Pp
+.Nm Lprm
+announces the names of any files it removes and is silent if
+there are no jobs in the queue which match the request list.
+.Pp
+.Nm Lprm
+will kill off an active daemon, if necessary, before removing
+any spooling files. If a daemon is killed, a new one is
+automatically restarted upon completion of file removals.
+.Sh ENVIRONMENT
+If the following environment variable exists, it is utilized by
+.Nm lprm .
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+If the environment variable
+.Ev PRINTER
+exists,
+and a printer has not been specified with the
+.Fl P
+option,
+the default printer is assumed from
+.Ev PRINTER .
+.El
+.Sh FILES
+.Bl -tag -width /var/spool/*/lock/ -compact
+.It Pa /etc/printcap
+Printer characteristics file.
+.It Pa /var/spool/*
+Spooling directories.
+.It Pa /var/spool/*/lock
+Lock file used to obtain the pid of the current
+daemon and the job number of the currently active job.
+.El
+.Sh SEE ALSO
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lpd 8
+.Sh DIAGNOSTICS
+.Dq Permission denied
+if the user tries to remove files other than his own.
+.Sh BUGS
+Since there are race conditions possible in the update of the lock file,
+the currently active job may be incorrectly identified.
+.Sh HISTORY
+The
+.Nm lprm
+command appeared in
+.Bx 3.0 .
diff --git a/usr.sbin/lpr/lprm/lprm.c b/usr.sbin/lpr/lprm/lprm.c
new file mode 100644
index 00000000000..df3a6cb3b04
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * lprm - remove the current user's spool entry
+ *
+ * lprm [-] [[job #] [user] ...]
+ *
+ * Using information in the lock file, lprm will kill the
+ * currently active daemon (if necessary), remove the associated files,
+ * and startup a new daemon. Priviledged users may remove anyone's spool
+ * entries, otherwise one can only remove their own.
+ */
+
+#include <sys/param.h>
+
+#include <syslog.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+
+/*
+ * Stuff for handling job specifications
+ */
+char *person; /* name of person doing lprm */
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+uid_t uid, euid; /* real and effective user id's */
+
+static char luser[16]; /* buffer for person */
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *arg;
+ struct passwd *p;
+
+ uid = getuid();
+ euid = geteuid();
+ seteuid(uid); /* be safe */
+ name = argv[0];
+ gethostname(host, sizeof(host));
+ openlog("lpd", 0, LOG_LPR);
+ if ((p = getpwuid(getuid())) == NULL)
+ fatal("Who are you?");
+ if (strlen(p->pw_name) >= sizeof(luser))
+ fatal("Your name is too long");
+ strcpy(luser, p->pw_name);
+ person = luser;
+ while (--argc) {
+ if ((arg = *++argv)[0] == '-')
+ switch (arg[1]) {
+ case 'P':
+ if (arg[2])
+ printer = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ printer = *++argv;
+ }
+ break;
+ case '\0':
+ if (!users) {
+ users = -1;
+ break;
+ }
+ default:
+ usage();
+ }
+ else {
+ if (users < 0)
+ usage();
+ if (isdigit(arg[0])) {
+ if (requests >= MAXREQUESTS)
+ fatal("Too many requests");
+ requ[requests++] = atoi(arg);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = arg;
+ }
+ }
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+
+ rmjob();
+ exit(0);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: lprm [-] [-Pprinter] [[job #] [user] ...]\n");
+ exit(2);
+}
diff --git a/usr.sbin/lpr/lptest/Makefile b/usr.sbin/lpr/lptest/Makefile
new file mode 100644
index 00000000000..6ff8e7fe9c7
--- /dev/null
+++ b/usr.sbin/lpr/lptest/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lptest
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lptest/lptest.1 b/usr.sbin/lpr/lptest/lptest.1
new file mode 100644
index 00000000000..95b28f3525b
--- /dev/null
+++ b/usr.sbin/lpr/lptest/lptest.1
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1985, 1990, 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.
+.\"
+.\" @(#)lptest.1 8.2 (Berkeley) 12/30/93
+.\"
+.Dd December 30, 1993
+.Dt LPTEST 1
+.Os BSD 4.3
+.Sh NAME
+.Nm lptest
+.Nd generate lineprinter ripple pattern
+.Sh SYNOPSIS
+.Nm lptest
+.Op Ar length
+.Op Ar count
+.Sh DESCRIPTION
+.Nm Lptest
+writes the traditional "ripple test" pattern on standard output.
+In 96 lines,
+this pattern will print all 96 printable
+.Tn ASCII
+characters
+in each position.
+While originally created to test printers, it is quite
+useful for testing terminals,
+driving terminal ports for debugging purposes,
+or any other task where a quick supply of random data is needed.
+.Pp
+The
+.Ar length
+argument specifies the output line length if the default
+length of 79 is inappropriate.
+.Pp
+The
+.Ar count
+argument specifies the number of output lines to be generated if
+the default count of 200 is inappropriate.
+Note that if
+.Ar count
+is to be specified,
+.Ar length
+must be also be specified.
+.Sh HISTORY
+.Nm Lptest
+appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/lpr/lptest/lptest.c b/usr.sbin/lpr/lptest/lptest.c
new file mode 100644
index 00000000000..5ce80b5d4fa
--- /dev/null
+++ b/usr.sbin/lpr/lptest/lptest.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lptest.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * lptest -- line printer test program (and other devices).
+ */
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int len, count;
+ register i, j, fc, nc;
+ char outbuf[BUFSIZ];
+
+ setbuf(stdout, outbuf);
+ if (argc >= 2)
+ len = atoi(argv[1]);
+ else
+ len = 79;
+ if (argc >= 3)
+ count = atoi(argv[2]);
+ else
+ count = 200;
+ fc = ' ';
+ for (i = 0; i < count; i++) {
+ if (++fc == 0177)
+ fc = ' ';
+ nc = fc;
+ for (j = 0; j < len; j++) {
+ putchar(nc);
+ if (++nc == 0177)
+ nc = ' ';
+ }
+ putchar('\n');
+ }
+ (void) fflush(stdout);
+ exit(0);
+}
diff --git a/usr.sbin/lpr/pac/Makefile b/usr.sbin/lpr/pac/Makefile
new file mode 100644
index 00000000000..e3fb65a3ee0
--- /dev/null
+++ b/usr.sbin/lpr/pac/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pac
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN= pac.8
+SRCS= pac.c common.c
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/pac/pac.8 b/usr.sbin/lpr/pac/pac.8
new file mode 100644
index 00000000000..6e7ffc0b765
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.8
@@ -0,0 +1,106 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)pac.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt PAC 8
+.Os BSD 4.2
+.Sh NAME
+.Nm pac
+.Nd printer/plotter accounting information
+.Sh SYNOPSIS
+.Nm pac
+.Op Fl P Ns Ar printer
+.Op Fl c
+.Op Fl m
+.Op Fl p Ns Ar price
+.Op Fl s
+.Op Fl r
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm Pac
+reads the printer/plotter accounting files, accumulating the number
+of pages (the usual case) or feet (for raster devices)
+of paper consumed by each user, and printing out
+how much each user consumed in pages or feet and dollars.
+.Pp
+Options and operands available:
+.Bl -tag -width PPprinter
+.It Fl P Ns Ar printer
+Accounting is done for the named printer.
+Normally, accounting is done for the default printer (site dependent) or
+the value of the environment variable
+.Ev PRINTER
+is used.
+.It Fl c
+flag causes the output to be sorted by cost; usually the
+output is sorted alphabetically by name.
+.It Fl m
+flag causes the host name to be ignored in the accounting file. This
+allows for a user on multiple machines to have all of his printing
+charges grouped together.
+.It Fl p Ns Ar price
+The value
+.Ar price
+is used for the cost in dollars instead of the default value of 0.02
+or the price specified in
+.Pa /etc/printcap .
+.It Fl r
+Reverse the sorting order.
+.It Fl s
+Accounting information is summarized on the
+summary accounting file; this summarization is necessary since on a
+busy system, the accounting file can grow by several lines per day.
+.It Ar names
+Statistics are only printed for user(s)
+.Ar name ;
+usually, statistics are printed for every user who has used any paper.
+.El
+.Sh FILES
+.Bl -tag -width /var/account/?_sum -compact
+.It Pa /var/account/?acct
+raw accounting files
+.It Pa /var/account/?_sum
+summary accounting files
+.It Pa /etc/printcap
+printer capability data base
+.El
+.Sh SEE ALSO
+.Xr printcap 5
+.Sh BUGS
+The relationship between the computed price and reality is
+as yet unknown.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/lpr/pac/pac.c b/usr.sbin/lpr/pac/pac.c
new file mode 100644
index 00000000000..cadaba2c7fb
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Do Printer accounting summary.
+ * Currently, usage is
+ * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
+ * to print the usage information for the named people.
+ */
+
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+
+static char *acctfile; /* accounting file (input data) */
+static int allflag = 1; /* Get stats on everybody */
+static int errs;
+static int hcount; /* Count of hash entries */
+static int mflag = 0; /* disregard machine names */
+static int pflag = 0; /* 1 if -p on cmd line */
+static float price = 0.02; /* cost per page (or what ever) */
+static long price100; /* per-page cost in 100th of a cent */
+static int reverse; /* Reverse sort order */
+static int sort; /* Sort by cost */
+static char *sumfile; /* summary file */
+static int summarize; /* Compress accounting file */
+
+uid_t uid, euid;
+
+/*
+ * Grossness follows:
+ * Names to be accumulated are hashed into the following
+ * table.
+ */
+
+#define HSHSIZE 97 /* Number of hash buckets */
+
+struct hent {
+ struct hent *h_link; /* Forward hash link */
+ char *h_name; /* Name of this user */
+ float h_feetpages; /* Feet or pages of paper */
+ int h_count; /* Number of runs */
+};
+
+static struct hent *hashtab[HSHSIZE]; /* Hash table proper */
+
+static void account __P((FILE *));
+static int any __P((int, char []));
+static int chkprinter __P((char *));
+static void dumpit __P((void));
+static int hash __P((char []));
+static struct hent *enter __P((char []));
+static struct hent *lookup __P((char []));
+static int qucmp __P((const void *, const void *));
+static void rewrite __P((void));
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register FILE *acct;
+ register char *cp;
+
+ euid = geteuid(); /* these aren't used in pac(1) */
+ uid = getuid();
+ while (--argc) {
+ cp = *++argv;
+ if (*cp++ == '-') {
+ switch(*cp++) {
+ case 'P':
+ /*
+ * Printer name.
+ */
+ printer = cp;
+ continue;
+
+ case 'p':
+ /*
+ * get the price.
+ */
+ price = atof(cp);
+ pflag = 1;
+ continue;
+
+ case 's':
+ /*
+ * Summarize and compress accounting file.
+ */
+ summarize++;
+ continue;
+
+ case 'c':
+ /*
+ * Sort by cost.
+ */
+ sort++;
+ continue;
+
+ case 'm':
+ /*
+ * disregard machine names for each user
+ */
+ mflag = 1;
+ continue;
+
+ case 'r':
+ /*
+ * Reverse sorting order.
+ */
+ reverse++;
+ continue;
+
+ default:
+fprintf(stderr,
+ "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
+ exit(1);
+ }
+ }
+ (void) enter(--cp);
+ allflag = 0;
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+ if (!chkprinter(printer)) {
+ printf("pac: unknown printer %s\n", printer);
+ exit(2);
+ }
+
+ if ((acct = fopen(acctfile, "r")) == NULL) {
+ perror(acctfile);
+ exit(1);
+ }
+ account(acct);
+ fclose(acct);
+ if ((acct = fopen(sumfile, "r")) != NULL) {
+ account(acct);
+ fclose(acct);
+ }
+ if (summarize)
+ rewrite();
+ else
+ dumpit();
+ exit(errs);
+}
+
+/*
+ * Read the entire accounting file, accumulating statistics
+ * for the users that we have in the hash table. If allflag
+ * is set, then just gather the facts on everyone.
+ * Note that we must accomodate both the active and summary file
+ * formats here.
+ * Host names are ignored if the -m flag is present.
+ */
+static void
+account(acct)
+ register FILE *acct;
+{
+ char linebuf[BUFSIZ];
+ double t;
+ register char *cp, *cp2;
+ register struct hent *hp;
+ register int ic;
+
+ while (fgets(linebuf, BUFSIZ, acct) != NULL) {
+ cp = linebuf;
+ while (any(*cp, " t\t"))
+ cp++;
+ t = atof(cp);
+ while (any(*cp, ".0123456789"))
+ cp++;
+ while (any(*cp, " \t"))
+ cp++;
+ for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
+ ;
+ ic = atoi(cp2);
+ *cp2 = '\0';
+ if (mflag && index(cp, ':'))
+ cp = index(cp, ':') + 1;
+ hp = lookup(cp);
+ if (hp == NULL) {
+ if (!allflag)
+ continue;
+ hp = enter(cp);
+ }
+ hp->h_feetpages += t;
+ if (ic)
+ hp->h_count += ic;
+ else
+ hp->h_count++;
+ }
+}
+
+/*
+ * Sort the hashed entries by name or footage
+ * and print it all out.
+ */
+static void
+dumpit()
+{
+ struct hent **base;
+ register struct hent *hp, **ap;
+ register int hno, c, runs;
+ float feet;
+
+ hp = hashtab[0];
+ hno = 1;
+ base = (struct hent **) calloc(sizeof hp, hcount);
+ for (ap = base, c = hcount; c--; ap++) {
+ while (hp == NULL)
+ hp = hashtab[hno++];
+ *ap = hp;
+ hp = hp->h_link;
+ }
+ qsort(base, hcount, sizeof hp, qucmp);
+ printf(" Login pages/feet runs price\n");
+ feet = 0.0;
+ runs = 0;
+ for (ap = base, c = hcount; c--; ap++) {
+ hp = *ap;
+ runs += hp->h_count;
+ feet += hp->h_feetpages;
+ printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name,
+ hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
+ }
+ if (allflag) {
+ printf("\n");
+ printf("%-24s %7.2f %4d $%6.2f\n", "total", feet,
+ runs, feet * price);
+ }
+}
+
+/*
+ * Rewrite the summary file with the summary information we have accumulated.
+ */
+static void
+rewrite()
+{
+ register struct hent *hp;
+ register int i;
+ register FILE *acctf;
+
+ if ((acctf = fopen(sumfile, "w")) == NULL) {
+ perror(sumfile);
+ errs++;
+ return;
+ }
+ for (i = 0; i < HSHSIZE; i++) {
+ hp = hashtab[i];
+ while (hp != NULL) {
+ fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
+ hp->h_name, hp->h_count);
+ hp = hp->h_link;
+ }
+ }
+ fflush(acctf);
+ if (ferror(acctf)) {
+ perror(sumfile);
+ errs++;
+ }
+ fclose(acctf);
+ if ((acctf = fopen(acctfile, "w")) == NULL)
+ perror(acctfile);
+ else
+ fclose(acctf);
+}
+
+/*
+ * Hashing routines.
+ */
+
+/*
+ * Enter the name into the hash table and return the pointer allocated.
+ */
+
+static struct hent *
+enter(name)
+ char name[];
+{
+ register struct hent *hp;
+ register int h;
+
+ if ((hp = lookup(name)) != NULL)
+ return(hp);
+ h = hash(name);
+ hcount++;
+ hp = (struct hent *) calloc(sizeof *hp, 1);
+ hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
+ strcpy(hp->h_name, name);
+ hp->h_feetpages = 0.0;
+ hp->h_count = 0;
+ hp->h_link = hashtab[h];
+ hashtab[h] = hp;
+ return(hp);
+}
+
+/*
+ * Lookup a name in the hash table and return a pointer
+ * to it.
+ */
+
+static struct hent *
+lookup(name)
+ char name[];
+{
+ register int h;
+ register struct hent *hp;
+
+ h = hash(name);
+ for (hp = hashtab[h]; hp != NULL; hp = hp->h_link)
+ if (strcmp(hp->h_name, name) == 0)
+ return(hp);
+ return(NULL);
+}
+
+/*
+ * Hash the passed name and return the index in
+ * the hash table to begin the search.
+ */
+static int
+hash(name)
+ char name[];
+{
+ register int h;
+ register char *cp;
+
+ for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
+ ;
+ return((h & 0x7fffffff) % HSHSIZE);
+}
+
+/*
+ * Other stuff
+ */
+static int
+any(ch, str)
+ int ch;
+ char str[];
+{
+ register int c = ch;
+ register char *cp = str;
+
+ while (*cp)
+ if (*cp++ == c)
+ return(1);
+ return(0);
+}
+
+/*
+ * The qsort comparison routine.
+ * The comparison is ascii collating order
+ * or by feet of typesetter film, according to sort.
+ */
+static int
+qucmp(a, b)
+ const void *a, *b;
+{
+ register struct hent *h1, *h2;
+ register int r;
+
+ h1 = *(struct hent **)a;
+ h2 = *(struct hent **)b;
+ if (sort)
+ r = h1->h_feetpages < h2->h_feetpages ?
+ -1 : h1->h_feetpages > h2->h_feetpages;
+ else
+ r = strcmp(h1->h_name, h2->h_name);
+ return(reverse ? -r : r);
+}
+
+/*
+ * Perform lookup for printer name or abbreviation --
+ */
+static int
+chkprinter(s)
+ register char *s;
+{
+ int stat;
+
+ if ((stat = cgetent(&bp, printcapdb, s)) == -2) {
+ printf("pac: can't open printer description file\n");
+ exit(3);
+ } else if (stat == -1)
+ return(0);
+ else if (stat == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "af", &acctfile) == -1) {
+ printf("accounting not enabled for printer %s\n", printer);
+ exit(2);
+ }
+ if (!pflag && (cgetnum(bp, "pc", &price100) == 0))
+ price = price100/10000.0;
+ sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
+ if (sumfile == NULL) {
+ perror("pac");
+ exit(1);
+ }
+ strcpy(sumfile, acctfile);
+ strcat(sumfile, "_sum");
+ return(1);
+}
diff --git a/usr.sbin/map-mbone/Makefile b/usr.sbin/map-mbone/Makefile
new file mode 100644
index 00000000000..d95bbb13d6d
--- /dev/null
+++ b/usr.sbin/map-mbone/Makefile
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile,v 1.2 1995/10/03 23:16:47 thorpej Exp $
+# from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
+
+.PATH: ${.CURDIR}/../mrouted
+CFLAGS+= -I${.CURDIR}/../mrouted
+
+PROG= map-mbone
+SRCS= igmp.c inet.c kern.c mapper.c
+MAN= map-mbone.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/map-mbone/map-mbone.8 b/usr.sbin/map-mbone/map-mbone.8
new file mode 100644
index 00000000000..3c54a50d84f
--- /dev/null
+++ b/usr.sbin/map-mbone/map-mbone.8
@@ -0,0 +1,91 @@
+.\" $NetBSD: map-mbone.8,v 1.2 1995/10/03 23:16:53 thorpej Exp $
+.\"
+.TH MAP-MBONE 8
+.UC 5
+.SH NAME
+map-mbone \- Multicast connection mapper
+.SH SYNOPSIS
+.B /usr/sbin/map-mbone
+[
+.B \-d
+.I debug_level
+] [
+.B \-f
+] [
+.B \-g
+] [
+.B \-n
+] [
+.B \-r
+.I retry_count
+] [
+.B \-t
+.I timeout_count
+] [
+.B starting_router
+]
+.SH DESCRIPTION
+.I map-mbone
+attempts to display all multicast routers that are reachable from the multicast
+.I starting_router.
+If not specified on the command line, the default multicast
+.I starting_router
+is the localhost.
+.PP
+.I map-mbone
+traverses neighboring multicast routers by sending the ASK_NEIGHBORS IGMP
+message to the multicast starting_router. If this multicast router responds,
+the version number and a list of their neighboring multicast router addresses is
+part of that response. If the responding router has recent multicast version
+number, then
+.I map-mbone
+requests additional information such as metrics, thresholds, and flags from the
+multicast router. For each new occurrence of neighboring multicast router in
+the reply and provided the flooding option has been selected, then
+.I map-mbone
+asks each of this multicast router for a list of neighbors. This search
+for unique routers will continue until no new neighboring multicast routers
+are reported.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+"\-d" option sets the debug level. When the debug level is greater than the
+default value of 0, addition debugging messages are printed. Regardless of
+the debug level, an error condition, will always write an error message and will
+cause
+.I map-mbone
+to terminate.
+Non-zero debug levels have the following effects:
+.IP "level 1"
+packet warnings are printed to stderr.
+.IP "level 2"
+all level 1 messages plus notifications down networks are printed to stderr.
+.IP "level 3"
+all level 2 messages plus notifications of all packet
+timeouts are printed to stderr.
+.PP
+"\-f" option sets flooding option. Flooding allows the recursive search
+of neighboring multicast routers and is enable by default when starting_router
+is not used.
+.PP
+"\-g" option sets graphing in GraphEd format.
+.PP
+"\-n" option disables the DNS lookup for the multicast routers names.
+.PP
+"\-r retry_count" sets the neighbor query retry limit. Default is 1 retry.
+.PP
+"\-t timeout_count" sets the number of seconds to wait for a neighbor query
+reply before retrying. Default timeout is 2 seconds.
+.PP
+.SH IMPORTANT NOTE
+.I map-mbone
+must be run as root.
+.PP
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR mrinfo (8) ,
+.BR mtrace (8)
+.PP
+.SH AUTHOR
+Pavel Curtis
diff --git a/usr.sbin/map-mbone/mapper.c b/usr.sbin/map-mbone/mapper.c
new file mode 100644
index 00000000000..e58b0fb3bad
--- /dev/null
+++ b/usr.sbin/map-mbone/mapper.c
@@ -0,0 +1,960 @@
+/* $NetBSD: mapper.c,v 1.2 1995/10/03 23:16:56 thorpej Exp $ */
+
+/* Mapper for connections between MRouteD multicast routers.
+ * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
+ */
+
+/*
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative
+ * works for research and evaluation purposes, provided that Xerox is
+ * acknowledged in all documentation pertaining to any such copy or derivative
+ * work. Xerox grants no other licenses expressed or implied. The Xerox trade
+ * name should not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
+ * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
+ * express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#include <string.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 1 /* How many times to ask each router */
+
+
+/* All IP addresses are stored in the data structure in NET order. */
+
+typedef struct neighbor {
+ struct neighbor *next;
+ u_int32_t addr; /* IP address in NET order */
+ u_char metric; /* TTL cost of forwarding */
+ u_char threshold; /* TTL threshold to forward */
+ u_short flags; /* flags on connection */
+#define NF_PRESENT 0x8000 /* True if flags are meaningful */
+} Neighbor;
+
+typedef struct interface {
+ struct interface *next;
+ u_int32_t addr; /* IP address of the interface in NET order */
+ Neighbor *neighbors; /* List of neighbors' IP addresses */
+} Interface;
+
+typedef struct node {
+ u_int32_t addr; /* IP address of this entry in NET order */
+ u_int32_t version; /* which mrouted version is running */
+ int tries; /* How many requests sent? -1 for aliases */
+ union {
+ struct node *alias; /* If alias, to what? */
+ struct interface *interfaces; /* Else, neighbor data */
+ } u;
+ struct node *left, *right;
+} Node;
+
+
+Node *routers = 0;
+u_int32_t our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int show_names = TRUE;
+vifi_t numvifs; /* to keep loader happy */
+ /* (see COPY_TABLES macro called in kern.c) */
+
+
+Node *find_node(addr, ptr)
+ u_int32_t addr;
+ Node **ptr;
+{
+ Node *n = *ptr;
+
+ if (!n) {
+ *ptr = n = (Node *) malloc(sizeof(Node));
+ n->addr = addr;
+ n->version = 0;
+ n->tries = 0;
+ n->u.interfaces = 0;
+ n->left = n->right = 0;
+ return n;
+ } else if (addr == n->addr)
+ return n;
+ else if (addr < n->addr)
+ return find_node(addr, &(n->left));
+ else
+ return find_node(addr, &(n->right));
+}
+
+
+Interface *find_interface(addr, node)
+ u_int32_t addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ if (ifc->addr == addr)
+ return ifc;
+
+ ifc = (Interface *) malloc(sizeof(Interface));
+ ifc->addr = addr;
+ ifc->next = node->u.interfaces;
+ node->u.interfaces = ifc;
+ ifc->neighbors = 0;
+
+ return ifc;
+}
+
+
+Neighbor *find_neighbor(addr, node)
+ u_int32_t addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next)
+ if (nb->addr == addr)
+ return nb;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0: if (severity > LOG_WARNING) return;
+ case 1: if (severity > LOG_NOTICE ) return;
+ case 2: if (severity > LOG_INFO ) return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+
+/*
+ * Send a neighbors-list request.
+ */
+void ask(dst)
+ u_int32_t dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void ask2(dst)
+ u_int32_t dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group)
+ u_int32_t src, dst, group;
+{
+ log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst)
+ u_int32_t src, dst;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming route report message.
+ */
+void accept_report(src, dst, p, datalen)
+ u_int32_t src, dst;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list request message.
+ */
+void accept_neighbor_request(src, dst)
+ u_int32_t src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+void accept_neighbor_request2(src, dst)
+ u_int32_t src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors(src, dst, p, datalen, level)
+ u_int32_t src, dst, level;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+#define GET_ADDR(a) (a = ((u_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\
+ a += ((u_int32_t)*p++ << 8), a += *p++)
+
+ /* if node is running a recent mrouted, ask for additional info */
+ if (level != 0) {
+ node->version = ntohl(level);
+ node->tries = 0;
+ ask2(src);
+ return;
+ }
+
+ if (debug > 3) {
+ int i;
+
+ fprintf(stderr, " datalen = %d\n", datalen);
+ for (i = 0; i < datalen; i++) {
+ if ((i & 0xF) == 0)
+ fprintf(stderr, " ");
+ fprintf(stderr, " %02x", p[i]);
+ if ((i & 0xF) == 0xF)
+ fprintf(stderr, "\n");
+ }
+ if ((datalen & 0xF) != 0xF)
+ fprintf(stderr, "\n");
+ }
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_int32_t ifc_addr;
+ u_char metric, threshold, ncount;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 3) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(ifc_addr);
+ ifc_addr = htonl(ifc_addr);
+ metric = *p++;
+ threshold = *p++;
+ ncount = *p++;
+ datalen -= 4 + 3;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_int32_t neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ datalen -= 4;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = 0;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+void accept_neighbors2(src, dst, p, datalen)
+ u_int32_t src, dst;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_int32_t ifc_addr;
+ u_char metric, threshold, ncount, flags;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 4) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ ifc_addr = *(u_int32_t*)p;
+ p += 4;
+ metric = *p++;
+ threshold = *p++;
+ flags = *p++;
+ ncount = *p++;
+ datalen -= 4 + 4;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_int32_t neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ neighbor = *(u_int32_t*)p;
+ p += 4;
+ datalen -= 4;
+ if (neighbor == 0)
+ /* make leaf nets point to themselves */
+ neighbor = ifc_addr;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = flags | NF_PRESENT;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+
+void check_vif_state()
+{
+ log(LOG_NOTICE, 0, "network marked down...");
+}
+
+
+int retry_requests(node)
+ Node *node;
+{
+ int result;
+
+ if (node) {
+ result = retry_requests(node->left);
+ if (node->tries > 0 && node->tries < retries) {
+ if (node->version)
+ ask2(node->addr);
+ else
+ ask(node->addr);
+ node->tries++;
+ result = 1;
+ }
+ return retry_requests(node->right) || result;
+ } else
+ return 0;
+}
+
+
+char *inet_name(addr)
+ u_int32_t addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : 0;
+}
+
+
+void print_map(node)
+ Node *node;
+{
+ if (node) {
+ char *name, *addr;
+
+ print_map(node->left);
+
+ addr = inet_fmt(node->addr, s1);
+ if (!target_addr
+ || (node->tries >= 0 && node->u.interfaces)
+ || (node->tries == -1
+ && node->u.alias->tries >= 0
+ && node->u.alias->u.interfaces)) {
+ if (show_names && (name = inet_name(node->addr)))
+ printf("%s (%s):", addr, name);
+ else
+ printf("%s:", addr);
+ if (node->tries < 0)
+ printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1));
+ else if (!node->u.interfaces)
+ printf(" no response to query\n\n");
+ else {
+ Interface *ifc;
+
+ if (node->version)
+ printf(" <v%d.%d>", node->version & 0xff,
+ (node->version >> 8) & 0xff);
+ printf("\n");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+ char *ifc_name = inet_fmt(ifc->addr, s1);
+ int ifc_len = strlen(ifc_name);
+ int count = 0;
+
+ printf(" %s:", ifc_name);
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ if (count > 0)
+ printf("%*s", ifc_len + 5, "");
+ printf(" %s", inet_fmt(nb->addr, s1));
+ if (show_names && (name = inet_name(nb->addr)))
+ printf(" (%s)", name);
+ printf(" [%d/%d", nb->metric, nb->threshold);
+ if (nb->flags) {
+ u_short flags = nb->flags;
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ }
+ printf("]\n");
+ count++;
+ }
+ }
+ printf("\n");
+ }
+ }
+ print_map(node->right);
+ }
+}
+
+
+char *graph_name(addr, buf)
+ u_int32_t addr;
+ char *buf;
+{
+ char *name;
+
+ if (show_names && (name = inet_name(addr)))
+ strcpy(buf, name);
+ else
+ inet_fmt(addr, buf);
+
+ return buf;
+}
+
+
+void graph_edges(node)
+ Node *node;
+{
+ Interface *ifc;
+ Neighbor *nb;
+ char name[100];
+
+ if (node) {
+ graph_edges(node->left);
+ if (node->tries >= 0) {
+ printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
+ (int) node->addr,
+ node->addr & 0xFF, (node->addr >> 8) & 0xFF,
+ graph_name(node->addr, name),
+ node->u.interfaces ? "" : "*");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+ Neighbor *nb2;
+
+ if (nb_node->tries < 0)
+ nb_node = nb_node->u.alias;
+
+ if (node != nb_node &&
+ (!(nb2 = find_neighbor(node->addr, nb_node))
+ || node->addr < nb_node->addr)) {
+ printf(" %d \"%d/%d",
+ nb_node->addr, nb->metric, nb->threshold);
+ if (nb2 && (nb2->metric != nb->metric
+ || nb2->threshold != nb->threshold))
+ printf(",%d/%d", nb2->metric, nb2->threshold);
+ if (nb->flags & NF_PRESENT)
+ printf("%s%s",
+ nb->flags & DVMRP_NF_SRCRT ? "" :
+ nb->flags & DVMRP_NF_TUNNEL ? "E" : "P",
+ nb->flags & DVMRP_NF_DOWN ? "D" : "");
+ printf("\"\n");
+ }
+ }
+ printf(" ;\n");
+ }
+ graph_edges(node->right);
+ }
+}
+
+void elide_aliases(node)
+ Node *node;
+{
+ if (node) {
+ elide_aliases(node->left);
+ if (node->tries >= 0) {
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+
+ if (nb_node->tries < 0)
+ nb->addr = nb_node->u.alias->addr;
+ }
+ }
+ }
+ elide_aliases(node->right);
+ }
+}
+
+void graph_map()
+{
+ time_t now = time(0);
+ char *nowstr = ctime(&now);
+
+ nowstr[24] = '\0'; /* Kill the newline at the end */
+ elide_aliases(routers);
+ printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
+ nowstr);
+ graph_edges(routers);
+ printf("END\n");
+}
+
+
+int get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+u_int32_t host_addr(name)
+ char *name;
+{
+ struct hostent *e = gethostbyname(name);
+ int addr;
+
+ if (e)
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(name);
+ if (addr == -1)
+ addr = 0;
+ }
+
+ return addr;
+}
+
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int flood = FALSE, graph = FALSE;
+
+#ifdef SYSV
+ setvbuf(stderr, NULL, _IOLBF, 0);
+#else
+ setlinebuf(stderr);
+#endif
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ goto usage;
+ break;
+ case 'f':
+ flood = TRUE;
+ break;
+ case 'g':
+ graph = TRUE;
+ break;
+ case 'n':
+ show_names = FALSE;
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ goto usage;
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ argv++, argc--;
+ }
+
+ if (argc > 1) {
+ usage:
+ fprintf(stderr,
+ "Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
+ "[-r retries] [-d [debug-level]] [router]");
+ fprintf(stderr, "\t-f Flood the routing graph with queries\n");
+ fprintf(stderr, "\t (True by default unless `router' is given)\n");
+ fprintf(stderr, "\t-g Generate output in GraphEd format\n");
+ fprintf(stderr, "\t-n Don't look up DNS names for routers\n");
+ exit(1);
+ } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) {
+ fprintf(stderr, "Unknown host: %s\n", argv[0]);
+ exit(2);
+ }
+
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
+ addr.sin_addr.s_addr = dvmrp_group;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ /* Send initial seed message to all local routers */
+ ask(target_addr ? target_addr : allhosts_group);
+
+ if (target_addr) {
+ Node *n = find_node(target_addr, &routers);
+
+ n->tries = 1;
+
+ if (flood)
+ target_addr = 0;
+ }
+
+ /* Main receive loop */
+ for(;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (retry_requests(routers))
+ continue;
+ else
+ break;
+ }
+
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, NULL, &dummy);
+ if (recvlen >= 0)
+ accept_igmp(recvlen);
+ else if (errno != EINTR)
+ perror("recvfrom");
+ }
+
+ printf("\n");
+
+ if (graph)
+ graph_map();
+ else {
+ if (!target_addr)
+ printf("Multicast Router Connectivity:\n\n");
+ print_map(routers);
+ }
+
+ exit(0);
+}
+
+void accept_prune()
+{
+}
+void accept_graft()
+{
+}
+void accept_g_ack()
+{
+}
+void add_table_entry()
+{
+}
+void accept_leave_message()
+{
+}
+void accept_mtrace()
+{
+}
+void accept_membership_query()
+{
+}
diff --git a/usr.sbin/mrinfo/Makefile b/usr.sbin/mrinfo/Makefile
new file mode 100644
index 00000000000..fd54edbdb54
--- /dev/null
+++ b/usr.sbin/mrinfo/Makefile
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.3 1995/10/03 23:20:30 thorpej Exp $
+# from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
+
+.PATH: ${.CURDIR}/../mrouted
+CFLAGS+= -I${.CURDIR}/../mrouted
+
+PROG= mrinfo
+SRCS= igmp.c inet.c kern.c mrinfo.c
+MAN= mrinfo.8
+BINOWN= root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrinfo/mrinfo.8 b/usr.sbin/mrinfo/mrinfo.8
new file mode 100644
index 00000000000..60174c8686b
--- /dev/null
+++ b/usr.sbin/mrinfo/mrinfo.8
@@ -0,0 +1,85 @@
+.\" $NetBSD: mrinfo.8,v 1.2 1995/10/03 23:20:39 thorpej Exp $
+.\"
+.TH MRINFO 8
+.UC 5
+.SH NAME
+mrinfo \- Displays configuration info from a multicast router
+.SH SYNOPSIS
+.B /usr/sbin/mrinfo
+[
+.B \-d
+.I debug_level
+] [
+.B \-r
+.I retry_count
+] [
+.B \-t
+.I timeout_count
+]
+.B multicast_router
+
+.SH DESCRIPTION
+.I mrinfo
+attempts to display the configuration information from the multicast router
+.I multicast_router.
+.PP
+.I mrinfo
+uses the ASK_NEIGHBORS IGMP message to the specified multicast router. If this
+multicast router responds, the version number and a list of their neighboring
+multicast router addresses is part of that response. If the responding router
+has a recent multicast version number, then
+.I mrinfo
+requests additional information such as metrics, thresholds, and flags from the
+multicast router. Once the specified multicast router responds, the
+configuration is displayed to the standard output.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+"\-d" option sets the debug level. When the debug level is greater than the
+default value of 0, addition debugging messages are printed. Regardless of
+the debug level, an error condition, will always write an error message and will
+cause
+.I mrinfo
+to terminate.
+Non-zero debug levels have the following effects:
+.IP "level 1"
+packet warnings are printed to stderr.
+.IP "level 2"
+all level 1 messages plus notifications down networks are printed to stderr.
+.IP "level 3"
+all level 2 messages plus notifications of all packet
+timeouts are printed to stderr.
+.PP
+"\-r retry_count" sets the neighbor query retry limit. Default is 3 retry.
+.PP
+"\-t timeout_count" sets the number of seconds to wait for a neighbor query
+reply. Default timeout is 4 seconds.
+.PP
+.SH SAMPLE OUTPUT
+.nf
+.I mrinfo mbone.phony.dom.net
+127.148.176.10 (mbone.phony.dom.net) [version 3.3]:
+ 127.148.176.10 -> 0.0.0.0 (?) [1/1/querier]
+ 127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel]
+ 127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down]
+ 127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel]
+.fi
+.PP
+For each neighbor of the queried multicast router, the IP of the queried router
+is displayed, followed by the IP and name of the neighbor. In square brackets
+the metric (cost of connection), the treashold (multicast ttl) is displayed. If
+the queried multicast router has a newer version number, the type (tunnel,
+srcrt) and status (disabled, down) of the connection is displayed.
+.PP
+.SH IMPORTANT NOTE
+.I mrinfo
+must be run as root.
+.PP
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR map-mbone (8) ,
+.BR mtrace (8)
+.PP
+.SH AUTHOR
+Van Jacobson
diff --git a/usr.sbin/mrinfo/mrinfo.c b/usr.sbin/mrinfo/mrinfo.c
new file mode 100644
index 00000000000..20bd54fcf36
--- /dev/null
+++ b/usr.sbin/mrinfo/mrinfo.c
@@ -0,0 +1,532 @@
+/* $NetBSD: mrinfo.c,v 1.3 1995/10/03 23:20:45 thorpej Exp $ */
+
+/*
+ * This tool requests configuration info from a multicast router
+ * and prints the reply (if any). Invoke it as:
+ *
+ * mrinfo router-name-or-address
+ *
+ * Written Wed Mar 24 1993 by Van Jacobson (adapted from the
+ * multicast mapper written by Pavel Curtis).
+ *
+ * The lawyers insist we include the following UC copyright notice.
+ * The mapper from which this is derived contained a Xerox copyright
+ * notice which follows the UC one. Try not to get depressed noting
+ * that the legal gibberish is larger than the program.
+ *
+ * Copyright (c) 1993 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ---------------------------------
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Xerox is acknowledged
+ * in all documentation pertaining to any such copy or derivative work. Xerox
+ * grants no other licenses expressed or implied. The Xerox trade name should
+ * not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
+ * ANY PARTICULAR PURPOSE. The software is provided "as is" without express
+ * or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $NetBSD: mrinfo.c,v 1.3 1995/10/03 23:20:45 thorpej Exp $";
+/* original rcsid:
+ "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
+*/
+#endif
+
+#include <string.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+#include <arpa/inet.h>
+
+#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to ask each router */
+
+u_int32_t our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int nflag = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int target_level;
+vifi_t numvifs; /* to keep loader happy */
+ /* (see COPY_TABLES macro called in kern.c) */
+
+char *
+inet_name(addr)
+ u_int32_t addr;
+{
+ struct hostent *e;
+ struct in_addr in;
+
+ if (addr == 0)
+ return "local";
+
+ if (nflag ||
+ (e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) {
+ in.s_addr = addr;
+ return (inet_ntoa(in));
+ }
+ return (e->h_name);
+}
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void
+log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0:
+ if (severity > LOG_WARNING)
+ return;
+ case 1:
+ if (severity > LOG_NOTICE)
+ return;
+ case 2:
+ if (severity > LOG_INFO)
+ return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+/*
+ * Send a neighbors-list request.
+ */
+void
+ask(dst)
+ u_int32_t dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void
+ask2(dst)
+ u_int32_t dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void
+accept_neighbors(src, dst, p, datalen)
+ u_int32_t src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+#define GET_ADDR(a) (a = ((u_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\
+ a += ((u_int32_t)*p++ << 8), a += *p++)
+
+ printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
+ while (p < ep) {
+ register u_int32_t laddr;
+ register u_char metric;
+ register u_char thresh;
+ register int ncount;
+
+ GET_ADDR(laddr);
+ laddr = htonl(laddr);
+ metric = *p++;
+ thresh = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_int32_t neighbor;
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ }
+ }
+}
+
+void
+accept_neighbors2(src, dst, p, datalen)
+ u_int32_t src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+ u_int broken_cisco = ((target_level & 0xffff) == 0x020a); /* 10.2 */
+ /* well, only possibly_broken_cisco, but that's too long to type. */
+
+ printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
+ target_level & 0xff, (target_level >> 8) & 0xff);
+
+ while (p < ep) {
+ register u_char metric;
+ register u_char thresh;
+ register u_char flags;
+ register int ncount;
+ register u_int32_t laddr = *(u_int32_t*)p;
+
+ p += 4;
+ metric = *p++;
+ thresh = *p++;
+ flags = *p++;
+ ncount = *p++;
+ if (broken_cisco && ncount == 0) /* dumb Ciscos */
+ ncount = 1;
+ if (broken_cisco && ncount > 15) /* dumb Ciscos */
+ ncount = ncount & 0xf;
+ while (--ncount >= 0 && p < ep) {
+ register u_int32_t neighbor = *(u_int32_t*)p;
+ p += 4;
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_PIM)
+ printf("/pim");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ if (flags & DVMRP_NF_LEAF)
+ printf("/leaf");
+ printf("]\n");
+ }
+ }
+}
+
+int
+get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next
+ * argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+u_int32_t
+host_addr(name)
+ char *name;
+{
+ struct hostent *e;
+ u_int32_t addr;
+
+ addr = inet_addr(name);
+ if ((int)addr == -1) {
+ e = gethostbyname(name);
+ if (e == NULL || e->h_length != sizeof(addr))
+ return (0);
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ }
+ return(addr);
+}
+
+void
+usage()
+{
+ fprintf(stderr,
+ "Usage: mrinfo [-n] [-t timeout] [-r retries] [router]\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ setlinebuf(stderr);
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mrinfo: must be root\n");
+ exit(1);
+ }
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ usage();
+ break;
+ case 'n':
+ ++nflag;
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ usage();
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ usage();
+ break;
+ default:
+ usage();
+ }
+ argv++, argc--;
+ }
+ if (argc > 1)
+ usage();
+ if (argc == 1)
+ target_addr = host_addr(argv[0]);
+ else
+ target_addr = host_addr("127.0.0.1");
+
+ if (target_addr == 0) {
+ fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
+ exit(1);
+ }
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
+ addr.sin_addr.s_addr = target_addr;
+ addr.sin_port = htons(2000); /* any port over 1024 will
+ * do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ ask(target_addr);
+
+ /* Main receive loop */
+ for (;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+ register u_int32_t src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (--retries < 0)
+ exit(1);
+ if (target_level == 0)
+ ask(target_addr);
+ else
+ ask2(target_addr);
+ continue;
+ }
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, NULL, &dummy);
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR)
+ perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "packet too short (%u bytes) for IP header",
+ recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ if (ip->ip_p == 0)
+ continue; /* Request to install cache entry */
+ src = ip->ip_src.s_addr;
+ dst = ip->ip_dst.s_addr;
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ continue;
+ }
+ if (igmp->igmp_type != IGMP_DVMRP)
+ continue;
+
+ switch (igmp->igmp_code) {
+ case DVMRP_NEIGHBORS:
+ case DVMRP_NEIGHBORS2:
+ if (src != target_addr) {
+ fprintf(stderr, "mrinfo: got reply from %s",
+ inet_fmt(src, s1));
+ fprintf(stderr, " instead of %s\n",
+ inet_fmt(target_addr, s1));
+ /*continue;*/
+ }
+ break;
+ default:
+ continue; /* ignore all other DVMRP messages */
+ }
+
+ switch (igmp->igmp_code) {
+
+ case DVMRP_NEIGHBORS:
+ if (group) {
+ /* knows about DVMRP_NEIGHBORS2 msg */
+ if (target_level == 0) {
+ target_level = ntohl(group);
+ ask2(target_addr);
+ }
+ } else {
+ accept_neighbors(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ break;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ }
+}
+
+/* dummies */
+void accept_probe()
+{
+}
+void accept_group_report()
+{
+}
+void accept_neighbor_request2()
+{
+}
+void accept_report()
+{
+}
+void accept_neighbor_request()
+{
+}
+void accept_prune()
+{
+}
+void accept_graft()
+{
+}
+void accept_g_ack()
+{
+}
+void add_table_entry()
+{
+}
+void check_vif_state()
+{
+}
+void accept_leave_message()
+{
+}
+void accept_mtrace()
+{
+}
+void accept_membership_query()
+{
+}
diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE
new file mode 100644
index 00000000000..ef7da470b11
--- /dev/null
+++ b/usr.sbin/mrouted/LICENSE
@@ -0,0 +1,48 @@
+
+The mrouted program is covered by the following license. Use of the
+mrouted program represents acceptance of these terms and conditions.
+
+1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
+to use, copy and modify the computer software ``mrouted'' (hereinafter
+called the ``Program''), upon the terms and conditions hereinafter set
+out and until Licensee discontinues use of the Licensed Program.
+
+2. LICENSEE acknowledges that the Program is a research tool still in
+the development state, that it is being supplied ``as is,'' without any
+accompanying services from STANFORD, and that this license is entered
+into in order to encourage scientific collaboration aimed at further
+development and application of the Program.
+
+3. LICENSEE may copy the Program and may sublicense others to use object
+code copies of the Program or any derivative version of the Program.
+All copies must contain all copyright and other proprietary notices found
+in the Program as provided by STANFORD. Title to copyright to the
+Program remains with STANFORD.
+
+4. LICENSEE may create derivative versions of the Program. LICENSEE
+hereby grants STANFORD a royalty-free license to use, copy, modify,
+distribute and sublicense any such derivative works. At the time
+LICENSEE provides a copy of a derivative version of the Program to a
+third party, LICENSEE shall provide STANFORD with one copy of the source
+code of the derivative version at no charge to STANFORD.
+
+5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
+By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
+OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
+COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
+for any liability nor for any direct, indirect or consequential damages
+with respect to any claim by LICENSEE or any third party on account of or
+arising from this Agreement or use of the Program.
+
+6. This agreement shall be construed, interpreted and applied in
+accordance with the State of California and any legal action arising
+out of this Agreement or use of the Program shall be filed in a court
+in the State of California.
+
+7. Nothing in this Agreement shall be construed as conferring rights to
+use in advertising, publicity or otherwise any trademark or the name
+of ``Stanford''.
+
+The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+Leland Stanford Junior University.
diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile
new file mode 100644
index 00000000000..fc24ca1911d
--- /dev/null
+++ b/usr.sbin/mrouted/Makefile
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile,v 1.5 1995/10/09 03:51:32 thorpej Exp $
+# from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
+
+PROG= mrouted
+SRCS= igmp.c inet.c kern.c config.c cfparse.c main.c route.c vif.c \
+ prune.c callout.c
+MAN= mrouted.8
+
+CLEANFILES+= cfparse.c y.tab.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c
new file mode 100644
index 00000000000..943ace50507
--- /dev/null
+++ b/usr.sbin/mrouted/callout.c
@@ -0,0 +1,201 @@
+/* $NetBSD: callout.c,v 1.2 1995/10/09 03:51:34 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+#include "defs.h"
+
+/* the code below implements a callout queue */
+static int id = 0;
+static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
+
+static int in_callout= 0;
+
+typedef void (* cfunc_t)();
+
+struct timeout_q {
+ struct timeout_q *next; /* next event */
+ int id;
+ cfunc_t func ; /* function to call */
+ char *data; /* func's data */
+ int time; /* time offset to next event*/
+};
+
+static void print_Q();
+
+void callout_init()
+{
+ Q = (struct timeout_q *) 0;
+}
+
+
+/*
+ * signal handler for SIGALARM that is called once every second
+ */
+void age_callout_queue()
+{
+ struct timeout_q *ptr;
+
+ if (in_callout)
+ return;
+
+ in_callout = 1;
+ ptr = Q;
+
+ while (ptr){
+ if (!ptr->time ) {
+ /* timeout has happened */
+ if(ptr->func)
+ ptr->func(ptr->data);
+ Q = Q->next;
+
+ free(ptr);
+ ptr = Q;
+ }
+ else {
+ ptr->time --;
+#ifdef IGMP_DEBUG
+ log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
+#endif IGMP_DEBUG
+ in_callout = 0; return;
+ }
+ }
+ in_callout = 0;
+ return;
+}
+
+
+/*
+ * sets the timer
+ */
+int timer_setTimer(delay, action, data)
+ int delay; /* number of units for timeout */
+ cfunc_t action; /* function to be called on timeout */
+ char *data; /* what to call the timeout function with */
+{
+ struct timeout_q *ptr, *node, *prev;
+
+ if (in_callout)
+ return -1;
+
+ in_callout = 1;
+
+ /* create a node */
+ node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
+ if (node == 0) {
+ log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
+ in_callout = 0;
+ return -1;
+ }
+ node->func = action;
+ node->data = data;
+ node->time = delay;
+ node->next = 0;
+ node->id = ++id;
+
+ prev = ptr = Q;
+
+ /* insert node in the queue */
+
+ /* if the queue is empty, insert the node and return */
+ if (!Q)
+ Q = node;
+ else {
+ /* chase the pointer looking for the right place */
+ while (ptr){
+
+ if (delay < ptr->time){
+ /* right place */
+
+ node->next = ptr;
+ if (ptr == Q)
+ Q = node;
+ else
+ prev->next = node;
+ ptr->time -= node->time;
+ print_Q();
+ in_callout = 0;
+ return node->id;
+ }
+ else {
+ /* keep moving */
+
+ delay -= ptr->time; node->time = delay;
+ prev = ptr;
+ ptr = ptr->next;
+ }
+ }
+ prev->next = node;
+ }
+ print_Q();
+ in_callout = 0;
+ return node->id;
+}
+
+
+/* clears the associated timer */
+void timer_clearTimer( timer_id)
+ int timer_id;
+{
+ struct timeout_q *ptr, *prev;
+
+ if (in_callout) return;
+ in_callout = 1;
+
+
+ if ( !timer_id ) {in_callout = 0; return;}
+
+ prev = ptr = Q;
+
+ /*
+ * find the right node, delete it. the subsequent node's time
+ * gets bumped up
+ */
+
+ print_Q();
+ while (ptr){
+ if (ptr->id == timer_id){
+ /* got the right node */
+
+ /* unlink it from the queue */
+ if ( ptr == Q)
+ Q = Q->next;
+ else
+ prev->next = ptr->next;
+
+ /* increment next node if any */
+ if (ptr->next != 0)
+ (ptr->next)->time += ptr->time;
+
+ free(ptr->data);
+ free(ptr);
+ print_Q();
+ in_callout = 0;
+ return;
+ }
+ prev = ptr;
+ ptr = ptr->next;
+ }
+ print_Q();
+ in_callout = 0;
+}
+
+/*
+ * debugging utility
+ */
+static void print_Q()
+{
+#ifdef IGMP_DEBUG
+ struct timeout_q *ptr;
+
+ for(ptr = Q; ptr; ptr = ptr->next)
+ log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
+#endif IGMP_DEBUG
+}
+
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y
new file mode 100644
index 00000000000..9538200f814
--- /dev/null
+++ b/usr.sbin/mrouted/cfparse.y
@@ -0,0 +1,512 @@
+%{
+/* $NetBSD: cfparse.y,v 1.3 1995/10/09 03:51:35 thorpej Exp $ */
+
+/*
+ * Configuration file parser for mrouted.
+ *
+ * Written by Bill Fenner, NRL, 1994
+ */
+#include <stdio.h>
+#include <string.h>
+#include <varargs.h>
+#include "defs.h"
+
+static FILE *f;
+
+extern int udp_socket;
+char *configfilename = _PATH_MROUTED_CONF;
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+static int lineno;
+static struct ifreq ifbuf[32];
+static struct ifconf ifc;
+
+static struct uvif *v;
+
+static int order;
+
+struct addrmask {
+ u_int32_t addr;
+ int mask;
+};
+
+struct boundnam {
+ char *name;
+ struct addrmask bound;
+};
+
+#define MAXBOUNDS 20
+
+struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
+int numbounds = 0; /* Number of named boundaries */
+
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+ struct addrmask addrmask;
+ u_int32_t addr;
+};
+
+%token CACHE_LIFETIME PRUNING
+%token PHYINT TUNNEL NAME
+%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
+%token <num> BOOLEAN
+%token <num> NUMBER
+%token <ptr> STRING
+%token <addrmask> ADDRMASK
+%token <addr> ADDR
+
+%type <addr> interface
+%type <addrmask> bound boundary addrmask
+
+%start conf
+
+%%
+
+conf : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | PHYINT interface {
+
+ vifi_t vifi;
+
+ if (order)
+ fatal("phyints must appear before tunnels");
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ $2 == v->uv_lcl_addr)
+ break;
+
+ if (vifi == numvifs)
+ fatal("%s is not a configured interface",
+ inet_fmt($2,s1));
+
+ /*log(LOG_INFO, 0, "phyint: %x\n", v);*/
+ }
+ ifmods
+ | TUNNEL interface ADDR {
+
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ vifi_t vifi;
+
+ order++;
+
+ ifr = ifconfaddr(&ifc, $2);
+ if (ifr == 0)
+ fatal("Tunnel local address %s is not mine",
+ inet_fmt($2, s1));
+
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
+ fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
+ if (ffr.ifr_flags & IFF_LOOPBACK)
+ fatal("Tunnel local address %s is a loopback interface",
+ inet_fmt($2, s1));
+
+ if (ifconfaddr(&ifc, $3) != 0)
+ fatal("Tunnel remote address %s is one of mine",
+ inet_fmt($3, s1));
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if ($3 == v->uv_rmt_addr)
+ fatal("Duplicate tunnel to %s",
+ inet_fmt($3, s1));
+ } else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (($3 & v->uv_subnetmask) == v->uv_subnet)
+ fatal("Unnecessary tunnel to %s",
+ inet_fmt($3,s1));
+ }
+
+ if (numvifs == MAXVIFS)
+ fatal("too many vifs");
+
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = $2;
+ v->uv_rmt_addr = $3;
+ v->uv_subnet = 0;
+ v->uv_subnetmask= 0;
+ v->uv_subnetbcast= 0;
+ strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+ v->uv_acl = NULL;
+ v->uv_addrs = NULL;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
+ }
+ tunnelmods
+ {
+ log(LOG_INFO, 0,
+ "installing tunnel from %s to %s as vif #%u - rate=%d",
+ inet_fmt($2, s1), inet_fmt($3, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+ }
+ | PRUNING BOOLEAN { pruning = $2; }
+ | CACHE_LIFETIME NUMBER { cache_lifetime = $2;
+ max_prune_lifetime = cache_lifetime * 2;
+ }
+ | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
+ fatal("Too many named boundaries (max %d)", MAXBOUNDS);
+ }
+
+ boundlist[numbounds].name = malloc(strlen($2) + 1);
+ strcpy(boundlist[numbounds].name, $2);
+ boundlist[numbounds++].bound = $3;
+ }
+ ;
+
+tunnelmods : /* empty */
+ | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
+ ;
+
+tunnelmod : mod
+ | SRCRT { fatal("Source-route tunnels not supported"); }
+ ;
+
+ifmods : /* empty */
+ | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
+ ;
+
+ifmod : mod
+ | DISABLE { v->uv_flags |= VIFF_DISABLED; }
+ | NETMASK ADDR { v->uv_subnetmask = $2; }
+ | ALTNET addrmask {
+
+ struct phaddr *ph;
+
+ ph = (struct phaddr *)malloc(sizeof(struct phaddr));
+ if (ph == NULL)
+ fatal("out of memory");
+ if ($2.mask) {
+ VAL_TO_MASK(ph->pa_mask, $2.mask);
+ } else
+ ph->pa_mask = v->uv_subnetmask;
+ ph->pa_addr = $2.addr & ph->pa_mask;
+ if ($2.addr & ~ph->pa_mask)
+ warn("Extra addr %s/%d has host bits set",
+ inet_fmt($2.addr,s1), $2.mask);
+ ph->pa_next = v->uv_addrs;
+ v->uv_addrs = ph;
+
+ }
+ ;
+
+mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
+ fatal("Invalid threshold %d",$2);
+ v->uv_threshold = $2;
+ }
+ | THRESHOLD {
+
+ warn("Expected number after threshold keyword");
+
+ }
+ | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
+ fatal("Invalid metric %d",$2);
+ v->uv_metric = $2;
+ }
+ | METRIC {
+
+ warn("Expected number after metric keyword");
+
+ }
+ | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
+ fatal("Invalid rate_limit %d",$2);
+ v->uv_rate_limit = $2;
+ }
+ | RATE_LIMIT {
+
+ warn("Expected number after rate_limit keyword");
+
+ }
+ | BOUNDARY bound {
+
+ struct vif_acl *v_acl;
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ fatal("out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, $2.mask);
+ v_acl->acl_addr = $2.addr & v_acl->acl_mask;
+ if ($2.addr & ~v_acl->acl_mask)
+ warn("Boundary spec %s/%d has host bits set",
+ inet_fmt($2.addr,s1),$2.mask);
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+
+ }
+ | BOUNDARY {
+
+ warn("Expected boundary spec after boundary keyword");
+
+ }
+ ;
+
+interface : ADDR { $$ = $1; }
+ | STRING {
+ $$ = valid_if($1);
+ if ($$ == 0)
+ fatal("Invalid interface name %s",$1);
+ }
+ ;
+
+bound : boundary { $$ = $1; }
+ | STRING { int i;
+
+ for (i=0; i < numbounds; i++) {
+ if (!strcmp(boundlist[i].name, $1)) {
+ $$ = boundlist[i].bound;
+ break;
+ }
+ }
+ if (i == numbounds) {
+ fatal("Invalid boundary name %s",$1);
+ }
+ }
+ ;
+
+boundary : ADDRMASK {
+
+ if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
+ fatal("Boundaries must be 239.x.x.x, not %s/%d",
+ inet_fmt($1.addr, s1), $1.mask);
+ }
+ $$ = $1;
+
+ }
+ ;
+
+addrmask : ADDRMASK { $$ = $1; }
+ | ADDR { $$.addr = $1; $$.mask = 0; }
+ ;
+%%
+/*VARARGS1*/
+static void fatal(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+/*VARARGS1*/
+static void warn(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+void yyerror(s)
+char *s;
+{
+ log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
+}
+
+char *next_word()
+{
+ static char buf[1024];
+ static char *p=NULL;
+ extern FILE *f;
+ char *q;
+
+ while (1) {
+ if (!p || !*p) {
+ lineno++;
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return NULL;
+ p = buf;
+ }
+ while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
+ p++;
+ if (*p == '#') {
+ p = NULL; /* skip comments */
+ continue;
+ }
+ q = p;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n')
+ p++; /* find next whitespace */
+ *p++ = '\0'; /* null-terminate string */
+
+ if (!*q) {
+ p = NULL;
+ continue; /* if 0-length string, read another line */
+ }
+
+ return q;
+ }
+}
+
+int yylex()
+{
+ int n;
+ u_int32_t addr;
+ char *q;
+
+ if ((q = next_word()) == NULL) {
+ return 0;
+ }
+
+ if (!strcmp(q,"cache_lifetime"))
+ return CACHE_LIFETIME;
+ if (!strcmp(q,"pruning"))
+ return PRUNING;
+ if (!strcmp(q,"phyint"))
+ return PHYINT;
+ if (!strcmp(q,"tunnel"))
+ return TUNNEL;
+ if (!strcmp(q,"disable"))
+ return DISABLE;
+ if (!strcmp(q,"metric"))
+ return METRIC;
+ if (!strcmp(q,"threshold"))
+ return THRESHOLD;
+ if (!strcmp(q,"rate_limit"))
+ return RATE_LIMIT;
+ if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
+ return SRCRT;
+ if (!strcmp(q,"boundary"))
+ return BOUNDARY;
+ if (!strcmp(q,"netmask"))
+ return NETMASK;
+ if (!strcmp(q,"name"))
+ return NAME;
+ if (!strcmp(q,"altnet"))
+ return ALTNET;
+ if (!strcmp(q,"on") || !strcmp(q,"yes")) {
+ yylval.num = 1;
+ return BOOLEAN;
+ }
+ if (!strcmp(q,"off") || !strcmp(q,"no")) {
+ yylval.num = 0;
+ return BOOLEAN;
+ }
+ if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
+ if ((addr = inet_parse(s1)) != 0xffffffff) {
+ yylval.addrmask.mask = n;
+ yylval.addrmask.addr = addr;
+ return ADDRMASK;
+ }
+ /* fall through to returning STRING */
+ }
+ if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
+ if ((addr = inet_parse(s1)) != 0xffffffff &&
+ inet_valid_host(addr)) {
+ yylval.addr = addr;
+ return ADDR;
+ }
+ }
+ if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
+ yylval.addr = n;
+ return ADDR;
+ }
+ if (sscanf(q,"%d%c",&n,s1) == 1) {
+ yylval.num = n;
+ return NUMBER;
+ }
+ yylval.ptr = q;
+ return STRING;
+}
+
+void config_vifs_from_file()
+{
+ extern FILE *f;
+
+ order = 0;
+ numbounds = 0;
+ lineno = 0;
+
+ if ((f = fopen(configfilename, "r")) == NULL) {
+ if (errno != ENOENT)
+ log(LOG_ERR, errno, "can't open %s", configfilename);
+ return;
+ }
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ yyparse();
+
+ close(f);
+}
+
+static u_int32_t
+valid_if(s)
+char *s;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
+ if (!strcmp(v->uv_name, s))
+ return v->uv_lcl_addr;
+
+ return 0;
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_int32_t a;
+{
+ int n;
+ struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
+ struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
+
+ while (ifrp < ifend) {
+ if (ifrp->ifr_addr.sa_family == AF_INET &&
+ ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
+ return (ifrp);
+#if (defined(BSD) && (BSD >= 199006))
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ++ifrp;
+ else
+ ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+ ++ifrp;
+#endif
+ }
+ return (0);
+}
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
new file mode 100644
index 00000000000..3a4e1bd2f60
--- /dev/null
+++ b/usr.sbin/mrouted/config.c
@@ -0,0 +1,145 @@
+/* $NetBSD: config.c,v 1.5 1995/10/09 03:51:37 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Query the kernel to find network interfaces that are multicast-capable
+ * and install them in the uvifs array.
+ */
+void config_vifs_from_kernel()
+{
+ struct ifreq ifbuf[32];
+ struct ifreq *ifrp, *ifend;
+ struct ifconf ifc;
+ register struct uvif *v;
+ register vifi_t vifi;
+ int n;
+ u_int32_t addr, mask, subnet;
+ short flags;
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ ifrp = (struct ifreq *)ifbuf;
+ ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
+ /*
+ * Loop through all of the interfaces.
+ */
+ for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
+ struct ifreq ifr;
+#if BSD >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+#else
+ n = sizeof(*ifrp);
+#endif
+ /*
+ * Ignore any interface for an address family other than IP.
+ */
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
+
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+
+ /*
+ * Ignore loopback interfaces and interfaces that do not support
+ * multicast.
+ */
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+ flags = ifr.ifr_flags;
+ if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue;
+
+ /*
+ * Ignore any interface whose address and mask do not define a
+ * valid subnet number, or whose address is of the form {subnet,0}
+ * or {subnet,-1}.
+ */
+ if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
+ mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ subnet = addr & mask;
+ if (!inet_valid_subnet(subnet, mask) ||
+ addr == subnet ||
+ addr == (subnet | ~mask)) {
+ log(LOG_WARNING, 0,
+ "ignoring %s, has invalid address (%s) and/or mask (%s)",
+ ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
+ continue;
+ }
+
+ /*
+ * Ignore any interface that is connected to the same subnet as
+ * one already installed in the uvifs array.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if ((addr & v->uv_subnetmask) == v->uv_subnet ||
+ (v->uv_subnet & mask) == subnet) {
+ log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
+ ifr.ifr_name, v->uv_name);
+ break;
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * If there is room in the uvifs array, install this interface.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = 0;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = addr;
+ v->uv_rmt_addr = 0;
+ v->uv_subnet = subnet;
+ v->uv_subnetmask = mask;
+ v->uv_subnetbcast = subnet | ~mask;
+ strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+ v->uv_acl = NULL;
+ v->uv_addrs = NULL;
+
+ log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
+ v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+
+ /*
+ * If the interface is not yet up, set the vifs_down flag to
+ * remind us to check again later.
+ */
+ if (!(flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+}
diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h
new file mode 100644
index 00000000000..8d5aa9c6d3a
--- /dev/null
+++ b/usr.sbin/mrouted/defs.h
@@ -0,0 +1,230 @@
+/* $NetBSD: defs.h,v 1.5 1995/10/09 03:51:38 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/igmp.h>
+#include <netinet/ip_mroute.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#ifdef RSRR
+#include <sys/un.h>
+#endif /* RSRR */
+
+#include "dvmrp.h"
+#include "vif.h"
+#include "route.h"
+#include "prune.h"
+#include "pathnames.h"
+#ifdef RSRR
+#include "rsrr.h"
+#endif /* RSRR */
+
+/*
+ * Miscellaneous constants and macros.
+ */
+#define FALSE 0
+#define TRUE 1
+
+#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
+
+#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
+
+#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
+
+#define MROUTED_VERSION 5 /* increment on local changes or bug fixes, */
+ /* reset to 0 whever PROTOCOL_VERSION increments */
+
+#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
+ ((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
+ /* for IGMP 'group' field of DVMRP messages */
+
+#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
+ /* more for IGMP 'group' field of DVMRP messages */
+#define DEL_RTE_GROUP 0
+#define DEL_ALL_ROUTES 1
+ /* for Deleting kernel table entries */
+
+/* obnoxious gcc gives an extraneous warning about this constant... */
+#if defined(__STDC__) || defined(__GNUC__)
+#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
+#else
+#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
+#endif
+
+#ifdef RSRR
+#define BIT_ZERO(X) ((X) = 0)
+#define BIT_SET(X,n) ((X) |= 1 << (n))
+#define BIT_CLR(X,n) ((X) &= ~(1 << (n)))
+#define BIT_TST(X,n) ((X) & 1 << (n))
+#endif /* RSRR */
+
+/*
+ * External declarations for global variables and functions.
+ */
+#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
+extern char *recv_buf;
+extern char *send_buf;
+extern int igmp_socket;
+#ifdef RSRR
+extern int rsrr_socket;
+#endif /* RSRR */
+extern u_int32_t allhosts_group;
+extern u_int32_t allrtrs_group;
+extern u_int32_t dvmrp_group;
+extern u_int32_t dvmrp_genid;
+
+#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
+
+extern int debug;
+extern u_char pruning;
+
+extern int routes_changed;
+extern int delay_change_reports;
+extern unsigned nroutes;
+
+extern struct uvif uvifs[MAXVIFS];
+extern vifi_t numvifs;
+extern int vifs_down;
+extern int udp_socket;
+extern int vifs_with_neighbors;
+
+extern char s1[];
+extern char s2[];
+extern char s3[];
+extern char s4[];
+
+extern void log();
+
+extern void init_igmp();
+extern void accept_igmp();
+extern void send_igmp();
+
+extern void init_routes();
+extern void start_route_updates();
+extern void update_route();
+extern void age_routes();
+extern void expire_all_routes();
+extern void free_all_routes();
+
+extern void accept_probe();
+extern void accept_report();
+extern void report();
+extern void report_to_all_neighbors();
+extern int report_next_chunk();
+extern void add_vif_to_routes();
+extern void delete_vif_from_routes();
+extern void delete_neighbor_from_routes();
+extern void dump_routes();
+
+extern void init_vifs();
+extern void check_vif_state();
+extern vifi_t find_vif();
+extern void age_vifs();
+extern void dump_vifs();
+extern void stop_all_vifs();
+extern struct listaddr *neighbor_info();
+
+extern void accept_group_report();
+extern void query_groups();
+extern void probe_for_neighbors();
+extern int update_neighbor();
+extern void accept_neighbor_request();
+extern void accept_neighbor_request2();
+extern void accept_neighbors();
+extern void accept_neighbors2();
+
+extern void config_vifs_from_kernel();
+extern void config_vifs_from_file();
+
+extern int inet_valid_host();
+extern int inet_valid_subnet();
+extern char * inet_fmt();
+extern char * inet_fmts();
+extern u_int32_t inet_parse();
+extern int inet_cksum();
+
+extern struct rtentry * determine_route();
+
+extern void init_ktable();
+extern void add_table_entry();
+extern void del_table_entry();
+extern void update_table_entry();
+extern void update_lclgrp();
+extern void delete_lclgrp();
+
+extern unsigned kroutes;
+extern void accept_prune();
+extern int no_entry_exists();
+extern int rtr_cnt();
+extern void free_all_prunes();
+extern void age_table_entry();
+extern void dump_cache();
+
+#ifdef SNMP
+extern struct rtentry * snmp_find_route();
+extern struct gtable * find_grp();
+extern struct stable * find_grp_src();
+#endif
+
+extern void chkgrp_graft();
+extern void accept_graft();
+extern void accept_g_ack();
+extern void accept_mtrace();
+extern void accept_leave_message();
+extern void accept_membership_query();
+#ifdef RSRR
+extern struct gtable *kernel_table;
+extern struct gtable *gtp;
+extern int find_src_grp();
+extern int grplst_mem();
+extern int scoped_addr();
+#endif /* RSRR */
+
+extern void k_set_rcvbuf();
+extern void k_hdr_include();
+extern void k_set_ttl();
+extern void k_set_loop();
+extern void k_set_if();
+extern void k_join();
+extern void k_leave();
+extern void k_init_dvmrp();
+extern void k_stop_dvmrp();
+extern void k_add_vif();
+extern void k_del_vif();
+extern void k_add_rg();
+extern int k_del_rg();
+extern int k_get_version();
+
+extern char * malloc();
+extern char * fgets();
+extern FILE * fopen();
+
+#if !defined(htonl) && !defined(__osf__)
+extern u_long htonl();
+extern u_long ntohl();
+#endif
+
+#ifdef RSRR
+extern void rsrr_init();
+extern void rsrr_read();
+#endif /* RSRR */
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
new file mode 100644
index 00000000000..c008dd37151
--- /dev/null
+++ b/usr.sbin/mrouted/dvmrp.h
@@ -0,0 +1,160 @@
+/* $NetBSD: dvmrp.h,v 1.4 1995/10/09 03:51:39 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+/*
+ * A DVMRP message consists of an IP header + an IGMP header + (for some types)
+ * zero or more bytes of data.
+ *
+ * For REPORT messages, the data is route information; the route information
+ * consists of one or more lists of the following form:
+ *
+ * (mask, (origin, metric), (origin, metric), ...)
+ *
+ * where:
+ *
+ * "mask" is the subnet mask for all the origins in the list.
+ * It is always THREE bytes long, containing the low-order
+ * three bytes of the mask (the high-order byte is always
+ * 0xff and therefore need not be transmitted).
+ *
+ * "origin" is the number of a subnet from which multicast datagrams
+ * may originate. It is from one to four bytes long,
+ * depending on the value of "mask":
+ * if all bytes of the mask are zero
+ * the subnet number is one byte long
+ * else if the low-order two bytes of the mask are zero
+ * the subnet number is two bytes long
+ * else if the lowest-order byte of the mask is zero
+ * the subnet number is three bytes long,
+ * else
+ * the subnet number is four bytes long.
+ *
+ * "metric" is a one-byte value consisting of two subfields:
+ * - the high-order bit is a flag which, when set, indicates
+ * the last (origin, metric) pair of a list.
+ * - the low-order seven bits contain the routing metric for
+ * the corresponding origin, relative to the sender of the
+ * DVMRP report. The metric may have the value of UNREACHABLE
+ * added to it as a "split horizon" indication (so called
+ * "poisoned reverse").
+ *
+ * Within a list, the origin subnet numbers must be in ascending order, and
+ * the lists themselves are in order of increasing mask value. A message may
+ * not exceed 576 bytes, the default maximum IP reassembly size, including
+ * the IP and IGMP headers; the route information may be split across more
+ * than one message if necessary, by terminating a list in one message and
+ * starting a new list in the next message (repeating the same mask value,
+ * if necessary).
+ *
+ * For NEIGHBORS messages, the data is neighboring-router information
+ * consisting of one or more lists of the following form:
+ *
+ * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...)
+ *
+ * where:
+ *
+ * "local-addr" is the sending router's address as seen by the neighbors
+ * in this list; it is always four bytes long.
+ * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding
+ * packets to any of the neighbors on this list.
+ * "threshold" is a one-byte unsigned value, a lower bound on the TTL a
+ * packet must have to be forwarded to any of the neighbors on
+ * this list.
+ * "ncount" is the number of neighbors in this list.
+ * "neighbor" is the address of a neighboring router, four bytes long.
+ *
+ * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes,
+ * including the IP and IGMP headers; split longer messages by terminating the
+ * list in one and continuing in another, repeating the local-addr, etc., if
+ * necessary.
+ *
+ * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except
+ * there is a flags byte before the neighbor count:
+ *
+ * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...)
+ */
+
+/*
+ * DVMRP message types (carried in the "code" field of an IGMP header)
+ */
+#define DVMRP_PROBE 1 /* for finding neighbors */
+#define DVMRP_REPORT 2 /* for reporting some or all routes */
+#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */
+ /* of this router's neighbors. */
+#define DVMRP_NEIGHBORS 4 /* response to such a request */
+#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */
+#define DVMRP_NEIGHBORS2 6
+#define DVMRP_PRUNE 7 /* prune message */
+#define DVMRP_GRAFT 8 /* graft message */
+#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */
+
+/*
+ * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
+ */
+#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
+#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
+#define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */
+#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
+#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
+#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
+#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
+
+/*
+ * Limit on length of route data
+ */
+#define MAX_IP_PACKET_LEN 576
+#define MIN_IP_HEADER_LEN 20
+#define MAX_IP_HEADER_LEN 60
+#define MAX_DVMRP_DATA_LEN \
+ ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )
+
+/*
+ * Various protocol constants (all times in seconds)
+ */
+ /* address for multicast DVMRP msgs */
+#define INADDR_DVMRP_GROUP (u_int32_t)0xe0000004 /* 224.0.0.4 */
+ /* address for multicast mtrace msg */
+#define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */
+
+#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
+ /* (This is the timer interrupt */
+ /* interval; all times must be */
+ /* multiples of this value.) */
+
+#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */
+#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */
+#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */
+#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */
+
+#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */
+
+#define NEIGHBOR_PROBE_INTERVAL 10 /* periodic neighbor probe interval */
+#define NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */
+
+#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
+#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
+#define LEAVE_EXPIRE_TIME 3 /* " " after receiving a leave */
+/* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
+ * the timer in mrouted doesn't allow us to follow the spec and make it any
+ * shorter. */
+
+#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
+#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
+#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
+
+#define MAX_RATE_LIMIT 100000 /* max rate limit */
+#define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */
+#define DEFAULT_TUN_RATE_LIMIT 500 /* default tunnel rate limit */
+
+#define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */
+#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */
+
+#define OLD_AGE_THRESHOLD 2
diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c
new file mode 100644
index 00000000000..f4c19d85b53
--- /dev/null
+++ b/usr.sbin/mrouted/igmp.c
@@ -0,0 +1,305 @@
+/* $NetBSD: igmp.c,v 1.4 1995/10/09 03:51:40 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char *recv_buf; /* input packet buffer */
+char *send_buf; /* output packet buffer */
+int igmp_socket; /* socket for all network I/O */
+u_int32_t allhosts_group; /* All hosts addr in net order */
+u_int32_t allrtrs_group; /* All-Routers " in net order */
+u_int32_t dvmrp_group; /* DVMRP grp addr in net order */
+u_int32_t dvmrp_genid; /* IGMP generation id */
+
+/*
+ * Open and initialize the igmp socket, and fill in the non-changing
+ * IP header fields in the output packet buffer.
+ */
+void init_igmp()
+{
+ struct ip *ip;
+
+ recv_buf = malloc(RECV_BUF_SIZE);
+ send_buf = malloc(RECV_BUF_SIZE);
+
+ if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
+ log(LOG_ERR, errno, "IGMP socket");
+
+ k_hdr_include(TRUE); /* include IP header when sending */
+ k_set_rcvbuf(48*1024); /* lots of input buffering */
+ k_set_ttl(1); /* restrict multicasts to one hop */
+ k_set_loop(FALSE); /* disable multicast loopback */
+
+ ip = (struct ip *)send_buf;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_v = IPVERSION;
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = IPPROTO_IGMP;
+ ip->ip_ttl = MAXTTL; /* applies to unicasts only */
+
+ allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
+ dvmrp_group = htonl(INADDR_DVMRP_GROUP);
+ allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
+}
+
+#define PIM_QUERY 0
+#define PIM_REGISTER 1
+#define PIM_REGISTER_STOP 2
+#define PIM_JOIN_PRUNE 3
+#define PIM_RP_REACHABLE 4
+#define PIM_ASSERT 5
+#define PIM_GRAFT 6
+#define PIM_GRAFT_ACK 7
+
+static char *packet_kind(type, code)
+ u_char type, code;
+{
+ switch (type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
+ case IGMP_v1_HOST_MEMBERSHIP_REPORT: return "membership report ";
+ case IGMP_v2_HOST_MEMBERSHIP_REPORT: return "new member report ";
+ case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
+ case IGMP_DVMRP:
+ switch (code) {
+ case DVMRP_PROBE: return "neighbor probe ";
+ case DVMRP_REPORT: return "route report ";
+ case DVMRP_ASK_NEIGHBORS: return "neighbor request ";
+ case DVMRP_NEIGHBORS: return "neighbor list ";
+ case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
+ case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
+ case DVMRP_PRUNE: return "prune message ";
+ case DVMRP_GRAFT: return "graft message ";
+ case DVMRP_GRAFT_ACK: return "graft message ack ";
+ default: return "unknown DVMRP msg ";
+ }
+ case IGMP_PIM:
+ switch (code) {
+ case PIM_QUERY: return "PIM Router-Query ";
+ case PIM_REGISTER: return "PIM Register ";
+ case PIM_REGISTER_STOP: return "PIM Register-Stop ";
+ case PIM_JOIN_PRUNE: return "PIM Join/Prune ";
+ case PIM_RP_REACHABLE: return "PIM RP-Reachable ";
+ case PIM_ASSERT: return "PIM Assert ";
+ case PIM_GRAFT: return "PIM Graft ";
+ case PIM_GRAFT_ACK: return "PIM Graft-Ack ";
+ default: return "unknown PIM msg ";
+ }
+ case IGMP_MTRACE_QUERY: return "IGMP trace query ";
+ case IGMP_MTRACE_REPLY: return "IGMP trace reply ";
+ default: return "unknown IGMP msg ";
+ }
+}
+
+/*
+ * Process a newly received IGMP packet that is sitting in the input
+ * packet buffer.
+ */
+void accept_igmp(recvlen)
+ int recvlen;
+{
+ register u_int32_t src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "received packet too short (%u bytes) for IP header", recvlen);
+ return;
+ }
+
+ ip = (struct ip *)recv_buf;
+ src = ip->ip_src.s_addr;
+ dst = ip->ip_dst.s_addr;
+
+ /*
+ * this is most likely a message from the kernel indicating that
+ * a new src grp pair message has arrived and so, it would be
+ * necessary to install a route into the kernel for this.
+ */
+ if (ip->ip_p == 0) {
+ if (src == 0 || dst == 0)
+ log(LOG_WARNING, 0, "kernel request not accurate");
+ else
+ add_table_entry(src, dst);
+ return;
+ }
+
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "received packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ return;
+ }
+
+ igmp = (struct igmp *)(recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "received IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ return;
+ }
+
+ log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
+ packet_kind(igmp->igmp_type, igmp->igmp_code),
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ accept_membership_query(src, dst, group, igmp->igmp_code);
+ return;
+
+ case IGMP_v1_HOST_MEMBERSHIP_REPORT:
+ case IGMP_v2_HOST_MEMBERSHIP_REPORT:
+ accept_group_report(src, dst, group, igmp->igmp_type);
+ return;
+
+ case IGMP_HOST_LEAVE_MESSAGE:
+ accept_leave_message(src, dst, group);
+ return;
+
+ case IGMP_DVMRP:
+ group = ntohl(group);
+
+ switch (igmp->igmp_code) {
+ case DVMRP_PROBE:
+ accept_probe(src, dst,
+ (char *)(igmp+1), igmpdatalen, group);
+ return;
+
+ case DVMRP_REPORT:
+ accept_report(src, dst,
+ (char *)(igmp+1), igmpdatalen, group);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS:
+ accept_neighbor_request(src, dst);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS2:
+ accept_neighbor_request2(src, dst);
+ return;
+
+ case DVMRP_NEIGHBORS:
+ accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ case DVMRP_PRUNE:
+ accept_prune(src, dst, (char *)(igmp+1), igmpdatalen);
+ return;
+
+ case DVMRP_GRAFT:
+ accept_graft(src, dst, (char *)(igmp+1), igmpdatalen);
+ return;
+
+ case DVMRP_GRAFT_ACK:
+ accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
+ return;
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown DVMRP message code %u from %s to %s",
+ igmp->igmp_code, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+
+ case IGMP_PIM:
+ return;
+
+ case IGMP_MTRACE_REPLY:
+ return;
+
+ case IGMP_MTRACE_QUERY:
+ accept_mtrace(src, dst, group, (char *)(igmp+1),
+ igmp->igmp_code, igmpdatalen);
+ return;
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown IGMP message type %x from %s to %s",
+ igmp->igmp_type, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+}
+
+
+/*
+ * Construct an IGMP message in the output packet buffer. The caller may
+ * have already placed data in that buffer, of length 'datalen'. Then send
+ * the message from the interface with IP address 'src' to destination 'dst'.
+ */
+void
+send_igmp(src, dst, type, code, group, datalen)
+ u_int32_t src, dst;
+ int type, code;
+ u_int32_t group;
+ int datalen;
+{
+ static struct sockaddr_in sdst;
+ struct ip *ip;
+ struct igmp *igmp;
+
+ ip = (struct ip *)send_buf;
+ ip->ip_src.s_addr = src;
+ ip->ip_dst.s_addr = dst;
+ ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
+
+ igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
+ igmp->igmp_type = type;
+ igmp->igmp_code = code;
+ igmp->igmp_group.s_addr = group;
+ igmp->igmp_cksum = 0;
+ igmp->igmp_cksum = inet_cksum((u_short *)igmp,
+ IGMP_MINLEN + datalen);
+
+ if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
+ if (dst == allhosts_group) k_set_loop(TRUE);
+
+ bzero(&sdst, sizeof(sdst));
+ sdst.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ sdst.sin_len = sizeof(sdst);
+#endif
+ sdst.sin_addr.s_addr = dst;
+ if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
+ (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
+ if (errno == ENETDOWN)
+ check_vif_state();
+ else
+ log(LOG_WARNING, errno,
+ "sendto to %s on %s",
+ inet_fmt(dst, s1), inet_fmt(src, s2));
+ }
+
+ if (dst == allhosts_group) k_set_loop(FALSE);
+
+ log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
+ packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
+}
diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c
new file mode 100644
index 00000000000..b6c6a01788d
--- /dev/null
+++ b/usr.sbin/mrouted/inet.c
@@ -0,0 +1,202 @@
+/* $NetBSD: inet.c,v 1.3 1995/10/09 03:51:42 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char s1[19]; /* buffers to hold the string representations */
+char s2[19]; /* of IP addresses, to be passed to inet_fmt() */
+char s3[19]; /* or inet_fmts(). */
+char s4[19];
+
+
+/*
+ * Verify that a given IP address is credible as a host address.
+ * (Without a mask, cannot detect addresses of the form {subnet,0} or
+ * {subnet,-1}.)
+ */
+int inet_valid_host(naddr)
+ u_int32_t naddr;
+{
+ register u_int32_t addr;
+
+ addr = ntohl(naddr);
+
+ return (!(IN_MULTICAST(addr) ||
+ IN_BADCLASS (addr) ||
+ (addr & 0xff000000) == 0));
+}
+
+
+/*
+ * Verify that a given subnet number and mask pair are credible.
+ *
+ * With CIDR, almost any subnet and mask are credible. mrouted still
+ * can't handle aggregated class A's, so we still check that, but
+ * otherwise the only requirements are that the subnet address is
+ * within the [ABC] range and that the host bits of the subnet
+ * are all 0.
+ */
+int inet_valid_subnet(nsubnet, nmask)
+ u_int32_t nsubnet, nmask;
+{
+ register u_int32_t subnet, mask;
+
+ subnet = ntohl(nsubnet);
+ mask = ntohl(nmask);
+
+ if ((subnet & mask) != subnet) return (FALSE);
+
+ if (subnet == 0 && mask == 0)
+ return (TRUE);
+
+ if (IN_CLASSA(subnet)) {
+ if (mask < 0xff000000 ||
+ (subnet & 0xff000000) == 0x7f000000) return (FALSE);
+ }
+ else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
+ /* Above Class C address space */
+ return (FALSE);
+ }
+ else if (subnet & ~mask) {
+ /* Host bits are set in the subnet */
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Convert an IP address in u_long (network) format into a printable string.
+ */
+char *inet_fmt(addr, s)
+ u_int32_t addr;
+ char *s;
+{
+ register u_char *a;
+
+ a = (u_char *)&addr;
+ sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ return (s);
+}
+
+
+/*
+ * Convert an IP subnet number in u_long (network) format into a printable
+ * string including the netmask as a number of bits.
+ */
+char *inet_fmts(addr, mask, s)
+ u_int32_t addr, mask;
+ char *s;
+{
+ register u_char *a, *m;
+ int bits;
+
+ if ((addr == 0) && (mask == 0)) {
+ sprintf(s, "default");
+ return (s);
+ }
+ a = (u_char *)&addr;
+ m = (u_char *)&mask;
+ bits = 33 - ffs(ntohl(mask));
+
+ if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
+ bits);
+ else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits);
+ else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits);
+ else sprintf(s, "%u/%d", a[0], bits);
+
+ return (s);
+}
+
+/*
+ * Convert the printable string representation of an IP address into the
+ * u_long (network) format. Return 0xffffffff on error. (To detect the
+ * legal address with that value, you must explicitly compare the string
+ * with "255.255.255.255".)
+ */
+u_int32_t inet_parse(s)
+ char *s;
+{
+ u_int32_t a = 0;
+ u_int a0, a1, a2, a3;
+ char c;
+
+ if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
+ a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
+ return (0xffffffff);
+
+ ((u_char *)&a)[0] = a0;
+ ((u_char *)&a)[1] = a1;
+ ((u_char *)&a)[2] = a2;
+ ((u_char *)&a)[3] = a3;
+
+ return (a);
+}
+
+
+/*
+ * inet_cksum extracted from:
+ * P I N G . C
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ * Modified at Uc Berkeley
+ *
+ * (ping.c) Status -
+ * Public Domain. Distribution Unlimited.
+ *
+ * I N _ C K S U M
+ *
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ */
+int inet_cksum(addr, len)
+ u_short *addr;
+ u_int len;
+{
+ register int nleft = (int)len;
+ register u_short *w = addr;
+ u_short answer = 0;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while( nleft > 1 ) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if( nleft == 1 ) {
+ *(u_char *) (&answer) = *(u_char *)w ;
+ sum += answer;
+ }
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c
new file mode 100644
index 00000000000..0dbae18624a
--- /dev/null
+++ b/usr.sbin/mrouted/kern.c
@@ -0,0 +1,222 @@
+/* $NetBSD: kern.c,v 1.3 1995/10/09 03:51:43 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+void k_set_rcvbuf(bufsize)
+ int bufsize;
+{
+ if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
+ (char *)&bufsize, sizeof(bufsize)) < 0)
+ log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
+}
+
+
+void k_hdr_include(bool)
+ int bool;
+{
+#ifdef IP_HDRINCL
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&bool, sizeof(bool)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
+#endif
+}
+
+
+void k_set_ttl(t)
+ int t;
+{
+ u_char ttl;
+
+ ttl = t;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
+}
+
+
+void k_set_loop(l)
+ int l;
+{
+ u_char loop;
+
+ loop = l;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (char *)&loop, sizeof(loop)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
+}
+
+
+void k_set_if(ifa)
+ u_int32_t ifa;
+{
+ struct in_addr adr;
+
+ adr.s_addr = ifa;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
+ (char *)&adr, sizeof(adr)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
+ inet_fmt(ifa, s1));
+}
+
+
+void k_join(grp, ifa)
+ u_int32_t grp;
+ u_int32_t ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't join group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_leave(grp, ifa)
+ u_int32_t grp;
+ u_int32_t ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't leave group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_init_dvmrp()
+{
+#ifdef OLD_KERNEL
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
+ (char *)NULL, 0) < 0)
+#else
+ int v=1;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
+ (char *)&v, sizeof(int)) < 0)
+#endif
+ log(LOG_ERR, errno, "can't enable Multicast routing in kernel");
+}
+
+
+void k_stop_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
+ (char *)NULL, 0) < 0)
+ log(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
+}
+
+
+void k_add_vif(vifi, v)
+ vifi_t vifi;
+ struct uvif *v;
+{
+ struct vifctl vc;
+
+ vc.vifc_vifi = vifi;
+ vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
+ vc.vifc_threshold = v->uv_threshold;
+ vc.vifc_rate_limit = v->uv_rate_limit;
+ vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
+ vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
+ (char *)&vc, sizeof(vc)) < 0)
+ log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF");
+}
+
+
+void k_del_vif(vifi)
+ vifi_t vifi;
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
+ (char *)&vifi, sizeof(vifi)) < 0)
+ log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
+}
+
+
+/*
+ * Adds a (source, mcastgrp) entry to the kernel
+ */
+void k_add_rg(origin, g)
+ u_long origin;
+ struct gtable *g;
+{
+ struct mfcctl mc;
+ int i;
+
+ /* copy table values so that setsockopt can process it */
+ mc.mfcc_origin.s_addr = origin;
+#ifdef OLD_KERNEL
+ mc.mfcc_originmask.s_addr = 0xffffffff;
+#endif
+ mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
+ mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
+ for (i = 0; i < numvifs; i++)
+ mc.mfcc_ttls[i] = g->gt_ttls[i];
+
+ /* write to kernel space */
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
+ (char *)&mc, sizeof(mc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
+}
+
+
+/*
+ * Deletes a (source, mcastgrp) entry from the kernel
+ */
+int k_del_rg(origin, g)
+ u_long origin;
+ struct gtable *g;
+{
+ struct mfcctl mc;
+ int retval, i;
+
+ /* copy table values so that setsockopt can process it */
+ mc.mfcc_origin.s_addr = origin;
+#ifdef OLD_KERNEL
+ mc.mfcc_originmask.s_addr = 0xffffffff;
+#endif
+ mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
+
+ /* write to kernel space */
+ if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
+ (char *)&mc, sizeof(mc))) < 0)
+ log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
+
+ return retval;
+}
+
+/*
+ * Get the kernel's idea of what version of mrouted needs to run with it.
+ */
+int k_get_version()
+{
+ int vers;
+ int len = sizeof(vers);
+
+ if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
+ (char *)&vers, &len) < 0)
+ log(LOG_ERR, errno,
+ "getsockopt MRT_VERSION: perhaps your kernel is too old");
+
+ return vers;
+}
diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c
new file mode 100644
index 00000000000..71d9ee36f43
--- /dev/null
+++ b/usr.sbin/mrouted/main.c
@@ -0,0 +1,611 @@
+/* $NetBSD: main.c,v 1.5 1995/10/09 03:51:44 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+/*
+ * Written by Steve Deering, Stanford University, February 1989.
+ *
+ * (An earlier version of DVMRP was implemented by David Waitzman of
+ * BBN STC by extending Berkeley's routed program. Some of Waitzman's
+ * extensions have been incorporated into mrouted, but none of the
+ * original routed code has been adopted.)
+ */
+
+
+#include "defs.h"
+#include <string.h>
+#include <varargs.h>
+
+#ifdef SNMP
+#include "snmp.h"
+#endif
+
+extern char *configfilename;
+
+static char pidfilename[] = _PATH_MROUTED_PID;
+static char dumpfilename[] = _PATH_MROUTED_DUMP;
+static char cachefilename[] = _PATH_MROUTED_CACHE;
+static char genidfilename[] = _PATH_MROUTED_GENID;
+
+int cache_lifetime = DEFAULT_CACHE_LIFETIME;
+int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
+
+int debug = 0;
+u_char pruning = 1; /* Enable pruning by default */
+
+#define NHANDLERS 2
+
+static struct ihandler {
+ int fd; /* File descriptor */
+ void (*func)(); /* Function to call with &fd_set */
+} ihandlers[NHANDLERS];
+static int nhandlers = 0;
+
+/*
+ * Forward declarations.
+ */
+static void fasttimer();
+static void timer();
+static void cleanup();
+static void done();
+static void dump();
+static void fdump();
+static void cdump();
+static void restart();
+
+int
+register_input_handler(fd, func)
+ int fd;
+ void (*func)();
+{
+ if (nhandlers >= NHANDLERS)
+ return -1;
+
+ ihandlers[nhandlers].fd = fd;
+ ihandlers[nhandlers++].func = func;
+
+ return 0;
+}
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int recvlen;
+ register int omask;
+ int dummy;
+ FILE *fp;
+ extern uid_t geteuid();
+ struct timeval tv;
+ u_long prev_genid;
+ int vers;
+ fd_set rfds, readers;
+ int nfds, n, i;
+#ifdef SNMP
+ char *myname;
+ fd_set wfds;
+
+
+ if (myname = strrchr(argv[0], '/'))
+ myname++;
+ if (myname == NULL || *myname == 0)
+ myname = argv[0];
+ isodetailor (myname, 0);
+#endif
+
+#ifdef SYSV
+ setvbuf(stderr, NULL, _IOLBF, 0);
+#else
+ setlinebuf(stderr);
+#endif
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && *argv[0] == '-') {
+ if (strcmp(*argv, "-d") == 0) {
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ debug = atoi(*argv);
+ } else
+ debug = DEFAULT_DEBUG;
+ } else if (strcmp(*argv, "-c") == 0) {
+ if (argc > 1) {
+ argv++, argc--;
+ configfilename = *argv;
+ } else
+ goto usage;
+ } else if (strcmp(*argv, "-p") == 0) {
+ pruning = 0;
+ } else
+ goto usage;
+ argv++, argc--;
+ }
+
+ if (argc > 0) {
+usage: fprintf(stderr,
+ "usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
+ exit(1);
+ }
+
+ if (debug == 0) {
+ /*
+ * Detach from the terminal
+ */
+ int t;
+
+ if (fork()) exit(0);
+ (void)close(0);
+ (void)close(1);
+ (void)close(2);
+ (void)open("/", 0);
+ (void)dup2(0, 1);
+ (void)dup2(0, 2);
+#ifdef TIOCNOTTY
+ t = open("/dev/tty", 2);
+ if (t >= 0) {
+ (void)ioctl(t, TIOCNOTTY, (char *)0);
+ (void)close(t);
+ }
+#else
+ if (setsid() < 0)
+ perror("setsid");
+#endif
+ }
+ else
+ fprintf(stderr, "debug level %u\n", debug);
+
+#ifdef LOG_DAEMON
+ (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
+ (void)setlogmask(LOG_UPTO(LOG_NOTICE));
+#else
+ (void)openlog("mrouted", LOG_PID);
+#endif
+ log(LOG_NOTICE, 0, "mrouted version %d.%d",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+
+#ifdef SYSV
+ srand48(time(NULL));
+#else
+ srandom(gethostid());
+#endif
+
+ /*
+ * Get generation id
+ */
+ gettimeofday(&tv, 0);
+ dvmrp_genid = tv.tv_sec;
+
+ fp = fopen(genidfilename, "r");
+ if (fp != NULL) {
+ fscanf(fp, "%d", &prev_genid);
+ if (prev_genid == dvmrp_genid)
+ dvmrp_genid++;
+ (void) fclose(fp);
+ }
+
+ fp = fopen(genidfilename, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d", dvmrp_genid);
+ (void) fclose(fp);
+ }
+
+ callout_init();
+
+#ifdef SNMP
+ snmp_init();
+#endif
+
+ init_igmp();
+ k_init_dvmrp(); /* enable DVMRP routing in kernel */
+
+#ifndef OLD_KERNEL
+ vers = k_get_version();
+ if ((((vers >> 8) & 0xff) != PROTOCOL_VERSION) ||
+ ((vers & 0xff) != MROUTED_VERSION))
+ log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
+ (vers >> 8) & 0xff, vers & 0xff,
+ PROTOCOL_VERSION, MROUTED_VERSION);
+#endif
+
+ init_routes();
+ init_ktable();
+ init_vifs();
+#ifdef RSRR
+ rsrr_init();
+#endif /* RSRR */
+
+#if defined(__STDC__) || defined(__GNUC__)
+ /* Allow cleanup if unexpected exit. Apparently some architectures
+ * have a kernel bug where closing the socket doesn't do an
+ * ip_mrouter_done(), so we attempt to do it on exit.
+ */
+ atexit(cleanup);
+#endif
+
+ if (debug)
+ fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
+
+ fp = fopen(pidfilename, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+
+ if (debug >= 2) dump();
+
+ (void)signal(SIGALRM, fasttimer);
+
+ (void)signal(SIGHUP, restart);
+ (void)signal(SIGTERM, done);
+ (void)signal(SIGINT, done);
+ (void)signal(SIGUSR1, fdump);
+ (void)signal(SIGUSR2, cdump);
+ if (debug != 0)
+ (void)signal(SIGQUIT, dump);
+
+ FD_ZERO(&readers);
+ FD_SET(igmp_socket, &readers);
+ nfds = igmp_socket + 1;
+ for (i = 0; i < nhandlers; i++) {
+ FD_SET(ihandlers[i].fd, &readers);
+ if (ihandlers[i].fd >= nfds)
+ nfds = ihandlers[i].fd + 1;
+ }
+
+ (void)alarm(1); /* schedule first timer interrupt */
+
+ /*
+ * Main receive loop.
+ */
+ dummy = 0;
+ for(;;) {
+ bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
+#ifdef SNMP
+ FD_ZERO(&wfds);
+
+ if (smux_fd != NOTOK) {
+ if (rock_and_roll)
+ FD_SET(smux_fd, &rfds);
+ else
+ FD_SET(smux_fd, &wfds);
+ if (smux_fd >= nfds)
+ nfds = smux_fd + 1;
+ }
+
+ if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
+#else
+ if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
+#endif
+ if (errno != EINTR) /* SIGALRM is expected */
+ log(LOG_WARNING, errno, "select failed");
+ continue;
+ }
+
+ if (FD_ISSET(igmp_socket, &rfds)) {
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, NULL, &dummy);
+ if (recvlen < 0) {
+ if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
+ continue;
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ accept_igmp(recvlen);
+ (void)sigsetmask(omask);
+ }
+
+ for (i = 0; i < nhandlers; i++) {
+ if (FD_ISSET(ihandlers[i].fd, &rfds)) {
+ (*ihandlers[i].func)(&rfds);
+ }
+ }
+
+#ifdef SNMP
+ if (smux_fd != NOTOK) {
+ if (rock_and_roll) {
+ if (FD_ISSET(smux_fd, &rfds))
+ doit_smux();
+ } else if (FD_ISSET(smux_fd, &wfds))
+ start_smux();
+ }
+#endif
+ }
+}
+
+
+/*
+ * routine invoked every second. Its main goal is to cycle through
+ * the routing table and send partial updates to all neighbors at a
+ * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
+ * seconds. Also, every TIMER_INTERVAL seconds it calls timer() to
+ * do all the other time-based processing.
+ */
+static void
+fasttimer()
+{
+ static unsigned int tlast;
+ static unsigned int nsent;
+ register unsigned int t = tlast + 1;
+ register int n;
+
+ /*
+ * if we're in the last second, send everything that's left.
+ * otherwise send at least the fraction we should have sent by now.
+ */
+ if (t >= ROUTE_REPORT_INTERVAL) {
+ register int nleft = nroutes - nsent;
+ while (nleft > 0) {
+ if ((n = report_next_chunk()) <= 0)
+ break;
+ nleft -= n;
+ }
+ tlast = 0;
+ nsent = 0;
+ } else {
+ register unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
+ while (nsent < ncum) {
+ if ((n = report_next_chunk()) <= 0)
+ break;
+ nsent += n;
+ }
+ tlast = t;
+ }
+ if ((t % TIMER_INTERVAL) == 0)
+ timer();
+
+ age_callout_queue();/* Advance the timer for the callout queue
+ for groups */
+ alarm(1);
+}
+
+/*
+ * The 'virtual_time' variable is initialized to a value that will cause the
+ * first invocation of timer() to send a probe or route report to all vifs
+ * and send group membership queries to all subnets for which this router is
+ * querier. This first invocation occurs approximately TIMER_INTERVAL seconds
+ * after the router starts up. Note that probes for neighbors and queries
+ * for group memberships are also sent at start-up time, as part of initial-
+ * ization. This repetition after a short interval is desirable for quickly
+ * building up topology and membership information in the presence of possible
+ * packet loss.
+ *
+ * 'virtual_time' advances at a rate that is only a crude approximation of
+ * real time, because it does not take into account any time spent processing,
+ * and because the timer intervals are sometimes shrunk by a random amount to
+ * avoid unwanted synchronization with other routers.
+ */
+
+static u_long virtual_time = 0;
+
+
+/*
+ * Timer routine. Performs periodic neighbor probing, route reporting, and
+ * group querying duties, and drives various timers in routing entries and
+ * virtual interface data structures.
+ */
+static void
+timer()
+{
+ age_routes(); /* Advance the timers in the route entries */
+ age_vifs(); /* Advance the timers for neighbors */
+ age_table_entry(); /* Advance the timers for the cache entries */
+
+ if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
+ /*
+ * Time to query the local group memberships on all subnets
+ * for which this router is the elected querier.
+ */
+ query_groups();
+ }
+
+ if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
+ /*
+ * Time to send a probe on all vifs from which no neighbors have
+ * been heard. Also, check if any inoperative interfaces have now
+ * come up. (If they have, they will also be probed as part of
+ * their initialization.)
+ */
+ probe_for_neighbors();
+
+ if (vifs_down)
+ check_vif_state();
+ }
+
+ delay_change_reports = FALSE;
+ if (routes_changed) {
+ /*
+ * Some routes have changed since the last timer interrupt, but
+ * have not been reported yet. Report the changed routes to all
+ * neighbors.
+ */
+ report_to_all_neighbors(CHANGED_ROUTES);
+ }
+
+#ifdef SNMP
+ if (smux_fd == NOTOK && !dont_bother_anymore
+ && virtual_time % SNMPD_RETRY_INTERVAL == 0) {
+ /*
+ * Time to check for snmpd running.
+ */
+ try_smux_init();
+ }
+#endif
+
+ /*
+ * Advance virtual time
+ */
+ virtual_time += TIMER_INTERVAL;
+}
+
+
+/*
+ * On termination, let everyone know we're going away.
+ */
+static void
+done()
+{
+ log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+ cleanup();
+ _exit(1);
+}
+
+static void
+cleanup()
+{
+ static in_cleanup = 0;
+
+ if (!in_cleanup) {
+ in_cleanup++;
+#ifdef RSRR
+ rsrr_clean();
+#endif /* RSRR */
+ expire_all_routes();
+ report_to_all_neighbors(ALL_ROUTES);
+ k_stop_dvmrp();
+ }
+}
+
+
+/*
+ * Dump internal data structures to stderr.
+ */
+static void
+dump()
+{
+ dump_vifs(stderr);
+ dump_routes(stderr);
+}
+
+
+/*
+ * Dump internal data structures to a file.
+ */
+static void
+fdump()
+{
+ FILE *fp;
+
+ fp = fopen(dumpfilename, "w");
+ if (fp != NULL) {
+ dump_vifs(fp);
+ dump_routes(fp);
+ (void) fclose(fp);
+ }
+}
+
+
+/*
+ * Dump local cache contents to a file.
+ */
+static void
+cdump()
+{
+ FILE *fp;
+
+ fp = fopen(cachefilename, "w");
+ if (fp != NULL) {
+ dump_cache(fp);
+ (void) fclose(fp);
+ }
+}
+
+
+/*
+ * Restart mrouted
+ */
+static void
+restart()
+{
+ register int omask;
+
+ log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+
+ /*
+ * reset all the entries
+ */
+ omask = sigblock(sigmask(SIGALRM));
+ free_all_prunes();
+ free_all_routes();
+ stop_all_vifs();
+ k_stop_dvmrp();
+ close(igmp_socket);
+ close(udp_socket);
+
+ /*
+ * start processing again
+ */
+ dvmrp_genid++;
+ pruning = 1;
+
+ init_igmp();
+ k_init_dvmrp(); /* enable DVMRP routing in kernel */
+ init_routes();
+ init_ktable();
+ init_vifs();
+
+ (void)sigsetmask(omask);
+}
+
+
+/*
+ * Log errors and other messages to the system log daemon and to stderr,
+ * according to the severity of the message and the current debug level.
+ * For errors of severity LOG_ERR or worse, terminate the program.
+ */
+/*VARARGS3*/
+void
+log(severity, syserr, format, va_alist)
+ int severity, syserr;
+ char *format;
+ va_dcl
+{
+ va_list ap;
+ static char fmt[211] = "warning - ";
+ char *msg;
+ char tbuf[20];
+ struct timeval now;
+ struct tm *thyme;
+
+ va_start(ap);
+ vsprintf(&fmt[10], format, ap);
+ va_end(ap);
+ msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
+
+ switch (debug) {
+ case 0: break;
+ case 1: if (severity > LOG_NOTICE) break;
+ case 2: if (severity > LOG_INFO ) break;
+ default:
+ gettimeofday(&now,NULL);
+ thyme = localtime((time_t *)&now.tv_sec);
+ strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
+ fprintf(stderr, tbuf, now.tv_usec / 1000);
+ fprintf(stderr, "%s", msg);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, ": %s\n", strerror(syserr));
+ }
+
+ if (severity <= LOG_NOTICE) {
+ if (syserr != 0) {
+ errno = syserr;
+ syslog(severity, "%s: %m", msg);
+ } else
+ syslog(severity, "%s", msg);
+
+ if (severity <= LOG_ERR) exit(-1);
+ }
+}
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
new file mode 100644
index 00000000000..dd7c74f65c1
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.8
@@ -0,0 +1,399 @@
+'\" $NetBSD: mrouted.8,v 1.5 1995/10/09 03:51:46 thorpej Exp $
+'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
+.TH MROUTED 8
+.UC 5
+.SH NAME
+mrouted \- IP multicast routing daemon
+.SH SYNOPSIS
+.B /etc/mrouted
+[
+.B \-p
+] [
+.B \-c
+.I config_file
+] [
+.B \-d
+[
+.I debug_level
+]]
+.SH DESCRIPTION
+.I Mrouted
+is an implementation of the Distance-Vector Multicast Routing
+Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
+It maintains topological knowledge via a distance-vector routing protocol
+(like RIP, described in RFC-1058), upon which it implements a multicast
+datagram forwarding algorithm called Reverse Path Multicasting.
+.PP
+.I Mrouted
+forwards a multicast datagram along a shortest (reverse) path tree
+rooted at the subnet on which the datagram originates. The multicast
+delivery tree may be thought of as a broadcast delivery tree that has
+been pruned back so that it does not extend beyond those subnetworks
+that have members of the destination group. Hence, datagrams
+are not forwarded along those branches which have no listeners of the
+multicast group. The IP time-to-live of a multicast datagram can be
+used to limit the range of multicast datagrams.
+.PP
+In order to support multicasting among subnets that are separated by (unicast)
+routers that do not support IP multicasting,
+.I mrouted
+includes support for
+"tunnels", which are virtual point-to-point links between pairs of
+.IR mrouted s
+located anywhere in an internet. IP multicast packets are encapsulated for
+transmission through tunnels, so that they look like normal unicast datagrams
+to intervening routers and subnets. The encapsulation
+is added on entry to a tunnel, and stripped off
+on exit from a tunnel.
+By default, the packets are encapsulated using the IP-in-IP protocol
+(IP protocol number 4).
+Older versions of
+.I mrouted
+tunnel using IP source routing, which puts a heavy load on some
+types of routers.
+This version does not support IP source route tunnelling.
+.PP
+The tunnelling mechanism allows
+.I mrouted
+to establish a virtual internet, for
+the purpose of multicasting only, which is independent of the physical
+internet, and which may span multiple Autonomous Systems. This capability
+is intended for experimental support of internet multicasting only, pending
+widespread support for multicast routing by the regular (unicast) routers.
+.I Mrouted
+suffers from the well-known scaling problems of any distance-vector
+routing protocol, and does not (yet) support hierarchical multicast routing.
+.PP
+.I Mrouted
+handles multicast routing only; there may or may not be unicast routing
+software running on the same machine as
+.IR mrouted .
+With the use of tunnels, it
+is not necessary for
+.I mrouted
+to have access to more than one physical subnet
+in order to perform multicast forwarding.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+If no "\-d" option is given, or if the debug level is specified as 0,
+.I mrouted
+detaches from the invoking terminal. Otherwise, it remains attached to the
+invoking terminal and responsive to signals from that terminal. If "\-d" is
+given with no argument, the debug level defaults to 2. Regardless of the
+debug level,
+.I mrouted
+always writes warning and error messages to the system
+log demon. Non-zero debug levels have the following effects:
+.IP "level 1"
+all syslog'ed messages are also printed to stderr.
+.IP "level 2"
+all level 1 messages plus notifications of "significant"
+events are printed to stderr.
+.IP "level 3"
+all level 2 messages plus notifications of all packet
+arrivals and departures are printed to stderr.
+.PP
+Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
+.SH CONFIGURATION
+.PP
+.I Mrouted
+automatically configures itself to forward on all multicast-capable
+interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
+the loopback "interface"), and it finds other
+.IR mrouted s
+directly reachable
+via those interfaces. To override the default configuration, or to add
+tunnel links to other
+.IR mrouted s,
+configuration commands may be placed in
+/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
+There are four types of configuration commands:
+.nf
+
+ phyint <local-addr> [disable] [metric <m>]
+ [threshold <t>] [rate_limit <b>]
+ [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
+ [altnet <network>/<mask-len>]
+
+ tunnel <local-addr> <remote-addr> [metric <m>]
+ [threshold <t>] [srcrt] [rate_limit <b>]
+ [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
+
+ cache_lifetime <ct>
+
+ pruning <off/on>
+
+ name <boundary-name> <scoped-addr>/<mask-len>
+
+.fi
+.PP
+The file format is free-form; whitespace (including newlines) is not
+significant.
+The
+.I boundary
+and
+.I altnet
+options may be specified as many times as necessary.
+.PP
+The phyint command can be used to disable multicast routing on the physical
+interface identified by local IP address <local-addr>, or to associate a
+non-default metric or threshold with the specified physical interface.
+The local IP address <local-addr> may be alternatively replaced by the
+interface name (e.g le0).
+If a phyint is attached to multiple IP subnets, describe each additional subnet
+with the altnet keyword.
+Phyint commands must precede tunnel commands.
+.PP
+The tunnel command can be used to establish a tunnel link between local
+IP address <local-addr> and remote IP address <remote-addr>, and to associate
+a non-default metric or threshold with that tunnel. The tunnel must be set
+up in the mrouted.conf files of both routers before it can be used.
+'\"For backwards compatibility with older
+'\".IR mrouted s,
+'\"the srcrt keyword specifies
+'\"encapsulation using IP source routing.
+.PP
+The cache_lifetime is a value that determines the amount of time that a
+cached multicast route stays in kernel before timing out. The value of this
+entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
+.PP
+The pruning <off/on> option is provided for
+.IR mrouted
+to act as a non-pruning router. It is also possible to start
+.IR mrouted
+in a non-pruning mode using the "-p" option on the command line. It is
+expected that a router would be configured in this manner for test
+purposes only. The default mode is pruning enabled.
+.PP
+You may assign names to boundaries to make configuration easier with
+the name keyword. The boundary option on phyint or tunnel commands
+can accept either a name or a boundary.
+.PP
+The metric is the "cost" associated with sending a datagram on the given
+interface or tunnel; it may be used to influence the choice of routes.
+The metric defaults to 1. Metrics should be kept as small as possible,
+because
+.I mrouted
+cannot route along paths with a sum of metrics greater
+than 31.
+.LP
+The threshold is the minimum IP time-to-live required for a multicast datagram
+to be forwarded to the given interface or tunnel. It is used to control the
+scope of multicast datagrams. (The TTL of forwarded packets is only compared
+to the threshold, it is not decremented by the threshold. Every multicast
+router decrements the TTL by 1.) The default threshold is 1.
+.LP
+In general, all
+.IR mrouted s
+connected to a particular subnet or tunnel should
+use the same metric and threshold for that subnet or tunnel.
+.PP
+The rate_limit option allows the network administrator to specify a
+certain bandwidth in Kbits/second which would be allocated to multicast
+traffic. It defaults to 500Kbps on tunnels, and 0 (unlimited) on physical
+interfaces.
+.PP
+The boundary option allows an interface
+to be configured as an administrative boundary for the specified
+scoped address. Packets belonging to this address will not
+be forwarded on a scoped interface. The boundary option accepts either
+a name or a boundary spec.
+.PP
+.I Mrouted
+will not initiate execution if it has fewer than two enabled vifs,
+where a vif (virtual interface) is either a physical multicast-capable
+interface or a tunnel. It will log a warning if all of its vifs are
+tunnels; such an
+.I mrouted
+configuration would be better replaced by more
+direct tunnels (i.e., eliminate the middle man).
+.SH "EXAMPLE CONFIGURATION"
+.PP
+This is an example configuration for a mythical multicast router at a big
+school.
+.sp
+.nf
+#
+# mrouted.conf example
+#
+# Name our boundaries to make it easier
+name LOCAL 239.255.0.0/16
+name EE 239.254.0.0/16
+#
+# le1 is our gateway to compsci, don't forward our
+# local groups to them
+phyint le1 boundary EE
+#
+# le2 is our interface on the classroom net, it has four
+# different length subnets on it.
+# note that you can use either an ip address or an
+# interface name
+phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26
+ altnet 172.16.15.128/26 altnet 172.16.48.0/24
+#
+# atm0 is our ATM interface, which doesn't properly
+# support multicasting.
+phyint atm0 disable
+#
+# This is an internal tunnel to another EE subnet
+# Remove the default tunnel rate limit, since this
+# tunnel is over ethernets
+tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1
+ rate_limit 0
+#
+# This is our tunnel to the outside world.
+# Careful with those boundaries, Eugene.
+tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32
+ boundary LOCAL boundary EE
+.fi
+.SH SIGNALS
+.PP
+.I Mrouted
+responds to the following signals:
+.IP HUP
+restarts
+.I mrouted .
+The configuration file is reread every time this signal is evoked.
+.IP INT
+terminates execution gracefully (i.e., by sending
+good-bye messages to all neighboring routers).
+.IP TERM
+same as INT
+.IP USR1
+dumps the internal routing tables to /usr/tmp/mrouted.dump.
+.IP USR2
+dumps the internal cache tables to /usr/tmp/mrouted.cache.
+.IP QUIT
+dumps the internal routing tables to stderr (only if
+.I mrouted
+was invoked with a non-zero debug level).
+.PP
+For convenience in sending signals,
+.I mrouted
+writes its pid to /etc/mrouted.pid upon startup.
+.bp
+.SH EXAMPLE
+.PP
+The routing tables look like this:
+.nf
+
+Virtual Interface Table
+ Vif Local-Address Metric Thresh Flags
+ 0 36.2.0.8 subnet: 36.2 1 1 querier
+ groups: 224.0.2.1
+ 224.0.0.4
+ pkts in: 3456
+ pkts out: 2322323
+
+ 1 36.11.0.1 subnet: 36.11 1 1 querier
+ groups: 224.0.2.1
+ 224.0.1.0
+ 224.0.0.4
+ pkts in: 345
+ pkts out: 3456
+
+ 2 36.2.0.8 tunnel: 36.8.0.77 3 1
+ peers: 36.8.0.77 (2.2)
+ boundaries: 239.0.1
+ : 239.1.2
+ pkts in: 34545433
+ pkts out: 234342
+
+ 3 36.2.0.8 tunnel: 36.6.8.23 3 16
+
+Multicast Routing Table (1136 entries)
+ Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs
+ 36.2 1 45 0 1* 2 3*
+ 36.8 36.8.0.77 4 15 2 0* 1* 3*
+ 36.11 1 20 1 0* 2 3*
+ .
+ .
+ .
+
+.fi
+In this example, there are four vifs connecting to two subnets and two
+tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
+vif 1 subnets have some groups present; tunnels never have any groups. This
+instance of
+.I mrouted
+is the one responsible for sending periodic group
+membership queries on the vif 0 and vif 1 subnets, as indicated by the
+"querier" flags. The list of boundaries indicate the scoped addresses on that
+interface. A count of the no. of incoming and outgoing packets is also
+shown at each interface.
+.PP
+Associated with each subnet from which a multicast datagram can originate
+is the address of the previous hop router (unless the subnet is directly-
+connected), the metric of the path back to the origin, the amount of time
+since we last recieved an update for this subnet, the incoming vif for
+multicasts from that origin, and a list of outgoing vifs. "*" means that
+the outgoing vif is connected to a leaf of the broadcast tree rooted at the
+origin, and a multicast datagram from that origin will be forwarded on that
+outgoing vif only if there are members of the destination group on that leaf.
+.bp
+.PP
+.I Mrouted
+also maintains a copy of the kernel forwarding cache table. Entries
+are created and deleted by
+.I mrouted.
+.PP
+The cache tables look like this:
+.nf
+
+Multicast Routing Cache Table (147 entries)
+ Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
+ 13.2.116/22 224.2.127.255 3m 2m - 0 1
+>13.2.116.19
+>13.2.116.196
+ 138.96.48/21 224.2.127.255 5m 2m - 0 1
+>138.96.48.108
+ 128.9.160/20 224.2.127.255 3m 2m - 0 1
+>128.9.160.45
+ 198.106.194/24 224.2.135.190 9m 28s 9m 0P
+>198.106.194.22
+
+.fi
+Each entry is characterized by the origin subnet number and mask and the
+destination multicast group. The 'CTmr' field indicates the lifetime
+of the entry. The entry is deleted from the cache table
+when the timer decrements to zero. The 'Age' field is the time since
+this cache entry was originally created. Since cache entries get refreshed
+if traffic is flowing, routing entries can grow very old.
+The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
+amount of time until the upstream prune will time out.
+The 'Ivif' field indicates the
+incoming vif for multicast packets from that origin. Each router also
+maintains a record of the number of prunes received from neighbouring
+routers for a particular source and group. If there are no members of
+a multicast group on any downward link of the multicast tree for a
+subnet, a prune message is sent to the upstream router. They are
+indicated by a "P" after the vif number. The Forwvifs field shows the
+interfaces along which datagrams belonging to the source-group are
+forwarded. A "p" indicates that no datagrams are being forwarded along
+that interface. An unlisted interface is a leaf subnet with are no
+members of the particular group on that subnet. A "b" on an interface
+indicates that it is a boundary interface, i.e. traffic will not be
+forwarded on the scoped address on that interface.
+An additional line with a ">" as the first character is printed for
+each source on the subnet. Note that there can be many sources in
+one subnet.
+.SH FILES
+/etc/mrouted.conf
+.br
+/etc/mrouted.pid
+.br
+/usr/tmp/mrouted.dump
+.br
+/usr/tmp/mrouted.cache
+.SH SEE ALSO
+.BR mrinfo (8) ,
+.BR mtrace (8) ,
+.BR map-mbone (8)
+.sp
+DVMRP is described, along with other multicast routing algorithms, in the
+paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
+in the Proceedings of the ACM SIGCOMM '88 Conference.
+.SH AUTHORS
+Steve Deering, Ajit Thyagarajan, Bill Fenner
diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h
new file mode 100644
index 00000000000..c7939fde1c1
--- /dev/null
+++ b/usr.sbin/mrouted/pathnames.h
@@ -0,0 +1,17 @@
+/* $NetBSD: pathnames.h,v 1.3 1995/10/09 03:51:48 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
+
+#define _PATH_MROUTED_PID "/var/run/mrouted.pid"
+#define _PATH_MROUTED_GENID "/var/run/mrouted.genid"
+#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache"
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
new file mode 100644
index 00000000000..aaba6c318ee
--- /dev/null
+++ b/usr.sbin/mrouted/prune.c
@@ -0,0 +1,2259 @@
+/* $NetBSD: prune.c,v 1.2 1995/10/09 03:51:49 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+extern struct rtentry *routing_table;
+
+/*
+ * dither cache lifetime to obtain a value between x and 2*x
+ */
+#ifdef SYSV
+#define CACHE_LIFETIME(x) ((x) + (lrand48() % (x)))
+#else
+#define CACHE_LIFETIME(x) ((x) + (random() % (x)))
+#endif
+
+#define CHK_GS(x, y) { \
+ switch(x) { \
+ case 2: \
+ case 4: \
+ case 8: \
+ case 16: \
+ case 32: \
+ case 64: \
+ case 128: \
+ case 256: y = 1; \
+ break; \
+ default: y = 0; \
+ } \
+ }
+
+struct gtable *kernel_table; /* ptr to list of kernel grp entries*/
+static struct gtable *kernel_no_route; /* list of grp entries w/o routes */
+struct gtable *gtp; /* pointer for kernel rt entries */
+unsigned int kroutes; /* current number of cache entries */
+
+/****************************************************************************
+ Functions that are local to prune.c
+****************************************************************************/
+
+/*
+ * Updates the ttl values for each vif.
+ */
+static void
+prun_add_ttls(gt)
+ struct gtable *gt;
+{
+ struct uvif *v;
+ vifi_t vifi;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (VIFM_ISSET(vifi, gt->gt_grpmems))
+ gt->gt_ttls[vifi] = v->uv_threshold;
+ else
+ gt->gt_ttls[vifi] = 0;
+ }
+}
+
+/*
+ * checks for scoped multicast addresses
+ */
+#define GET_SCOPE(gt) { \
+ register int _i; \
+ if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
+ VIFM_SET(_i, (gt)->gt_scope); \
+ }
+
+int
+scoped_addr(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct vif_acl *acl;
+
+ for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
+ if ((addr & acl->acl_mask) == acl->acl_addr)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Determine if mcastgrp has a listener on vifi
+ */
+int
+grplst_mem(vifi, mcastgrp)
+ vifi_t vifi;
+ u_int32_t mcastgrp;
+{
+ register struct listaddr *g;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+
+ for (g = v->uv_groups; g != NULL; g = g->al_next)
+ if (mcastgrp == g->al_addr)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Finds the group entry with the specified source and netmask.
+ * If netmask is 0, it uses the route's netmask.
+ *
+ * Returns TRUE if found a match, and the global variable gtp is left
+ * pointing to entry before the found entry.
+ * Returns FALSE if no exact match found, gtp is left pointing to before
+ * the entry in question belongs, or is NULL if the it belongs at the
+ * head of the list.
+ */
+int
+find_src_grp(src, mask, grp)
+ u_int32_t src;
+ u_int32_t mask;
+ u_int32_t grp;
+{
+ struct gtable *gt;
+
+ gtp = NULL;
+ gt = kernel_table;
+ while (gt != NULL) {
+ if (grp == gt->gt_mcastgrp &&
+ (mask ? (gt->gt_route->rt_origin == src &&
+ gt->gt_route->rt_originmask == mask) :
+ ((src & gt->gt_route->rt_originmask) ==
+ gt->gt_route->rt_origin)))
+ return TRUE;
+ if (ntohl(grp) > ntohl(gt->gt_mcastgrp) ||
+ (grp == gt->gt_mcastgrp &&
+ (ntohl(mask) < ntohl(gt->gt_route->rt_originmask) ||
+ (mask == gt->gt_route->rt_originmask &&
+ (ntohl(src) > ntohl(gt->gt_route->rt_origin)))))) {
+ gtp = gt;
+ gt = gt->gt_gnext;
+ }
+ else break;
+ }
+ return FALSE;
+}
+
+/*
+ * Check if the neighbor supports pruning
+ */
+static int
+pruning_neighbor(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct listaddr *n = neighbor_info(vifi, addr);
+ int vers;
+
+ if (n == NULL)
+ return 0;
+
+ if (n->al_flags & NF_PRUNE)
+ return 1;
+
+ /*
+ * Versions from 3.0 to 3.4 relied on the version number to identify
+ * that they could handle pruning.
+ */
+ vers = NBR_VERS(n);
+ return (vers >= 0x0300 && vers <= 0x0304);
+}
+
+/*
+ * Can the neighbor in question handle multicast traceroute?
+ */
+static int
+can_mtrace(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct listaddr *n = neighbor_info(vifi, addr);
+ int vers;
+
+ if (n == NULL)
+ return 0;
+
+ if (n->al_flags & NF_MTRACE)
+ return 1;
+
+ /*
+ * Versions 3.3 and 3.4 relied on the version number to identify
+ * that they could handle traceroute.
+ */
+ vers = NBR_VERS(n);
+ return (vers >= 0x0303 && vers <= 0x0304);
+}
+
+/*
+ * Returns the prune entry of the router, or NULL if none exists
+ */
+static struct ptable *
+find_prune_entry(vr, pt)
+ u_int32_t vr;
+ struct ptable *pt;
+{
+ while (pt) {
+ if (pt->pt_router == vr)
+ return pt;
+ pt = pt->pt_next;
+ }
+
+ return NULL;
+}
+
+/*
+ * Send a prune message to the dominant router for
+ * this source.
+ *
+ * Record an entry that a prune was sent for this group
+ */
+static void
+send_prune(gt)
+ struct gtable *gt;
+{
+ struct ptable *pt;
+ char *p;
+ int i;
+ int datalen;
+ u_int32_t src;
+ u_int32_t dst;
+ u_int32_t tmp;
+
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
+
+ /* Can't process a prune if we don't have an associated route */
+ if (gt->gt_route == NULL)
+ return;
+
+ /* Don't send a prune to a non-pruning router */
+ if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
+ return;
+
+ /*
+ * sends a prune message to the router upstream.
+ */
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
+ dst = gt->gt_route->rt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ /*
+ * determine prune lifetime
+ */
+ gt->gt_prsent_timer = gt->gt_timer;
+ for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
+ if (pt->pt_timer < gt->gt_prsent_timer)
+ gt->gt_prsent_timer = pt->pt_timer;
+
+ /*
+ * If we have a graft pending, cancel graft retransmission
+ */
+ gt->gt_grftsnt = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_mcastgrp))[i];
+ tmp = htonl(gt->gt_prsent_timer);
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(tmp))[i];
+ datalen += 12;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
+ htonl(MROUTED_LEVEL), datalen);
+
+ log(LOG_DEBUG, 0, "sent prune for (%s %s)/%d on vif %d to %s",
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ gt->gt_prsent_timer, gt->gt_route->rt_parent,
+ inet_fmt(gt->gt_route->rt_gateway, s3));
+}
+
+/*
+ * a prune was sent upstream
+ * so, a graft has to be sent to annul the prune
+ * set up a graft timer so that if an ack is not
+ * heard within that time, another graft request
+ * is sent out.
+ */
+static void
+send_graft(gt)
+ struct gtable *gt;
+{
+ register char *p;
+ register int i;
+ int datalen;
+ u_int32_t src;
+ u_int32_t dst;
+
+ /* Can't send a graft without an associated route */
+ if (gt->gt_route == NULL)
+ return;
+
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
+ dst = gt->gt_route->rt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_mcastgrp))[i];
+ datalen += 8;
+
+ if (datalen != 0) {
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
+ htonl(MROUTED_LEVEL), datalen);
+ }
+ log(LOG_DEBUG, 0, "sent graft for (%s %s) to %s on vif %d",
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ inet_fmt(gt->gt_route->rt_gateway, s3), gt->gt_route->rt_parent);
+}
+
+/*
+ * Send an ack that a graft was received
+ */
+static void
+send_graft_ack(src, dst, origin, grp)
+ u_int32_t src;
+ u_int32_t dst;
+ u_int32_t origin;
+ u_int32_t grp;
+{
+ register char *p;
+ register int i;
+ int datalen;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(grp))[i];
+ datalen += 8;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
+ htonl(MROUTED_LEVEL), datalen);
+
+ log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s",
+ inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3));
+}
+
+/*
+ * Update the kernel cache with all the routes hanging off the group entry
+ */
+static void
+update_kernel(g)
+ struct gtable *g;
+{
+ struct stable *st;
+
+ for (st = g->gt_srctbl; st; st = st->st_next)
+ k_add_rg(st->st_origin, g);
+}
+
+/****************************************************************************
+ Functions that are used externally
+****************************************************************************/
+
+#ifdef SNMP
+#include <sys/types.h>
+#include "snmp.h"
+
+/*
+ * Find a specific group entry in the group table
+ */
+struct gtable *
+find_grp(grp)
+ u_long grp;
+{
+ struct gtable *gt;
+
+ for (gt = kernel_table; gt; gt = gt->gt_gnext) {
+ if (ntohl(grp) < ntohl(gt->gt_mcastgrp))
+ break;
+ if (gt->gt_mcastgrp == grp)
+ return gt;
+ }
+ return NULL;
+}
+
+/*
+ * Given a group entry and source, find the corresponding source table
+ * entry
+ */
+struct stable *
+find_grp_src(gt, src)
+ struct gtable *gt;
+ u_long src;
+{
+ struct stable *st;
+ u_long grp = gt->gt_mcastgrp;
+ struct gtable *gtcurr;
+
+ for (gtcurr = gt; gtcurr->gt_mcastgrp == grp; gtcurr = gtcurr->gt_gnext) {
+ for (st = gtcurr->gt_srctbl; st; st = st->st_next)
+ if (st->st_origin == src)
+ return st;
+ }
+ return NULL;
+}
+
+/*
+ * Find next entry > specification
+ */
+int
+next_grp_src_mask(gtpp, stpp, grp, src, mask)
+ struct gtable **gtpp; /* ordered by group */
+ struct stable **stpp; /* ordered by source */
+ u_long grp;
+ u_long src;
+ u_long mask;
+{
+ struct gtable *gt, *gbest = NULL;
+ struct stable *st, *sbest = NULL;
+
+ /* Find first group entry >= grp spec */
+ (*gtpp) = kernel_table;
+ while ((*gtpp) && ntohl((*gtpp)->gt_mcastgrp) < ntohl(grp))
+ (*gtpp)=(*gtpp)->gt_gnext;
+ if (!(*gtpp))
+ return 0; /* no more groups */
+
+ for (gt = kernel_table; gt; gt=gt->gt_gnext) {
+ /* Since grps are ordered, we can stop when group changes from gbest */
+ if (gbest && gbest->gt_mcastgrp != gt->gt_mcastgrp)
+ break;
+ for (st = gt->gt_srctbl; st; st=st->st_next) {
+
+ /* Among those entries > spec, find "lowest" one */
+ if (((ntohl(gt->gt_mcastgrp)> ntohl(grp))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
+ && ntohl(st->st_origin)> ntohl(src))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
+ && ntohl(st->st_origin)==src && 0xFFFFFFFF>ntohl(mask)))
+ && (!gbest
+ || (ntohl(gt->gt_mcastgrp)< ntohl(gbest->gt_mcastgrp))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(gbest->gt_mcastgrp)
+ && ntohl(st->st_origin)< ntohl(sbest->st_origin)))) {
+ gbest = gt;
+ sbest = st;
+ }
+ }
+ }
+ (*gtpp) = gbest;
+ (*stpp) = sbest;
+ return (*gtpp)!=0;
+}
+
+/*
+ * Ensure that sg contains current information for the given group,source.
+ * This is fetched from the kernel as a unit so that counts for the entry
+ * are consistent, i.e. packet and byte counts for the same entry are
+ * read at the same time.
+ */
+void
+refresh_sg(sg, gt, st)
+ struct sioc_sg_req *sg;
+ struct gtable *gt;
+ struct stable *st;
+{
+ static int lastq = -1;
+
+ if (quantum != lastq || sg->src.s_addr!=st->st_origin
+ || sg->grp.s_addr!=gt->gt_mcastgrp) {
+ lastq = quantum;
+ sg->src.s_addr = st->st_origin;
+ sg->grp.s_addr = gt->gt_mcastgrp;
+ ioctl(udp_socket, SIOCGETSGCNT, (char *)sg);
+ }
+}
+
+/*
+ * Return pointer to a specific route entry. This must be a separate
+ * function from find_route() which modifies rtp.
+ */
+struct rtentry *
+snmp_find_route(src, mask)
+ register u_long src, mask;
+{
+ register struct rtentry *rt;
+
+ for (rt = routing_table; rt; rt = rt->rt_next) {
+ if (src == rt->rt_origin && mask == rt->rt_originmask)
+ return rt;
+ }
+ return NULL;
+}
+
+/*
+ * Find next route entry > specification
+ */
+int
+next_route(rtpp, src, mask)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+{
+ struct rtentry *rt, *rbest = NULL;
+
+ /* Among all entries > spec, find "lowest" one in order */
+ for (rt = routing_table; rt; rt=rt->rt_next) {
+ if ((ntohl(rt->rt_origin) > ntohl(src)
+ || (ntohl(rt->rt_origin) == ntohl(src)
+ && ntohl(rt->rt_originmask) > ntohl(mask)))
+ && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
+ || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
+ && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
+ rbest = rt;
+ }
+ (*rtpp) = rbest;
+ return (*rtpp)!=0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next vifi/entry
+ */
+int
+next_route_child(rtpp, src, mask, vifi)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ struct rtentry *rt;
+
+ /* Get (S,M) entry */
+ if (!((*rtpp) = snmp_find_route(src,mask)))
+ if (!next_route(rtpp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
+ return 1;
+ *vifi = 0;
+ } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) );
+
+ return 0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next entry
+ * equal to or greater than those
+ */
+int
+next_child(gtpp, stpp, grp, src, mask, vifi)
+ struct gtable **gtpp;
+ struct stable **stpp;
+ u_long grp;
+ u_long src;
+ u_long mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ struct stable *st;
+
+ /* Get (G,S,M) entry */
+ if (mask!=0xFFFFFFFF
+ || !((*gtpp) = find_grp(grp))
+ || !((*stpp) = find_grp_src((*gtpp),src)))
+ if (!next_grp_src_mask(gtpp, stpp, grp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*gtpp)->gt_route->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*gtpp)->gt_route->rt_children))
+ return 1;
+ *vifi = 0;
+ } while (next_grp_src_mask(gtpp, stpp, (*gtpp)->gt_mcastgrp,
+ (*stpp)->st_origin, 0xFFFFFFFF) );
+
+ return 0;
+}
+#endif /* SNMP */
+
+/*
+ * Initialize the kernel table structure
+ */
+void
+init_ktable()
+{
+ kernel_table = NULL;
+ kernel_no_route = NULL;
+ kroutes = 0;
+}
+
+/*
+ * Add a new table entry for (origin, mcastgrp)
+ */
+void
+add_table_entry(origin, mcastgrp)
+ u_int32_t origin;
+ u_int32_t mcastgrp;
+{
+ struct rtentry *r;
+ struct gtable *gt,**gtnp,*prev_gt;
+ struct stable *st,**stnp;
+ int i;
+
+ r = determine_route(origin);
+ prev_gt = NULL;
+ if (r == NULL) {
+ /*
+ * Look for it on the no_route table; if it is found then
+ * it will be detected as a duplicate below.
+ */
+ for (gt = kernel_no_route; gt; gt = gt->gt_next)
+ if (mcastgrp == gt->gt_mcastgrp &&
+ gt->gt_srctbl && gt->gt_srctbl->st_origin == origin)
+ break;
+ gtnp = &kernel_no_route;
+ } else {
+ gtnp = &r->rt_groups;
+ while ((gt = *gtnp) != NULL) {
+ if (gt->gt_mcastgrp >= mcastgrp)
+ break;
+ gtnp = &gt->gt_next;
+ prev_gt = gt;
+ }
+ }
+
+ if (gt == NULL || gt->gt_mcastgrp != mcastgrp) {
+ gt = (struct gtable *)malloc(sizeof(struct gtable));
+ if (gt == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+
+ gt->gt_mcastgrp = mcastgrp;
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ time(&gt->gt_ctime);
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
+ gt->gt_prsent_timer = 0;
+ gt->gt_grftsnt = 0;
+ gt->gt_srctbl = NULL;
+ gt->gt_pruntbl = NULL;
+ gt->gt_route = r;
+
+ if (r != NULL) {
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
+ }
+ GET_SCOPE(gt);
+ if (VIFM_ISSET(r->rt_parent, gt->gt_scope))
+ gt->gt_scope = -1;
+ gt->gt_grpmems &= ~gt->gt_scope;
+ } else {
+ gt->gt_scope = -1;
+ gt->gt_grpmems = 0;
+ }
+
+ /* update ttls */
+ prun_add_ttls(gt);
+
+ gt->gt_next = *gtnp;
+ *gtnp = gt;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt;
+ gt->gt_prev = prev_gt;
+
+ if (r) {
+ if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) {
+ struct gtable *g;
+
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ log(LOG_WARNING, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
+ r, g->gt_route);
+ } else {
+ if (gtp) {
+ gt->gt_gnext = gtp->gt_gnext;
+ gt->gt_gprev = gtp;
+ gtp->gt_gnext = gt;
+ } else {
+ gt->gt_gnext = kernel_table;
+ gt->gt_gprev = NULL;
+ kernel_table = gt;
+ }
+ if (gt->gt_gnext)
+ gt->gt_gnext->gt_gprev = gt;
+ }
+ } else {
+ gt->gt_gnext = gt->gt_prev = NULL;
+ }
+ }
+
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ if (ntohl(st->st_origin) >= ntohl(origin))
+ break;
+ stnp = &st->st_next;
+ }
+
+ if (st == NULL || st->st_origin != origin) {
+ st = (struct stable *)malloc(sizeof(struct stable));
+ if (st == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+
+ st->st_origin = origin;
+ st->st_pktcnt = 0;
+ st->st_next = *stnp;
+ *stnp = st;
+ } else {
+ log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
+ inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
+ return;
+ }
+
+ kroutes++;
+ k_add_rg(origin, gt);
+
+ log(LOG_DEBUG, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d",
+ inet_fmt(origin, s1),
+ inet_fmt(mcastgrp, s2),
+ gt->gt_grpmems, r ? r->rt_parent : -1);
+
+ /* If there are no leaf vifs
+ * which have this group, then
+ * mark this src-grp as a prune candidate.
+ */
+ if (!gt->gt_prsent_timer && !gt->gt_grpmems && r && r->rt_gateway)
+ send_prune(gt);
+}
+
+/*
+ * An mrouter has gone down and come up on an interface
+ * Forward on that interface immediately
+ */
+void
+reset_neighbor_state(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt, *prev_pt;
+ struct stable *st, *prev_st;
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ r = g->gt_route;
+
+ /*
+ * If neighbor was the parent, remove the prune sent state
+ * Don't send any grafts upstream.
+ */
+ if (vifi == r->rt_parent) {
+ if (addr == r->rt_gateway) {
+ log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ /*
+ * Expire prune, send again on this vif.
+ */
+ VIFM_SET(pt->pt_vifi, g->gt_grpmems);
+ prev_pt = pt;
+ pt = prev_pt->pt_next;
+ free(prev_pt);
+ }
+ g->gt_pruntbl = NULL;
+
+ st = g->gt_srctbl;
+ while (st) {
+ log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "reset_neighbor_state trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ prev_st = st;
+ st = prev_st->st_next;
+ free(prev_st);
+ }
+ g->gt_srctbl = NULL;
+ /*
+ * Keep the group entries themselves around since the
+ * state will likely just come right back, and if not,
+ * the group entries will time out with no kernel entries
+ * and no prune state.
+ */
+ g->gt_prsent_timer = 0;
+ g->gt_grftsnt = 0;
+ }
+ } else {
+ /*
+ * Neighbor was not the parent, send grafts to join the groups
+ */
+ if (g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
+ g->gt_prsent_timer = 0;
+ }
+
+ /*
+ * Remove any prunes that this router has sent us.
+ */
+ prev_pt = (struct ptable *)&g->gt_pruntbl;
+ for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
+ if (pt->pt_vifi == vifi && pt->pt_router == addr) {
+ prev_pt->pt_next = pt->pt_next;
+ free(pt);
+ } else
+ prev_pt = pt;
+ }
+
+ /*
+ * And see if we want to forward again.
+ */
+ if (!VIFM_ISSET(vifi, g->gt_grpmems)) {
+ if (VIFM_ISSET(vifi, r->rt_children) &&
+ !(VIFM_ISSET(vifi, r->rt_leaves)))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ if (VIFM_ISSET(vifi, r->rt_leaves) &&
+ grplst_mem(vifi, g->gt_mcastgrp))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ g->gt_grpmems &= ~g->gt_scope;
+ prun_add_ttls(g);
+
+ /* Update kernel state */
+ update_kernel(g);
+
+ log(LOG_DEBUG, 0, "reset member state (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+ }
+ }
+ }
+}
+
+/*
+ * Delete table entry from the kernel
+ * del_flag determines how many entries to delete
+ */
+void
+del_table_entry(r, mcastgrp, del_flag)
+ struct rtentry *r;
+ u_int32_t mcastgrp;
+ u_int del_flag;
+{
+ struct gtable *g, *prev_g;
+ struct stable *st, *prev_st;
+ struct ptable *pt, *prev_pt;
+
+ if (del_flag == DEL_ALL_ROUTES) {
+ g = r->rt_groups;
+ while (g) {
+ log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ st = g->gt_srctbl;
+ while (st) {
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ prev_st = st;
+ st = st->st_next;
+ free(prev_st);
+ }
+ g->gt_srctbl = NULL;
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
+
+ if (g->gt_gnext)
+ g->gt_gnext->gt_gprev = g->gt_gprev;
+ if (g->gt_gprev)
+ g->gt_gprev->gt_gnext = g->gt_gnext;
+ else
+ kernel_table = g->gt_gnext;
+
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
+ }
+ r->rt_groups = NULL;
+ }
+
+ /*
+ * Dummy routine - someday this may be needed, so it is just there
+ */
+ if (del_flag == DEL_RTE_GROUP) {
+ prev_g = (struct gtable *)&r->rt_groups;
+ for (g = r->rt_groups; g; g = g->gt_next) {
+ if (g->gt_mcastgrp == mcastgrp) {
+ log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ st = g->gt_srctbl;
+ while (st) {
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ prev_st = st->st_next;
+ free(st);
+ st = prev_st;
+ }
+ g->gt_srctbl = NULL;
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
+
+ if (g->gt_gnext)
+ g->gt_gnext->gt_gprev = g->gt_gprev;
+ if (g->gt_gprev)
+ g->gt_gprev->gt_gnext = g->gt_gnext;
+ else
+ kernel_table = g->gt_gnext;
+
+ if (prev_g != (struct gtable *)&r->rt_groups)
+ g->gt_next->gt_prev = prev_g;
+ else
+ g->gt_next->gt_prev = NULL;
+ prev_g->gt_next = g->gt_next;
+
+ free(g);
+ g = prev_g;
+ } else {
+ prev_g = g;
+ }
+ }
+ }
+}
+
+/*
+ * update kernel table entry when a route entry changes
+ */
+void
+update_table_entry(r)
+ struct rtentry *r;
+{
+ struct gtable *g;
+ struct ptable *pt, *prev_pt;
+ int i;
+
+ for (g = r->rt_groups; g; g = g->gt_next) {
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
+
+ g->gt_grpmems = 0;
+
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, g->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, g->gt_mcastgrp))
+ VIFM_SET(i, g->gt_grpmems);
+ }
+ if (VIFM_ISSET(r->rt_parent, g->gt_scope))
+ g->gt_scope = -1;
+ g->gt_grpmems &= ~g->gt_scope;
+
+ log(LOG_DEBUG, 0, "updating cache entries (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
+ g->gt_grpmems);
+
+ if (g->gt_grpmems && g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
+ g->gt_prsent_timer = 0;
+ }
+
+ /* update ttls and add entry into kernel */
+ prun_add_ttls(g);
+ update_kernel(g);
+
+ /* Check if we want to prune this group */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ send_prune(g);
+ }
+ }
+}
+
+/*
+ * set the forwarding flag for all mcastgrps on this vifi
+ */
+void
+update_lclgrp(vifi, mcastgrp)
+ vifi_t vifi;
+ u_int32_t mcastgrp;
+{
+ struct rtentry *r;
+ struct gtable *g;
+
+ log(LOG_DEBUG, 0, "group %s joined on vif %d",
+ inet_fmt(mcastgrp, s1), vifi);
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ r = g->gt_route;
+ if (g->gt_mcastgrp == mcastgrp &&
+ VIFM_ISSET(vifi, r->rt_children)) {
+
+ VIFM_SET(vifi, g->gt_grpmems);
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
+ continue;
+
+ prun_add_ttls(g);
+ log(LOG_DEBUG, 0, "update lclgrp (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ update_kernel(g);
+ }
+ }
+}
+
+/*
+ * reset forwarding flag for all mcastgrps on this vifi
+ */
+void
+delete_lclgrp(vifi, mcastgrp)
+ vifi_t vifi;
+ u_int32_t mcastgrp;
+{
+ struct rtentry *r;
+ struct gtable *g;
+
+ log(LOG_DEBUG, 0, "group %s left on vif %d",
+ inet_fmt(mcastgrp, s1), vifi);
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ if (g->gt_mcastgrp == mcastgrp) {
+ int stop_sending = 1;
+
+ r = g->gt_route;
+ /*
+ * If this is not a leaf, then we have router neighbors on this
+ * vif. Only turn off forwarding if they have all pruned.
+ */
+ if (!VIFM_ISSET(vifi, r->rt_leaves)) {
+ struct listaddr *vr;
+
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+ }
+
+ if (stop_sending) {
+ VIFM_CLR(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "delete lclgrp (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+
+ /*
+ * If there are no more members of this particular group,
+ * send prune upstream
+ */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway)
+ send_prune(g);
+ }
+ }
+ }
+}
+
+/*
+ * Takes the prune message received and then strips it to
+ * determine the (src, grp) pair to be pruned.
+ *
+ * Adds the router to the (src, grp) entry then.
+ *
+ * Determines if further packets have to be sent down that vif
+ *
+ * Determines if a corresponding prune message has to be generated
+ */
+void
+accept_prune(src, dst, p, datalen)
+ u_int32_t src;
+ u_int32_t dst;
+ char *p;
+ int datalen;
+{
+ u_int32_t prun_src;
+ u_int32_t prun_grp;
+ u_int32_t prun_tmr;
+ vifi_t vifi;
+ int i;
+ int stop_sending;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt;
+ struct listaddr *vr;
+
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring prune report from non-neighbor %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ /* Check if enough data is present */
+ if (datalen < 12)
+ {
+ log(LOG_WARNING, 0,
+ "non-decipherable prune from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ for (i = 0; i< 4; i++)
+ ((char *)&prun_src)[i] = *p++;
+ for (i = 0; i< 4; i++)
+ ((char *)&prun_grp)[i] = *p++;
+ for (i = 0; i< 4; i++)
+ ((char *)&prun_tmr)[i] = *p++;
+
+ log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d",
+ inet_fmt(src, s1), vifi,
+ inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr);
+
+ /*
+ * Find the subnet for the prune
+ */
+ if (find_src_grp(prun_src, 0, prun_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ r = g->gt_route;
+
+ if (!VIFM_ISSET(vifi, r->rt_children)) {
+ log(LOG_WARNING, 0, "prune received from non-child %s for (%s %s)",
+ inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3));
+ return;
+ }
+ if (VIFM_ISSET(vifi, g->gt_scope)) {
+ log(LOG_WARNING, 0, "prune received from %s on scoped grp (%s %s)",
+ inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3));
+ return;
+ }
+ if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
+ /*
+ * If it's about to expire, then it's only still around because
+ * of timer granularity, so don't warn about it.
+ */
+ if (pt->pt_timer > 10) {
+ log(LOG_WARNING, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
+ "duplicate prune received on vif",
+ vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3), prun_tmr,
+ "old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
+ }
+ pt->pt_timer = prun_tmr;
+ } else {
+ /* allocate space for the prune structure */
+ pt = (struct ptable *)(malloc(sizeof(struct ptable)));
+ if (pt == NULL)
+ log(LOG_ERR, 0, "pt: ran out of memory");
+
+ pt->pt_vifi = vifi;
+ pt->pt_router = src;
+ pt->pt_timer = prun_tmr;
+
+ pt->pt_next = g->gt_pruntbl;
+ g->gt_pruntbl = pt;
+ }
+
+ /* Refresh the group's lifetime */
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ if (g->gt_timer < prun_tmr)
+ g->gt_timer = prun_tmr;
+
+ /*
+ * check if any more packets need to be sent on the
+ * vif which sent this message
+ */
+ stop_sending = 1;
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+
+ if (stop_sending && !grplst_mem(vifi, prun_grp)) {
+ VIFM_CLR(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "prune (%s %s), stop sending on vif %d, gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), vifi, g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+ }
+
+ /*
+ * check if all the child routers have expressed no interest
+ * in this group and if this group does not exist in the
+ * interface
+ * Send a prune message then upstream
+ */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
+ send_prune(g);
+ }
+ } else {
+ /*
+ * There is no kernel entry for this group. Therefore, we can
+ * simply ignore the prune, as we are not forwarding this traffic
+ * downstream.
+ */
+ log(LOG_DEBUG, 0, "%s (%s %s)/%d from %s",
+ "prune message received with no kernel entry for",
+ inet_fmt(prun_src, s1), inet_fmt(prun_grp, s2),
+ prun_tmr, inet_fmt(src, s3));
+ return;
+ }
+}
+
+/*
+ * Checks if this mcastgrp is present in the kernel table
+ * If so and if a prune was sent, it sends a graft upwards
+ */
+void
+chkgrp_graft(vifi, mcastgrp)
+ vifi_t vifi;
+ u_int32_t mcastgrp;
+{
+ struct rtentry *r;
+ struct gtable *g;
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ r = g->gt_route;
+ if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children))
+ if (g->gt_prsent_timer) {
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ /*
+ * If the vif that was joined was a scoped vif,
+ * ignore it ; don't graft back
+ */
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
+ continue;
+
+ /* set the flag for graft retransmission */
+ g->gt_grftsnt = 1;
+
+ /* send graft upwards */
+ send_graft(g);
+
+ /* reset the prune timer and update cache timer*/
+ g->gt_prsent_timer = 0;
+ g->gt_timer = max_prune_lifetime;
+
+ log(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+ }
+ }
+}
+
+/* determine the multicast group and src
+ *
+ * if it does, then determine if a prune was sent
+ * upstream.
+ * if prune sent upstream, send graft upstream and send
+ * ack downstream.
+ *
+ * if no prune sent upstream, change the forwarding bit
+ * for this interface and send ack downstream.
+ *
+ * if no entry exists for this group send ack downstream.
+ */
+void
+accept_graft(src, dst, p, datalen)
+ u_int32_t src;
+ u_int32_t dst;
+ char *p;
+ int datalen;
+{
+ vifi_t vifi;
+ u_int32_t graft_src;
+ u_int32_t graft_grp;
+ int i;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt, **ptnp;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring graft from non-neighbor %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ if (datalen < 8) {
+ log(LOG_WARNING, 0,
+ "received non-decipherable graft from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ for (i = 0; i< 4; i++)
+ ((char *)&graft_src)[i] = *p++;
+ for (i = 0; i< 4; i++)
+ ((char *)&graft_grp)[i] = *p++;
+
+ log(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)",
+ inet_fmt(src, s1), vifi,
+ inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3));
+
+ /*
+ * Find the subnet for the graft
+ */
+ if (find_src_grp(graft_src, 0, graft_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ r = g->gt_route;
+
+ if (VIFM_ISSET(vifi, g->gt_scope)) {
+ log(LOG_WARNING, 0, "graft received from %s on scoped grp (%s %s)",
+ inet_fmt(src, s1), inet_fmt(graft_src, s2),
+ inet_fmt(graft_grp, s3));
+ return;
+ }
+
+ ptnp = &g->gt_pruntbl;
+ while ((pt = *ptnp) != NULL) {
+ if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
+ *ptnp = pt->pt_next;
+ free(pt);
+
+ VIFM_SET(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "accept graft (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+ break;
+ } else {
+ ptnp = &pt->pt_next;
+ }
+ }
+
+ /* send ack downstream */
+ send_graft_ack(dst, src, graft_src, graft_grp);
+ g->gt_timer = max_prune_lifetime;
+
+ if (g->gt_prsent_timer) {
+ /* set the flag for graft retransmission */
+ g->gt_grftsnt = 1;
+
+ /* send graft upwards */
+ send_graft(g);
+
+ /* reset the prune sent timer */
+ g->gt_prsent_timer = 0;
+ }
+ } else {
+ /*
+ * We have no state for the source and group in question.
+ * We can simply acknowledge the graft, since we know
+ * that we have no prune state, and grafts are requests
+ * to remove prune state.
+ */
+ send_graft_ack(dst, src, graft_src, graft_grp);
+ log(LOG_DEBUG, 0, "%s (%s %s) from %s",
+ "graft received with no kernel entry for",
+ inet_fmt(graft_src, s1), inet_fmt(graft_grp, s2),
+ inet_fmt(src, s3));
+ return;
+ }
+}
+
+/*
+ * find out which group is involved first of all
+ * then determine if a graft was sent.
+ * if no graft sent, ignore the message
+ * if graft was sent and the ack is from the right
+ * source, remove the graft timer so that we don't
+ * have send a graft again
+ */
+void
+accept_g_ack(src, dst, p, datalen)
+ u_int32_t src;
+ u_int32_t dst;
+ char *p;
+ int datalen;
+{
+ struct gtable *g;
+ vifi_t vifi;
+ u_int32_t grft_src;
+ u_int32_t grft_grp;
+ int i;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring graft ack from non-neighbor %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ if (datalen < 0 || datalen > 8) {
+ log(LOG_WARNING, 0,
+ "received non-decipherable graft ack from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ for (i = 0; i< 4; i++)
+ ((char *)&grft_src)[i] = *p++;
+ for (i = 0; i< 4; i++)
+ ((char *)&grft_grp)[i] = *p++;
+
+ log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)",
+ inet_fmt(src, s1), vifi,
+ inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3));
+
+ /*
+ * Find the subnet for the graft ack
+ */
+ if (find_src_grp(grft_src, 0, grft_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ g->gt_grftsnt = 0;
+ } else {
+ log(LOG_WARNING, 0, "%s (%s, %s) from %s",
+ "rcvd graft ack with no kernel entry for",
+ inet_fmt(grft_src, s1), inet_fmt(grft_grp, s2),
+ inet_fmt(src, s3));
+ return;
+ }
+}
+
+
+/*
+ * free all prune entries and kernel routes
+ * normally, this should inform the kernel that all of its routes
+ * are going away, but this is only called by restart(), which is
+ * about to call MRT_DONE which does that anyway.
+ */
+void
+free_all_prunes()
+{
+ register struct rtentry *r;
+ register struct gtable *g, *prev_g;
+ register struct stable *s, *prev_s;
+ register struct ptable *p, *prev_p;
+
+ for (r = routing_table; r; r = r->rt_next) {
+ g = r->rt_groups;
+ while (g) {
+ s = g->gt_srctbl;
+ while (s) {
+ prev_s = s->st_next;
+ free(s);
+ s = prev_s;
+ }
+
+ p = g->gt_pruntbl;
+ while (p) {
+ prev_p = p->pt_next;
+ free(p);
+ p = prev_p;
+ }
+
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
+ }
+ r->rt_groups = NULL;
+ }
+ kernel_table = NULL;
+
+ g = kernel_no_route;
+ while (g) {
+ if (g->gt_srctbl)
+ free(g->gt_srctbl);
+
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
+ }
+ kernel_no_route = NULL;
+}
+
+/*
+ * When a new route is created, search
+ * a) The less-specific part of the routing table
+ * b) The route-less kernel table
+ * for sources that the new route might want to handle.
+ *
+ * "Inheriting" these sources might be cleanest, but simply deleting
+ * them is easier, and letting the kernel re-request them.
+ */
+void
+steal_sources(rt)
+ struct rtentry *rt;
+{
+ register struct rtentry *rp;
+ register struct gtable *gt, **gtnp;
+ register struct stable *st, **stnp;
+
+ for (rp = rt->rt_next; rp; rp = rp->rt_next) {
+ if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
+ log(LOG_DEBUG, 0, "Route for %s stealing sources from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
+ for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
+ log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmt(st->st_origin, s3),
+ inet_fmt(gt->gt_mcastgrp, s4),
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s, %s)",
+ "steal_sources trying to delete",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ *stnp = st->st_next;
+ kroutes--;
+ free(st);
+ } else {
+ stnp = &st->st_next;
+ }
+ }
+ }
+ }
+ }
+
+ gtnp = &kernel_no_route;
+ while ((gt = *gtnp) != NULL) {
+ if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask)
+ == rt->rt_origin)) {
+ log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmt(gt->gt_srctbl->st_origin, s3),
+ inet_fmt(gt->gt_mcastgrp, s4),
+ "no_route table");
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "steal_sources trying to delete",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ free(gt->gt_srctbl);
+ *gtnp = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+ free(gt);
+ } else {
+ gtnp = &gt->gt_next;
+ }
+ }
+}
+
+/*
+ * Advance the timers on all the cache entries.
+ * If there are any entries whose timers have expired,
+ * remove these entries from the kernel cache.
+ */
+void
+age_table_entry()
+{
+ struct rtentry *r;
+ struct gtable *gt, **gtnptr;
+ struct stable *st, **stnp;
+ struct ptable *pt, **ptnp;
+ struct sioc_sg_req sg_req;
+
+ log(LOG_DEBUG, 0, "ageing entries");
+
+ gtnptr = &kernel_table;
+ while ((gt = *gtnptr) != NULL) {
+ r = gt->gt_route;
+
+ /* advance the timer for the kernel entry */
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
+
+ /* decrement prune timer if need be */
+ if (gt->gt_prsent_timer > 0) {
+ gt->gt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
+ if (gt->gt_prsent_timer <= 0) {
+ log(LOG_DEBUG, 0, "upstream prune tmo (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ gt->gt_prsent_timer = -1;
+ }
+ }
+
+ /* retransmit graft if graft sent flag is still set */
+ if (gt->gt_grftsnt) {
+ register int y;
+ CHK_GS(gt->gt_grftsnt++, y);
+ if (y)
+ send_graft(gt);
+ }
+
+ /*
+ * Age prunes
+ *
+ * If a prune expires, forward again on that vif.
+ */
+ ptnp = &gt->gt_pruntbl;
+ while ((pt = *ptnp) != NULL) {
+ if ((pt->pt_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
+ log(LOG_DEBUG, 0, "expire prune (%s %s) from %s on vif %d",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ inet_fmt(pt->pt_router, s3),
+ pt->pt_vifi);
+
+ /*
+ * No need to send a graft, any prunes that we sent
+ * will expire before any prunes that we have received.
+ */
+ if (gt->gt_prsent_timer > 0) {
+ log(LOG_DEBUG, 0, "prune expired with %d left on %s",
+ gt->gt_prsent_timer, "prsent_timer");
+ gt->gt_prsent_timer = 0;
+ }
+
+ /* modify the kernel entry to forward packets */
+ if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
+ VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
+ log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
+ pt->pt_vifi);
+
+ prun_add_ttls(gt);
+ update_kernel(gt);
+ }
+
+ /* remove the router's prune entry and await new one */
+ *ptnp = pt->pt_next;
+ free(pt);
+ } else {
+ ptnp = &pt->pt_next;
+ }
+ }
+
+ /*
+ * If the cache entry has expired, check for downstream prunes.
+ *
+ * If there are downstream prunes, refresh the cache entry's timer.
+ * Otherwise, check for traffic. If no traffic, delete this
+ * entry.
+ */
+ if (gt->gt_timer <= 0) {
+ if (gt->gt_pruntbl) {
+ if (gt->gt_prsent_timer == -1)
+ gt->gt_prsent_timer = 0;
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ gtnptr = &gt->gt_gnext;
+ continue;
+ }
+
+ /*
+ * If this entry was pruned, but all downstream prunes
+ * have expired, then it is safe to simply delete it.
+ * Otherwise, check for traffic before deleting.
+ */
+ if (gt->gt_prsent_timer == 0) {
+ sg_req.grp.s_addr = gt->gt_mcastgrp;
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ sg_req.src.s_addr = st->st_origin;
+ if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req)
+ < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry: SIOCGETSGCNT failing for",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ /* Make sure it gets deleted below */
+ sg_req.pktcnt = st->st_pktcnt;
+ }
+ if (sg_req.pktcnt == st->st_pktcnt) {
+ *stnp = st->st_next;
+ log(LOG_DEBUG, 0,
+ "age_table_entry deleting (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno,
+ "age_table_entry trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ free(st);
+ } else {
+ stnp = &st->st_next;
+ }
+ }
+
+ if (gt->gt_srctbl) {
+ /* At least one source in the list still has traffic */
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ gtnptr = &gt->gt_gnext;
+ continue;
+ }
+ }
+
+ log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+
+ /* free all the source entries */
+ while (st = gt->gt_srctbl) {
+ log(LOG_DEBUG, 0,
+ "age_table_entry (P) deleting (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno,
+ "age_table_entry (P) trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ gt->gt_srctbl = st->st_next;
+ free(st);
+ }
+
+ /* free all the prune list entries */
+ while (gt->gt_pruntbl) {
+ gt->gt_pruntbl = pt->pt_next;
+ free(pt);
+ }
+
+ if (gt->gt_prev)
+ gt->gt_prev->gt_next = gt->gt_next;
+ else
+ gt->gt_route->rt_groups = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+
+ if (gt->gt_gprev) {
+ gt->gt_gprev->gt_gnext = gt->gt_gnext;
+ gtnptr = &gt->gt_gprev->gt_gnext;
+ } else {
+ kernel_table = gt->gt_gnext;
+ gtnptr = &kernel_table;
+ }
+ if (gt->gt_gnext)
+ gt->gt_gnext->gt_gprev = gt->gt_gprev;
+
+ free((char *)gt);
+ } else {
+ if (gt->gt_prsent_timer == -1)
+ gt->gt_prsent_timer = 0;
+ gtnptr = &gt->gt_gnext;
+ }
+ }
+
+ /*
+ * When traversing the no_route table, the decision is much easier.
+ * Just delete it if it has timed out.
+ */
+ gtnptr = &kernel_no_route;
+ while ((gt = *gtnptr) != NULL) {
+ /* advance the timer for the kernel entry */
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
+
+ if (gt->gt_timer < 0) {
+ if (gt->gt_srctbl) {
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry trying to delete no-route",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ free(gt->gt_srctbl);
+ }
+ *gtnptr = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+
+ free((char *)gt);
+ } else {
+ gtnptr = &gt->gt_next;
+ }
+ }
+}
+
+char *
+scaletime(t)
+ u_long t;
+{
+ static char buf1[5];
+ static char buf2[5];
+ static char *buf=buf1;
+ char s;
+ char *p;
+
+ p = buf;
+ if (buf == buf1)
+ buf = buf2;
+ else
+ buf = buf1;
+
+ if (t < 120) {
+ s = 's';
+ } else if (t < 3600) {
+ t /= 60;
+ s = 'm';
+ } else if (t < 86400) {
+ t /= 3600;
+ s = 'h';
+ } else if (t < 864000) {
+ t /= 86400;
+ s = 'd';
+ } else {
+ t /= 604800;
+ s = 'w';
+ }
+ if (t > 999)
+ return "*** ";
+
+ sprintf(p,"%3d%c", t, s);
+
+ return p;
+}
+
+/*
+ * Print the contents of the cache table on file 'fp2'.
+ */
+void
+dump_cache(fp2)
+ FILE *fp2;
+{
+ register struct rtentry *r;
+ register struct gtable *gt;
+ register struct stable *st;
+ register struct ptable *pt;
+ register int i;
+ register time_t thyme = time(0);
+
+ fprintf(fp2,
+ "Multicast Routing Cache Table (%d entries)\n%s", kroutes,
+ " Origin Mcast-group CTmr Age Ptmr IVif Forwvifs\n");
+
+ for (gt = kernel_no_route; gt; gt = gt->gt_next) {
+ if (gt->gt_srctbl) {
+ fprintf(fp2, " %-18s %-15s %-4s %-4s - -1\n",
+ inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1),
+ inet_fmt(gt->gt_mcastgrp, s2), scaletime(gt->gt_timer),
+ scaletime(thyme - gt->gt_ctime));
+ fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin, s1));
+ }
+ }
+
+ for (gt = kernel_table; gt; gt = gt->gt_gnext) {
+ r = gt->gt_route;
+ fprintf(fp2, " %-18s %-15s",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+
+ fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
+
+ fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
+ gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
+ " -");
+
+ fprintf(fp2, "%2u%c%c ", r->rt_parent,
+ gt->gt_prsent_timer ? 'P' : ' ',
+ VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' ');
+
+ for (i = 0; i < numvifs; ++i) {
+ if (VIFM_ISSET(i, gt->gt_grpmems))
+ fprintf(fp2, " %u ", i);
+ else if (VIFM_ISSET(i, r->rt_children) &&
+ !VIFM_ISSET(i, r->rt_leaves))
+ fprintf(fp2, " %u%c", i,
+ VIFM_ISSET(i, gt->gt_scope) ? 'b' : 'p');
+ }
+ fprintf(fp2, "\n");
+ for (st = gt->gt_srctbl; st; st = st->st_next) {
+ fprintf(fp2, ">%s\n", inet_fmt(st->st_origin, s1));
+ }
+#ifdef DEBUG_PRUNES
+ for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
+ fprintf(fp2, "<r:%s v:%d t:%d\n", inet_fmt(pt->pt_router, s1),
+ pt->pt_vifi, pt->pt_timer);
+ }
+#endif
+ }
+}
+
+/*
+ * Traceroute function which returns traceroute replies to the requesting
+ * router. Also forwards the request to downstream routers.
+ */
+void
+accept_mtrace(src, dst, group, data, no, datalen)
+ u_int32_t src;
+ u_int32_t dst;
+ u_int32_t group;
+ char *data;
+ u_char no;
+ int datalen;
+{
+ u_char type;
+ struct rtentry *rt;
+ struct gtable *gt;
+ struct tr_query *qry;
+ struct tr_resp *resp;
+ int vifi;
+ char *p;
+ int rcount;
+ int errcode = TR_NO_ERR;
+ int resptype;
+ struct timeval tp;
+ struct sioc_vif_req v_req;
+ struct sioc_sg_req sg_req;
+
+ /* Remember qid across invocations */
+ static u_int32_t oqid = 0;
+
+ /* timestamp the request/response */
+ gettimeofday(&tp, 0);
+
+ /*
+ * Check if it is a query or a response
+ */
+ if (datalen == QLEN) {
+ type = QUERY;
+ log(LOG_DEBUG, 0, "Traceroute query rcvd from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+ }
+ else if ((datalen - QLEN) % RLEN == 0) {
+ type = RESP;
+ log(LOG_DEBUG, 0, "Traceroute response rcvd from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+ if IN_MULTICAST(ntohl(dst)) {
+ log(LOG_DEBUG, 0, "Dropping multicast response");
+ return;
+ }
+ }
+ else {
+ log(LOG_WARNING, 0, "%s from %s to %s",
+ "Non decipherable tracer request recieved",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+ return;
+ }
+
+ qry = (struct tr_query *)data;
+
+ if (oqid == qry->tr_qid) {
+ /*
+ * If the multicast router is a member of the group being
+ * queried, and the query is multicasted, then the router can
+ * recieve multiple copies of the same query. If we have already
+ * replied to this traceroute, just ignore it this time.
+ *
+ * This is not a total solution, but since if this fails you
+ * only get N copies, N <= the number of interfaces on the router,
+ * it is not fatal.
+ */
+ log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
+ return;
+ } else
+ oqid = qry->tr_qid;
+
+ /*
+ * if it is a packet with all reports filled, drop it
+ */
+ if ((rcount = (datalen - QLEN)/RLEN) == no) {
+ log(LOG_DEBUG, 0, "packet with all reports filled in");
+ return;
+ }
+
+ log(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
+ inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
+ log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
+ inet_fmt(qry->tr_raddr, s1));
+ log(LOG_DEBUG, 0, "rcount:%d", rcount);
+
+ /* determine the routing table entry for this traceroute */
+ rt = determine_route(qry->tr_src);
+ if (rt) {
+ log(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d",
+ rt->rt_parent, inet_fmt(rt->rt_gateway, s1), rt->rt_metric);
+ log(LOG_DEBUG, 0, "rt origin %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1));
+ } else
+ log(LOG_DEBUG, 0, "...no route");
+
+ /*
+ * Query type packet - check if rte exists
+ * Check if the query destination is a vif connected to me.
+ * and if so, whether I should start response back
+ */
+ if (type == QUERY) {
+ if (rt == NULL) {
+ log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
+ inet_fmt(qry->tr_src, s1));
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ }
+ vifi = find_vif(qry->tr_dst, 0);
+
+ if (vifi == NO_VIF) {
+ /* The traceroute destination is not on one of my subnet vifs. */
+ log(LOG_DEBUG, 0, "Destination %s not an interface",
+ inet_fmt(qry->tr_dst, s1));
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ errcode = TR_WRONG_IF;
+ } else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
+ log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
+ inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ errcode = TR_WRONG_IF;
+ }
+ }
+ else {
+ /*
+ * determine which interface the packet came in on
+ * RESP packets travel hop-by-hop so this either traversed
+ * a tunnel or came from a directly attached mrouter.
+ */
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_DEBUG, 0, "Wrong interface for packet");
+ errcode = TR_WRONG_IF;
+ }
+ }
+
+ log(LOG_DEBUG, 0, "Sending traceroute response");
+
+ /* copy the packet to the sending buffer */
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+
+ bcopy(data, p, datalen);
+
+ p += datalen;
+
+ /*
+ * If there is no room to insert our reply, coopt the previous hop
+ * error indication to relay this fact.
+ */
+ if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE) {
+ resp = (struct tr_resp *)p - 1;
+ resp->tr_rflags = TR_NO_SPACE;
+ rt = NULL;
+ goto sendit;
+ }
+
+ /*
+ * fill in initial response fields
+ */
+ resp = (struct tr_resp *)p;
+ bzero(resp, sizeof(struct tr_resp));
+ datalen += RLEN;
+
+ resp->tr_qarr = ((tp.tv_sec + JAN_1970) << 16) +
+ ((tp.tv_usec >> 4) & 0xffff);
+
+ resp->tr_rproto = PROTO_DVMRP;
+ if (errcode != TR_NO_ERR) {
+ resp->tr_rflags = errcode;
+ rt = NULL; /* hack to enforce send straight to requestor */
+ goto sendit;
+ }
+ resp->tr_outaddr = uvifs[vifi].uv_lcl_addr;
+ resp->tr_fttl = uvifs[vifi].uv_threshold;
+ resp->tr_rflags = TR_NO_ERR;
+
+ /*
+ * obtain # of packets out on interface
+ */
+ v_req.vifi = vifi;
+ if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
+ resp->tr_vifout = v_req.ocount;
+
+ /*
+ * fill in scoping & pruning information
+ */
+ if (rt)
+ for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
+ if (gt->gt_mcastgrp >= group)
+ break;
+ }
+ else
+ gt = NULL;
+
+ if (gt && gt->gt_mcastgrp == group) {
+ sg_req.src.s_addr = qry->tr_src;
+ sg_req.grp.s_addr = group;
+ if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
+ resp->tr_pktcnt = sg_req.pktcnt;
+
+ if (VIFM_ISSET(vifi, gt->gt_scope))
+ resp->tr_rflags = TR_SCOPED;
+ else if (gt->gt_prsent_timer)
+ resp->tr_rflags = TR_PRUNED;
+ else if (!VIFM_ISSET(vifi, gt->gt_grpmems))
+ if (VIFM_ISSET(vifi, rt->rt_children) &&
+ !VIFM_ISSET(vifi, rt->rt_leaves))
+ resp->tr_rflags = TR_OPRUNED;
+ else
+ resp->tr_rflags = TR_NO_FWD;
+ } else {
+ if (scoped_addr(vifi, group))
+ resp->tr_rflags = TR_SCOPED;
+ else if (!VIFM_ISSET(vifi, rt->rt_children))
+ resp->tr_rflags = TR_NO_FWD;
+ }
+
+ /*
+ * if no rte exists, set NO_RTE error
+ */
+ if (rt == NULL) {
+ src = dst; /* the dst address of resp. pkt */
+ resp->tr_inaddr = 0;
+ resp->tr_rflags = TR_NO_RTE;
+ resp->tr_rmtaddr = 0;
+ } else {
+ /* get # of packets in on interface */
+ v_req.vifi = rt->rt_parent;
+ if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
+ resp->tr_vifin = v_req.icount;
+
+ MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
+ src = uvifs[rt->rt_parent].uv_lcl_addr;
+ resp->tr_inaddr = src;
+ resp->tr_rmtaddr = rt->rt_gateway;
+ if (!VIFM_ISSET(vifi, rt->rt_children)) {
+ log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
+ inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
+ resp->tr_rflags = TR_WRONG_IF;
+ }
+ if (rt->rt_metric >= UNREACHABLE) {
+ resp->tr_rflags = TR_NO_RTE;
+ /* Hack to send reply directly */
+ rt = NULL;
+ }
+ }
+
+sendit:
+ /*
+ * if metric is 1 or no. of reports is 1, send response to requestor
+ * else send to upstream router. If the upstream router can't handle
+ * mtrace, set an error code and send to requestor anyway.
+ */
+ log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
+
+ if ((rcount + 1 == no) || (rt == NULL) || (rt->rt_metric == 1)) {
+ resptype = IGMP_MTRACE_REPLY;
+ dst = qry->tr_raddr;
+ } else
+ if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
+ dst = qry->tr_raddr;
+ resp->tr_rflags = TR_OLD_ROUTER;
+ resptype = IGMP_MTRACE_REPLY;
+ } else {
+ dst = rt->rt_gateway;
+ resptype = IGMP_MTRACE_QUERY;
+ }
+
+ log(LOG_DEBUG, 0, "Sending %s to %s from %s",
+ resptype == IGMP_MTRACE_REPLY ? "response" : "request on",
+ inet_fmt(dst, s1), inet_fmt(src, s2));
+
+ if (IN_MULTICAST(ntohl(dst))) {
+ k_set_ttl(qry->tr_rttl);
+ /* Let the kernel pick the source address, since we might have picked
+ * a disabled phyint to multicast on.
+ */
+ send_igmp(INADDR_ANY, dst,
+ resptype, no, group,
+ datalen);
+ k_set_ttl(1);
+ } else
+ send_igmp(src, dst,
+ resptype, no, group,
+ datalen);
+ return;
+}
diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h
new file mode 100644
index 00000000000..22df280b830
--- /dev/null
+++ b/usr.sbin/mrouted/prune.h
@@ -0,0 +1,139 @@
+/* $NetBSD: prune.h,v 1.2 1995/10/09 03:51:52 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+/*
+ * Group table
+ *
+ * Each group entry is a member of two doubly-linked lists:
+ *
+ * a) A list hanging off of the routing table entry for this source (rt_groups)
+ * sorted by group address under the routing entry (gt_next, gt_prev)
+ * b) An independent list pointed to by kernel_table, which is a list of
+ * active source,group's (gt_gnext, gt_gprev).
+ *
+ */
+struct gtable {
+ struct gtable *gt_next; /* pointer to the next entry */
+ struct gtable *gt_prev; /* back pointer for linked list */
+ struct gtable *gt_gnext; /* fwd pointer for group list */
+ struct gtable *gt_gprev; /* rev pointer for group list */
+ u_int32_t gt_mcastgrp; /* multicast group associated */
+ vifbitmap_t gt_scope; /* scoped interfaces */
+ u_char gt_ttls[MAXVIFS]; /* ttl vector for forwarding */
+ vifbitmap_t gt_grpmems; /* forw. vifs for src, grp */
+ int gt_prsent_timer; /* prune timer for this group */
+ int gt_timer; /* timer for this group entry */
+ time_t gt_ctime; /* time of entry creation */
+ u_char gt_grftsnt; /* graft sent/retransmit timer */
+ struct stable *gt_srctbl; /* source table */
+ struct ptable *gt_pruntbl; /* prune table */
+ struct rtentry *gt_route; /* parent route */
+};
+
+/*
+ * Source table
+ *
+ * When source-based prunes exist, there will be a struct ptable here as well.
+ */
+struct stable
+{
+ struct stable *st_next; /* pointer to the next entry */
+ u_int32_t st_origin; /* host origin of multicasts */
+ u_long st_pktcnt; /* packet count for src-grp entry */
+};
+
+/*
+ * structure to store incoming prunes. Can hang off of either group or source.
+ */
+struct ptable
+{
+ struct ptable *pt_next; /* pointer to the next entry */
+ u_int32_t pt_router; /* router that sent this prune */
+ vifi_t pt_vifi; /* vif prune received on */
+ int pt_timer; /* timer for prune */
+};
+
+/*
+ * The packet format for a traceroute request.
+ */
+struct tr_query {
+ u_int32_t tr_src; /* traceroute source */
+ u_int32_t tr_dst; /* traceroute destination */
+ u_int32_t tr_raddr; /* traceroute response address */
+#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+ struct {
+ u_int qid : 24; /* traceroute query id */
+ u_int ttl : 8; /* traceroute response ttl */
+ } q;
+#else
+ struct {
+ u_int ttl : 8; /* traceroute response ttl */
+ u_int qid : 24; /* traceroute query id */
+ } q;
+#endif /* BYTE_ORDER */
+};
+
+#define tr_rttl q.ttl
+#define tr_qid q.qid
+
+/*
+ * Traceroute response format. A traceroute response has a tr_query at the
+ * beginning, followed by one tr_resp for each hop taken.
+ */
+struct tr_resp {
+ u_int32_t tr_qarr; /* query arrival time */
+ u_int32_t tr_inaddr; /* incoming interface address */
+ u_int32_t tr_outaddr; /* outgoing interface address */
+ u_int32_t tr_rmtaddr; /* parent address in source tree */
+ u_int32_t tr_vifin; /* input packet count on interface */
+ u_int32_t tr_vifout; /* output packet count on interface */
+ u_int32_t tr_pktcnt; /* total incoming packets for src-grp */
+ u_char tr_rproto; /* routing protocol deployed on router */
+ u_char tr_fttl; /* ttl required to forward on outvif */
+ u_char tr_smask; /* subnet mask for src addr */
+ u_char tr_rflags; /* forwarding error codes */
+};
+
+/* defs within mtrace */
+#define QUERY 1
+#define RESP 2
+#define QLEN sizeof(struct tr_query)
+#define RLEN sizeof(struct tr_resp)
+
+/* fields for tr_rflags (forwarding error codes) */
+#define TR_NO_ERR 0
+#define TR_WRONG_IF 1
+#define TR_PRUNED 2
+#define TR_OPRUNED 3
+#define TR_SCOPED 4
+#define TR_NO_RTE 5
+#define TR_NO_FWD 7
+#define TR_NO_SPACE 0x81
+#define TR_OLD_ROUTER 0x82
+
+/* fields for tr_rproto (routing protocol) */
+#define PROTO_DVMRP 1
+#define PROTO_MOSPF 2
+#define PROTO_PIM 3
+#define PROTO_CBT 4
+
+#define MASK_TO_VAL(x, i) { \
+ u_int32_t _x = ntohl(x); \
+ (i) = 0; \
+ while ((_x) << (i)) \
+ (i)++; \
+ };
+
+#define VAL_TO_MASK(x, i) { \
+ x = htonl(~((1 << (32 - (i))) - 1)); \
+ };
+
+#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
new file mode 100644
index 00000000000..d45de2361af
--- /dev/null
+++ b/usr.sbin/mrouted/route.c
@@ -0,0 +1,1139 @@
+/* $NetBSD: route.c,v 1.4 1995/10/09 03:51:53 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * This define statement saves a lot of space later
+ */
+#define RT_ADDR (struct rtentry *)&routing_table
+
+/*
+ * Exported variables.
+ */
+int routes_changed; /* 1=>some routes have changed */
+int delay_change_reports; /* 1=>postpone change reports */
+
+
+/*
+ * The routing table is shared with prune.c , so must not be static.
+ */
+struct rtentry *routing_table; /* pointer to list of route entries */
+
+/*
+ * Private variables.
+ */
+static struct rtentry *rtp; /* pointer to a route entry */
+static struct rtentry *rt_end; /* pointer to last route entry */
+unsigned int nroutes; /* current number of route entries */
+
+/*
+ * Initialize the routing table and associated variables.
+ */
+void
+init_routes()
+{
+ routing_table = NULL;
+ nroutes = 0;
+ routes_changed = FALSE;
+ delay_change_reports = FALSE;
+}
+
+
+/*
+ * Initialize the children and leaf bits for route 'r', along with the
+ * associated dominant, subordinate, and leaf timing data structures.
+ * Return TRUE if this changes the value of either the children or
+ * leaf bitmaps for 'r'.
+ */
+static int
+init_children_and_leaves(r, parent)
+ register struct rtentry *r;
+ register vifi_t parent;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ vifbitmap_t old_children, old_leaves;
+
+ VIFM_COPY(r->rt_children, old_children);
+ VIFM_COPY(r->rt_leaves, old_leaves );
+
+ VIFM_CLRALL(r->rt_children);
+ VIFM_CLRALL(r->rt_leaves);
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+
+ if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ VIFM_SET(vifi, r->rt_children);
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else {
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ }
+
+ return (!VIFM_SAME(r->rt_children, old_children) ||
+ !VIFM_SAME(r->rt_leaves, old_leaves));
+}
+
+
+/*
+ * A new vif has come up -- update the children and leaf bitmaps in all route
+ * entries to take that into account.
+ */
+void
+add_vif_to_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE &&
+ !VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ update_table_entry(r);
+ }
+ }
+}
+
+
+/*
+ * A vif has gone down -- expire all routes that have that vif as parent,
+ * and update the children bitmaps in all other route entries to take into
+ * account the failed vif.
+ */
+void
+delete_vif_from_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (vifi == r->rt_parent) {
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ update_table_entry(r);
+ }
+ else {
+ r->rt_dominants[vifi] = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * A neighbor has failed or become unreachable. If that neighbor was
+ * considered a dominant or subordinate router in any route entries,
+ * take appropriate action.
+ */
+void
+delete_neighbor_from_routes(addr, vifi)
+ register u_int32_t addr;
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (r->rt_dominants[vifi] == addr) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ update_table_entry(r);
+ }
+ else if (r->rt_subordinates[vifi] == addr) {
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ update_table_entry(r);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else if (v->uv_neighbors == NULL &&
+ r->rt_leaf_timers[vifi] != 0) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ update_table_entry(r);
+ }
+ }
+ }
+}
+
+
+/*
+ * Prepare for a sequence of ordered route updates by initializing a pointer
+ * to the start of the routing table. The pointer is used to remember our
+ * position in the routing table in order to avoid searching from the
+ * beginning for each update; this relies on having the route reports in
+ * a single message be in the same order as the route entries in the routing
+ * table.
+ */
+void
+start_route_updates()
+{
+ rtp = RT_ADDR;
+}
+
+
+/*
+ * Starting at the route entry following the one to which 'rtp' points,
+ * look for a route entry matching the specified origin and mask. If a
+ * match is found, return TRUE and leave 'rtp' pointing at the found entry.
+ * If no match is found, return FALSE and leave 'rtp' pointing to the route
+ * entry preceding the point at which the new origin should be inserted.
+ * This code is optimized for the normal case in which the first entry to
+ * be examined is the matching entry.
+ */
+static int
+find_route(origin, mask)
+ register u_int32_t origin, mask;
+{
+ register struct rtentry *r;
+
+ r = rtp->rt_next;
+ while (r != NULL) {
+ if (origin == r->rt_origin && mask == r->rt_originmask) {
+ rtp = r;
+ return (TRUE);
+ }
+ if (ntohl(mask) < ntohl(r->rt_originmask) ||
+ (mask == r->rt_originmask &&
+ ntohl(origin) < ntohl(r->rt_origin))) {
+ rtp = r;
+ r = r->rt_next;
+ }
+ else break;
+ }
+ return (FALSE);
+}
+
+/*
+ * Create a new routing table entry for the specified origin and link it into
+ * the routing table. The shared variable 'rtp' is assumed to point to the
+ * routing entry after which the new one should be inserted. It is left
+ * pointing to the new entry.
+ *
+ * Only the origin, originmask, originwidth and flags fields are initialized
+ * in the new route entry; the caller is responsible for filling in the the
+ * rest.
+ */
+static void
+create_route(origin, mask)
+ u_int32_t origin, mask;
+{
+ register struct rtentry *r;
+
+ if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
+ (2 * numvifs * sizeof(u_int32_t)) +
+ (numvifs * sizeof(u_long)))) == NULL) {
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+ }
+ r->rt_origin = origin;
+ r->rt_originmask = mask;
+ if (((char *)&mask)[3] != 0) r->rt_originwidth = 4;
+ else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3;
+ else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
+ else r->rt_originwidth = 1;
+ r->rt_flags = 0;
+ r->rt_dominants = (u_int32_t *)(r + 1);
+ r->rt_subordinates = (u_int32_t *)(r->rt_dominants + numvifs);
+ r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
+ r->rt_groups = NULL;
+
+ r->rt_next = rtp->rt_next;
+ rtp->rt_next = r;
+ r->rt_prev = rtp;
+ if (r->rt_next != NULL)
+ (r->rt_next)->rt_prev = r;
+ else
+ rt_end = r;
+ rtp = r;
+ ++nroutes;
+}
+
+
+/*
+ * Discard the routing table entry following the one to which 'prev_r' points.
+ */
+static void
+discard_route(prev_r)
+ register struct rtentry *prev_r;
+{
+ register struct rtentry *r;
+
+ r = prev_r->rt_next;
+ prev_r->rt_next = r->rt_next;
+ if (prev_r->rt_next != NULL)
+ (prev_r->rt_next)->rt_prev = prev_r;
+ else
+ rt_end = prev_r;
+ free((char *)r);
+ --nroutes;
+}
+
+
+/*
+ * Process a route report for a single origin, creating or updating the
+ * corresponding routing table entry if necessary. 'src' is either the
+ * address of a neighboring router from which the report arrived, or zero
+ * to indicate a change of status of one of our own interfaces.
+ */
+void
+update_route(origin, mask, metric, src, vifi)
+ u_int32_t origin, mask;
+ int metric;
+ u_int32_t src;
+ vifi_t vifi;
+{
+ register struct rtentry *r;
+ struct rtentry *prev_r;
+ int adj_metric;
+
+ /*
+ * Compute an adjusted metric, taking into account the cost of the
+ * subnet or tunnel over which the report arrived, and normalizing
+ * all unreachable/poisoned metrics into a single value.
+ */
+ if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
+ log(LOG_WARNING, 0,
+ "%s reports out-of-range metric %u for origin %s",
+ inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2));
+ return;
+ }
+ adj_metric = metric + uvifs[vifi].uv_metric;
+ if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;
+
+ /*
+ * Look up the reported origin in the routing table.
+ */
+ if (!find_route(origin, mask)) {
+ register struct rtentry *rp;
+ register struct gtable *gt;
+ register struct stable *st, **stnp;
+
+ /*
+ * Not found.
+ * Don't create a new entry if the report says it's unreachable,
+ * or if the reported origin and mask are invalid.
+ */
+ if (adj_metric == UNREACHABLE) {
+ return;
+ }
+ if (src != 0 && !inet_valid_subnet(origin, mask)) {
+ log(LOG_WARNING, 0,
+ "%s reports an invalid origin (%s) and/or mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+
+ /*
+ * OK, create the new routing entry. 'rtp' will be left pointing
+ * to the new entry.
+ */
+ create_route(origin, mask);
+
+ /*
+ * Now "steal away" any sources that belong under this route
+ * by deleting any cache entries they might have created
+ * and allowing the kernel to re-request them.
+ */
+ steal_sources(rtp);
+
+ rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
+ }
+
+ /*
+ * We now have a routing entry for the reported origin. Update it?
+ */
+ r = rtp;
+ if (r->rt_metric == UNREACHABLE) {
+ /*
+ * The routing entry is for a formerly-unreachable or new origin.
+ * If the report claims reachability, update the entry to use
+ * the reported route.
+ */
+ if (adj_metric == UNREACHABLE)
+ return;
+
+ r->rt_parent = vifi;
+ init_children_and_leaves(r, vifi);
+
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ update_table_entry(r);
+ }
+ else if (src == r->rt_gateway) {
+ /*
+ * The report has come either from the interface directly-connected
+ * to the origin subnet (src and r->rt_gateway both equal zero) or
+ * from the gateway we have chosen as the best first-hop gateway back
+ * towards the origin (src and r->rt_gateway not equal zero). Reset
+ * the route timer and, if the reported metric has changed, update
+ * our entry accordingly.
+ */
+ r->rt_timer = 0;
+ if (adj_metric == r->rt_metric)
+ return;
+
+ if (adj_metric == UNREACHABLE) {
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ }
+ else if (adj_metric < r->rt_metric) {
+ if (init_children_and_leaves(r, vifi)) {
+ update_table_entry(r);
+ }
+ }
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (src == 0 ||
+ (r->rt_gateway != 0 &&
+ (adj_metric < r->rt_metric ||
+ (adj_metric == r->rt_metric &&
+ r->rt_timer >= ROUTE_SWITCH_TIME)))) {
+ /*
+ * The report is for an origin we consider reachable; the report
+ * comes either from one of our own interfaces or from a gateway
+ * other than the one we have chosen as the best first-hop gateway
+ * back towards the origin. If the source of the update is one of
+ * our own interfaces, or if the origin is not a directly-connected
+ * subnet and the reported metric for that origin is better than
+ * what our routing entry says, update the entry to use the new
+ * gateway and metric. We also switch gateways if the reported
+ * metric is the same as the one in the route entry and the gateway
+ * associated with the route entry has not been heard from recently.
+ * Did you get all that?
+ */
+ if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
+ r->rt_parent = vifi;
+ if (init_children_and_leaves(r, vifi)) {
+ update_table_entry(r);
+ }
+ }
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (vifi != r->rt_parent) {
+ /*
+ * The report came from a vif other than the route's parent vif.
+ * Update the children and leaf info, if necessary.
+ */
+ if (VIFM_ISSET(vifi, r->rt_children)) {
+ /*
+ * Vif is a child vif for this route.
+ */
+ if (metric < r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
+ /*
+ * Neighbor has lower metric to origin (or has same metric
+ * and lower IP address) -- it becomes the dominant router,
+ * and vif is no longer a child for me.
+ */
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_dominants [vifi] = src;
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ update_table_entry(r);
+ }
+ else if (metric > UNREACHABLE) { /* "poisoned reverse" */
+ /*
+ * Neighbor considers this vif to be on path to route's
+ * origin; if no subordinate recorded, record this neighbor
+ * as subordinate and clear the leaf flag.
+ */
+ if (r->rt_subordinates[vifi] == 0) {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = src;
+ r->rt_leaf_timers [vifi] = 0;
+ update_table_entry(r);
+ }
+ }
+ else if (src == r->rt_subordinates[vifi]) {
+ /*
+ * Current subordinate no longer considers this vif to be on
+ * path to route's origin; it is no longer a subordinate
+ * router, and we set the leaf confirmation timer to give
+ * us time to hear from other subordinates.
+ */
+ r->rt_subordinates[vifi] = 0;
+ if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ update_table_entry(r);
+ }
+ else {
+ r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+
+ }
+ else if (src == r->rt_dominants[vifi] &&
+ (metric > r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
+ /*
+ * Current dominant no longer has a lower metric to origin
+ * (or same metric and lower IP address); we adopt the vif
+ * as our own child.
+ */
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ if (metric > UNREACHABLE) {
+ r->rt_subordinates[vifi] = src;
+ }
+ else if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ update_table_entry(r);
+ }
+ }
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each routing entry.
+ */
+void
+age_routes()
+{
+ register struct rtentry *r;
+ register struct rtentry *prev_r;
+ register vifi_t vifi;
+
+ for (prev_r = RT_ADDR, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next) {
+
+ if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) {
+ /*
+ * Route is still good; see if any leaf timers need to be
+ * advanced.
+ */
+ if (r->rt_flags & RTF_LEAF_TIMING) {
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+ for (vifi = 0; vifi < numvifs; ++vifi) {
+ if (r->rt_leaf_timers[vifi] != 0) {
+ /*
+ * Unlike other timers, leaf timers decrement.
+ */
+ if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
+#ifdef NOTYET
+ /* If the vif is a physical leaf but has neighbors,
+ * it is not a tree leaf. If I am a leaf, then no
+ * interface with neighbors is a tree leaf. */
+ if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
+ (vifs_with_neighbors == 1)) &&
+ (uvifs[vifi].uv_neighbors != NULL))) {
+#endif
+ VIFM_SET(vifi, r->rt_leaves);
+ update_table_entry(r);
+#ifdef NOTYET
+ }
+#endif
+ }
+ else {
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ }
+ }
+ }
+ else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
+ /*
+ * Time to garbage-collect the route entry.
+ */
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ discard_route(prev_r);
+ r = prev_r;
+ }
+ else if (r->rt_metric != UNREACHABLE) {
+ /*
+ * Time to expire the route entry. If the gateway is zero,
+ * i.e., it is a route to a directly-connected subnet, just
+ * set the timer back to zero; such routes expire only when
+ * the interface to the subnet goes down.
+ */
+ if (r->rt_gateway == 0) {
+ r->rt_timer = 0;
+ }
+ else {
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Mark all routes as unreachable. This function is called only from
+ * hup() in preparation for informing all neighbors that we are going
+ * off the air. For consistency, we ought also to delete all reachable
+ * route entries from the kernel, but since we are about to exit we rely
+ * on the kernel to do its own cleanup -- no point in making all those
+ * expensive kernel calls now.
+ */
+void
+expire_all_routes()
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+}
+
+
+/*
+ * Delete all the routes in the routing table.
+ */
+void
+free_all_routes()
+{
+ register struct rtentry *r;
+
+ r = RT_ADDR;
+
+ while (r->rt_next)
+ discard_route(r);
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void
+accept_probe(src, dst, p, datalen, level)
+ u_int32_t src;
+ u_int32_t dst;
+ char *p;
+ int datalen;
+ u_int32_t level;
+{
+ vifi_t vifi;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring probe from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level))
+ return;
+
+ report(ALL_ROUTES, vifi, src);
+}
+
+struct newrt {
+ u_int32_t mask;
+ u_int32_t origin;
+ int metric;
+ int pad;
+};
+
+int
+compare_rts(r1, r2)
+ register struct newrt *r1;
+ register struct newrt *r2;
+{
+ register u_int32_t m1 = ntohl(r1->mask);
+ register u_int32_t m2 = ntohl(r2->mask);
+ register u_int32_t o1, o2;
+
+ if (m1 > m2)
+ return (-1);
+ if (m1 < m2)
+ return (1);
+
+ /* masks are equal */
+ o1 = ntohl(r1->origin);
+ o2 = ntohl(r2->origin);
+ if (o1 > o2)
+ return (-1);
+ if (o1 < o2)
+ return (1);
+ return (0);
+}
+
+/*
+ * Process an incoming route report message.
+ */
+void
+accept_report(src, dst, p, datalen, level)
+ u_int32_t src, dst, level;
+ register char *p;
+ register int datalen;
+{
+ vifi_t vifi;
+ register int width, i, nrt = 0;
+ int metric;
+ u_int32_t mask;
+ u_int32_t origin;
+ struct newrt rt[4096];
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring route report from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level))
+ return;
+
+ if (datalen > 2*4096) {
+ log(LOG_INFO, 0,
+ "ignoring oversize (%d bytes) route report from %s",
+ datalen, inet_fmt(src, s1));
+ return;
+ }
+
+ while (datalen > 0) { /* Loop through per-mask lists. */
+
+ if (datalen < 3) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+ ((u_char *)&mask)[0] = 0xff; width = 1;
+ if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
+ if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
+ if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
+ datalen -= 3;
+
+ do { /* Loop through (origin, metric) pairs */
+ if (datalen < width + 1) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+ origin = 0;
+ for (i = 0; i < width; ++i)
+ ((char *)&origin)[i] = *p++;
+ metric = *p++;
+ datalen -= width + 1;
+ rt[nrt].mask = mask;
+ rt[nrt].origin = origin;
+ rt[nrt].metric = (metric & 0x7f);
+ ++nrt;
+ } while (!(metric & 0x80));
+ }
+ qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
+ start_route_updates();
+ /*
+ * If the last entry is default, change mask from 0xff000000 to 0
+ */
+ if (rt[nrt-1].origin == 0)
+ rt[nrt-1].mask = 0;
+
+ log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+ for (i = 0; i < nrt; ++i)
+ update_route(rt[i].origin, rt[i].mask, rt[i].metric,
+ src, vifi);
+
+ if (routes_changed && !delay_change_reports)
+ report_to_all_neighbors(CHANGED_ROUTES);
+}
+
+
+/*
+ * Send a route report message to destination 'dst', via virtual interface
+ * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void
+report(which_routes, vifi, dst)
+ int which_routes;
+ vifi_t vifi;
+ u_int32_t dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ int datalen;
+ int width;
+ u_int32_t mask;
+ u_int32_t src;
+ u_int32_t nflags;
+
+ src = uvifs[vifi].uv_lcl_addr;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+#ifdef NOTYET
+ /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
+ if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
+ *p++ = 0; /* 0xff000000 mask */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0; /* class A net 0.0.0.0 == default */
+ *p++ = 0x81; /*XXX metric 1, is this safe? */
+ datalen += 5;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+ return;
+ }
+#endif
+
+ nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
+
+ for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
+
+ if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
+ continue;
+
+ /*
+ * If there is no room for this route in the current message,
+ * send the message and start a new one.
+ */
+ if (datalen + ((r->rt_originmask == mask) ?
+ (width + 1) :
+ (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL | nflags), datalen);
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+ }
+
+ if(r->rt_originmask != mask) {
+ mask = r->rt_originmask;
+ width = r->rt_originwidth;
+ if (datalen != 0) *(p-1) |= 0x80;
+ *p++ = ((char *)&mask)[1];
+ *p++ = ((char *)&mask)[2];
+ *p++ = ((char *)&mask)[3];
+ datalen += 3;
+ }
+
+ for (i = 0; i < width; ++i)
+ *p++ = ((char *)&(r->rt_origin))[i];
+
+ *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
+ (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
+ (char)(r->rt_metric);
+
+ datalen += width + 1;
+ }
+
+ if (datalen != 0) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL | nflags), datalen);
+ }
+}
+
+
+/*
+ * Send a route report message to all neighboring routers.
+ * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void
+report_to_all_neighbors(which_routes)
+ int which_routes;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct rtentry *r;
+ int routes_changed_before;
+
+ /*
+ * Remember the state of the global routes_changed flag before
+ * generating the reports, and clear the flag.
+ */
+ routes_changed_before = routes_changed;
+ routes_changed = FALSE;
+
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_neighbors != NULL) {
+ report(which_routes, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group);
+ }
+ }
+
+ /*
+ * If there were changed routes before we sent the reports AND
+ * if no new changes occurred while sending the reports, clear
+ * the change flags in the individual route entries. If changes
+ * did occur while sending the reports, new reports will be
+ * generated at the next timer interrupt.
+ */
+ if (routes_changed_before && !routes_changed) {
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_flags &= ~RTF_CHANGED;
+ }
+ }
+
+ /*
+ * Set a flag to inhibit further reports of changed routes until the
+ * next timer interrupt. This is to alleviate update storms.
+ */
+ delay_change_reports = TRUE;
+}
+
+/*
+ * Send a route report message to destination 'dst', via virtual interface
+ * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+int
+report_chunk(start_rt, vifi, dst)
+ register struct rtentry *start_rt;
+ vifi_t vifi;
+ u_int32_t dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ register int nrt = 0;
+ int datalen;
+ int width;
+ u_int32_t mask;
+ u_int32_t src;
+ u_int32_t nflags;
+
+ src = uvifs[vifi].uv_lcl_addr;
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+ nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
+
+ for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
+
+#ifdef NOTYET
+ /* Don't send poisoned routes back to parents if I am a leaf */
+ if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
+ && (r->rt_metric > 1)) {
+ ++nrt;
+ continue;
+ }
+#endif
+
+ /*
+ * If there is no room for this route in the current message,
+ * send it & return how many routes we sent.
+ */
+ if (datalen + ((r->rt_originmask == mask) ?
+ (width + 1) :
+ (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL | nflags), datalen);
+ return (nrt);
+ }
+ if(r->rt_originmask != mask) {
+ mask = r->rt_originmask;
+ width = r->rt_originwidth;
+ if (datalen != 0) *(p-1) |= 0x80;
+ *p++ = ((char *)&mask)[1];
+ *p++ = ((char *)&mask)[2];
+ *p++ = ((char *)&mask)[3];
+ datalen += 3;
+ }
+ for (i = 0; i < width; ++i)
+ *p++ = ((char *)&(r->rt_origin))[i];
+
+ *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
+ (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
+ (char)(r->rt_metric);
+ ++nrt;
+ datalen += width + 1;
+ }
+ if (datalen != 0) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL | nflags), datalen);
+ }
+ return (nrt);
+}
+
+/*
+ * send the next chunk of our routing table to all neighbors.
+ * return the length of the smallest chunk we sent out.
+ */
+int
+report_next_chunk()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct rtentry *sr;
+ register int i, n = 0, min = 20000;
+ static int start_rt;
+
+ if (nroutes <= 0)
+ return (0);
+
+ /*
+ * find this round's starting route.
+ */
+ for (sr = rt_end, i = start_rt; --i >= 0; ) {
+ sr = sr->rt_prev;
+ if (sr == RT_ADDR)
+ sr = rt_end;
+ }
+
+ /*
+ * send one chunk of routes starting at this round's start to
+ * all our neighbors.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if ((v->uv_neighbors != NULL)
+#ifdef NOTYET
+ && !(v->uv_flags & VIFF_LEAF)
+#endif
+ ) {
+ n = report_chunk(sr, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group);
+ if (n < min)
+ min = n;
+ }
+ }
+ if (min == 20000)
+ min = 0; /* Neighborless router didn't send any routes */
+
+ n = min;
+ log(LOG_INFO, 0, "update %d starting at %d of %d",
+ n, (nroutes - start_rt), nroutes);
+
+ start_rt = (start_rt + n) % nroutes;
+ return (n);
+}
+
+
+/*
+ * Print the contents of the routing table on file 'fp'.
+ */
+void
+dump_routes(fp)
+ FILE *fp;
+{
+ register struct rtentry *r;
+ register int i;
+ register time_t thyme = time(0);
+
+
+ fprintf(fp,
+ "Multicast Routing Table (%u %s)\n%s\n",
+ nroutes, (nroutes == 1) ? "entry" : "entries",
+ " Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs");
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ fprintf(fp, " %-18s %-15s ",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
+
+ fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
+ r->rt_metric);
+
+ fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent);
+
+ for (i = 0; i < numvifs; ++i) {
+ if (VIFM_ISSET(i, r->rt_children)) {
+ fprintf(fp, " %u%c",
+ i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
+
+struct rtentry *
+determine_route(src)
+ u_int32_t src;
+{
+ struct rtentry *rt;
+
+ for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
+ if (rt->rt_origin == (src & rt->rt_originmask))
+ break;
+ }
+ return rt;
+}
diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h
new file mode 100644
index 00000000000..5bc27b891af
--- /dev/null
+++ b/usr.sbin/mrouted/route.h
@@ -0,0 +1,50 @@
+/* $NetBSD: route.h,v 1.3 1995/10/09 03:51:54 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+/*
+ * Routing Table Entry, one per subnet from which a multicast could originate.
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ *
+ * The Routing Table is stored as a doubly-linked list of these structures,
+ * ordered by decreasing value of rt_originmask and, secondarily, by
+ * decreasing value of rt_origin within each rt_originmask value.
+ * This data structure is efficient for generating route reports, whether
+ * full or partial, for processing received full reports, for clearing the
+ * CHANGED flags, and for periodically advancing the timers in all routes.
+ * It is not so efficient for updating a small number of routes in response
+ * to a partial report. In a stable topology, the latter are rare; if they
+ * turn out to be costing a lot, we can add an auxiliary hash table for
+ * faster access to arbitrary route entries.
+ */
+struct rtentry {
+ struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
+ u_int32_t rt_origin; /* subnet origin of multicasts */
+ u_int32_t rt_originmask; /* subnet mask for origin */
+ short rt_originwidth; /* # bytes of origin subnet number */
+ u_char rt_metric; /* cost of route back to origin */
+ u_char rt_flags; /* RTF_ flags defined below */
+ u_int32_t rt_gateway; /* first-hop gateway back to origin */
+ vifi_t rt_parent; /* incoming vif (ie towards origin) */
+ vifbitmap_t rt_children; /* outgoing children vifs */
+ vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
+ u_int32_t *rt_dominants; /* per vif dominant gateways */
+ u_int32_t *rt_subordinates; /* per vif subordinate gateways */
+ u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
+ u_long rt_timer; /* for timing out the route entry */
+ struct rtentry *rt_prev; /* link to previous entry */
+ struct gtable *rt_groups; /* link to active groups */
+};
+
+#define RTF_CHANGED 0x01 /* route changed but not reported */
+#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
+
+#define ALL_ROUTES 0 /* possible arguments to report() */
+#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c
new file mode 100644
index 00000000000..f5b41955ea4
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.c
@@ -0,0 +1,366 @@
+/* $NetBSD: rsrr.c,v 1.2 1995/10/09 03:51:56 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1993 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation. and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+
+/* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
+ * April 1995.
+ */
+
+#ifdef RSRR
+
+#include "defs.h"
+
+/* Taken from prune.c */
+/*
+ * checks for scoped multicast addresses
+ */
+#define GET_SCOPE(gt) { \
+ register int _i; \
+ if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
+ VIFM_SET(_i, (gt)->gt_scope); \
+ }
+
+/*
+ * Exported variables.
+ */
+int rsrr_socket; /* interface to reservation protocol */
+
+/*
+ * Global RSRR variables.
+ */
+char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
+char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
+
+/*
+ * Procedure definitions needed internally.
+ */
+void rsrr_accept();
+void rsrr_send();
+void rsrr_accept_iq();
+void rsrr_accept_rq();
+
+/* Initialize RSRR socket */
+void
+rsrr_init()
+{
+ int servlen;
+ struct sockaddr_un serv_addr;
+
+ if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "Can't create RSRR socket");
+
+ unlink(RSRR_SERV_PATH);
+ bzero((char *) &serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
+ servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
+
+ if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
+ log(LOG_ERR, errno, "Can't bind RSRR socket");
+
+ if (register_input_handler(rsrr_socket,rsrr_read) < 0)
+ log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
+}
+
+/* Read a message from the RSRR socket */
+void
+rsrr_read()
+{
+ register int rsrr_recvlen;
+ struct sockaddr_un client_addr;
+ int client_length = sizeof(client_addr);
+ register int omask;
+
+ bzero((char *) &client_addr, sizeof(client_addr));
+ rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
+ 0, &client_addr, &client_length);
+ if (rsrr_recvlen < 0) {
+ if (errno != EINTR)
+ log(LOG_ERR, errno, "RSRR recvfrom");
+ return;
+ }
+ /* Use of omask taken from main() */
+ omask = sigblock(sigmask(SIGALRM));
+ rsrr_accept(rsrr_recvlen,&client_addr,client_length);
+ (void)sigsetmask(omask);
+}
+
+/* Accept a message from the reservation protocol and take
+ * appropriate action.
+ */
+void
+rsrr_accept(recvlen,client_addr,client_length)
+ int recvlen;
+ struct sockaddr_un *client_addr;
+ int client_length;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rq *route_query;
+
+ if (recvlen < RSRR_HEADER_LEN) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet of %d bytes, which is less than min size",
+ recvlen);
+ return;
+ }
+
+ rsrr = (struct rsrr_header *) rsrr_recv_buf;
+
+ if (rsrr->version > RSRR_MAX_VERSION) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ return;
+ }
+
+ switch (rsrr->version) {
+ case 1:
+ switch (rsrr->type) {
+ case RSRR_INITIAL_QUERY:
+ /* Send Initial Reply to client */
+ log(LOG_INFO, 0, "Received Initial Query\n");
+ rsrr_accept_iq(client_addr,client_length);
+ break;
+ case RSRR_ROUTE_QUERY:
+ /* Check size */
+ if (recvlen < RSRR_RQ_LEN) {
+ log(LOG_WARNING, 0,
+ "Received Route Query of %d bytes, which is too small",
+ recvlen);
+ break;
+ }
+ /* Get the query */
+ route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
+ log(LOG_INFO, 0,
+ "Received Route Query for src %s grp %s notification %d",
+ inet_fmt(route_query->source_addr.s_addr, s1),
+ inet_fmt(route_query->dest_addr.s_addr,s2),
+ BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
+ /* Send Route Reply to client */
+ rsrr_accept_rq(rsrr,route_query,client_addr,client_length);
+ break;
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet type %d, which I don't handle",
+ rsrr->type);
+ break;
+ }
+ break;
+
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ break;
+ }
+}
+
+/* Send an Initial Reply to the reservation protocol. */
+void
+rsrr_accept_iq(client_addr,client_length)
+ struct sockaddr_un *client_addr;
+ int client_length;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_vif *vif_list;
+ struct uvif *v;
+ int vifi, sendlen;
+
+ /* Check for space. There should be room for plenty of vifs,
+ * but we should check anyway.
+ */
+ if (numvifs > RSRR_MAX_VIFS) {
+ log(LOG_WARNING, 0,
+ "Can't send RSRR Route Reply because %d is too many vifs %d",
+ numvifs);
+ return;
+ }
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_INITIAL_REPLY;
+ rsrr->flags = 0;
+ rsrr->num = numvifs;
+
+ vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
+
+ /* Include the vif list. */
+ for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ vif_list[vifi].id = vifi;
+ vif_list[vifi].status = 0;
+ if (v->uv_flags & VIFF_DISABLED)
+ BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
+ vif_list[vifi].threshold = v->uv_threshold;
+ vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
+ }
+
+ /* Get the size. */
+ sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
+
+ /* Send it. */
+ log(LOG_INFO, 0, "Send RSRR Initial Reply");
+ rsrr_send(sendlen,client_addr,client_length);
+}
+
+/* Send a Route Reply to the reservation protocol. */
+void
+rsrr_accept_rq(rsrr_in,route_query,client_addr,client_length)
+ struct rsrr_header *rsrr_in;
+ struct rsrr_rq *route_query;
+ struct sockaddr_un *client_addr;
+ int client_length;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rr *route_reply;
+ struct gtable *gt,local_g;
+ struct rtentry *r;
+ int sendlen,i;
+ u_long mcastgrp;
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_ROUTE_REPLY;
+ rsrr->flags = rsrr_in->flags;
+ rsrr->num = 0;
+
+ route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
+ route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
+ route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
+ route_reply->query_id = route_query->query_id;
+
+ /* Blank routing entry for error. */
+ route_reply->in_vif = 0;
+ route_reply->reserved = 0;
+ route_reply->out_vif_bm = 0;
+
+ /* Clear error bit. */
+ BIT_CLR(rsrr->flags,RSRR_ERROR_BIT);
+ /* Turn notification off. We don't do it yet. */
+ BIT_CLR(rsrr->flags,RSRR_NOTIFICATION_BIT);
+
+ /* First check kernel. Code taken from add_table_entry() */
+ if (find_src_grp(route_query->source_addr.s_addr, 0,
+ route_query->dest_addr.s_addr)) {
+ gt = gtp ? gtp->gt_gnext : kernel_table;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ } else {
+ /* No kernel entry; use routing table. */
+ r = determine_route(route_query->source_addr.s_addr);
+
+ if (r != NULL) {
+ /* We need to mimic what will happen if a data packet
+ * is forwarded by multicast routing -- the kernel will
+ * make an upcall and mrouted will install a route in the kernel.
+ * Our outgoing vif bitmap should reflect what that table
+ * will look like. Grab code from add_table_entry().
+ * This is gross, but it's probably better to be accurate.
+ */
+
+ gt = &local_g;
+ mcastgrp = route_query->dest_addr.s_addr;
+
+ gt->gt_mcastgrp = mcastgrp;
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
+ gt->gt_route = r;
+
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
+ }
+
+ GET_SCOPE(gt);
+ gt->gt_grpmems &= ~gt->gt_scope;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ } else {
+ /* Set error bit. */
+ BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
+ }
+ }
+
+ /* Get the size. */
+ sendlen = RSRR_RR_LEN;
+
+ log(LOG_INFO, 0, "Send RSRR Route Reply for src %s grp %s ",
+ inet_fmt(route_reply->source_addr.s_addr,s1),
+ inet_fmt(route_reply->dest_addr.s_addr,s2));
+ log(LOG_INFO, 0, "in vif %d out vif %d\n",
+ route_reply->in_vif,route_reply->out_vif_bm);
+
+ /* Send it. */
+ rsrr_send(sendlen,client_addr,client_length);
+}
+
+/* Send an RSRR message. */
+void
+rsrr_send(sendlen,client_addr,client_length)
+ int sendlen;
+ struct sockaddr_un *client_addr;
+ int client_length;
+{
+ int error;
+
+ /* Send it. */
+ error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
+ *client_addr, client_length);
+
+ /* Check for errors. */
+ if (error < 0) {
+ log(LOG_WARNING, errno, "Failed send on RSRR socket");
+ return;
+ }
+ if (error != sendlen) {
+ log(LOG_WARNING, 0,
+ "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
+ return;
+ }
+}
+
+void
+rsrr_clean()
+{
+ unlink(RSRR_SERV_PATH);
+}
+
+#endif RSRR
diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h
new file mode 100644
index 00000000000..bdbf429714c
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.h
@@ -0,0 +1,140 @@
+/* $NetBSD: rsrr.h,v 1.2 1995/10/09 03:51:57 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1993 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation. and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+
+#define RSRR_SERV_PATH "/tmp/.rsrr_svr"
+/* Note this needs to be 14 chars for 4.3 BSD compatibility */
+#define RSRR_CLI_PATH "/tmp/.rsrr_cli"
+
+#define RSRR_MAX_LEN 2048
+#define RSRR_HEADER_LEN (sizeof(struct rsrr_header))
+#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq))
+#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr))
+#define RSRR_VIF_LEN (sizeof(struct rsrr_vif))
+
+/* Current maximum number of vifs. */
+#define RSRR_MAX_VIFS 32
+
+/* Maximum acceptable version */
+#define RSRR_MAX_VERSION 1
+
+/* RSRR message types */
+#define RSRR_ALL_TYPES 0
+#define RSRR_INITIAL_QUERY 1
+#define RSRR_INITIAL_REPLY 2
+#define RSRR_ROUTE_QUERY 3
+#define RSRR_ROUTE_REPLY 4
+
+/* RSRR Initial Reply (Vif) Status bits
+ * Each definition represents the position of the bit from right to left.
+ *
+ * Right-most bit is the disabled bit, set if the vif is administratively
+ * disabled.
+ */
+#define RSRR_DISABLED_BIT 0
+/* All other bits are zeroes */
+
+/* RSRR Route Query/Reply flag bits
+ * Each definition represents the position of the bit from right to left.
+ *
+ * Right-most bit is the Route Change Notification bit, set if the
+ * reservation protocol wishes to receive notification of
+ * a route change for the source-destination pair listed in the query.
+ * Notification is in the form of an unsolicitied Route Reply.
+ */
+#define RSRR_NOTIFICATION_BIT 0
+/* Next bit indicates an error returning the Route Reply. */
+#define RSRR_ERROR_BIT 1
+/* All other bits are zeroes */
+
+/* Definition of an RSRR message header.
+ * An Initial Query uses only the header, and an Initial Reply uses
+ * the header and a list of vifs.
+ */
+struct rsrr_header {
+ u_char version; /* RSRR Version, currently 1 */
+ u_char type; /* type of message, as defined above */
+ u_char flags; /* flags; defined by type */
+ u_char num; /* number; defined by type */
+};
+
+/* Definition of a vif as seen by the reservation protocol.
+ *
+ * Routing gives the reservation protocol a list of vifs in the
+ * Initial Reply.
+ *
+ * We explicitly list the ID because we can't assume that all routing
+ * protocols will use the same numbering scheme.
+ *
+ * The status is a bitmask of status flags, as defined above. It is the
+ * responsibility of the reservation protocol to perform any status checks
+ * if it uses the MULTICAST_VIF socket option.
+ *
+ * The threshold indicates the ttl an outgoing packet needs in order to
+ * be forwarded. The reservation protocol must perform this check itself if
+ * it uses the MULTICAST_VIF socket option.
+ *
+ * The local address is the address of the physical interface over which
+ * packets are sent.
+ */
+struct rsrr_vif {
+ u_char id; /* vif id */
+ u_char threshold; /* vif threshold ttl */
+ u_short status; /* vif status bitmask */
+ struct in_addr local_addr; /* vif local address */
+};
+
+/* Definition of an RSRR Route Query.
+ *
+ * The query asks routing for the forwarding entry for a particular
+ * source and destination. The query ID uniquely identifies the query
+ * for the reservation protocol. Thus, the combination of the client's
+ * address and the query ID forms a unique identifier for routing.
+ * Flags are defined above.
+ */
+struct rsrr_rq {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+};
+
+/* Definition of an RSRR Route Reply.
+ *
+ * Routing uses the reply to give the reservation protocol the
+ * forwarding entry for a source-destination pair. Routing copies the
+ * query ID from the query and fills in the incoming vif and a bitmask
+ * of the outgoing vifs.
+ * Flags are defined above.
+ */
+struct rsrr_rr {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+ u_short in_vif; /* incoming vif */
+ u_short reserved; /* reserved */
+ u_long out_vif_bm; /* outgoing vif bitmask */
+};
diff --git a/usr.sbin/mrouted/snmp.c b/usr.sbin/mrouted/snmp.c
new file mode 100644
index 00000000000..5298da5dbc8
--- /dev/null
+++ b/usr.sbin/mrouted/snmp.c
@@ -0,0 +1,1307 @@
+/* $NetBSD: snmp.c,v 1.2 1995/10/09 03:51:58 thorpej Exp $ */
+
+/*
+ * snmp.c
+ *
+ * Code written by David Thaler <thalerd@eecs.umich.edu>
+ * Moved to a seperate file by Bill Fenner <fenner@parc.xerox.com>
+ */
+
+
+#include "defs.h"
+#include <string.h>
+#include "snmp.h"
+
+#define NUMMIBS 2
+#define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
+
+char *mibs[]={ "ipMRouteMIB", "dvmrpMIB" };
+
+extern int o_ipMRouteTable();
+extern int o_ipMRouteNextHopTable();
+extern int o_dvmrpRouteTable();
+extern int o_dvmrpRouteNextHopTable();
+
+ int smux_fd = NOTOK;
+ int rock_and_roll = 0;
+ int dont_bother_anymore = 0;
+ int quantum = 0;
+static OID subtree[NUMMIBS] = NULLOID;
+static struct smuxEntry *se = NULL;
+extern int smux_errno;
+extern char smux_info[BUFSIZ];
+
+/*
+ * Place an IP address into an OID starting at element n
+ */
+void
+put_address(oid, addr, n)
+ OID oid;
+ u_long addr;
+ int n;
+{
+ int i;
+
+ for (i=n+3; i>=n+0; i--) {
+ oid->oid_elements[i] = addr & 0xFF;
+ addr >>= 8;
+ }
+}
+
+/* Get an IP address from an OID starting at element n */
+int
+get_address(oid, addr, n)
+ OID oid;
+ u_long *addr;
+ int n;
+{
+ int i;
+ int ok = 1;
+
+ (*addr) = 0;
+
+ if (oid -> oid_nelem < n+4)
+ return 0;
+
+ for (i=n; i<n+4; i++) {
+ (*addr) <<= 8;
+ if (i >= oid->oid_nelem)
+ ok = 0;
+ else
+ (*addr) |= oid->oid_elements[i];
+ }
+
+ return ok;
+}
+
+/*
+ * Attempt to start up SMUX protocol
+ */
+void
+try_smux_init()
+{
+ if (smux_fd != NOTOK || dont_bother_anymore)
+ return;
+ if ((smux_fd = smux_init(debug)) == NOTOK) {
+ log(LOG_WARNING, 0,"smux_init: %s [%s]", smux_error(smux_errno),
+ smux_info);
+ } else
+ rock_and_roll = 0;
+}
+
+/*
+ * Implements scalar objects from both MIBs
+ */
+static int
+o_scalar(oi, v, offset)
+ OI oi;
+ register struct type_SNMP_VarBind *v;
+ int offset;
+{
+ int ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid -> oid_nelem !=
+ ot -> ot_name -> oid_nelem + 1
+ || oid -> oid_elements[oid -> oid_nelem - 1]
+ != 0)
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ if (oid -> oid_nelem
+ == ot -> ot_name -> oid_nelem) {
+ OID new;
+
+ if ((new = oid_extend (oid, 1)) == NULLOID)
+ return int_SNMP_error__status_genErr;
+ new -> oid_elements[new -> oid_nelem - 1] = 0;
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+ }
+ else
+ return NOTOK;
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+ case ipMRouteEnable:
+ return o_integer (oi, v, 1);
+
+ case dvmrpVersion: {
+ static char buff[15];
+
+ sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
+ return o_string (oi, v, buff, strlen (buff));
+ }
+
+ case dvmrpGenerationId:
+ return o_integer (oi, v, dvmrp_genid);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Find if a specific scoped boundary exists on a Vif
+ */
+struct vif_acl *
+find_boundary(vifi, addr, mask)
+ int vifi;
+ int addr;
+ int mask;
+{
+ struct vif_acl *n;
+
+ for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
+ if (addr == n->acl_addr && mask==n->acl_mask)
+ return n;
+ }
+ return NULL;
+}
+
+/*
+ * Find the next scoped boundary in order after a given spec
+ */
+struct vif_acl *
+next_boundary(vifi, addr, mask)
+ int *vifi;
+ int addr;
+ int mask;
+{
+ struct vif_acl *bestn, *n;
+ int i;
+
+ for (i = *vifi; i < numvifs; i++) {
+ bestn = NULL;
+ for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
+ if ((i > *vifi || n->acl_addr > addr
+ || (n->acl_addr==addr && n->acl_mask>mask))
+ && (!bestn || n->acl_addr < bestn->acl_addr
+ || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
+ bestn = n;
+ }
+ if (bestn) {
+ *vifi = i;
+ return bestn;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Implements the Boundary Table portion of the DVMRP MIB
+ */
+static int
+o_dvmrpBoundaryTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+{
+ int ifvar, vifi,
+ addr, mask;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct vif_acl *bound;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid->oid_nelem != ot->ot_name->oid_nelem + 9)
+ return int_SNMP_error__status_noSuchName;
+
+ if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
+ return int_SNMP_error__status_noSuchName;
+
+ if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+5))
+ return int_SNMP_error__status_noSuchName;
+
+ if (!(bound = find_boundary(vifi, addr, mask)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ if (oid->oid_nelem < ot->ot_name->oid_nelem + 9) {
+ OID new;
+
+ if (oid->oid_nelem == ot->ot_name->oid_nelem) {
+ vifi = addr = mask = 0;
+ } else {
+ vifi = oid->oid_elements[ot->ot_name->oid_nelem];
+ get_address(oid, &addr, ot->ot_name->oid_nelem+1);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+5);
+ }
+
+ bound = next_boundary(&vifi,addr,mask);
+ if (!bound)
+ return NOTOK;
+
+ new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+ new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
+ put_address(new, bound->acl_addr, ot->ot_name->oid_nelem+1);
+ put_address(new, bound->acl_mask, ot->ot_name->oid_nelem+5);
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+ } else { /* get next entry given previous */
+ int i = ot -> ot_name -> oid_nelem;
+
+ vifi = oid->oid_elements[i];
+ get_address(oid, &addr, ot->ot_name->oid_nelem+1);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+5);
+ if (!(bound = next_boundary(&vifi,addr,mask+1)))
+ return NOTOK;
+
+ put_address(oid, bound->acl_addr, ot->ot_name->oid_nelem+1);
+ put_address(oid, bound->acl_mask, ot->ot_name->oid_nelem+5);
+ oid->oid_elements[i] = vifi;
+ oid->oid_nelem = i + 9;
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+
+ case dvmrpBoundaryVifIndex:
+ return o_integer (oi, v, vifi);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Given a vif index and address, return the next greater neighbor entry
+ */
+struct listaddr *
+next_neighbor(vifi, addr)
+ int *vifi;
+ int addr;
+{
+ struct listaddr *bestn, *n;
+ int i;
+
+ for (i = *vifi; i < numvifs; i++) {
+ bestn = NULL;
+ for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
+ if ((i > *vifi || n->al_addr > addr)
+ && (!bestn || n->al_addr < bestn->al_addr))
+ bestn = n;
+ }
+ if (bestn) {
+ *vifi = i;
+ return bestn;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Find a neighbor, if it exists off a given Vif
+ */
+struct listaddr *
+find_neighbor(vifi, addr)
+ int vifi;
+ int addr;
+{
+ struct listaddr *n;
+
+ for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
+ if (addr == n->al_addr)
+ return n;
+ }
+ return NULL;
+}
+
+/*
+ * Implements the Neighbor Table portion of the DVMRP MIB
+ */
+static int
+o_dvmrpNeighborTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+{
+ int ifvar, vifi,
+ addr;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct listaddr *neighbor;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid->oid_nelem != ot->ot_name->oid_nelem + 5)
+ return int_SNMP_error__status_noSuchName;
+
+ if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
+ return int_SNMP_error__status_noSuchName;
+
+ if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1))
+ return int_SNMP_error__status_noSuchName;
+
+ if (!(neighbor = find_neighbor(vifi, addr)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ if (oid->oid_nelem < ot->ot_name->oid_nelem + 5) {
+ OID new;
+
+ if (oid->oid_nelem == ot->ot_name->oid_nelem) {
+ vifi = addr = 0;
+ } else {
+ vifi = oid->oid_elements[ot->ot_name->oid_nelem];
+ get_address(oid, &addr, ot->ot_name->oid_nelem+1);
+ }
+
+ neighbor = next_neighbor(&vifi,addr); /* Get first entry */
+ if (!neighbor)
+ return NOTOK;
+
+ new = oid_extend (oid, ot->ot_name->oid_nelem+5-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+ new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
+ put_address(new, neighbor->al_addr, ot->ot_name->oid_nelem+1);
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ } else { /* get next entry given previous */
+ int i = ot -> ot_name -> oid_nelem;
+
+ vifi = oid->oid_elements[i];
+ get_address(oid, &addr, ot->ot_name->oid_nelem+1);
+ if (!(neighbor = next_neighbor(&vifi,addr+1)))
+ return NOTOK;
+
+ put_address(oid, neighbor->al_addr, ot->ot_name->oid_nelem+1);
+ oid->oid_elements[i] = vifi;
+ oid->oid_nelem = i + 5;
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+
+ case dvmrpNeighborUpTime: {
+ time_t currtime;
+ time(&currtime);
+ return o_integer (oi, v, (currtime - neighbor->al_ctime)*100);
+ }
+
+ case dvmrpNeighborExpiryTime:
+ return o_integer (oi, v, (NEIGHBOR_EXPIRE_TIME-neighbor->al_timer) * 100);
+
+ case dvmrpNeighborVersion: {
+ static char buff[15];
+
+ sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv);
+ return o_string (oi, v, buff, strlen (buff));
+ }
+
+ case dvmrpNeighborGenerationId:
+ return o_integer (oi, v, neighbor->al_genid);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Given a virtual interface number, make sure we have the current
+ * kernel information for that Vif.
+ */
+refresh_vif(v_req, ifnum)
+ struct sioc_vif_req *v_req;
+ int ifnum;
+{
+ static int lastq = -1;
+
+ if (quantum!=lastq || v_req->vifi != ifnum) {
+ lastq = quantum;
+ v_req->vifi = ifnum;
+ if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
+ v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
+ }
+}
+
+/*
+ * Implements the Multicast Routing Interface Table portion of the Multicast MIB
+ */
+static int
+o_ipMRouteInterfaceTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+int offset;
+{
+ int ifnum,
+ ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+static struct sioc_vif_req v_req;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
+ return int_SNMP_error__status_noSuchName;
+ if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) >= numvifs)
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
+ OID new;
+
+ ifnum = 0;
+
+ if ((new = oid_extend (oid, 1)) == NULLOID)
+ return NOTOK;
+ new -> oid_elements[new -> oid_nelem - 1] = ifnum;
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ } else {
+ int i = ot -> ot_name -> oid_nelem;
+
+ if ((ifnum = oid -> oid_elements[i] + 1) >= numvifs)
+ return NOTOK;
+
+ oid -> oid_elements[i] = ifnum;
+ oid -> oid_nelem = i + 1;
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+ case ipMRouteInterfaceTtl:
+ return o_integer (oi, v, uvifs[ifnum].uv_threshold);
+
+ case dvmrpVInterfaceType:
+ if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
+ return o_integer (oi, v, 2);
+ else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
+ return o_integer (oi, v, 1);
+ else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
+ return o_integer (oi, v, 3);
+ else /* SUBNET */
+ return o_integer (oi, v, 4);
+
+ case dvmrpVInterfaceState:
+ if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
+ return o_integer (oi, v, 3);
+ else if (uvifs[ifnum].uv_flags & VIFF_DOWN)
+ return o_integer (oi, v, 2);
+ else /* UP */
+ return o_integer (oi, v, 1);
+
+ case dvmrpVInterfaceLocalAddress: {
+ struct sockaddr_in tmp;
+ tmp.sin_addr.s_addr = uvifs[ifnum].uv_lcl_addr;
+ return o_ipaddr (oi, v, &tmp);
+ }
+
+ case dvmrpVInterfaceRemoteAddress: {
+ struct sockaddr_in tmp;
+ tmp.sin_addr.s_addr = (uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
+ uvifs[ifnum].uv_rmt_addr :
+ uvifs[ifnum].uv_subnet;
+ return o_ipaddr (oi, v, &tmp);
+ }
+
+ case dvmrpVInterfaceRemoteSubnetMask: {
+ struct sockaddr_in tmp;
+ tmp.sin_addr.s_addr = uvifs[ifnum].uv_subnetmask;
+ return o_ipaddr (oi, v, &tmp);
+ }
+
+ case dvmrpVInterfaceMetric:
+ return o_integer (oi, v, uvifs[ifnum].uv_metric);
+
+ case dvmrpVInterfaceRateLimit:
+ return o_integer (oi, v, uvifs[ifnum].uv_rate_limit);
+
+ case dvmrpVInterfaceInPkts:
+ refresh_vif(&v_req, ifnum);
+ return o_integer(oi, v, v_req.icount);
+
+ case dvmrpVInterfaceOutPkts:
+ refresh_vif(&v_req, ifnum);
+ return o_integer(oi, v, v_req.ocount);
+
+ case dvmrpVInterfaceInOctets:
+ refresh_vif(&v_req, ifnum);
+ return o_integer(oi, v, v_req.ibytes);
+
+ case dvmrpVInterfaceOutOctets:
+ refresh_vif(&v_req, ifnum);
+ return o_integer(oi, v, v_req.obytes);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+struct mib_variable {
+ char *name; /* MIB variable name */
+ int (*function)(); /* Function to call */
+ int info; /* Which variable */
+} mib_vars[] = {
+ "ipMRouteEnable", o_scalar, ipMRouteEnable,
+ "ipMRouteUpstreamNeighbor", o_ipMRouteTable, ipMRouteUpstreamNeighbor,
+ "ipMRouteInIfIndex", o_ipMRouteTable, ipMRouteInIfIndex,
+ "ipMRouteUpTime", o_ipMRouteTable, ipMRouteUpTime,
+ "ipMRouteExpiryTime", o_ipMRouteTable, ipMRouteExpiryTime,
+ "ipMRoutePkts", o_ipMRouteTable, ipMRoutePkts,
+ "ipMRouteDifferentInIfIndexes", o_ipMRouteTable, ipMRouteDifferentInIfIndexes,
+ "ipMRouteOctets", o_ipMRouteTable, ipMRouteOctets,
+ "ipMRouteProtocol", o_ipMRouteTable, ipMRouteProtocol,
+ "ipMRouteNextHopState", o_ipMRouteNextHopTable, ipMRouteNextHopState,
+ "ipMRouteNextHopUpTime", o_ipMRouteNextHopTable, ipMRouteNextHopUpTime,
+ "ipMRouteNextHopExpiryTime", o_ipMRouteNextHopTable, ipMRouteNextHopExpiryTime,
+ "ipMRouteNextHopClosestMemberHops", o_ipMRouteNextHopTable, ipMRouteNextHopClosestMemberHops,
+ "ipMRouteNextHopProtocol", o_ipMRouteNextHopTable, ipMRouteNextHopProtocol,
+ "ipMRouteInterfaceTtl", o_ipMRouteInterfaceTable, ipMRouteInterfaceTtl,
+ "dvmrpVersion", o_scalar, dvmrpVersion,
+ "dvmrpGenerationId", o_scalar, dvmrpGenerationId,
+ "dvmrpVInterfaceType", o_ipMRouteInterfaceTable, dvmrpVInterfaceType,
+ "dvmrpVInterfaceState", o_ipMRouteInterfaceTable, dvmrpVInterfaceState,
+ "dvmrpVInterfaceLocalAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceLocalAddress,
+ "dvmrpVInterfaceRemoteAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteAddress,
+ "dvmrpVInterfaceRemoteSubnetMask", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteSubnetMask,
+ "dvmrpVInterfaceMetric", o_ipMRouteInterfaceTable, dvmrpVInterfaceMetric,
+ "dvmrpVInterfaceRateLimit", o_ipMRouteInterfaceTable, dvmrpVInterfaceRateLimit,
+ "dvmrpVInterfaceInPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceInPkts,
+ "dvmrpVInterfaceOutPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutPkts,
+ "dvmrpVInterfaceInOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceInOctets,
+ "dvmrpVInterfaceOutOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutOctets,
+ "dvmrpNeighborUpTime", o_dvmrpNeighborTable, dvmrpNeighborUpTime,
+ "dvmrpNeighborExpiryTime", o_dvmrpNeighborTable, dvmrpNeighborExpiryTime,
+ "dvmrpNeighborVersion", o_dvmrpNeighborTable, dvmrpNeighborVersion,
+ "dvmrpNeighborGenerationId",o_dvmrpNeighborTable, dvmrpNeighborGenerationId,
+ "dvmrpRouteUpstreamNeighbor", o_dvmrpRouteTable, dvmrpRouteUpstreamNeighbor,
+ "dvmrpRouteInVifIndex", o_dvmrpRouteTable, dvmrpRouteInVifIndex,
+ "dvmrpRouteMetric", o_dvmrpRouteTable, dvmrpRouteMetric,
+ "dvmrpRouteExpiryTime", o_dvmrpRouteTable, dvmrpRouteExpiryTime,
+ "dvmrpRouteNextHopType", o_dvmrpRouteNextHopTable, dvmrpRouteNextHopType,
+ "dvmrpBoundaryVifIndex", o_dvmrpBoundaryTable, dvmrpBoundaryVifIndex,
+ 0, 0, 0
+};
+
+/*
+ * Register variables as part of the MIBs
+ */
+void
+init_mib()
+{
+ register OT ot;
+ int i;
+
+ for (i=0; mib_vars[i].name; i++)
+ if (ot=text2obj(mib_vars[i].name)) {
+ ot->ot_getfnx = mib_vars[i].function;
+ ot->ot_info = (caddr_t)mib_vars[i].info;
+ }
+}
+
+/*
+ * Initialize the SNMP part of mrouted
+ */
+void
+snmp_init()
+{
+ OT ot;
+ int i;
+
+ if (readobjects("mrouted.defs") == NOTOK)
+ log(LOG_ERR, 0, "readobjects: %s", PY_pepy);
+ for (i=0; i < NUMMIBS; i++) {
+ if ((ot = text2obj(mibs[i])) == NULL)
+ log(LOG_ERR, 0, "object \"%s\" not in \"%s\"",
+ mibs[i], "mrouted.defs");
+ subtree[i] = ot -> ot_name;
+ }
+ init_mib();
+ try_smux_init();
+}
+
+/*
+ * Process an SNMP "get" or "get-next" request
+ */
+static
+get_smux (pdu, offset)
+ register struct type_SNMP_GetRequest__PDU *pdu;
+ int offset;
+{
+ int idx,
+ status;
+ object_instance ois;
+ register struct type_SNMP_VarBindList *vp;
+ IFP method;
+
+ quantum = pdu -> request__id;
+ idx = 0;
+ for (vp = pdu -> variable__bindings; vp; vp = vp -> next) {
+ register OI oi;
+ register OT ot;
+ register struct type_SNMP_VarBind *v = vp -> VarBind;
+
+ idx++;
+
+ if (offset == type_SNMP_SMUX__PDUs_get__next__request) {
+ if ((oi = name2inst (v -> name)) == NULLOI
+ && (oi = next2inst (v -> name)) == NULLOI)
+ goto no_name;
+
+ if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP)
+ goto get_next;
+ }
+ else
+ if ((oi = name2inst (v -> name)) == NULLOI
+ || (ot = oi -> oi_type) -> ot_getfnx
+ == NULLIFP) {
+no_name: ;
+ pdu -> error__status =
+ int_SNMP_error__status_noSuchName;
+ goto out;
+ }
+
+try_again: ;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (!(method = ot -> ot_getfnx))
+ goto no_name;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ if (!(method = ot -> ot_getfnx))
+ goto get_next;
+ break;
+
+ case type_SNMP_SMUX__PDUs_set__request:
+ if (!(method = ot -> ot_setfnx))
+ goto no_name;
+ break;
+
+ default:
+ goto no_name;
+ }
+
+ switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
+ case NOTOK: /* get-next wants a bump */
+get_next: ;
+ oi = &ois;
+ for (;;) {
+ if ((ot = ot -> ot_next) == NULLOT) {
+ pdu -> error__status =
+ int_SNMP_error__status_noSuchName;
+ goto out;
+ }
+ oi -> oi_name =
+ (oi -> oi_type = ot) -> ot_name;
+ if (ot -> ot_getfnx)
+ goto try_again;
+ }
+
+ case int_SNMP_error__status_noError:
+ break;
+
+ default:
+ pdu -> error__status = status;
+ goto out;
+ }
+ }
+ idx = 0;
+
+out: ;
+ pdu -> error__index = idx;
+
+ if (smux_response (pdu) == NOTOK) {
+ log(LOG_WARNING,0,"smux_response: %s [%s]",
+ smux_error (smux_errno), smux_info);
+ smux_fd = NOTOK;
+ }
+}
+
+/*
+ * Handle SNMP "set" request by replying that it is illegal
+ */
+static
+set_smux(event)
+ struct type_SNMP_SMUX__PDUs *event;
+{
+ switch (event -> offset) {
+ case type_SNMP_SMUX__PDUs_set__request:
+ {
+ register struct type_SNMP_GetResponse__PDU *pdu =
+ event -> un.get__response;
+
+ pdu -> error__status = int_SNMP_error__status_noSuchName;
+ pdu -> error__index = pdu -> variable__bindings ? 1 : 0;
+
+ if (smux_response (pdu) == NOTOK) {
+ log(LOG_WARNING, 0,
+ "smux_response: %s [%s]",
+ smux_error (smux_errno),
+ smux_info);
+ smux_fd = NOTOK;
+ }
+ }
+ break;
+
+ case type_SNMP_SMUX__PDUs_commitOrRollback:
+ {
+ struct type_SNMP_SOutPDU *cor =
+ event -> un.commitOrRollback;
+
+ if (cor -> parm == int_SNMP_SOutPDU_commit) {
+ /* "should not happen" */
+ (void) smux_close (protocolError);
+ smux_fd = NOTOK;
+ }
+ }
+ break;
+ }
+}
+
+/*
+ * Handle an incoming SNMP message
+ */
+void
+doit_smux()
+{
+ struct type_SNMP_SMUX__PDUs *event;
+
+ if (smux_wait(&event, NOTOK)==NOTOK) {
+ if (smux_errno==inProgress)
+ return;
+ log(LOG_WARNING, 0, "smux_wait: %s [%s]", smux_error(smux_errno),
+ smux_info);
+ smux_fd = NOTOK;
+ return;
+ }
+
+ switch (event -> offset) {
+ case type_SNMP_SMUX__PDUs_registerResponse:
+ {
+ struct type_SNMP_RRspPDU *rsp =
+ event -> un.registerResponse;
+
+ if (rsp -> parm == int_SNMP_RRspPDU_failure) {
+ log(LOG_WARNING,0,"SMUX registration of subtree failed");
+ dont_bother_anymore = 1;
+ (void) smux_close (goingDown);
+ break;
+ }
+ }
+ if (smux_trap(NULLOID, int_SNMP_generic__trap_coldStart, 0,
+ (struct type_SNMP_VarBindList *)0) == NOTOK) {
+ log(LOG_WARNING,0,"smux_trap: %s [%s]", smux_error (smux_errno),
+ smux_info);
+ break;
+ }
+ return;
+
+ case type_SNMP_SMUX__PDUs_get__request:
+ case type_SNMP_SMUX__PDUs_get__next__request:
+ get_smux (event -> un.get__request, event -> offset);
+ return;
+
+ case type_SNMP_SMUX__PDUs_close:
+ log(LOG_WARNING, 0, "SMUX close: %s",
+ smux_error (event -> un.close -> parm));
+ break;
+
+ case type_SNMP_SMUX__PDUs_set__request:
+ case type_SNMP_SMUX__PDUs_commitOrRollback:
+ set_smux (event);
+ return;
+
+ default:
+ log(LOG_WARNING,0,"bad SMUX operation: %d", event -> offset);
+ (void) smux_close (protocolError);
+ break;
+ }
+ smux_fd = NOTOK;
+}
+
+/*
+ * Inform snmpd that we are here and handling our MIBs
+ */
+void
+start_smux()
+{
+ int i;
+
+ for (i=0; i<NUMMIBS; i++) {
+ if ((se = getsmuxEntrybyname (mibs[i])) == NULL) {
+ log(LOG_WARNING,0,"no SMUX entry for \"%s\"", mibs[i]);
+ return;
+ }
+
+ /* Only open a new connection the first time through */
+ if (!i) {
+ if (smux_simple_open(&se->se_identity, mibs[i],
+ se->se_password, strlen(se->se_password))==NOTOK) {
+ if (smux_errno == inProgress)
+ return;
+
+ log(LOG_WARNING, 0,"smux_simple_open: %s [%s]",
+ smux_error(smux_errno), smux_info);
+ smux_fd = NOTOK;
+ return;
+ }
+ log(LOG_NOTICE,0, "SMUX open: %s \"%s\"",
+ oid2ode (&se->se_identity), se->se_name);
+ rock_and_roll = 1;
+ }
+
+ if (smux_register(subtree[i], -1, readWrite)==NOTOK) {
+ log(LOG_WARNING, 0,"smux_register: %s [%s]", smux_error(smux_errno),
+ smux_info);
+ smux_fd = NOTOK;
+ return;
+ }
+ }
+ log(LOG_NOTICE, 0, "SMUX registered");
+}
+
+/*
+ * Implements the DVMRP Route Table portion of the DVMRP MIB
+ */
+int
+o_dvmrpRouteTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+int offset;
+{
+ u_long src, mask;
+ int ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct rtentry *rt = NULL;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (!get_address(oid, &src, ot->ot_name->oid_nelem)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
+ || !(rt = snmp_find_route(src,mask)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+
+ /* Check if we're requesting the first row */
+ if (oid->oid_nelem < ot->ot_name->oid_nelem+8) {
+ OID new;
+
+ /* Get partial specification (if any) */
+ get_address(oid, &src, ot->ot_name->oid_nelem);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+4);
+
+ if (!next_route(&rt,src,mask)) /* Get first entry */
+ return NOTOK;
+
+ /* Extend by 8 more ints to hold index columns */
+ new = oid_extend (oid, ot->ot_name->oid_nelem+8-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+
+ put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
+ put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ /* Else we start from a previous row */
+ } else {
+ int i = ot -> ot_name -> oid_nelem;
+
+ /* Get the lowest entry in the table > the given grp/src/mask */
+ get_address(oid, &src, ot->ot_name->oid_nelem);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+4);
+ if (!next_route(&rt, src,mask))
+ return NOTOK;
+
+ put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
+ put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+ case dvmrpRouteUpstreamNeighbor: {
+ struct sockaddr_in tmp;
+ tmp.sin_addr.s_addr = rt->rt_gateway;
+ return o_ipaddr (oi, v, &tmp);
+ }
+
+ case dvmrpRouteInVifIndex:
+ return o_integer (oi, v, rt->rt_parent);
+
+ case dvmrpRouteMetric:
+ return o_integer (oi, v, rt->rt_metric);
+
+ case dvmrpRouteExpiryTime:
+ return o_integer (oi, v, rt->rt_timer*100);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
+ */
+int
+o_dvmrpRouteNextHopTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+int offset;
+{
+ u_long src, mask;
+ vifi_t vifi;
+ int ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct rtentry *rt = NULL;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid->oid_nelem != ot->ot_name->oid_nelem+9)
+ return int_SNMP_error__status_noSuchName;
+
+ if (!get_address(oid, &src, ot->ot_name->oid_nelem)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
+ || (!(rt=snmp_find_route(src,mask))))
+ return int_SNMP_error__status_noSuchName;
+
+ vifi = oid->oid_elements[ot->ot_name->oid_nelem+8];
+ if (!(VIFM_ISSET(vifi, rt->rt_children)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+
+ /* Check if we're requesting the first row */
+ if (oid->oid_nelem < ot->ot_name->oid_nelem+9) {
+ OID new;
+
+ get_address(oid, &src, ot->ot_name->oid_nelem);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+4);
+
+ /* Find first child vif */
+ vifi=0;
+ if (!next_route_child(&rt, src, mask, &vifi))
+ return NOTOK;
+
+ /* Extend by 9 more ints to hold index columns */
+ new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+
+ put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
+ put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
+ new->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ /* Else we start from a previous row */
+ } else {
+ int i = ot -> ot_name -> oid_nelem;
+
+ /* Get the lowest entry in the table > the given grp/src/mask */
+ vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
+ if (!get_address(oid, &src, ot->ot_name->oid_nelem)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
+ || !next_route_child(&rt, src, mask, &vifi))
+ return NOTOK;
+
+ put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
+ put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
+ oid->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+
+ case dvmrpRouteNextHopType:
+ return o_integer (oi, v, (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Implements the IP Multicast Route Table portion of the Multicast MIB
+ */
+int
+o_ipMRouteTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+int offset;
+{
+ u_long src, grp, mask;
+ int ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct gtable *gt = NULL;
+ struct stable *st = NULL;
+static struct sioc_sg_req sg_req;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
+ || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
+ || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
+ || !(gt = find_grp(grp))
+ || !(st = find_grp_src(gt,src)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+
+ /* Check if we're requesting the first row */
+ if (oid->oid_nelem < ot->ot_name->oid_nelem+12) {
+ OID new;
+
+ /* Get partial specification (if any) */
+ get_address(oid, &grp, ot->ot_name->oid_nelem);
+ get_address(oid, &src, ot->ot_name->oid_nelem+4);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+8);
+
+ if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
+ return NOTOK;
+
+ /* Extend by 12 more ints to hold index columns */
+ new = oid_extend (oid, ot->ot_name->oid_nelem+12-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+
+ put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
+ put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
+ put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ /* Else we start from a previous row */
+ } else {
+ int i = ot -> ot_name -> oid_nelem;
+
+ /* Get the lowest entry in the table > the given grp/src/mask */
+ get_address(oid, &grp, ot->ot_name->oid_nelem);
+ get_address(oid, &src, ot->ot_name->oid_nelem+4);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+8);
+ if (!next_grp_src_mask(&gt, &st, grp,src,mask))
+ return NOTOK;
+
+ put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
+ put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
+ put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+ case ipMRouteUpstreamNeighbor: {
+ struct sockaddr_in tmp;
+ tmp.sin_addr.s_addr = gt->gt_route->rt_gateway;
+ return o_ipaddr (oi, v, &tmp);
+ }
+
+ case ipMRouteInIfIndex:
+ return o_integer (oi, v, gt->gt_route->rt_parent);
+
+ case ipMRouteUpTime: {
+ time_t currtime;
+ time(&currtime);
+ return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
+ }
+
+ case ipMRouteExpiryTime:
+ return o_integer (oi, v, gt->gt_timer*100);
+
+ case ipMRoutePkts:
+ refresh_sg(&sg_req, gt, st);
+ return o_integer (oi, v, sg_req.pktcnt);
+
+ case ipMRouteOctets:
+ refresh_sg(&sg_req, gt, st);
+ return o_integer (oi, v, sg_req.bytecnt);
+
+ case ipMRouteDifferentInIfIndexes:
+ refresh_sg(&sg_req, gt, st);
+ return o_integer (oi, v, sg_req.wrong_if);
+
+ case ipMRouteProtocol:
+ return o_integer (oi, v, 4);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
+
+/*
+ * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
+ * MIB
+ */
+int
+o_ipMRouteNextHopTable (oi, v, offset)
+OI oi;
+register struct type_SNMP_VarBind *v;
+int offset;
+{
+ u_long src, grp, mask, addr;
+ vifi_t vifi;
+ int ifvar;
+ register OID oid = oi -> oi_name;
+ register OT ot = oi -> oi_type;
+ struct gtable *gt;
+ struct stable *st;
+
+ ifvar = (int) ot -> ot_info;
+ switch (offset) {
+ case type_SNMP_SMUX__PDUs_get__request:
+ if (oid->oid_nelem != ot->ot_name->oid_nelem+17)
+ return int_SNMP_error__status_noSuchName;
+
+ if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
+ || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
+ || !get_address(oid, &addr, ot->ot_name->oid_nelem+13)
+ || grp!=addr
+ || mask!=0xFFFFFFFF
+ || (!(gt=find_grp(grp)))
+ || (!(st=find_grp_src(gt,src))))
+ return int_SNMP_error__status_noSuchName;
+
+ vifi = oid->oid_elements[ot->ot_name->oid_nelem+12];
+ if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
+ return int_SNMP_error__status_noSuchName;
+ break;
+
+ case type_SNMP_SMUX__PDUs_get__next__request:
+
+ /* Check if we're requesting the first row */
+ if (oid->oid_nelem < ot->ot_name->oid_nelem+17) {
+ OID new;
+
+ get_address(oid, &grp, ot->ot_name->oid_nelem);
+ get_address(oid, &src, ot->ot_name->oid_nelem+4);
+ get_address(oid, &mask, ot->ot_name->oid_nelem+8);
+
+ /* Find first child vif */
+ vifi=0;
+ if (!next_child(&gt, &st, grp, src, mask, &vifi))
+ return NOTOK;
+
+ /* Extend by 17 more ints to hold index columns */
+ new = oid_extend (oid, ot->ot_name->oid_nelem+17-oid->oid_nelem);
+ if (new == NULLOID)
+ return NOTOK;
+
+ put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
+ put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
+ put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
+ new->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
+ put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
+
+ if (v -> name)
+ free_SNMP_ObjectName (v -> name);
+ v -> name = new;
+
+ /* Else we start from a previous row */
+ } else {
+ int i = ot -> ot_name -> oid_nelem;
+
+ /* Get the lowest entry in the table > the given grp/src/mask */
+ vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
+ if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
+ || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
+ || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
+ || !next_child(&gt, &st, grp, src, mask, &vifi))
+ return NOTOK;
+
+ put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
+ put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
+ put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
+ oid->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
+ put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
+ }
+ break;
+
+ default:
+ return int_SNMP_error__status_genErr;
+ }
+
+ switch (ifvar) {
+
+ case ipMRouteNextHopState:
+ return o_integer (oi, v, (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1);
+
+ /* Currently equal to ipMRouteUpTime */
+ case ipMRouteNextHopUpTime: {
+ time_t currtime;
+ time(&currtime);
+ return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
+ }
+
+ case ipMRouteNextHopExpiryTime:
+ return o_integer (oi, v, gt->gt_prsent_timer);
+
+ case ipMRouteNextHopClosestMemberHops:
+ return o_integer (oi, v, 0);
+
+ case ipMRouteNextHopProtocol:
+ return o_integer (oi, v, 4);
+
+ default:
+ return int_SNMP_error__status_noSuchName;
+ }
+}
diff --git a/usr.sbin/mrouted/snmp.h b/usr.sbin/mrouted/snmp.h
new file mode 100644
index 00000000000..c78c050d6b3
--- /dev/null
+++ b/usr.sbin/mrouted/snmp.h
@@ -0,0 +1,505 @@
+/* $NetBSD: snmp.h,v 1.2 1995/10/09 03:52:00 thorpej Exp $ */
+
+/*
+ * This file contains excepts from ISODE include files, and is
+ * subject to the following notice:
+ *
+ * The ISODE is not proprietary, but it is not in the public domain. This was
+ * necessary to include a "hold harmless" clause in the release. The upshot
+ * of all this is that anyone can get a copy of the release and do anything
+ * they want with it, but no one takes any responsibility whatsoever for any
+ * (mis)use.
+ */
+
+typedef u_char PElementClass;
+typedef u_char PElementForm;
+typedef u_short PElementID; /* 0..16383 are meaningful (14 bits) */
+typedef int PElementLen;
+typedef u_char *PElementData;
+typedef int (*IFP) ();
+#define INTDEF long
+typedef INTDEF integer;
+#undef IP
+typedef int *IP;
+#define NULLIP ((IP) 0)
+#define NULLIFP ((IFP) 0)
+#define NULLFD ((fd_set *) 0)
+#define NULLCP ((char *) 0)
+#define NULLVP ((char **) 0)
+
+#ifndef SFD
+#if !defined(SVR3) && !defined(SUNOS4) && !defined(BSD44) && !defined(ultrix)
+#define SFD int
+#define SFP IFP
+#else
+#define SFD void
+#define SFP VFP
+#endif
+#endif
+
+typedef struct {
+ int pe_type; /* Type of entry */
+ integer pe_ucode; /* index to user's code if any */
+ int pe_tag; /* Tag of this entry if any */
+ int pe_flags; /* Flags */
+} tpe;
+
+typedef struct {
+ int pe_type; /* Type of entry */
+ integer pe_ucode; /* index to user's code if any */
+ int pe_tag; /* Tag of this entry if any */
+ int pe_flags; /* Flags */
+ char **pe_typename; /* User defined name of variable */
+} ptpe;
+
+typedef struct {
+ char *md_name; /* Name of this module */
+ int md_nentries; /* Number of entries */
+ tpe **md_etab; /* Pointer to encoding tables */
+ tpe **md_dtab; /* Pointer to decoding tables */
+ ptpe **md_ptab; /* Pointer to printing tables */
+ int (*md_eucode)(); /* User code for encoding */
+ int (*md_ducode)(); /* User code for decoding */
+ int (*md_pucode)(); /* User code for printing */
+ caddr_t *md_ptrtab; /* pointer table */
+} modtyp;
+
+#define type_SNMP_ObjectSyntax PElement
+typedef struct PElement {
+ int pe_errno; /* Error codes */
+ int pe_context; /* indirect reference */
+ PElementClass pe_class;
+#define PE_CLASS_UNIV 0x0 /* Universal */
+ PElementForm pe_form;
+#define PE_FORM_PRIM 0x0 /* PRIMitive */
+ PElementID pe_id; /* should be extensible, 14 bits for now */
+#define PE_PRIM_NULL 0x005 /* Null */
+ PElementLen pe_len;
+ PElementLen pe_ilen;
+ union {
+ PElementData un_pe_prim; /* PRIMitive value */
+ struct PElement *un_pe_cons; /* CONStructor head */
+ } pe_un1;
+ union {
+ int un_pe_cardinal; /* cardinality of list */
+ int un_pe_nbits; /* number of bits in string */
+ } pe_un2;
+ int pe_inline; /* for "ultra-efficient" PElements */
+ char *pe_realbase; /* .. */
+ int pe_offset; /* offset of element in sequence */
+ struct PElement *pe_next;
+ int pe_refcnt; /* hack for ANYs in pepy */
+} *PE;
+#define NULLPE ((PE) 0)
+
+typedef struct OIDentifier {
+ int oid_nelem; /* number of sub-identifiers */
+
+ unsigned int *oid_elements; /* the (ordered) list of sub-identifiers */
+} OIDentifier, *OID;
+#define NULLOID ((OID) 0)
+#define type_SNMP_ObjectName OIDentifier
+
+typedef struct object_syntax {
+ char *os_name; /* syntax name */
+ IFP os_encode; /* data -> PE */
+ IFP os_decode; /* PE -> data */
+ IFP os_free; /* free data */
+ IFP os_parse; /* str -> data */
+ IFP os_print; /* data -> tty */
+ char **os_data1; /* for moresyntax() in snmpi... */
+ int os_data2; /* .. */
+} *OS;
+
+typedef struct object_type {
+ char *ot_text; /* OBJECT DESCRIPTOR */
+ char *ot_id; /* OBJECT IDENTIFIER */
+ OID ot_name; /* .. */
+ OS ot_syntax; /* SYNTAX */
+ int ot_access; /* ACCESS */
+ u_long ot_views; /* for views */
+ int ot_status; /* STATUS */
+ caddr_t ot_info; /* object information */
+ IFP ot_getfnx; /* get/get-next method */
+ IFP ot_setfnx; /* set method */
+ caddr_t ot_save; /* for set method */
+ caddr_t ot_smux; /* for SMUX */
+ struct object_type *ot_chain; /* hash-bucket for text2obj */
+ struct object_type *ot_sibling; /* linked-list for name2obj */
+ struct object_type *ot_children; /* .. */
+ struct object_type *ot_next; /* linked-list for get-next */
+} *OT;
+#define NULLOT ((OT) 0)
+
+typedef struct object_instance {
+ OID oi_name; /* instance OID */
+ OT oi_type; /* prototype */
+} object_instance, *OI;
+#define NULLOI ((OI) 0)
+
+struct type_SNMP_VarBind {
+ struct type_SNMP_ObjectName *name;
+ struct type_SNMP_ObjectSyntax *value;
+};
+
+struct type_SNMP_VarBindList {
+ struct type_SNMP_VarBind *VarBind;
+ struct type_SNMP_VarBindList *next;
+};
+
+#define type_SNMP_GetRequest__PDU type_SNMP_PDU
+#define type_SNMP_GetResponse__PDU type_SNMP_PDU
+struct type_SNMP_PDU {
+ integer request__id;
+ integer error__status;
+#define int_SNMP_error__status_noError 0
+#define int_SNMP_error__status_noSuchName 2
+#define int_SNMP_error__status_genErr 5
+ integer error__index;
+ struct type_SNMP_VarBindList *variable__bindings;
+};
+
+struct type_SNMP_PDUs {
+ int offset;
+#define type_SNMP_PDUs_get__request 1
+#define type_SNMP_PDUs_get__next__request 2
+#define type_SNMP_PDUs_get__response 3
+#define type_SNMP_PDUs_set__request 4
+ union {
+ struct type_SNMP_GetRequest__PDU *get__request;
+ struct type_SNMP_GetNextRequest__PDU *get__next__request;
+ struct type_SNMP_GetResponse__PDU *get__response;
+ struct type_SNMP_SetRequest__PDU *set__request;
+ struct type_SNMP_Trap__PDU *trap;
+ } un;
+};
+
+struct type_SNMP_Message {
+ integer version;
+#define int_SNMP_version_version__1 0
+ struct qbuf *community;
+ struct type_SNMP_PDUs *data;
+};
+
+struct type_SNMP_SMUX__PDUs {
+ int offset;
+#define type_SNMP_SMUX__PDUs_close 2
+#define type_SNMP_SMUX__PDUs_registerResponse 4
+#define type_SNMP_SMUX__PDUs_get__request 5
+#define type_SNMP_SMUX__PDUs_get__next__request 6
+#define type_SNMP_SMUX__PDUs_set__request 8
+#define type_SNMP_SMUX__PDUs_commitOrRollback 10
+ union {
+ struct type_SNMP_SimpleOpen *simple;
+ struct type_SNMP_ClosePDU *close;
+ struct type_SNMP_RReqPDU *registerRequest;
+ struct type_SNMP_RRspPDU *registerResponse;
+ struct type_SNMP_GetRequest__PDU *get__request;
+ struct type_SNMP_GetNextRequest__PDU *get__next__request;
+ struct type_SNMP_GetResponse__PDU *get__response;
+ struct type_SNMP_SetRequest__PDU *set__request;
+ struct type_SNMP_Trap__PDU *trap;
+ struct type_SNMP_SOutPDU *commitOrRollback;
+ } un;
+};
+
+struct type_SNMP_RReqPDU {
+ struct type_SNMP_ObjectName *subtree;
+ integer priority;
+ integer operation;
+#define int_SNMP_operation_readWrite 2
+};
+
+struct type_SNMP_ClosePDU {
+ integer parm;
+#define int_SNMP_ClosePDU_goingDown 0
+#define int_SNMP_ClosePDU_protocolError 3
+};
+
+struct type_SNMP_RRspPDU {
+ integer parm;
+#define int_SNMP_RRspPDU_failure -1
+};
+
+struct type_SNMP_SOutPDU {
+ integer parm;
+#define int_SNMP_SOutPDU_commit 0
+};
+
+struct type_SNMP_Trap__PDU {
+ OID enterprise;
+ struct type_SNMP_NetworkAddress *agent__addr;
+ integer generic__trap;
+#define int_SNMP_generic__trap_coldStart 0
+ integer specific__trap;
+ struct type_SNMP_TimeTicks *time__stamp;
+ struct type_SNMP_VarBindList *variable__bindings;
+};
+
+struct smuxEntry {
+ char *se_name;
+ OIDentifier se_identity;
+ char *se_password;
+ int se_priority;
+};
+
+typedef struct {
+ int ps_errno; /* Error codes */
+#define PS_ERR_NONE 0 /* No error */
+#define PS_ERR_OVERID 1 /* Overflow in ID */
+#define PS_ERR_OVERLEN 2 /* Overflow in length */
+#define PS_ERR_NMEM 3 /* Out of memory */
+#define PS_ERR_EOF 4 /* End of file */
+#define PS_ERR_EOFID 5 /* End of file reading extended ID */
+#define PS_ERR_EOFLEN 6 /* End of file reading extended length */
+#define PS_ERR_LEN 7 /* Length mismatch */
+#define PS_ERR_TRNC 8 /* Truncated */
+#define PS_ERR_INDF 9 /* Indefinite length in primitive form */
+#define PS_ERR_IO 10 /* I/O error */
+#define PS_ERR_EXTRA 11 /* Extraneous octets */
+#define PS_ERR_XXX 12 /* XXX */
+ union {
+ caddr_t un_ps_addr;
+ struct {
+ char *st_ps_base;
+ int st_ps_cnt;
+ char *st_ps_ptr;
+ int st_ps_bufsiz;
+ } un_ps_st;
+ struct {
+ struct udvec *uv_ps_head;
+ struct udvec *uv_ps_cur;
+ struct udvec *uv_ps_end;
+ int uv_ps_elems;
+ int uv_ps_slop;
+ int uv_ps_cc;
+ } un_ps_uv;
+ } ps_un;
+#define ps_addr ps_un.un_ps_addr
+#define ps_base ps_un.un_ps_st.st_ps_base
+#define ps_cnt ps_un.un_ps_st.st_ps_cnt
+#define ps_ptr ps_un.un_ps_st.st_ps_ptr
+#define ps_bufsiz ps_un.un_ps_st.st_ps_bufsiz
+#define ps_head ps_un.un_ps_uv.uv_ps_head
+#define ps_cur ps_un.un_ps_uv.uv_ps_cur
+#define ps_end ps_un.un_ps_uv.uv_ps_end
+#define ps_elems ps_un.un_ps_uv.uv_ps_elems
+#define ps_slop ps_un.un_ps_uv.uv_ps_slop
+#define ps_cc ps_un.un_ps_uv.uv_ps_cc
+ caddr_t ps_extra; /* for George's recursive PStreams */
+ int ps_inline; /* for "ultra-efficient" PStreams */
+ int ps_scratch; /* XXX */
+ int ps_byteno; /* byte position */
+ IFP ps_primeP;
+ IFP ps_readP;
+ IFP ps_writeP;
+ IFP ps_flushP;
+ IFP ps_closeP;
+} PStream, *PS;
+#define NULLPS ((PS) 0)
+
+struct NSAPaddr { /* this structure shouldn't have holes in it */
+ long na_stack; /* TS-stack */
+#define NA_TCP 1 /* RFC1006/TCP */
+ long na_community; /* internal community # */
+ union {
+ struct na_nsap { /* real network service */
+#define NASIZE 64 /* 20 ought to do it */
+ char na_nsap_address[NASIZE];
+ char na_nsap_addrlen;
+ } un_na_nsap;
+ struct na_tcp { /* emulation via RFC1006 */
+#define NSAP_DOMAINLEN 63
+ char na_tcp_domain[NSAP_DOMAINLEN + 1];
+ u_short na_tcp_port; /* non-standard TCP port */
+ u_short na_tcp_tset; /* transport set */
+#define NA_TSET_TCP 0x0001 /* .. TCP */
+#define NA_TSET_UDP 0x0002 /* .. UDP */
+ } un_na_tcp;
+ struct na_x25 { /* X.25 (assume single subnet) */
+#define NSAP_DTELEN 36
+ char na_x25_dte[NSAP_DTELEN + 1]; /* Numeric DTE + Link */
+ char na_x25_dtelen; /* number of digits used */
+
+/* Conventionally, the PID sits at the first head bytes of user data and so
+ * should probably not be mentioned specially. A macro might do it, if
+ * necessary.
+ */
+#define NPSIZE 4
+ char na_x25_pid[NPSIZE]; /* X.25 protocol id */
+ char na_x25_pidlen; /* .. */
+#define CUDFSIZE 16
+ char na_x25_cudf[CUDFSIZE];/* call user data field */
+ char na_x25_cudflen; /* .. */
+/*
+ * X25 Facilities field.
+ */
+#define FACSIZE 6
+ char na_x25_fac[FACSIZE]; /* X.25 facilities */
+ char na_x25_faclen; /* .. */
+ } un_na_x25;
+ } na_un;
+#define na_address na_un.un_na_nsap.na_nsap_address
+#define na_addrlen na_un.un_na_nsap.na_nsap_addrlen
+#define na_domain na_un.un_na_tcp.na_tcp_domain
+#define na_port na_un.un_na_tcp.na_tcp_port
+#define na_tset na_un.un_na_tcp.na_tcp_tset
+#define na_dte na_un.un_na_x25.na_x25_dte
+#define na_dtelen na_un.un_na_x25.na_x25_dtelen
+#define na_pid na_un.un_na_x25.na_x25_pid
+#define na_pidlen na_un.un_na_x25.na_x25_pidlen
+#define na_cudf na_un.un_na_x25.na_x25_cudf
+#define na_cudflen na_un.un_na_x25.na_x25_cudflen
+#define na_fac na_un.un_na_x25.na_x25_fac
+#define na_faclen na_un.un_na_x25.na_x25_faclen
+/* for backwards compatibility... these two will be removed after ISODE 7.0 */
+#define na_type na_stack
+#define na_subnet na_community
+};
+
+struct TSAPaddr {
+#define NTADDR 8 /* according to NIST OIW */
+ struct NSAPaddr ta_addrs[NTADDR]; /* choice of network addresses */
+ int ta_naddr;
+#define TSSIZE 64
+ int ta_selectlen;
+ union un_ta_type { /* TSAP selector */
+ char ta_un_selector[TSSIZE];
+ u_short ta_un_port;
+ } un_ta;
+#define ta_selector un_ta.ta_un_selector
+#define ta_port un_ta.ta_un_port
+};
+
+struct qbuf {
+ struct qbuf *qb_forw; /* doubly-linked list */
+ struct qbuf *qb_back; /* .. */
+ int qb_len; /* length of data */
+ char *qb_data; /* current pointer into data */
+ char qb_base[1]; /* extensible... */
+};
+
+#define start_udp_client start_udp_server
+#define read_udp_socket read_dgram_socket
+#define write_udp_socket write_dgram_socket
+#define close_udp_socket close_dgram_socket
+#define check_udp_socket check_dgram_socket
+#define free_SNMP_ObjectName oid_free
+#define o_ipaddr(oi,v,value) o_specific ((oi), (v), (caddr_t) (value))
+#define o_integer(oi,v,value) o_longword ((oi), (v), (integer) (value))
+#define oid2ode(i) oid2ode_aux ((i), 1)
+#define ps2pe(ps) ps2pe_aux ((ps), 1, 1)
+#define pe2ps(ps, pe) pe2ps_aux ((ps), (pe), 1)
+#define str2vec(s,v) str2vecX ((s), (v), 0, NULLIP, NULL, 1)
+#define free_SNMP_Message(parm)\
+ (void) fre_obj((char *) parm, _ZSNMP_mod.md_dtab[_ZMessageSNMP], &_ZSNMP_mod, 1)
+#define encode_SNMP_Message(pe, top, len, buffer, parm) \
+ enc_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer, (char *) parm)
+#define print_SNMP_Message(pe, top, len, buffer, parm) \
+ prnt_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer)
+#define decode_SNMP_Message(pe, top, len, buffer, parm) \
+ dec_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer, (char **) parm)
+#define inaddr_copy(hp,sin) \
+ bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length)
+#define join_udp_server(fd,sock) \
+ join_dgram_aux ((fd), (struct sockaddr *) (sock), 0)
+
+#define MAXDGRAM 8192
+#define NOTOK (-1)
+#define OK 0
+#define NVEC 100
+#define invalidOperation (-1)
+#define parameterMissing (-2)
+#define systemError (-3)
+#define youLoseBig (-4)
+#define congestion (-5)
+#define inProgress (-6)
+#define protocolError int_SNMP_ClosePDU_protocolError
+#define goingDown int_SNMP_ClosePDU_goingDown
+#define readWrite int_SNMP_operation_readWrite
+
+OID oid_extend(), text2oid (), oid_cpy ();
+OT text2obj ();
+OI name2inst (), next2inst (), text2inst ();
+OS text2syn ();
+PS ps_alloc ();
+PE pe_alloc (), ps2pe_aux ();
+struct smuxEntry *getsmuxEntrybyname ();
+struct hostent *gethostbystring ();
+char *getlocalhost (), *oid2ode_aux ();
+struct TSAPaddr *str2taddr (); /* string encoding to TSAPaddr */
+int dg_open (), read_dgram_socket (), write_dgram_socket ();
+int check_dgram_socket (), pe2ps_aux ();
+struct qbuf *str2qb ();
+
+integer request__id;
+extern char PY_pepy[];
+extern int quantum;
+extern int ts_comm_tcp_default, ps_len_strategy;
+extern modtyp _ZSNMP_mod;
+#define _ZMessageSNMP 0
+
+#define PS_LEN_LONG 2
+
+/* Scalars */
+#define ipMRouteEnable 0
+
+/* IP Multicast Route Table */
+#define ipMRouteUpstreamNeighbor 0
+#define ipMRouteInIfIndex 1
+#define ipMRouteUpTime 2
+#define ipMRouteExpiryTime 3
+#define ipMRoutePkts 4
+#define ipMRouteDifferentInIfIndexes 5
+#define ipMRouteOctets 6
+#define ipMRouteProtocol 7
+
+/* IP Multicast Routing Next Hop Table */
+#define ipMRouteNextHopState 0
+#define ipMRouteNextHopUpTime 1
+#define ipMRouteNextHopExpiryTime 2
+#define ipMRouteNextHopClosestMemberHops 3
+#define ipMRouteNextHopProtocol 4
+
+/* Multicast Routing Interface Table */
+#define ipMRouteInterfaceTtl 0
+
+/* Scalars (cont.) */
+#define dvmrpVersion 1
+#define dvmrpGenerationId 2
+
+/* DVMRP Virtual Interface Table */
+#define dvmrpVInterfaceType 1
+#define dvmrpVInterfaceState 2
+#define dvmrpVInterfaceLocalAddress 3
+#define dvmrpVInterfaceRemoteAddress 4
+#define dvmrpVInterfaceRemoteSubnetMask 5
+#define dvmrpVInterfaceMetric 6
+#define dvmrpVInterfaceRateLimit 7
+#define dvmrpVInterfaceInPkts 8
+#define dvmrpVInterfaceOutPkts 9
+#define dvmrpVInterfaceInOctets 10
+#define dvmrpVInterfaceOutOctets 11
+
+/* DVMRP Neighbor Table */
+#define dvmrpNeighborUpTime 0
+#define dvmrpNeighborExpiryTime 1
+#define dvmrpNeighborVersion 2
+#define dvmrpNeighborGenerationId 3
+
+/* DVMRP Route Table */
+#define dvmrpRouteUpstreamNeighbor 0
+#define dvmrpRouteInVifIndex 1
+#define dvmrpRouteMetric 2
+#define dvmrpRouteExpiryTime 3
+
+/* DVMRP Routing Next Hop Table */
+#define dvmrpRouteNextHopType 0
+
+/* Boundary Table */
+#define dvmrpBoundaryVifIndex 0
+
+#define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
+extern int smux_fd;
+extern int rock_and_roll;
+extern int dont_bother_anymore;
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c
new file mode 100644
index 00000000000..406e8157858
--- /dev/null
+++ b/usr.sbin/mrouted/vif.c
@@ -0,0 +1,1373 @@
+/* $NetBSD: vif.c,v 1.5 1995/10/09 03:52:01 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
+vifi_t numvifs; /* number of vifs in use */
+int vifs_down; /* 1=>some interfaces are down */
+int udp_socket; /* Since the honkin' kernel doesn't support */
+ /* ioctls on raw IP sockets, we need a UDP */
+ /* socket as well as our IGMP (raw) socket. */
+ /* How dumb. */
+int vifs_with_neighbors; /* == 1 if I am a leaf */
+
+/*
+ * Forward declarations.
+ */
+static void start_vif();
+static void stop_vif();
+static void age_old_hosts();
+
+/*
+ * Initialize the virtual interfaces.
+ */
+void
+init_vifs()
+{
+ vifi_t vifi;
+ struct uvif *v;
+ int enabled_vifs, enabled_phyints;
+ extern char *configfilename;
+
+ numvifs = 0;
+ vifs_down = FALSE;
+
+ /*
+ * Configure the vifs based on the interface configuration of the
+ * the kernel and the contents of the configuration file.
+ * (Open a UDP socket for ioctl use in the config procedures.)
+ */
+ if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "UDP socket");
+ log(LOG_INFO,0,"Getting vifs from kernel interfaces");
+ config_vifs_from_kernel();
+ log(LOG_INFO,0,"Getting vifs from %s",configfilename);
+ config_vifs_from_file();
+
+ /*
+ * Quit if there are fewer than two enabled vifs.
+ */
+ enabled_vifs = 0;
+ enabled_phyints = 0;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ ++enabled_vifs;
+ if (!(v->uv_flags & VIFF_TUNNEL))
+ ++enabled_phyints;
+ }
+ }
+ if (enabled_vifs < 2)
+ log(LOG_ERR, 0, "can't forward: %s",
+ enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
+
+ if (enabled_phyints == 0)
+ log(LOG_WARNING, 0,
+ "no enabled interfaces, forwarding via tunnels only");
+
+ /*
+ * Start routing on all virtual interfaces that are not down or
+ * administratively disabled.
+ */
+ log(LOG_INFO,0,"Installing vifs in kernel...");
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (!(v->uv_flags & VIFF_DOWN)) {
+ if (v->uv_flags & VIFF_TUNNEL)
+ log(LOG_INFO,0,"vif #%d, tunnel %s -> %s", vifi,
+ inet_fmt(v->uv_lcl_addr,s1),
+ inet_fmt(v->uv_rmt_addr,s2));
+ else
+ log(LOG_INFO,0,"vif #%d, phyint %s", vifi,
+ inet_fmt(v->uv_lcl_addr,s1));
+ start_vif(vifi);
+ } else log(LOG_INFO, 0,
+ "%s is not yet up; vif #%u not in service",
+ v->uv_name, vifi);
+ }
+ }
+}
+
+
+/*
+ * See if any interfaces have changed from up state to down, or vice versa,
+ * including any non-multicast-capable interfaces that are in use as local
+ * tunnel end-points. Ignore interfaces that have been administratively
+ * disabled.
+ */
+void
+check_vif_state()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ struct ifreq ifr;
+
+ vifs_down = FALSE;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+
+ if (v->uv_flags & VIFF_DISABLED) continue;
+
+ strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+
+ if (v->uv_flags & VIFF_DOWN) {
+ if (ifr.ifr_flags & IFF_UP) {
+ v->uv_flags &= ~VIFF_DOWN;
+ start_vif(vifi);
+ log(LOG_INFO, 0,
+ "%s has come up; vif #%u now in service",
+ v->uv_name, vifi);
+ }
+ else vifs_down = TRUE;
+ }
+ else {
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ stop_vif(vifi);
+ v->uv_flags |= VIFF_DOWN;
+ log(LOG_INFO, 0,
+ "%s has gone down; vif #%u taken out of service",
+ v->uv_name, vifi);
+ vifs_down = TRUE;
+ }
+ }
+ }
+}
+
+/*
+ * Send a probe message on vif v
+ */
+void
+send_probe_on_vif(v)
+ register struct uvif *v;
+{
+ register char *p;
+ register int datalen = 0;
+ struct listaddr *nbr;
+ int i;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(dvmrp_genid))[i];
+ datalen += 4;
+
+ /*
+ * add the neighbor list on the interface to the message
+ */
+ nbr = v->uv_neighbors;
+
+ while (nbr) {
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&nbr->al_addr)[i];
+ datalen +=4;
+ nbr = nbr->al_next;
+ }
+
+ send_igmp(v->uv_lcl_addr,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group,
+ IGMP_DVMRP, DVMRP_PROBE,
+ htonl(MROUTED_LEVEL |
+ ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)),
+ datalen);
+}
+
+/*
+ * Start routing on the specified virtual interface.
+ */
+static void
+start_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ u_int32_t src;
+ struct phaddr *p;
+
+ v = &uvifs[vifi];
+ src = v->uv_lcl_addr;
+
+ /*
+ * Install the interface in the kernel's vif structure.
+ */
+ k_add_vif(vifi, &uvifs[vifi]);
+
+ /*
+ * Update the existing route entries to take into account the new vif.
+ */
+ add_vif_to_routes(vifi);
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Join the DVMRP multicast group on the interface.
+ * (This is not strictly necessary, since the kernel promiscuously
+ * receives IGMP packets addressed to ANY IP multicast group while
+ * multicast routing is enabled. However, joining the group allows
+ * this host to receive non-IGMP packets as well, such as 'pings'.)
+ */
+ k_join(dvmrp_group, src);
+
+ /*
+ * Join the ALL-ROUTERS multicast group on the interface.
+ * This allows mtrace requests to loop back if they are run
+ * on the multicast router.
+ */
+ k_join(allrtrs_group, src);
+
+ /*
+ * Install an entry in the routing table for the subnet to which
+ * the interface is connected.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
+ for (p = v->uv_addrs; p; p = p->pa_next) {
+ start_route_updates();
+ update_route(p->pa_addr, p->pa_mask, 0, 0, vifi);
+ }
+
+ /*
+ * Until neighbors are discovered, assume responsibility for sending
+ * periodic group membership queries to the subnet. Send the first
+ * query.
+ */
+ v->uv_flags |= VIFF_QUERIER;
+ send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
+ IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
+ age_old_hosts();
+ }
+
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+
+ /*
+ * Send a probe via the new vif to look for neighbors.
+ */
+ send_probe_on_vif(v);
+}
+
+/*
+ * Stop routing on the specified virtual interface.
+ */
+static void
+stop_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ struct listaddr *a;
+ struct phaddr *p;
+
+ v = &uvifs[vifi];
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Depart from the DVMRP multicast group on the interface.
+ */
+ k_leave(dvmrp_group, v->uv_lcl_addr);
+
+ /*
+ * Depart from the ALL-ROUTERS multicast group on the interface.
+ */
+ k_leave(allrtrs_group, v->uv_lcl_addr);
+
+ /*
+ * Update the entry in the routing table for the subnet to which
+ * the interface is connected, to take into account the interface
+ * failure.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
+ for (p = v->uv_addrs; p; p = p->pa_next) {
+ start_route_updates();
+ update_route(p->pa_addr, p->pa_mask, UNREACHABLE, 0, vifi);
+ }
+
+ /*
+ * Discard all group addresses. (No need to tell kernel;
+ * the k_del_vif() call, below, will clean up kernel state.)
+ */
+ while (v->uv_groups != NULL) {
+ a = v->uv_groups;
+ v->uv_groups = a->al_next;
+ free((char *)a);
+ }
+
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ /*
+ * Update the existing route entries to take into account the vif failure.
+ */
+ delete_vif_from_routes(vifi);
+
+ /*
+ * Delete the interface from the kernel's vif structure.
+ */
+ k_del_vif(vifi);
+
+ /*
+ * Discard all neighbor addresses.
+ */
+ if (v->uv_neighbors)
+ vifs_with_neighbors--;
+
+ while (v->uv_neighbors != NULL) {
+ a = v->uv_neighbors;
+ v->uv_neighbors = a->al_next;
+ free((char *)a);
+ }
+}
+
+
+/*
+ * stop routing on all vifs
+ */
+void
+stop_all_vifs()
+{
+ vifi_t vifi;
+ struct uvif *v;
+ struct listaddr *a;
+ struct vif_acl *acl;
+
+ for (vifi = 0; vifi < numvifs; vifi++) {
+ v = &uvifs[vifi];
+ while (v->uv_groups != NULL) {
+ a = v->uv_groups;
+ v->uv_groups = a->al_next;
+ free((char *)a);
+ }
+ while (v->uv_neighbors != NULL) {
+ a = v->uv_neighbors;
+ v->uv_neighbors = a->al_next;
+ free((char *)a);
+ }
+ while (v->uv_acl != NULL) {
+ acl = v->uv_acl;
+ v->uv_acl = acl->acl_next;
+ free((char *)acl);
+ }
+ }
+}
+
+
+/*
+ * Find the virtual interface from which an incoming packet arrived,
+ * based on the packet's source and destination IP addresses.
+ */
+vifi_t
+find_vif(src, dst)
+ register u_int32_t src;
+ register u_int32_t dst;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct phaddr *p;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr)
+ return(vifi);
+ }
+ else {
+ if ((src & v->uv_subnetmask) == v->uv_subnet &&
+ src != v->uv_subnetbcast)
+ return(vifi);
+ for (p=v->uv_addrs; p; p=p->pa_next) {
+ if ((src & p->pa_mask) == p->pa_addr &&
+ src != p->pa_addr)
+ return(vifi);
+ }
+ }
+ }
+ }
+ return (NO_VIF);
+}
+
+static void
+age_old_hosts()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *g;
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ /* -*- increment the time since an old report was heard */
+ for (g = v->uv_groups; g != NULL; g = g->al_next) {
+ g->al_last ++;
+ if (g->al_last >= OLD_AGE_THRESHOLD){
+ g->al_old = 0;
+ g->al_last = OLD_AGE_THRESHOLD;
+ }
+ }
+ }
+}
+
+
+/*
+ * Send group membership queries to all subnets for which I am querier.
+ */
+void
+query_groups()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_QUERIER) {
+ send_igmp(v->uv_lcl_addr, allhosts_group,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
+ }
+ }
+ age_old_hosts();
+}
+
+/*
+ * Process an incoming host membership query
+ */
+void
+accept_membership_query(src, dst, group, tmo)
+ u_int32_t src, dst, group;
+ int tmo;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group membership query from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ /* If we consider ourselves the querier for this vif, but hear a
+ * query from a router with a lower IP address, yield to them.
+ *
+ * This is done here as well as in the neighbor discovery in case
+ * there is a querier that doesn't speak DVMRP.
+ */
+ if ((v->uv_flags & VIFF_QUERIER) &&
+ (ntohl(src) < ntohl(v->uv_lcl_addr))) {
+
+ v->uv_flags &= ~VIFF_QUERIER;
+
+ }
+}
+
+/*
+ * Process an incoming group membership report.
+ */
+void
+accept_group_report(src, dst, group, r_type)
+ u_int32_t src, dst, group;
+ int r_type;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *g;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group membership report from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ /*
+ * Look for the group in our group list; if found, reset its timer.
+ */
+ for (g = v->uv_groups; g != NULL; g = g->al_next) {
+ if (group == g->al_addr) {
+ if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT) {
+ g->al_last = OLD_AGE_THRESHOLD;
+ g->al_old = 0;
+ }
+ else {
+ g->al_last = 0;
+ g->al_old = 1;
+ }
+
+ /** delete old timer set a timer for expiration **/
+ g->al_timer= GROUP_EXPIRE_TIME;
+ if (g->al_query)
+ g->al_query = DeleteTimer(g->al_query);
+ if (g->al_timerid)
+ g->al_timerid = DeleteTimer(g->al_timerid);
+ g->al_timerid = SetTimer(vifi, g);
+ break;
+ }
+ }
+
+ /*
+ * If not found, add it to the list and update kernel cache.
+ */
+ if (g == NULL) {
+ g = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (g == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ g->al_addr = group;
+ if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT) {
+ g->al_last = OLD_AGE_THRESHOLD;
+ g->al_old = 0;
+ }
+ else {
+ g->al_last = 0;
+ g->al_old = 1;
+ }
+
+ /** set a timer for expiration **/
+ g->al_query = 0;
+ g->al_timer = GROUP_EXPIRE_TIME;
+ time(&g->al_ctime);
+ g->al_timerid = SetTimer(vifi, g);
+ g->al_next = v->uv_groups;
+ v->uv_groups = g;
+
+ update_lclgrp(vifi, group);
+ }
+
+ /*
+ * Check if a graft is necessary for this group
+ */
+ chkgrp_graft(vifi, group);
+}
+
+
+void
+accept_leave_message( src, dst, group)
+ u_int32_t src, dst, group;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *g;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group leave report from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ if (!(v->uv_flags & VIFF_QUERIER))
+ return;
+
+ /*
+ * Look for the group in our group list in order to set up a short-timeout
+ * query.
+ */
+ for (g = v->uv_groups; g != NULL; g = g->al_next) {
+ if (group == g->al_addr) {
+ log(LOG_DEBUG, 0,
+ "[vif.c, _accept_leave_message] %d %d \n",
+ g->al_old, g->al_query);
+
+ /* Ignore the leave message if there are old hosts present */
+ if (g->al_old)
+ return;
+
+ /* still waiting for a reply to a query, ignore the leave */
+ if (g->al_query)
+ return;
+
+ /** delete old timer set a timer for expiration **/
+ if (g->al_timerid)
+ g->al_timerid = DeleteTimer(g->al_timerid);
+
+ /** send a group specific querry **/
+ g->al_timer = LEAVE_EXPIRE_TIME;
+ send_igmp(v->uv_lcl_addr, g->al_addr,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE,
+ g->al_addr, 0);
+ g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3,
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE);
+ g->al_timerid = SetTimer(vifi, g);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Send a periodic probe on all vifs.
+ * Useful to determine one-way interfaces.
+ * Detect neighbor loss faster.
+ */
+void
+probe_for_neighbors()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ send_probe_on_vif(v);
+ }
+ }
+}
+
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void
+accept_neighbor_request(src, dst)
+ u_int32_t src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_int32_t temp_addr, us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+#define PUT_ADDR(a) temp_addr = ntohl(a); \
+ *p++ = temp_addr >> 24; \
+ *p++ = (temp_addr >> 16) & 0xFF; \
+ *p++ = (temp_addr >> 8) & 0xFF; \
+ *p++ = temp_addr & 0xFF;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_DISABLED)
+ continue;
+
+ ncount = 0;
+
+ for (la = v->uv_neighbors; la; la = la->al_next) {
+
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ PUT_ADDR(v->uv_lcl_addr);
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 3;
+ }
+
+ PUT_ADDR(la->al_addr);
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void
+accept_neighbor_request2(src, dst)
+ u_int32_t src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_int32_t us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ register u_short vflags = v->uv_flags;
+ register u_char rflags = 0;
+ if (vflags & VIFF_TUNNEL)
+ rflags |= DVMRP_NF_TUNNEL;
+ if (vflags & VIFF_SRCRT)
+ rflags |= DVMRP_NF_SRCRT;
+ if (vflags & VIFF_DOWN)
+ rflags |= DVMRP_NF_DOWN;
+ if (vflags & VIFF_DISABLED)
+ rflags |= DVMRP_NF_DISABLED;
+ if (vflags & VIFF_QUERIER)
+ rflags |= DVMRP_NF_QUERIER;
+ if (vflags & VIFF_LEAF)
+ rflags |= DVMRP_NF_LEAF;
+ ncount = 0;
+ la = v->uv_neighbors;
+ if (la == NULL) {
+ /*
+ * include down & disabled interfaces and interfaces on
+ * leaf nets.
+ */
+ if (rflags & DVMRP_NF_TUNNEL)
+ rflags |= DVMRP_NF_DOWN;
+ if (datalen > MAX_DVMRP_DATA_LEN - 12) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ }
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ *p++ = 1;
+ *(u_int*)p = v->uv_rmt_addr;
+ p += 4;
+ datalen += 12;
+ } else {
+ for ( ; la; la = la->al_next) {
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 4;
+ }
+ *(u_int*)p = la->al_addr;
+ p += 4;
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+ }
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void
+accept_neighbors(src, dst, p, datalen, level)
+ u_int32_t src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void
+accept_neighbors2(src, dst, p, datalen, level)
+ u_int32_t src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
+ * 'msgtype' is the type of DVMRP message received from the neighbor.
+ * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
+ */
+int
+update_neighbor(vifi, addr, msgtype, p, datalen, level)
+ vifi_t vifi;
+ u_int32_t addr;
+ int msgtype;
+ char *p;
+ int datalen;
+ u_int32_t level;
+{
+ register struct uvif *v;
+ register struct listaddr *n;
+ u_int32_t genid = 0;
+ u_int32_t router;
+ int he_hears_me = TRUE;
+ int nflags;
+
+ v = &uvifs[vifi];
+ nflags = (level >> 16) & 0xff;
+
+ /*
+ * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
+ * IT IS ASSUMED that this was preceded by a call to find_vif(), which
+ * checks that 'addr' is either a valid remote tunnel endpoint or a
+ * non-broadcast address belonging to a directly-connected subnet.
+ * Therefore, here we check only that 'addr' is not our own address
+ * (due to an impostor or erroneous loopback) or an address of the form
+ * {subnet,0} ("the unknown host"). These checks are not performed in
+ * find_vif() because those types of address are acceptable for some
+ * types of IGMP message (such as group membership reports).
+ */
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ (addr == v->uv_lcl_addr ||
+ addr == v->uv_subnet )) {
+ log(LOG_WARNING, 0,
+ "received DVMRP message from 'the unknown host' or self: %s",
+ inet_fmt(addr, s1));
+ return (FALSE);
+ }
+
+ /*
+ * If we have received a route report from a neighbor, and we believed
+ * that we had no neighbors on this vif, send a full route report to
+ * all neighbors on the vif.
+ */
+
+ if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL)
+ report(ALL_ROUTES, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
+
+ /*
+ * Check if the router gen-ids are the same (only if vers > 3.2)
+ * Need to reset the prune state of the router if not.
+ */
+ if (msgtype == DVMRP_PROBE) {
+
+ /* Check genid neighbor flag. Also check version number; 3.3 and
+ * 3.4 didn't set this flag. */
+ if ((((level >> 16) & 0xff) & NF_GENID) ||
+ (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) {
+
+ int i;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0,
+ "received truncated probe message from %s (len %d)",
+ inet_fmt(addr, s1), datalen);
+ return (FALSE);
+ }
+
+ for (i = 0; i < 4; i++)
+ ((char *)&genid)[i] = *p++;
+ datalen -=4;
+
+ /*
+ * loop through router list and check for one-way ifs.
+ */
+
+ he_hears_me = FALSE;
+
+ while (datalen > 0) {
+ if (datalen < 4) {
+ log(LOG_WARNING, 0,
+ "received truncated probe message from %s (len %d)",
+ inet_fmt(addr, s1), datalen);
+ return (FALSE);
+ }
+ for (i = 0; i < 4; i++)
+ ((char *)&router)[i] = *p++;
+ datalen -= 4;
+ if (router == v->uv_lcl_addr) {
+ he_hears_me = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ /*
+ * Look for addr in list of neighbors; if found, reset its timer.
+ */
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (addr == n->al_addr) {
+ n->al_timer = 0;
+
+ /*
+ * If probe message and version no >= 3.3 check genid
+ */
+ if (msgtype == DVMRP_PROBE &&
+ ((n->al_pv >= 3 && n->al_mv > 2) || n->al_pv > 3)) {
+ if (he_hears_me == TRUE && v->uv_flags & VIFF_ONEWAY)
+ v->uv_flags &= ~VIFF_ONEWAY;
+
+ if (he_hears_me == FALSE)
+ v->uv_flags |= VIFF_ONEWAY;
+
+ if (n->al_genid == 0)
+ n->al_genid = genid;
+ else if (n->al_genid != genid) {
+ log(LOG_DEBUG, 0,
+ "reset neighbor %s on vif %d [old genid:%x, new:%x]",
+ inet_fmt(addr, s1), vifi, n->al_genid, genid);
+
+ n->al_genid = genid;
+ n->al_pv = level & 0xff;
+ n->al_mv = (level >> 8) & 0xff;
+ n->al_flags = 0; /*XXX*/
+ reset_neighbor_state(vifi, addr);
+
+ /*
+ * need to do a full route report here
+ * it gets done by accept_probe()
+ */
+ return (TRUE);
+ }
+
+ /*XXX nflags shouldn't be dealt with in 2 places in the same
+ *XXX routine...*/
+ if (n->al_flags != nflags) {
+ n->al_flags = nflags;
+ if (nflags & NF_LEAF) {
+ if (!v->uv_leaf_timer)
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+ } else {
+ v->uv_flags &= ~VIFF_LEAF;
+ v->uv_leaf_timer = 0;
+ }
+ /* Neighbor flags changed, do a full report */
+ return TRUE;
+ }
+ }
+
+ /*
+ * update the neighbors version and protocol number
+ * if changed => router went down and came up,
+ * so take action immediately.
+ */
+ if ((n->al_pv != (level & 0xff)) ||
+ (n->al_mv != ((level >> 8) & 0xff))) {
+
+ log(LOG_DEBUG, 0,
+ "resetting neighbor %s [old:%d.%d, new:%d.%d]",
+ inet_fmt(addr, s1),
+ n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
+
+ n->al_pv = level & 0xff;
+ n->al_mv = (level >> 8) & 0xff;
+
+ reset_neighbor_state(vifi, addr);
+ }
+
+ /* recurring probe - so no need to do a route report */
+ if (msgtype == DVMRP_PROBE)
+ return (FALSE);
+ else
+ return (TRUE);
+ }
+ }
+
+ /*
+ * If not found, add it to the list. If the neighbor has a lower
+ * IP address than me, yield querier duties to it.
+ */
+ if (n == NULL) {
+ log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
+ inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
+ (level >> 16) & 0xff);
+
+ n = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (n == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ n->al_addr = addr;
+ n->al_pv = level & 0xff;
+ n->al_mv = (level >> 8) & 0xff;
+ if (msgtype == DVMRP_PROBE)
+ n->al_genid = genid;
+ else
+ n->al_genid = 0;
+
+ time(&n->al_ctime);
+ n->al_timer = 0;
+ n->al_next = v->uv_neighbors;
+
+ if (v->uv_neighbors == NULL)
+ vifs_with_neighbors++;
+
+ v->uv_neighbors = n;
+
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ ntohl(addr) < ntohl(v->uv_lcl_addr))
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ n->al_flags = nflags;
+ if (!(n->al_flags & NF_LEAF)) {
+ v->uv_flags &= ~VIFF_LEAF;
+ v->uv_leaf_timer = 0;
+ } else {
+ /*XXX If we have non-leaf neighbors then we know we shouldn't
+ * mark this vif as a leaf. For now we just count on other
+ * probes and/or reports resetting the timer. */
+ if (!v->uv_leaf_timer)
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each neighbor and
+ * group entry on every vif.
+ */
+void
+age_vifs()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a, *prev_a, *n;
+ register u_int32_t addr;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
+ if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
+ v->uv_flags |= VIFF_LEAF;
+ }
+
+ for (prev_a = (struct listaddr *)&(v->uv_neighbors),
+ a = v->uv_neighbors;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME)
+ continue;
+
+ /*
+ * Neighbor has expired; delete it from the neighbor list,
+ * delete it from the 'dominants' and 'subordinates arrays of
+ * any route entries and assume querier duties unless there is
+ * another neighbor with a lower IP address than mine.
+ */
+ addr = a->al_addr;
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+
+ delete_neighbor_from_routes(addr, vifi);
+
+ if (v->uv_neighbors == NULL)
+ vifs_with_neighbors--;
+
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ v->uv_flags |= VIFF_QUERIER;
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+ if (!(n->al_flags & NF_LEAF)) {
+ v->uv_leaf_timer = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Returns the neighbor info struct for a given neighbor
+ */
+struct listaddr *
+neighbor_info(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct listaddr *u;
+
+ for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
+ if (u->al_addr == addr)
+ return u;
+
+ return NULL;
+}
+
+/*
+ * Return the neighbor's version number
+ * returns (protocol_version << 8 + mrouted_version) of neighbor
+ */
+int
+nbr_vers(vifi, addr)
+ vifi_t vifi;
+ u_int32_t addr;
+{
+ struct listaddr *u = neighbor_info(vifi, addr);
+
+ return u ? NBR_VERS(u) : 0;
+}
+
+/*
+ * Print the contents of the uvifs array on file 'fp'.
+ */
+void
+dump_vifs(fp)
+ FILE *fp;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a;
+ register struct phaddr *p;
+ struct sioc_vif_req v_req;
+
+ fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
+
+ if (vifs_with_neighbors == 1)
+ fprintf(fp,"[This host is a leaf]\n\n");
+
+ fprintf(fp,
+ "\nVirtual Interface Table\n%s",
+ "Vif Name Local-Address ");
+ fprintf(fp,
+ "M Thr Rate Flags\n");
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+
+ fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ",
+ vifi,
+ v->uv_name,
+ inet_fmt(v->uv_lcl_addr, s1),
+ (v->uv_flags & VIFF_TUNNEL) ?
+ "tunnel":
+ "subnet",
+ (v->uv_flags & VIFF_TUNNEL) ?
+ inet_fmt(v->uv_rmt_addr, s2) :
+ inet_fmts(v->uv_subnet, v->uv_subnetmask, s3),
+ v->uv_metric,
+ v->uv_threshold,
+ v->uv_rate_limit);
+
+ if (v->uv_flags & VIFF_ONEWAY) fprintf(fp, " one-way");
+ if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down");
+ if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
+ if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
+ if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
+ if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf");
+ fprintf(fp, "\n");
+
+ if (v->uv_addrs != NULL) {
+ fprintf(fp, " alternate subnets: %s\n",
+ inet_fmts(v->uv_addrs->pa_addr, v->uv_addrs->pa_mask, s1));
+ for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
+ fprintf(fp, " %s\n",
+ inet_fmts(p->pa_addr, p->pa_mask, s1));
+ }
+ }
+
+ if (v->uv_neighbors != NULL) {
+ fprintf(fp, " peers: %s (%d.%d) (0x%x)\n",
+ inet_fmt(v->uv_neighbors->al_addr, s1),
+ v->uv_neighbors->al_pv, v->uv_neighbors->al_mv,
+ v->uv_neighbors->al_flags);
+ for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %s (%d.%d) (0x%x)\n",
+ inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv,
+ a->al_flags);
+ }
+ }
+
+ if (v->uv_groups != NULL) {
+ fprintf(fp, " groups: %-15s\n",
+ inet_fmt(v->uv_groups->al_addr, s1));
+ for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %-15s\n",
+ inet_fmt(a->al_addr, s1));
+ }
+ }
+ if (v->uv_acl != NULL) {
+ struct vif_acl *acl;
+
+ fprintf(fp, " boundaries: %-18s\n",
+ inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1));
+ for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) {
+ fprintf(fp, " : %-18s\n",
+ inet_fmts(acl->acl_addr, acl->acl_mask, s1));
+ }
+ }
+ v_req.vifi = vifi;
+ if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
+ log(LOG_WARNING, 0,
+ "SIOCGETVIFCNT fails");
+ }
+ else {
+ fprintf(fp, " pkts in : %d\n",
+ v_req.icount);
+ fprintf(fp, " pkts out: %d\n",
+ v_req.ocount);
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
+
+
+/**** the timeout routines ********/
+
+typedef struct {
+ vifi_t vifi;
+ struct listaddr *g;
+ int q_time;
+} cbk_t;
+
+static cbk_t *cbk;
+
+void
+DelVif(cbk)
+cbk_t *cbk;
+{
+ /* -*- make the list consistent */
+ register vifi_t vifi = cbk->vifi;
+ register struct uvif *v;
+ register struct listaddr *a, *prev_a, *g = cbk->g;
+
+ v = &uvifs[vifi];
+
+ for (prev_a = (struct listaddr *)&(v->uv_groups),
+ a = v->uv_groups;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if (a != g) continue;
+
+ /*
+ * Group has expired
+ * delete all kernel cache entries with this group
+ */
+ if (g->al_query) DeleteTimer(g->al_query);
+ delete_lclgrp(vifi, a->al_addr);
+
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+ }
+
+ free(cbk);
+}
+
+
+int
+SetTimer( vifi, g)
+ vifi_t vifi; struct listaddr *g;
+{
+ cbk = (cbk_t *) malloc(sizeof(cbk_t));
+ cbk->g = g;
+ cbk->vifi = vifi;
+ return timer_setTimer(g->al_timer,DelVif,cbk);
+}
+
+int
+DeleteTimer( id)
+int id;
+{
+ timer_clearTimer(id);
+ return 0;
+}
+
+void
+SendQuery(cbk)
+cbk_t *cbk;
+{
+ register struct uvif *v = &uvifs[cbk->vifi];
+ send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ cbk->q_time, 0, 0);
+ cbk->g->al_query = 0;
+ free(cbk);
+}
+
+int
+SetQueryTimer(g , vifi, to_expire, q_time)
+ struct listaddr *g; vifi_t vifi;
+ int to_expire, q_time;
+{
+ cbk = (cbk_t *) malloc(sizeof(cbk_t));
+ cbk->g = g;
+ cbk->q_time = q_time; cbk-> vifi = vifi;
+ return timer_setTimer(to_expire,SendQuery,cbk);
+}
diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h
new file mode 100644
index 00000000000..4ff8194946d
--- /dev/null
+++ b/usr.sbin/mrouted/vif.h
@@ -0,0 +1,76 @@
+/* $NetBSD: vif.h,v 1.5 1995/10/09 03:52:03 thorpej Exp $ */
+
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ */
+
+/*
+ * User level Virtual Interface structure
+ *
+ * A "virtual interface" is either a physical, multicast-capable interface
+ * (called a "phyint") or a virtual point-to-point link (called a "tunnel").
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ */
+struct uvif {
+ u_short uv_flags; /* VIFF_ flags defined below */
+ u_char uv_metric; /* cost of this vif */
+ u_int uv_rate_limit; /* rate limit on this vif */
+ u_char uv_threshold; /* min ttl required to forward on vif */
+ u_int32_t uv_lcl_addr; /* local address of this vif */
+ u_int32_t uv_rmt_addr; /* remote end-point addr (tunnels only) */
+ u_int32_t uv_subnet; /* subnet number (phyints only) */
+ u_int32_t uv_subnetmask; /* subnet mask (phyints only) */
+ u_int32_t uv_subnetbcast;/* subnet broadcast addr (phyints only) */
+ char uv_name[IFNAMSIZ]; /* interface name */
+ struct listaddr *uv_groups; /* list of local groups (phyints only) */
+ struct listaddr *uv_neighbors; /* list of neighboring routers */
+ struct vif_acl *uv_acl; /* access control list of groups */
+ int uv_leaf_timer; /* time until this vif is considrd leaf */
+ struct phaddr *uv_addrs; /* Additional subnets on this vif */
+};
+
+#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
+#define VIFF_DOWN 0x0100 /* kernel state of interface */
+#define VIFF_DISABLED 0x0200 /* administratively disabled */
+#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
+#define VIFF_ONEWAY 0x0800 /* Maybe one way interface */
+#define VIFF_LEAF 0x1000 /* all neighbors are leaves */
+
+struct phaddr {
+ struct phaddr *pa_next;
+ u_long pa_addr;
+ u_long pa_mask;
+};
+
+struct vif_acl {
+ struct vif_acl *acl_next; /* next acl member */
+ u_int32_t acl_addr; /* Group address */
+ u_int32_t acl_mask; /* Group addr. mask */
+};
+
+struct listaddr {
+ struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
+ u_int32_t al_addr; /* local group or neighbor address */
+ u_long al_timer; /* for timing out group or neighbor */
+ time_t al_ctime; /* neighbor creation time */
+ u_int32_t al_genid; /* generation id for neighbor */
+ u_char al_pv; /* router protocol version */
+ u_char al_mv; /* router mrouted version */
+ u_long al_timerid; /* returned by set timer */
+ u_long al_query; /* second query in case of leave */
+ u_short al_old; /* if old memberships are present */
+ u_short al_last; /* # of query's since last old rep */
+ u_char al_flags; /* flags related to this neighbor */
+};
+
+#define NF_LEAF 0x01 /* This neighbor is a leaf */
+#define NF_PRUNE 0x02 /* This neighbor understands prunes */
+#define NF_GENID 0x04 /* I supply genid & rtrlist in probe*/
+#define NF_MTRACE 0x08 /* I can understand mtrace requests */
+
+#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
diff --git a/usr.sbin/mtrace/Makefile b/usr.sbin/mtrace/Makefile
new file mode 100644
index 00000000000..30a653063d7
--- /dev/null
+++ b/usr.sbin/mtrace/Makefile
@@ -0,0 +1,14 @@
+# $NetBSD: Makefile,v 1.3 1995/10/04 03:47:51 thorpej Exp $
+# from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
+
+.PATH: ${.CURDIR}/../mrouted
+CFLAGS+= -I${.CURDIR}/../mrouted
+
+PROG= mtrace
+SRCS= igmp.c inet.c kern.c mtrace.c
+MAN= mtrace.8
+
+BINMODE=4555
+BINOWN= root
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mtrace/mtrace.8 b/usr.sbin/mtrace/mtrace.8
new file mode 100644
index 00000000000..37495c5b44e
--- /dev/null
+++ b/usr.sbin/mtrace/mtrace.8
@@ -0,0 +1,498 @@
+.\" $NetBSD: mtrace.8,v 1.3 1995/10/04 03:47:54 thorpej Exp $
+.\"
+.\" Copyright (c) 1995 by the University of Southern California
+.\" All rights reserved.
+.\"
+.\" Permission to use, copy, modify, and distribute this software and its
+.\" documentation in source and binary forms for non-commercial purposes
+.\" and without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both the copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" any documentation, advertising materials, and other materials related
+.\" to such distribution and use acknowledge that the software was
+.\" developed by the University of Southern California, Information
+.\" Sciences Institute. The name of the University may not be used to
+.\" endorse or promote products derived from this software without
+.\" specific prior written permission.
+.\"
+.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+.\" the suitability of this software for any purpose. THIS SOFTWARE IS
+.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" Other copyrights might apply to parts of this software and are so
+.\" noted when applicable.
+.\"
+.\" This manual page (but not the software) was derived from the
+.\" manual page for the traceroute program which bears the following
+.\" copyright notice:
+.\"
+.\" Copyright (c) 1988 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.TH MTRACE 8 "May 8, 1995"
+.UC 6
+.SH NAME
+mtrace \- print multicast path from a source to a receiver
+.SH SYNOPSIS
+.B mtrace
+[
+.B \-g
+.I gateway
+] [
+.B \-i
+.I if_addr
+] [
+.B \-l
+] [
+.B \-M
+] [
+.B \-m
+.I max_hops
+] [
+.B \-n
+] [
+.B \-p
+] [
+.B \-q
+.I nqueries
+] [
+.B \-r
+.I resp_dest
+] [
+.B \-s
+] [
+.B \-t
+.I ttl
+] [
+.B \-w
+.I waittime
+]
+.I source
+[
+.I receiver
+] [
+.I group
+]
+.SH DESCRIPTION
+Assessing problems in the distribution of IP multicast traffic
+can be difficult.
+.B mtrace
+utilizes a tracing feature implemented in multicast routers
+.RB ( mrouted
+version 3.3 and later) that is
+accessed via an extension to the IGMP protocol. A trace query is
+passed hop-by-hop along the reverse path from the
+.I receiver
+to the
+.IR source ,
+collecting hop addresses, packet counts, and routing error conditions
+along the path, and then the response is returned to the requestor.
+.PP
+The only required parameter is the
+.I source
+host name or address. The default
+.I receiver
+is the host running mtrace, and the default
+.I group
+is "MBone Audio" (224.2.0.1), which is sufficient if packet loss
+statistics for a particular multicast group are not needed. These two
+optional parameters may be specified to test the path to some other
+receiver in a particular group, subject to some constraints as
+detailed below. The two parameters can be distinguished because the
+.I receiver
+is a unicast address and the
+.I group
+is a multicast address.
+.SH OPTIONS
+.TP 8 8
+.BI \-g\ gwy
+Send the trace query via unicast directly to the multicast router
+.I gwy
+rather than multicasting the query.
+This must be the last-hop router on the path from the intended
+.I source
+to the
+.IR receiver .
+.RS 8
+.TP 12 12
+.I CAUTION!!
+Version 3.3 of
+.B mrouted
+will crash if a trace query is received via a
+unicast packet and
+.B mrouted
+has no route for the
+.I source
+address. Therefore, do not use the
+.B \-g
+option unless the target
+.B mrouted
+has been verified to be newer than 3.3.
+.RE
+.TP 8 8
+.BI \-i\ addr
+Use
+.I addr
+as the local interface address (on a multi-homed host) for sending the
+trace query and as the default for the
+.I receiver
+and the response destination.
+.TP 8 8
+.B \-l
+Loop indefinitely printing packet rate and loss statistics for the
+multicast path every 10 seconds.
+.TP 8 8
+.B \-M
+Always send the response using multicast rather than attempting
+unicast first.
+.TP 8 8
+.BI \-m\ n
+Set to
+.I n
+the maximum number of hops that will be traced from the
+.I receiver
+back toward the
+.IR source .
+The default is 32 hops (infinity for the DVMRP routing protocol).
+.TP 8 8
+.B \-n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each router found on the
+path).
+.TP 8 8
+.BI \-q\ n
+Set the maximum number of query attempts for any hop to
+.IR n .
+The default is 3.
+.TP 8 8
+.B \-p
+Listen passively for multicast responses from traces initiated by
+others (not implemented yet).
+.TP 8 8
+.BI \-r\ host
+Send the trace response to
+.I host
+rather than to the host on which
+.B mtrace
+is being run, or to a multicast address other than the one registered
+for this purpose (224.0.1.32).
+.TP 8 8
+.B \-s
+Print a short form output including only the multicast path and not
+the packet rate and loss statistics.
+.TP 8 8
+.BI \-t\ ttl
+Set the
+.I ttl
+(time-to-live, or number of hops) for multicast trace queries and
+responses. The default is 64, except for local queries to the "all
+routers" multicast group which use ttl 1.
+.TP 8 8
+.BI \-w\ n
+Set the time to wait for a trace response to
+.I n
+seconds (default 3 seconds).
+.SH USAGE
+.SS How It Works
+The technique used by the
+.B traceroute
+tool to trace unicast network paths will not work for IP multicast
+because ICMP responses are specifically forbidden for multicast traffic.
+Instead, a tracing feature has been built into the multicast routers.
+This technique has the advantage that additional information about
+packet rates and losses can be accumulated while the number of packets
+sent is minimized.
+.PP
+Since multicast uses
+reverse path forwarding, the trace is run backwards from the
+.I receiver
+to the
+.IR source .
+A trace query packet is sent to the last
+hop multicast router (the leaf router for the desired
+.I receiver
+address). The last hop router builds a trace response packet, fills in
+a report for its hop, and forwards the trace packet using unicast to
+the router it believes is the previous hop for packets originating
+from the specified
+.IR source .
+Each router along the path adds its report and forwards the packet.
+When the trace response packet reaches the first hop router (the router
+that is directly connected to the source's net), that router sends the
+completed response to the response destination address specified in
+the trace query.
+.PP
+If some multicast router along the path does not implement the
+multicast traceroute feature or if there is some outage, then no
+response will be returned. To solve this problem, the trace query
+includes a maximum hop count field to limit the number of hops traced
+before the response is returned. That allows a partial path to be
+traced.
+.PP
+The reports inserted by each router contain not only the address of
+the hop, but also the ttl required to forward and some flags to indicate
+routing errors, plus counts of the total number of packets on the
+incoming and outgoing interfaces and those forwarded for the specified
+.IR group .
+Taking differences in these counts for two traces separated in time
+and comparing the output packet counts from one hop with the input
+packet counts of the next hop allows the calculation of packet rate
+and packet loss statistics for each hop to isolate congestion
+problems.
+.SS Finding the Last-Hop Router
+The trace query must be sent to the multicast router which is the
+last hop on the path from the
+.I source
+to the
+.IR receiver .
+If the receiver is on the local subnet (as determined using the subnet
+mask), then the default method is to multicast the trace query to
+all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the
+trace query is multicast to the
+.I group
+address since the last hop router will be a member of that group if
+the receiver is. Therefore it is necessary to specify a group that
+the intended receiver has joined. This multicast is sent with a
+default ttl of 64, which may not be sufficient for all cases (changed
+with the
+.B \-t
+option).
+If the last hop router is known, it may also be addressed directly
+using the
+.B \-g
+option). Alternatively, if it is desired to trace a group that the
+receiver has not joined, but it is known that the last-hop router is a
+member of another group, the
+.B \-g
+option may also be used to specify a different multicast address for the
+trace query.
+.PP
+When tracing from a multihomed host or router, the default receiver
+address may not be the desired interface for the path from the source.
+In that case, the desired interface should be specified explicitly as
+the
+.IR receiver .
+.SS Directing the Response
+By default,
+.B mtrace
+first attempts to trace the full reverse path, unless the number of
+hops to trace is explicitly set with the
+.B \-m
+option. If there is no response within a 3 second timeout interval
+(changed with the
+.B \-w
+option), a "*" is printed and the probing switches to hop-by-hop mode.
+Trace queries are issued starting with a maximum hop count of one and
+increasing by one until the full path is traced or no response is
+received. At each hop, multiple probes are sent (default is three,
+changed with
+.B \-q
+option). The first half of the attempts (default is one) are made with
+the unicast address of the host running
+.B mtrace
+as the destination for the response. Since the unicast route may be
+blocked, the remainder of attempts request that the response be
+multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more
+than what's needed to pass the thresholds seen so far along the path
+to the receiver. For the last quarter of the attempts (default is
+one), the ttl is increased by another 32 each time up to a maximum of
+192. Alternatively, the ttl may be set explicity with the
+.B \-t
+option and/or the initial unicast attempts can be forced to use
+multicast instead with the
+.B \-M
+option. For each attempt, if no response is received within the
+timeout, a "*" is printed. After the specified number of attempts
+have failed,
+.B mtrace
+will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2
+request (as used by the
+.B mrinfo
+program) to see what kind of router it is.
+.SH EXAMPLES
+The output of
+.B mtrace
+is in two sections. The first section is a short listing of the hops
+in the order they are queried, that is, in the reverse of the order
+from the
+.I source
+to the
+.IR receiver .
+For each hop, a line is printed showing the hop number (counted
+negatively to indicate that this is the reverse path); the multicast
+routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to
+forward data (to the previous hop in the listing as indicated by the
+up-arrow character); and the cumulative delay for the query to reach
+that hop (valid only if the clocks are synchronized). This first
+section ends with a line showing the round-trip time which measures
+the interval from when the query is issued until the response is
+received, both derived from the local system clock. A sample use and
+output might be:
+.PP
+.nf
+.ft C
+oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3
+Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3
+Querying full reverse path...
+ 0 oak.isi.edu (128.9.160.100)
+ -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms
+ -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms
+ -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms
+ -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms
+ -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms
+ -6 caraway.lcs.mit.edu (18.26.0.170)
+Round trip time 124 ms
+.fi
+.PP
+The second section provides a pictorial view of the path in the
+forward direction with data flow indicated by arrows pointing downward
+and the query path indicated by arrows pointing upward. For each hop,
+both the entry and exit addresses of the router are shown if
+different, along with the initial ttl required on the packet in order
+to be forwarded at this hop and the propagation delay across the hop
+assuming that the routers at both ends have synchronized clocks. The
+right half of this section is composed of several columns of
+statistics in two groups. Within each group, the columns are the
+number of packets lost, the number of packets sent, the percentage
+lost, and the average packet rate at each hop. These statistics are
+calculated from differences between traces and from hop to hop as
+explained above. The first group shows the statistics for all traffic
+flowing out the interface at one hop and in the interface at the next
+hop. The second group shows the statistics only for traffic forwarded
+from the specified
+.I source
+to the specified
+.IR group .
+.PP
+These statistics are shown on one or two lines for each hop. Without
+any options, this second section of the output is printed only once,
+approximately 10 seconds after the initial trace. One line is shown
+for each hop showing the statistics over that 10-second period. If
+the
+.B \-l
+option is given, the second section is repeated every 10 seconds and
+two lines are shown for each hop. The first line shows the statistics
+for the last 10 seconds, and the second line shows the cumulative
+statistics over the period since the initial trace, which is 101
+seconds in the example below. The second section of the output is
+omitted if the
+.B \-s
+option is set.
+.ie t \{\
+.ft C
+. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
+(If this example is not properly columned with a fixed-width font, get
+.B groff
+and try again.)
+. \}
+.\}
+.PP
+.ft C
+.nf
+Waiting to accumulate statistics... Results after 101 seconds:
+
+ Source Response Dest Packet Statistics For Only For Traffic
+18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170
+ | __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3
+ v / hop 65 ms --------------------- ------------------
+18.26.0.144
+140.173.48.2 mit.dart.net
+ | ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.48.1
+140.173.32.1 bbn.dart.net
+ | ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.32.2
+140.173.64.1 dc.dart.net
+ | ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps
+ v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps
+140.173.64.2
+140.173.128.1 la.dart.net
+ | ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps
+ v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps
+140.173.128.2
+128.9.160.153 cub.isi.edu
+ | \\__ ttl 5 833 83 pps 2 0 pps
+ v \\ hop -8 ms 8075 79 pps 18 0 pps
+128.9.160.100 128.9.160.100
+ Receiver Query Source
+.fi
+.PP
+Because the packet counts may be changing as the trace query is
+propagating, there may be small errors (off by 1 or 2) in these
+statistics. However, those errors should not accumulate, so the
+cumulative statistics line should increase in accuracy as a new trace
+is run every 10 seconds. There are two sources of larger errors, both
+of which show up as negative losses:
+.LP
+.RS
+.PD 0
+.TP 3
+\(bu
+If the input to a node is from a multi-access network with more than
+one other node attached, then the input count will be (close to) the
+sum of the output counts from all the attached nodes, but the output
+count from the previous hop on the traced path will be only part of
+that. Hence the output count minus the input count will be negative.
+.TP 3
+\(bu
+In release 3.3 of the DVMRP multicast forwarding software for SunOS
+and other systems, a multicast packet generated on a router will be
+counted as having come in an interface even though it did not. This
+creates the negative loss that can be seen in the example above.
+.PD
+.RE
+.LP
+Note that these negative losses may mask positive losses.
+.PP
+In the example, there is also one negative hop time. This simply
+indicates a lack of synchronization between the system clocks across
+that hop. This example also illustrates how the percentage loss is
+shown as two dashes when the number of packets sent is less than 10
+because the percentage would not be statistically valid.
+.PP
+A second example shows a trace to a receiver that is not local; the
+query is sent to the last-hop router with the
+.B \-g
+option. In this example, the trace of the full reverse path resulted
+in no response because there was a node running an old version of
+.B mrouted
+that did not implement the multicast traceroute function, so
+.B mtrace
+switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code
+indicates that traffic for group 224.2.143.24 would not be forwarded.
+.PP
+.nf
+.ft C
+oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\
+ butter.lcs.mit.edu 224.2.143.24
+Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24
+Querying full reverse path... * switching to hop-by-hop:
+ 0 butter.lcs.mit.edu (18.26.0.151)
+ -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned
+ -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms
+ -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms
+ -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms
+ -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond
+Round trip time 95 ms
+.fi
+.SH AUTHOR
+Implemented by Steve Casner based on an initial prototype written by
+Ajit Thyagarajan. The multicast traceroute mechanism was designed by
+Van Jacobson with help from Steve Casner, Steve Deering, Dino
+Farinacci, and Deb Agrawal; it was implemented in
+.B mrouted
+by Ajit Thyagarajan and Bill Fenner. The option syntax and the output
+format of
+.B mtrace
+are modeled after the unicast
+.B traceroute
+program written by Van Jacobson.
+.SH SEE ALSO
+.BR mrouted (8),
+.BR mrinfo (8),
+.BR map-mbone (8),
+.BR traceroute (8)
diff --git a/usr.sbin/mtrace/mtrace.c b/usr.sbin/mtrace/mtrace.c
new file mode 100644
index 00000000000..d7bfe3f1c3a
--- /dev/null
+++ b/usr.sbin/mtrace/mtrace.c
@@ -0,0 +1,1343 @@
+/* $NetBSD: mtrace.c,v 1.4 1995/10/04 03:47:57 thorpej Exp $ */
+
+/*
+ * mtrace.c
+ *
+ * This tool traces the branch of a multicast tree from a source to a
+ * receiver for a particular multicast group and gives statistics
+ * about packet rate and loss for each hop along the path. It can
+ * usually be invoked just as
+ *
+ * mtrace source
+ *
+ * to trace the route from that source to the local host for a default
+ * group when only the route is desired and not group-specific packet
+ * counts. See the usage line for more complex forms.
+ *
+ *
+ * Released 4 Apr 1995. This program was adapted by Steve Casner
+ * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and
+ * Xerox PARC). It attempts to parallel in command syntax and output
+ * format the unicast traceroute program written by Van Jacobson (LBL)
+ * for the parts where that makes sense.
+ *
+ * Copyright (c) 1995 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ *
+ * In particular, parts of the prototype version of this program may
+ * have been derived from mrouted programs sources covered by the
+ * license in the accompanying file named "LICENSE".
+ */
+
+#include <sys/filio.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <memory.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int optind;
+extern char *optarg;
+
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to try */
+#define MAXHOPS UNREACHABLE /* Don't need more hops than max metric */
+#define UNICAST_TTL 255 /* TTL for unicast response */
+#define MULTICAST_TTL1 64 /* Default TTL for multicast query/response */
+#define MULTICAST_TTL_INC 32 /* TTL increment for increase after timeout */
+#define MULTICAST_TTL_MAX 192 /* Maximum TTL allowed (protect low-BW links */
+
+struct resp_buf {
+ u_long qtime; /* Time query was issued */
+ u_long rtime; /* Time response was received */
+ int len; /* Number of reports or length of data */
+ struct igmp igmp; /* IGMP header */
+ union {
+ struct {
+ struct tr_query q; /* Query/response header */
+ struct tr_resp r[MAXHOPS]; /* Per-hop reports */
+ } t;
+ char d[MAX_DVMRP_DATA_LEN]; /* Neighbor data */
+ } u;
+} base, incr[2];
+
+#define qhdr u.t.q
+#define resps u.t.r
+#define ndata u.d
+
+char names[MAXHOPS][40];
+
+int timeout = DEFAULT_TIMEOUT;
+int nqueries = DEFAULT_RETRIES;
+int numeric = FALSE;
+int debug = 0;
+int passive = FALSE;
+int multicast = FALSE;
+
+u_int32_t defgrp; /* Default group if not specified */
+u_int32_t query_cast; /* All routers multicast addr */
+u_int32_t resp_cast; /* Mtrace response multicast addr */
+
+u_int32_t lcl_addr = 0; /* This host address, in NET order */
+u_int32_t dst_netmask; /* netmask to go with qdst */
+
+/*
+ * Query/response parameters, all initialized to zero and set later
+ * to default values or from options.
+ */
+u_int32_t qsrc = 0;
+u_int32_t qgrp = 0;
+u_int32_t qdst = 0;
+u_char qno = 0;
+u_int32_t raddr = 0;
+int qttl = 0;
+u_char rttl = 0;
+u_int32_t gwy = 0;
+
+vifi_t numvifs; /* to keep loader happy */
+ /* (see kern.c) */
+extern void k_join();
+extern void k_leave();
+extern void k_set_ttl();
+extern void exit();
+#ifndef SYSV
+extern long random();
+#endif
+extern int errno;
+
+void
+usage()
+{
+
+ printf("\
+Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
+ [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
+ exit(1);
+}
+
+
+char *
+inet_name(addr)
+ u_int32_t addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : "?";
+}
+
+
+u_int32_t
+host_addr(name)
+ char *name;
+{
+ struct hostent *e;
+ struct in_addr ina;
+ int i, dots = 3;
+ char buf[40];
+ char *ip = name;
+ char *op = buf;
+
+ /*
+ * Undo the BSD-ism `127.1' == `127.0.0.1'. We change this to
+ * `127.1' == `127.1.0.0'.
+ */
+
+ for (i = sizeof(buf) - 7; i > 0; --i) {
+ if (*ip == '.')
+ --dots;
+ if (*ip == '\0')
+ break;
+ *op++ = *ip++;
+ }
+ for (i = 0; i < dots; ++i) {
+ *op++ = '.';
+ *op++ = '0';
+ }
+ *op = '\0';
+
+ if (inet_aton(buf, &ina) == 0) {
+ if ((e = gethostbyname(name)) == NULL) {
+ ina.s_addr = 0;
+ printf("Could not parse %s as host name or address\n", name);
+ } else
+ memcpy((char *)&ina.s_addr, e->h_addr_list[0], e->h_length);
+ }
+
+ return (ina.s_addr);
+}
+
+
+char *
+proto_type(type)
+ u_char type;
+{
+ static char buf[80];
+
+ switch (type) {
+ case PROTO_DVMRP:
+ return ("DVMRP");
+ case PROTO_MOSPF:
+ return ("MOSPF");
+ case PROTO_PIM:
+ return ("PIM");
+ case PROTO_CBT:
+ return ("CBT");
+ default:
+ (void) sprintf(buf, "Unknown protocol code %d", type);
+ return (buf);
+ }
+}
+
+
+char *
+flag_type(type)
+ u_char type;
+{
+ static char buf[80];
+
+ switch (type) {
+ case TR_NO_ERR:
+ return ("");
+ case TR_WRONG_IF:
+ return ("Wrong interface");
+ case TR_PRUNED:
+ return ("Prune sent upstream");
+ case TR_OPRUNED:
+ return ("Output pruned");
+ case TR_SCOPED:
+ return ("Hit scope boundary");
+ case TR_NO_RTE:
+ return ("No route");
+ case TR_OLD_ROUTER:
+ return ("Next router no mtrace");
+ case TR_NO_FWD:
+ return ("Not forwarding");
+ case TR_NO_SPACE:
+ return ("No space in packet");
+ default:
+ (void) sprintf(buf, "Unknown error code %d", type);
+ return (buf);
+ }
+}
+
+/*
+ * If destination is on a local net, get the netmask, else set the
+ * netmask to all ones. There are two side effects: if the local
+ * address was not explicitly set, and if the destination is on a
+ * local net, use that one; in either case, verify that the local
+ * address is valid.
+ */
+
+u_int32_t
+get_netmask(s, dst)
+ int s;
+ u_int32_t dst;
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int i;
+ u_int32_t if_addr, if_mask;
+ u_int32_t retval = 0xFFFFFFFF;
+ int found = FALSE;
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+ perror("ioctl (SIOCGIFCONF)");
+ return (retval);
+ }
+
+ for (i = 0; i < ifc.ifc_len; ) {
+ ifr = (struct ifreq *)((char *)ifc.ifc_req + i);
+ i += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ if_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
+ if (ioctl(s, SIOCGIFNETMASK, (char *)ifr) >= 0) {
+ if_mask = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
+ if ((dst & if_mask) == (if_addr & if_mask)) {
+ retval = if_mask;
+ if (lcl_addr == 0)
+ lcl_addr = if_addr;
+ }
+ }
+ if (lcl_addr == if_addr)
+ found = TRUE;
+ }
+ if (!found && lcl_addr != 0) {
+ printf("Interface address is not valid\n");
+ exit(1);
+ }
+ return (retval);
+}
+
+
+int
+get_ttl(buf)
+ struct resp_buf *buf;
+{
+ register rno;
+ register struct tr_resp *b;
+ register ttl;
+
+ if (buf && (rno = buf->len) > 0) {
+ b = buf->resps + rno - 1;
+ ttl = b->tr_fttl;
+
+ while (--rno > 0) {
+ --b;
+ if (ttl < b->tr_fttl)
+ ttl = b->tr_fttl;
+ else
+ ++ttl;
+ }
+ ttl += MULTICAST_TTL_INC;
+ if (ttl < MULTICAST_TTL1)
+ ttl = MULTICAST_TTL1;
+ if (ttl > MULTICAST_TTL_MAX)
+ ttl = MULTICAST_TTL_MAX;
+ return (ttl);
+ } else
+ return(MULTICAST_TTL1);
+}
+
+/*
+ * Calculate the difference between two 32-bit NTP timestamps and return
+ * the result in milliseconds.
+ */
+int
+t_diff(a, b)
+ u_long a, b;
+{
+ int d = a - b;
+
+ return ((d * 125) >> 13);
+}
+
+/*
+ * Fixup for incorrect time format in 3.3 mrouted.
+ * This is possible because (JAN_1970 mod 64K) is quite close to 32K,
+ * so correct and incorrect times will be far apart.
+ */
+u_long
+fixtime(time)
+ u_long time;
+{
+ if (abs((int)(time-base.qtime)) > 0x3FFFFFFF)
+ time = ((time & 0xFFFF0000) + (JAN_1970 << 16)) +
+ ((time & 0xFFFF) << 14) / 15625;
+ return (time);
+}
+
+int
+send_recv(dst, type, code, tries, save)
+ u_int32_t dst;
+ int type, code, tries;
+ struct resp_buf *save;
+{
+ fd_set fds;
+ struct timeval tq, tr, tv;
+ struct ip *ip;
+ struct igmp *igmp;
+ struct tr_query *query, *rquery;
+ int ipdatalen, iphdrlen, igmpdatalen;
+ u_int32_t local, group;
+ int datalen;
+ int count, recvlen, dummy = 0;
+ int len;
+ int i;
+
+ if (type == IGMP_MTRACE_QUERY) {
+ group = qgrp;
+ datalen = sizeof(struct tr_query);
+ } else {
+ group = htonl(MROUTED_LEVEL);
+ datalen = 0;
+ }
+ if (IN_MULTICAST(ntohl(dst)))
+ local = lcl_addr;
+ else
+ local = INADDR_ANY;
+
+ /*
+ * If the reply address was not explictly specified, start off
+ * with the unicast address of this host. Then, if there is no
+ * response after trying half the tries with unicast, switch to
+ * the standard multicast reply address. If the TTL was also not
+ * specified, set a multicast TTL and if needed increase it for the
+ * last quarter of the tries.
+ */
+ query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ query->tr_raddr = raddr ? raddr : multicast ? resp_cast : lcl_addr;
+ query->tr_rttl = rttl ? rttl :
+ IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL;
+
+ for (i = tries ; i > 0; --i) {
+ if (tries == nqueries && raddr == 0) {
+ if (i == ((nqueries + 1) >> 1)) {
+ query->tr_raddr = resp_cast;
+ if (rttl == 0) query->tr_rttl = get_ttl(save);
+ }
+ if (i <= ((nqueries + 3) >> 2) && rttl == 0) {
+ query->tr_rttl += MULTICAST_TTL_INC;
+ if (query->tr_rttl > MULTICAST_TTL_MAX)
+ query->tr_rttl = MULTICAST_TTL_MAX;
+ }
+ }
+
+ /*
+ * Change the qid for each request sent to avoid being confused
+ * by duplicate responses
+ */
+ query->tr_qid = ((u_int32_t)random() >> 8);
+
+ /*
+ * Set timer to calculate delays, then send query
+ */
+ gettimeofday(&tq, 0);
+ send_igmp(local, dst, type, code, group, datalen);
+
+ /*
+ * Wait for response, discarding false alarms
+ */
+ while (TRUE) {
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+ gettimeofday(&tv, 0);
+ tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;
+ tv.tv_usec = tq.tv_usec - tv.tv_usec;
+ if (tv.tv_usec < 0)
+ tv.tv_usec += 1000000L, --tv.tv_sec;
+ if (tv.tv_sec < 0)
+ tv.tv_sec = tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, (fd_set *)0, (fd_set *)0,
+ &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ printf("* ");
+ fflush(stdout);
+ break;
+ }
+
+ gettimeofday(&tr, 0);
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, (struct sockaddr *)0, &dummy);
+
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR)
+ perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ fprintf(stderr,
+ "packet too short (%u bytes) for IP header", recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ if (ip->ip_p == 0) /* ignore cache creation requests */
+ continue;
+
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ fprintf(stderr,
+ "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ fprintf(stderr,
+ "IP data field too short (%u bytes) for IGMP from %s\n",
+ ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
+ continue;
+ }
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_DVMRP:
+ if (igmp->igmp_code != DVMRP_NEIGHBORS2)
+ continue;
+ if (ip->ip_src.s_addr != dst)
+ continue;
+ len = igmpdatalen;
+ break;
+
+ case IGMP_MTRACE_QUERY: /* For backward compatibility with 3.3 */
+ case IGMP_MTRACE_REPLY:
+ if (igmpdatalen <= QLEN)
+ continue;
+ if ((igmpdatalen - QLEN)%RLEN) {
+ printf("packet with incorrect datalen\n");
+ continue;
+ }
+
+ /*
+ * Ignore responses that don't match query.
+ */
+ rquery = (struct tr_query *)(igmp + 1);
+ if (rquery->tr_qid != query->tr_qid)
+ continue;
+ if (rquery->tr_src != qsrc)
+ continue;
+ if (rquery->tr_dst != qdst)
+ continue;
+ len = (igmpdatalen - QLEN)/RLEN;
+
+ /*
+ * Ignore trace queries passing through this node when
+ * mtrace is run on an mrouter that is in the path
+ * (needed only because IGMP_MTRACE is accepted above
+ * for backward compatibility with multicast release 3.3).
+ */
+ if (igmp->igmp_type == IGMP_MTRACE_QUERY) {
+ struct tr_resp *r = (struct tr_resp *)(rquery+1) + len - 1;
+ u_int32_t smask;
+
+ VAL_TO_MASK(smask, r->tr_smask);
+ if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)
+ && r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))
+ continue;
+ }
+
+ /*
+ * A match, we'll keep this one.
+ */
+ if (len > code) {
+ fprintf(stderr,
+ "Num hops received (%d) exceeds request (%d)\n",
+ len, code);
+ }
+ rquery->tr_raddr = query->tr_raddr; /* Insure these are */
+ rquery->tr_rttl = query->tr_rttl; /* as we sent them */
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Most of the sanity checking done at this point.
+ * Return this packet we have been waiting for.
+ */
+ if (save) {
+ save->qtime = ((tq.tv_sec + JAN_1970) << 16) +
+ (tq.tv_usec << 10) / 15625;
+ save->rtime = ((tr.tv_sec + JAN_1970) << 16) +
+ (tr.tv_usec << 10) / 15625;
+ save->len = len;
+ bcopy((char *)igmp, (char *)&save->igmp, ipdatalen);
+ }
+ return (recvlen);
+ }
+ }
+ return (0);
+}
+
+
+char *
+print_host(addr)
+ u_int32_t addr;
+{
+ char *name;
+
+ if (numeric) {
+ printf("%s", inet_fmt(addr, s1));
+ return ("");
+ }
+ name = inet_name(addr);
+ printf("%s (%s)", name, inet_fmt(addr, s1));
+ return (name);
+}
+
+/*
+ * Print responses as received (reverse path from dst to src)
+ */
+void
+print_trace(index, buf)
+ int index;
+ struct resp_buf *buf;
+{
+ struct tr_resp *r;
+ char *name;
+ int i;
+
+ i = abs(index);
+ r = buf->resps + i - 1;
+
+ for (; i <= buf->len; ++i, ++r) {
+ if (index > 0) printf("%3d ", -i);
+ name = print_host(r->tr_outaddr);
+ printf(" %s thresh^ %d %d ms %s\n", proto_type(r->tr_rproto),
+ r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
+ flag_type(r->tr_rflags));
+ memcpy(names[i-1], name, sizeof(names[0]) - 1);
+ names[i-1][sizeof(names[0])-1] = '\0';
+ }
+}
+
+/*
+ * See what kind of router is the next hop
+ */
+void
+what_kind(buf)
+ struct resp_buf *buf;
+{
+ u_int32_t smask;
+ int recvlen;
+ int hops = buf->len;
+ struct tr_resp *r = buf->resps + hops - 1;
+ u_int32_t next = r->tr_rmtaddr;
+
+ recvlen = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
+ print_host(next);
+ if (recvlen) {
+ u_int32_t version = ntohl(incr[0].igmp.igmp_group.s_addr);
+ u_int32_t *p = (u_int32_t *)incr[0].ndata;
+ u_int32_t *ep = p + (incr[0].len >> 2);
+ printf(" [%s%d.%d] didn't respond\n",
+ (version == 1) ? "proteon/mrouted " :
+ ((version & 0xff) == 2) ? "mrouted " :
+ ((version & 0xff) == 3) ? "mrouted " :
+ ((version & 0xff) == 4) ? "mrouted " :
+ ((version & 0xff) == 10) ? "cisco " : "",
+ version & 0xff, (version >> 8) & 0xff);
+ VAL_TO_MASK(smask, r->tr_smask);
+ while (p < ep) {
+ register u_int32_t laddr = *p++;
+ register int n = ntohl(*p++) & 0xFF;
+ if ((laddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops+2));
+ print_host(qsrc);
+ printf("\n");
+ break;
+ }
+ p += n;
+ }
+ return;
+ }
+ printf(" didn't respond\n");
+}
+
+
+char *
+scale(hop)
+ int *hop;
+{
+ if (*hop > -1000 && *hop < 10000) return (" ms");
+ *hop /= 1000;
+ if (*hop > -1000 && *hop < 10000) return (" s ");
+ return ("s ");
+}
+
+/*
+ * Calculate and print one line of packet loss and packet rate statistics.
+ * Checks for count of all ones from mrouted 2.3 that doesn't have counters.
+ */
+#define NEITHER 0
+#define INS 1
+#define OUTS 2
+#define BOTH 3
+void
+stat_line(r, s, have_next)
+ struct tr_resp *r, *s;
+ int have_next;
+{
+ register timediff = (fixtime(ntohl(s->tr_qarr)) -
+ fixtime(ntohl(r->tr_qarr))) >> 16;
+ register v_lost, v_pct;
+ register g_lost, g_pct;
+ register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
+ register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
+ register v_pps, g_pps;
+ char v_str[8], g_str[8];
+ register have = NEITHER;
+
+ if (timediff == 0)
+ timediff = 1;
+ v_pps = v_out / timediff;
+ g_pps = g_out / timediff;
+
+ if (v_out || s->tr_vifout != 0xFFFFFFFF)
+ have |= OUTS;
+
+ if (have_next) {
+ --r, --s;
+ if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
+ have |= INS;
+ }
+
+ switch (have) {
+ case BOTH:
+ v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
+ if (v_out)
+ v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
+ else
+ v_pct = 0;
+ if (-100 < v_pct && v_pct < 101 && v_out > 10)
+ sprintf(v_str, "%3d", v_pct);
+ else
+ memcpy(v_str, " --", 4);
+
+ g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ if (g_out)
+ g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
+ else
+ g_pct = 0;
+ if (-100 < g_pct && g_pct < 101 && g_out > 10)
+ sprintf(g_str, "%3d", g_pct);
+ else
+ memcpy(g_str, " --", 4);
+
+ printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
+ v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
+ if (debug > 2) {
+ printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout));
+ printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(r->tr_vifout));
+ printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
+ printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ printf("time: %d\n", timediff);
+ }
+ break;
+
+ case INS:
+ v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
+ g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ v_pps = v_out / timediff;
+ g_pps = g_out / timediff;
+ /* Fall through */
+
+ case OUTS:
+ printf(" %-5d %4d pps %-5d %4d pps\n",
+ v_out, v_pps, g_out, g_pps);
+ break;
+
+ case NEITHER:
+ printf("\n");
+ break;
+ }
+}
+
+/*
+ * A fixup to check if any pktcnt has been reset.
+ */
+void
+fixup_stats(base, new)
+ struct resp_buf *base, *new;
+{
+ register rno = base->len;
+ register struct tr_resp *b = base->resps + rno;
+ register struct tr_resp *n = new->resps + rno;
+
+ while (--rno >= 0)
+ if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt))
+ break;
+
+ if (rno < 0)
+ return;
+
+ rno = base->len;
+ b = base->resps + rno;
+ n = new->resps + rno;
+
+ while (--rno >= 0)
+ (--b)->tr_pktcnt = (--n)->tr_pktcnt;
+}
+
+/*
+ * Print responses with statistics for forward path (from src to dst)
+ */
+void
+print_stats(base, prev, new)
+ struct resp_buf *base, *prev, *new;
+{
+ int rtt, hop;
+ register char *ms;
+ register u_int32_t smask;
+ register rno = base->len - 1;
+ register struct tr_resp *b = base->resps + rno;
+ register struct tr_resp *p = prev->resps + rno;
+ register struct tr_resp *n = new->resps + rno;
+ register u_long resptime = new->rtime;
+ register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
+ register ttl = n->tr_fttl;
+
+ VAL_TO_MASK(smask, b->tr_smask);
+ printf(" Source Response Dest");
+ printf(" Packet Statistics For Only For Traffic\n");
+ printf("%-15s %-15s All Multicast Traffic From %s\n",
+ ((b->tr_inaddr & smask) == (qsrc & smask)) ? s1 : " * * * ",
+ inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
+ rtt = t_diff(resptime, new->qtime);
+ ms = scale(&rtt);
+ printf(" | __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
+ rtt, ms, inet_fmt(qgrp, s2));
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v / hop%5d%s", hop, ms);
+ printf(" --------------------- --------------------\n");
+ if (debug > 2) {
+ printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
+ printf("v_out: %ld ", ntohl(n->tr_vifout));
+ printf("pkts: %ld\n", ntohl(n->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(b->tr_vifin));
+ printf("v_out: %ld ", ntohl(b->tr_vifout));
+ printf("pkts: %ld\n", ntohl(b->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
+ printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
+ printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
+ }
+
+ while (TRUE) {
+ if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr)) {
+ printf("Route changed, start again.\n");
+ exit(1);
+ }
+ if ((n->tr_inaddr != n->tr_outaddr))
+ printf("%-15s\n", inet_fmt(n->tr_inaddr, s1));
+ printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
+ flag_type(n->tr_rflags));
+
+ if (rno-- < 1) break;
+
+ printf(" | ^ ttl%5d ", ttl);
+ if (prev == new)
+ printf("\n");
+ else
+ stat_line(p, n, TRUE);
+ resptime = qarrtime;
+ qarrtime = fixtime(ntohl((n-1)->tr_qarr));
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v | hop%5d%s", hop, ms);
+ stat_line(b, n, TRUE);
+
+ --b, --p, --n;
+ if (ttl < n->tr_fttl)
+ ttl = n->tr_fttl;
+ else
+ ++ttl;
+ }
+
+ printf(" | \\__ ttl%5d ", ttl);
+ if (prev == new)
+ printf("\n");
+ else
+ stat_line(p, n, FALSE);
+ hop = t_diff(qarrtime, new->qtime);
+ ms = scale(&hop);
+ printf(" v \\ hop%5d%s", hop, ms);
+ stat_line(b, n, FALSE);
+ printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
+ printf(" Receiver Query Source\n\n");
+}
+
+
+/***************************************************************************
+ * main
+ ***************************************************************************/
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+ int recvlen;
+ struct timeval tv;
+ struct resp_buf *prev, *new;
+ struct tr_query *query;
+ struct tr_resp *r;
+ u_int32_t smask;
+ int rno;
+ int hops, tries;
+ int numstats = 1;
+ int waittime;
+ int seed;
+ int ch;
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mtrace: must be root\n");
+ exit(1);
+ }
+
+ while ((ch = getopt(argc, argv, "d:g:i:lMm:npq:r:st:w:")) != -1) {
+ switch (ch) {
+ case 'd': /* Unlisted debug print option */
+ if (!isdigit(*optarg))
+ usage();
+ debug = atoi(optarg);
+ if (debug < 0)
+ debug = 0;
+ else if (debug > 3)
+ debug = 3;
+ break;
+
+ case 'M': /* Use multicast for reponse */
+ multicast = TRUE;
+ break;
+
+ case 'l': /* Loop updating stats indefinitely */
+ numstats = 3153600;
+ break;
+
+ case 'n': /* Don't reverse map host addresses */
+ numeric = TRUE;
+ break;
+
+ case 'p': /* Passive listen for traces */
+ passive = TRUE;
+ break;
+
+ case 's': /* Short form, don't wait for stats */
+ numstats = 0;
+ break;
+
+ case 'w': /* Time to wait for packet arrival */
+ if (!isdigit(*optarg))
+ usage();
+ timeout = atoi(optarg);
+ if (timeout < 1)
+ timeout = 1;
+ break;
+
+ case 'm': /* Max number of hops to trace */
+ if (!isdigit(*optarg))
+ usage();
+ qno = atoi(optarg);
+ if (qno > MAXHOPS)
+ qno = MAXHOPS;
+ else if (qno < 1)
+ qno = 0;
+ break;
+
+ case 'q': /* Number of query retries */
+ if (!isdigit(*optarg))
+ usage();
+ nqueries = atoi(optarg);
+ if (nqueries < 1)
+ nqueries = 1;
+ break;
+
+ case 'g': /* Last-hop gateway (dest of query) */
+ if ((gwy = host_addr(optarg)) == 0)
+ usage();
+ break;
+
+ case 't': /* TTL for query packet */
+ if (!isdigit(*optarg))
+ usage();
+ qttl = atoi(optarg);
+ if (qttl < 1)
+ qttl = 1;
+ rttl = qttl;
+ break;
+
+ case 'r': /* Dest for response packet */
+ if ((raddr = host_addr(optarg)) == 0)
+ usage();
+ break;
+
+ case 'i': /* Local interface address */
+ if ((lcl_addr = host_addr(optarg)) == 0)
+ usage();
+ break;
+
+ default:
+ usage();
+ } /* switch */
+ } /* while */
+ argv += optind;
+ argc -= optind;
+
+ switch (argc) {
+ case 3: /* Path via group */
+ if ((qgrp = host_addr(argv[2])) == 0)
+ usage();
+ /* FALLTHROUGH */
+ case 2: /* dest of path */
+ if ((qdst = host_addr(argv[1])) == 0)
+ usage();
+ /* FALLTHROUGH */
+ case 1: /* source of path */
+ if ((qsrc = host_addr(argv[0])) == 0 || IN_MULTICAST(ntohl(qsrc)))
+ usage();
+ break;
+
+ default:
+ usage();
+ }
+
+ /*
+ * If argc is > 1 and the second argument is a multicast address,
+ * assume that the second argument is actually qgrp and the third
+ * (if any) is qdst; in this case, the third argument is not allowed
+ * to be a multicast address.
+ */
+ if (argc > 1) {
+ if (IN_MULTICAST(ntohl(qdst))) {
+ u_int32_t temp = qdst;
+ qdst = qgrp;
+ qgrp = temp;
+ if (IN_MULTICAST(ntohl(qdst)))
+ usage();
+ } else if (qgrp != 0 && !IN_MULTICAST(ntohl(qgrp)))
+ usage();
+ }
+
+ if (qsrc == 0)
+ usage();
+
+ init_igmp();
+
+ /*
+ * Set useful defaults for as many parameters as possible.
+ */
+
+ defgrp = htonl(0xE0020001); /* MBone Audio (224.2.0.1) */
+ query_cast = htonl(0xE0000002); /* All routers multicast addr */
+ resp_cast = htonl(0xE0000120); /* Mtrace response multicast addr */
+ if (qgrp == 0)
+ qgrp = defgrp;
+
+ /*
+ * Get default local address for multicasts to use in setting defaults.
+ */
+ addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof(addr);
+#endif
+ addr.sin_addr.s_addr = qgrp;
+ addr.sin_port = htons(2000); /* Any port above 1024 will do */
+
+ if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
+ (connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||
+ getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+
+ /*
+ * Default destination for path to be queried is the local host.
+ */
+ if (qdst == 0)
+ qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
+
+ /*
+ * If the destination is on the local net, the last-hop router can
+ * be found by multicast to the all-routers multicast group.
+ * Otherwise, use the group address that is the subject of the
+ * query since by definition the last hop router will be a member.
+ * Set default TTLs for local remote multicasts.
+ */
+ dst_netmask = get_netmask(udp, qdst);
+ close(udp);
+ if (lcl_addr == 0)
+ lcl_addr = addr.sin_addr.s_addr;
+ if (gwy == 0)
+ if ((qdst & dst_netmask) == (lcl_addr & dst_netmask))
+ gwy = query_cast;
+ else
+ gwy = qgrp;
+
+ if (IN_MULTICAST(ntohl(gwy))) {
+ k_set_loop(1); /* If I am running on a router, I need to hear this */
+ if (gwy == query_cast)
+ k_set_ttl(qttl ? qttl : 1);
+ else
+ k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
+ } else
+ if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]))
+ if (ntohl(incr[0].igmp.igmp_group.s_addr) == 0x0303) {
+ printf("Don't use -g to address an mrouted 3.3, it might crash\n");
+ exit(0);
+ }
+
+ printf("Mtrace from %s to %s via group %s\n",
+ inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));
+
+ if ((qdst & dst_netmask) == (qsrc & dst_netmask)) {
+ printf("Source & receiver are directly connected, no path to trace\n");
+ exit(0);
+ }
+
+ /*
+ * Make up the IGMP_MTRACE_QUERY query packet to send (some parameters
+ * are set later), including initializing the seed for random
+ * query identifiers.
+ */
+ query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ query->tr_src = qsrc;
+ query->tr_dst = qdst;
+
+ gettimeofday(&tv, 0);
+ seed = tv.tv_usec ^ lcl_addr;
+ srandom(seed);
+
+ /*
+ * If the response is to be a multicast address, make sure we
+ * are listening on that multicast address.
+ */
+ if (raddr && IN_MULTICAST(ntohl(raddr)))
+ k_join(raddr, lcl_addr);
+ else
+ k_join(resp_cast, lcl_addr);
+
+ /*
+ * Try a query at the requested number of hops or MAXOPS if unspecified.
+ */
+ if (qno == 0) {
+ hops = MAXHOPS;
+ tries = 1;
+ printf("Querying full reverse path... ");
+ fflush(stdout);
+ } else {
+ hops = qno;
+ tries = nqueries;
+ printf("Querying reverse path, maximum %d hops... ", qno);
+ fflush(stdout);
+ }
+ base.rtime = 0;
+ base.len = 0;
+
+ recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, hops, tries, &base);
+
+ /*
+ * If the initial query was successful, print it. Otherwise, if
+ * the query max hop count is the default of zero, loop starting
+ * from one until a timeout occurs.
+ */
+ if (recvlen) {
+ printf("\n 0 ");
+ print_host(qdst);
+ printf("\n");
+ print_trace(1, &base);
+ r = base.resps + base.len - 1;
+ if (r->tr_rflags == TR_OLD_ROUTER) {
+ printf("%3d ", -(base.len+1));
+ fflush(stdout);
+ what_kind(&base);
+ } else {
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(base.len+1));
+ print_host(qsrc);
+ printf("\n");
+ }
+ }
+ } else if (qno == 0) {
+ printf("switching to hop-by-hop:\n 0 ");
+ print_host(qdst);
+ printf("\n");
+
+ for (hops = 1; hops <= MAXHOPS; ++hops) {
+ printf("%3d ", -hops);
+ fflush(stdout);
+
+ recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, hops, nqueries, &base);
+
+ if (recvlen == 0) {
+ if (--hops == 0) break;
+ what_kind(&base);
+ break;
+ }
+ r = base.resps + base.len - 1;
+ if (base.len == hops)
+ print_trace(-hops, &base);
+ else {
+ hops = base.len;
+ if (r->tr_rflags == TR_OLD_ROUTER) {
+ what_kind(&base);
+ break;
+ }
+ if (r->tr_rflags == TR_NO_SPACE) {
+ printf("No space left in trace packet for further hops\n");
+ break; /* XXX could do segmented trace */
+ }
+ printf("Route must have changed...\n\n");
+ print_trace(1, &base);
+ }
+
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops+1));
+ print_host(qsrc);
+ printf("\n");
+ break;
+ }
+ if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80))
+ break;
+ }
+ }
+
+ if (base.rtime == 0) {
+ printf("Timed out receiving responses\n");
+ if (IN_MULTICAST(ntohl(gwy)))
+ if (gwy == query_cast)
+ printf("Perhaps no local router has a route for source %s\n",
+ inet_fmt(qsrc, s1));
+ else
+ printf("Perhaps receiver %s is not a member of group %s,\n\
+or no router local to it has a route for source %s,\n\
+or multicast at ttl %d doesn't reach its last-hop router for that source\n",
+ inet_fmt(qdst, s2), inet_fmt(qgrp, s3), inet_fmt(qsrc, s1),
+ qttl ? qttl : MULTICAST_TTL1);
+ exit(1);
+ }
+
+ printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime));
+
+ /*
+ * Use the saved response which was the longest one received,
+ * and make additional probes after delay to measure loss.
+ */
+ raddr = base.qhdr.tr_raddr;
+ rttl = base.qhdr.tr_rttl;
+ gettimeofday(&tv, 0);
+ waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
+ prev = new = &incr[numstats&1];
+
+ while (numstats--) {
+ if (waittime < 1) printf("\n");
+ else {
+ printf("Waiting to accumulate statistics... ");
+ fflush(stdout);
+ sleep((unsigned)waittime);
+ }
+ rno = base.len;
+ recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, rno, nqueries, new);
+
+ if (recvlen == 0) {
+ printf("Timed out.\n");
+ exit(1);
+ }
+
+ if (rno != new->len) {
+ printf("Trace length doesn't match.\n");
+ exit(1);
+ }
+
+ printf("Results after %d seconds:\n\n",
+ (new->qtime - base.qtime) >> 16);
+ fixup_stats(&base, new);
+ print_stats(&base, prev, new);
+ prev = new;
+ new = &incr[numstats&1];
+ waittime = 10;
+ }
+
+ /*
+ * If the response was multicast back, leave the group
+ */
+ if (raddr && IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
+ else k_leave(resp_cast, lcl_addr);
+
+ return (0);
+}
+
+void
+check_vif_state()
+{
+ log(LOG_WARNING, errno, "sendto");
+}
+
+/*
+ * Log errors and other messages to stderr, according to the severity
+ * of the message and the current debug level. For errors of severity
+ * LOG_ERR or worse, terminate the program.
+ */
+/*VARARGS3*/
+void
+log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0:
+ if (severity > LOG_WARNING)
+ return;
+ case 1:
+ if (severity > LOG_NOTICE)
+ return;
+ case 2:
+ if (severity > LOG_INFO)
+ return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if(syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+/* dummies */
+
+/*VARARGS*/
+void accept_probe() {} /*VARARGS*/
+void accept_group_report() {} /*VARARGS*/
+void accept_neighbors() {} /*VARARGS*/
+void accept_neighbors2() {} /*VARARGS*/
+void accept_neighbor_request() {} /*VARARGS*/
+void accept_neighbor_request2() {} /*VARARGS*/
+void accept_report() {} /*VARARGS*/
+void accept_prune() {} /*VARARGS*/
+void accept_graft() {} /*VARARGS*/
+void accept_g_ack() {} /*VARARGS*/
+void add_table_entry() {} /*VARARGS*/
+void accept_mtrace() {} /*VARARGS*/
+void accept_leave_message() {} /*VARARGS*/
+void accept_membership_query() {} /*VARARGS*/
diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile
new file mode 100644
index 00000000000..4197e911382
--- /dev/null
+++ b/usr.sbin/mtree/Makefile
@@ -0,0 +1,10 @@
+# $NetBSD: Makefile,v 1.8 1995/03/07 21:12:04 cgd Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= mtree
+#CFLAGS+=-DDEBUG
+MAN= mtree.8
+SRCS= compare.c crc.c create.c misc.c mtree.c spec.c verify.c
+.PATH: ${.CURDIR}/../../usr.bin/cksum
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mtree/compare.c b/usr.sbin/mtree/compare.c
new file mode 100644
index 00000000000..31a656d3021
--- /dev/null
+++ b/usr.sbin/mtree/compare.c
@@ -0,0 +1,277 @@
+/* $NetBSD: compare.c,v 1.8 1995/03/07 21:12:05 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 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
+#if 0
+static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: compare.c,v 1.8 1995/03/07 21:12:05 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int uflag;
+
+static char *ftype __P((u_int));
+
+#define INDENTNAMELEN 8
+#define LABEL \
+ if (!label++) { \
+ len = printf("%s: ", RP(p)); \
+ if (len > INDENTNAMELEN) { \
+ tab = "\t"; \
+ (void)printf("\n"); \
+ } else { \
+ tab = ""; \
+ (void)printf("%*s", INDENTNAMELEN - len, ""); \
+ } \
+ }
+
+int
+compare(name, s, p)
+ char *name;
+ register NODE *s;
+ register FTSENT *p;
+{
+ extern int uflag;
+ u_long len, val;
+ int fd, label;
+ char *cp, *tab;
+
+ label = 0;
+ switch(s->type) {
+ case F_BLOCK:
+ if (!S_ISBLK(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_CHAR:
+ if (!S_ISCHR(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_DIR:
+ if (!S_ISDIR(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_FIFO:
+ if (!S_ISFIFO(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_FILE:
+ if (!S_ISREG(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_LINK:
+ if (!S_ISLNK(p->fts_statp->st_mode))
+ goto typeerr;
+ break;
+ case F_SOCK:
+ if (!S_ISSOCK(p->fts_statp->st_mode)) {
+typeerr: LABEL;
+ (void)printf("\ttype (%s, %s)\n",
+ ftype(s->type), inotype(p->fts_statp->st_mode));
+ }
+ break;
+ }
+ /* Set the uid/gid first, then set the mode. */
+ if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
+ LABEL;
+ (void)printf("%suser (%u, %u",
+ tab, s->st_uid, p->fts_statp->st_uid);
+ if (uflag)
+ if (chown(p->fts_accpath, s->st_uid, -1))
+ (void)printf(", not modified: %s)\n",
+ strerror(errno));
+ else
+ (void)printf(", modified)\n");
+ else
+ (void)printf(")\n");
+ tab = "\t";
+ }
+ if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
+ LABEL;
+ (void)printf("%sgid (%u, %u",
+ tab, s->st_gid, p->fts_statp->st_gid);
+ if (uflag)
+ if (chown(p->fts_accpath, -1, s->st_gid))
+ (void)printf(", not modified: %s)\n",
+ strerror(errno));
+ else
+ (void)printf(", modified)\n");
+ else
+ (void)printf(")\n");
+ tab = "\t";
+ }
+ if (s->flags & F_MODE &&
+ s->st_mode != (p->fts_statp->st_mode & MBITS)) {
+ LABEL;
+ (void)printf("%spermissions (%#o, %#o",
+ tab, s->st_mode, p->fts_statp->st_mode & MBITS);
+ if (uflag)
+ if (chmod(p->fts_accpath, s->st_mode))
+ (void)printf(", not modified: %s)\n",
+ strerror(errno));
+ else
+ (void)printf(", modified)\n");
+ else
+ (void)printf(")\n");
+ tab = "\t";
+ }
+ if (s->flags & F_NLINK && s->type != F_DIR &&
+ s->st_nlink != p->fts_statp->st_nlink) {
+ LABEL;
+ (void)printf("%slink count (%u, %u)\n",
+ tab, s->st_nlink, p->fts_statp->st_nlink);
+ tab = "\t";
+ }
+ if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
+ LABEL;
+ (void)printf("%ssize (%qd, %qd)\n",
+ tab, s->st_size, p->fts_statp->st_size);
+ tab = "\t";
+ }
+ /*
+ * XXX
+ * Catches nano-second differences, but doesn't display them.
+ */
+ if (s->flags & F_TIME &&
+ s->st_mtimespec.ts_sec != p->fts_statp->st_mtimespec.ts_sec ||
+ s->st_mtimespec.ts_nsec != p->fts_statp->st_mtimespec.ts_nsec) {
+ LABEL;
+ (void)printf("%smodification time (%.24s, ",
+ tab, ctime(&s->st_mtimespec.ts_sec));
+ (void)printf("%.24s)\n",
+ ctime(&p->fts_statp->st_mtimespec.ts_sec));
+ tab = "\t";
+ }
+ if (s->flags & F_CKSUM)
+ if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
+ LABEL;
+ (void)printf("%scksum: %s: %s\n",
+ tab, p->fts_accpath, strerror(errno));
+ tab = "\t";
+ } else if (crc(fd, &val, &len)) {
+ (void)close(fd);
+ LABEL;
+ (void)printf("%scksum: %s: %s\n",
+ tab, p->fts_accpath, strerror(errno));
+ tab = "\t";
+ } else {
+ (void)close(fd);
+ if (s->cksum != val) {
+ LABEL;
+ (void)printf("%scksum (%lu, %lu)\n",
+ tab, s->cksum, val);
+ }
+ tab = "\t";
+ }
+ if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) {
+ LABEL;
+ (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink);
+ }
+ return (label);
+}
+
+char *
+inotype(type)
+ u_int type;
+{
+ switch(type & S_IFMT) {
+ case S_IFBLK:
+ return ("block");
+ case S_IFCHR:
+ return ("char");
+ case S_IFDIR:
+ return ("dir");
+ case S_IFIFO:
+ return ("fifo");
+ case S_IFREG:
+ return ("file");
+ case S_IFLNK:
+ return ("link");
+ case S_IFSOCK:
+ return ("socket");
+ default:
+ return ("unknown");
+ }
+ /* NOTREACHED */
+}
+
+static char *
+ftype(type)
+ u_int type;
+{
+ switch(type) {
+ case F_BLOCK:
+ return ("block");
+ case F_CHAR:
+ return ("char");
+ case F_DIR:
+ return ("dir");
+ case F_FIFO:
+ return ("fifo");
+ case F_FILE:
+ return ("file");
+ case F_LINK:
+ return ("link");
+ case F_SOCK:
+ return ("socket");
+ default:
+ return ("unknown");
+ }
+ /* NOTREACHED */
+}
+
+char *
+rlink(name)
+ char *name;
+{
+ static char lbuf[MAXPATHLEN];
+ register int len;
+
+ if ((len = readlink(name, lbuf, sizeof(lbuf))) == -1)
+ err("%s: %s", name, strerror(errno));
+ lbuf[len] = '\0';
+ return (lbuf);
+}
diff --git a/usr.sbin/mtree/create.c b/usr.sbin/mtree/create.c
new file mode 100644
index 00000000000..e2763491ffb
--- /dev/null
+++ b/usr.sbin/mtree/create.c
@@ -0,0 +1,296 @@
+/* $NetBSD: create.c,v 1.9 1995/03/07 21:12:06 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 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
+#if 0
+static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: create.c,v 1.9 1995/03/07 21:12:06 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <dirent.h>
+#include <grp.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+#define INDENTNAMELEN 15
+#define MAXLINELEN 80
+
+extern int crc_total, ftsoptions;
+extern int dflag, sflag;
+extern u_short keys;
+extern char fullpath[MAXPATHLEN];
+
+static gid_t gid;
+static uid_t uid;
+static mode_t mode;
+
+static int dsort __P((const FTSENT **, const FTSENT **));
+static void output __P((int *, const char *, ...));
+static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
+static void statf __P((FTSENT *));
+
+void
+cwalk()
+{
+ register FTS *t;
+ register FTSENT *p;
+ time_t clock;
+ char *argv[2], host[MAXHOSTNAMELEN];
+
+ (void)time(&clock);
+ (void)gethostname(host, sizeof(host));
+ (void)printf(
+ "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s",
+ getlogin(), host, fullpath, ctime(&clock));
+
+ argv[0] = ".";
+ argv[1] = NULL;
+ if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
+ err("fts_open: %s", strerror(errno));
+ while (p = fts_read(t))
+ switch(p->fts_info) {
+ case FTS_D:
+ (void)printf("\n# %s\n", p->fts_path);
+ statd(t, p, &uid, &gid, &mode);
+ statf(p);
+ break;
+ case FTS_DP:
+ if (p->fts_level > 0)
+ (void)printf("# %s\n..\n\n", p->fts_path);
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ (void)fprintf(stderr,
+ "mtree: %s: %s\n", p->fts_path, strerror(errno));
+ break;
+ default:
+ if (!dflag)
+ statf(p);
+ break;
+
+ }
+ (void)fts_close(t);
+ if (sflag && keys & F_CKSUM)
+ (void)fprintf(stderr,
+ "mtree: %s checksum: %lu\n", fullpath, crc_total);
+}
+
+static void
+statf(p)
+ FTSENT *p;
+{
+ struct group *gr;
+ struct passwd *pw;
+ u_long len, val;
+ int fd, indent;
+
+ if (S_ISDIR(p->fts_statp->st_mode))
+ indent = printf("%s", p->fts_name);
+ else
+ indent = printf(" %s", p->fts_name);
+
+ if (indent > INDENTNAMELEN)
+ indent = MAXLINELEN;
+ else
+ indent += printf("%*s", INDENTNAMELEN - indent, "");
+
+ if (!S_ISREG(p->fts_statp->st_mode))
+ output(&indent, "type=%s", inotype(p->fts_statp->st_mode));
+ if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid)
+ if (keys & F_UNAME && (pw = getpwuid(p->fts_statp->st_uid)))
+ output(&indent, "uname=%s", pw->pw_name);
+ else /* if (keys & F_UID) */
+ output(&indent, "uid=%u", p->fts_statp->st_uid);
+ if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid)
+ if (keys & F_GNAME && (gr = getgrgid(p->fts_statp->st_gid)))
+ output(&indent, "gname=%s", gr->gr_name);
+ else /* if (keys & F_GID) */
+ output(&indent, "gid=%u", p->fts_statp->st_gid);
+ if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
+ output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS);
+ if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
+ output(&indent, "nlink=%u", p->fts_statp->st_nlink);
+ if (keys & F_SIZE)
+ output(&indent, "size=%qd", p->fts_statp->st_size);
+ if (keys & F_TIME)
+ output(&indent, "time=%ld.%ld",
+ p->fts_statp->st_mtimespec.ts_sec,
+ p->fts_statp->st_mtimespec.ts_nsec);
+ if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
+ if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
+ crc(fd, &val, &len))
+ err("%s: %s", p->fts_accpath, strerror(errno));
+ (void)close(fd);
+ output(&indent, "cksum=%lu", val);
+ }
+ if (keys & F_SLINK &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
+ output(&indent, "link=%s", rlink(p->fts_accpath));
+ (void)putchar('\n');
+}
+
+#define MAXGID 5000
+#define MAXUID 5000
+#define MAXMODE MBITS + 1
+
+static int
+statd(t, parent, puid, pgid, pmode)
+ FTS *t;
+ FTSENT *parent;
+ uid_t *puid;
+ gid_t *pgid;
+ mode_t *pmode;
+{
+ register FTSENT *p;
+ register gid_t sgid;
+ register uid_t suid;
+ register mode_t smode;
+ struct group *gr;
+ struct passwd *pw;
+ gid_t savegid;
+ uid_t saveuid;
+ mode_t savemode;
+ u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
+
+ if ((p = fts_children(t, 0)) == NULL) {
+ if (errno)
+ err("%s: %s", RP(parent), strerror(errno));
+ return (1);
+ }
+
+ bzero(g, sizeof(g));
+ bzero(u, sizeof(u));
+ bzero(m, sizeof(m));
+
+ maxuid = maxgid = maxmode = 0;
+ for (; p; p = p->fts_link) {
+ smode = p->fts_statp->st_mode & MBITS;
+ if (smode < MAXMODE && ++m[smode] > maxmode) {
+ savemode = smode;
+ maxmode = m[smode];
+ }
+ sgid = p->fts_statp->st_gid;
+ if (sgid < MAXGID && ++g[sgid] > maxgid) {
+ savegid = sgid;
+ maxgid = g[sgid];
+ }
+ suid = p->fts_statp->st_uid;
+ if (suid < MAXUID && ++u[suid] > maxuid) {
+ saveuid = suid;
+ maxuid = u[suid];
+ }
+ }
+ (void)printf("/set type=file");
+ if (keys & F_GID)
+ (void)printf(" gid=%u", savegid);
+ if (keys & F_GNAME)
+ if ((gr = getgrgid(savegid)) != NULL)
+ (void)printf(" gname=%s", gr->gr_name);
+ else
+ (void)printf(" gid=%u", savegid);
+ if (keys & F_UNAME)
+ if ((pw = getpwuid(saveuid)) != NULL)
+ (void)printf(" uname=%s", pw->pw_name);
+ else
+ (void)printf(" uid=%u", saveuid);
+ if (keys & F_UID)
+ (void)printf(" uid=%u", saveuid);
+ if (keys & F_MODE)
+ (void)printf(" mode=%#o", savemode);
+ if (keys & F_NLINK)
+ (void)printf(" nlink=1");
+ (void)printf("\n");
+ *puid = saveuid;
+ *pgid = savegid;
+ *pmode = savemode;
+ return (0);
+}
+
+static int
+dsort(a, b)
+ const FTSENT **a, **b;
+{
+ if (S_ISDIR((*a)->fts_statp->st_mode)) {
+ if (!S_ISDIR((*b)->fts_statp->st_mode))
+ return (1);
+ } else if (S_ISDIR((*b)->fts_statp->st_mode))
+ return (-1);
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+output(int *offset, const char *fmt, ...)
+#else
+output(offset, fmt, va_alist)
+ int *offset;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ char buf[1024];
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (*offset + strlen(buf) > MAXLINELEN - 3) {
+ (void)printf(" \\\n%*s", INDENTNAMELEN, "");
+ *offset = INDENTNAMELEN;
+ }
+ *offset += printf(" %s", buf) + 1;
+}
diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/mtree/extern.h
new file mode 100644
index 00000000000..35bfb49fdc5
--- /dev/null
+++ b/usr.sbin/mtree/extern.h
@@ -0,0 +1,46 @@
+/* $NetBSD: extern.h,v 1.3 1995/03/07 21:12:07 cgd Exp $ */
+
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+int compare __P((char *, NODE *, FTSENT *));
+int crc __P((int, u_long *, u_long *));
+void cwalk __P((void));
+void err __P((const char *, ...));
+char *inotype __P((u_int));
+u_int parsekey __P((char *, int *));
+char *rlink __P((char *));
+NODE *spec __P((void));
+int verify __P((void));
diff --git a/usr.sbin/mtree/misc.c b/usr.sbin/mtree/misc.c
new file mode 100644
index 00000000000..f9a50be86c9
--- /dev/null
+++ b/usr.sbin/mtree/misc.c
@@ -0,0 +1,128 @@
+/* $NetBSD: misc.c,v 1.4 1995/03/07 21:26:23 cgd Exp $ */
+
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)misc.c 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int lineno;
+
+typedef struct _key {
+ char *name; /* key name */
+ u_int val; /* value */
+
+#define NEEDVALUE 0x01
+ u_int flags;
+} KEY;
+
+/* NB: the following table must be sorted lexically. */
+static KEY keylist[] = {
+ "cksum", F_CKSUM, NEEDVALUE,
+ "gid", F_GID, NEEDVALUE,
+ "gname", F_GNAME, NEEDVALUE,
+ "ignore", F_IGN, 0,
+ "link", F_SLINK, NEEDVALUE,
+ "mode", F_MODE, NEEDVALUE,
+ "nlink", F_NLINK, NEEDVALUE,
+ "optional", F_OPT, 0,
+ "size", F_SIZE, NEEDVALUE,
+ "time", F_TIME, NEEDVALUE,
+ "type", F_TYPE, NEEDVALUE,
+ "uid", F_UID, NEEDVALUE,
+ "uname", F_UNAME, NEEDVALUE,
+};
+
+u_int
+parsekey(name, needvaluep)
+ char *name;
+ int *needvaluep;
+{
+ KEY *k, tmp;
+ int keycompare __P((const void *, const void *));
+
+ tmp.name = name;
+ k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
+ sizeof(KEY), keycompare);
+ if (k == NULL)
+ err("unknown keyword %s", name);
+
+ if (needvaluep)
+ *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
+ return (k->val);
+}
+
+int
+keycompare(a, b)
+ const void *a, *b;
+{
+ return (strcmp(((KEY *)a)->name, ((KEY *)b)->name));
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "mtree: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ if (lineno)
+ (void)fprintf(stderr,
+ "mtree: failed at line %d of the specification\n", lineno);
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/mtree/mtree.8 b/usr.sbin/mtree/mtree.8
new file mode 100644
index 00000000000..8521f8ae6b9
--- /dev/null
+++ b/usr.sbin/mtree/mtree.8
@@ -0,0 +1,254 @@
+.\" $NetBSD: mtree.8,v 1.4 1995/03/07 21:26:25 cgd Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 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.
+.\"
+.\" @(#)mtree.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt MTREE 8
+.Os
+.Sh NAME
+.Nm mtree
+.Nd map a directory hierarchy
+.Sh SYNOPSIS
+.Nm mtree
+.Op Fl cderux
+.Op Fl f Ar spec
+.Op Fl K Ar keywords
+.Op Fl k Ar keywords
+.Op Fl p Ar path
+.Op Fl s Ar seed
+.Sh DESCRIPTION
+The utility
+.Nm mtree
+compares the file hierarchy rooted in the current directory against a
+specification read from the standard input.
+Messages are written to the standard output for any files whose
+characteristics do not match the specification, or which are
+missing from either the file hierarchy or the specification.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl c
+Print a specification for the file hierarchy to the standard output.
+.It Fl d
+Ignore everything except directory type files.
+.It Fl e
+Don't complain about files that are in the file hierarchy, but not in the
+specification.
+.It Fl f
+Read the specification from
+.Ar file ,
+instead of from the standard input.
+.It Fl K
+Add the specified (whitespace or comma separated) keywords to the current
+set of keywords.
+.It Fl k
+Use the ``type'' keyword plus the specified (whitespace or comma separated)
+keywords instead of the current set of keywords.
+.It Fl p
+Use the file hierarchy rooted in
+.Ar path ,
+instead of the current directory.
+.It Fl r
+Remove any files in the file hierarchy that are not described in the
+specification.
+.It Fl s
+Display a single checksum to the standard error output that represents all
+of the files for which the keyword
+.Cm cksum
+was specified.
+The checksum is seeded with the specified value.
+.It Fl u
+Modify the owner, group, and permissions of existing files to match
+the specification and create any missing directories.
+User, group, and permissions must all be specified for missing directories
+to be created.
+.It Fl x
+Don't descend below mount points in the file hierarchy.
+.El
+.Pp
+Specifications are mostly composed of ``keywords'', i.e. strings that
+that specify values relating to files.
+No keywords have default values, and if a keyword has no value set, no
+checks based on it are performed.
+.Pp
+Currently supported keywords are as follows:
+.Bl -tag -width Cm
+.It Cm cksum
+The checksum of the file using the default algorithm specified by
+the
+.Xr cksum 1
+utility.
+.It Cm ignore
+Ignore any file hierarchy below this file.
+.It Cm gid
+The file group as a numeric value.
+.It Cm gname
+The file group as a symbolic name.
+.It Cm link
+The file the symbolic link is expected to reference.
+.It Cm mode
+The current file's permissions as a numeric (octal) or symbolic
+value.
+.It Cm nlink
+The number of hard links the file is expected to have.
+.It Cm optional
+The file is optional; don't complain about the file if it's
+not in the file hierarchy.
+.It Cm uid
+The file owner as a numeric value.
+.It Cm uname
+The file owner as a symbolic name.
+.It Cm size
+The size, in bytes, of the file.
+.It Cm time
+The last modification time of the file.
+.It Cm type
+The type of the file; may be set to any one of the following:
+.sp
+.Bl -tag -width Cm -compact
+.It Cm block
+block special device
+.It Cm char
+character special device
+.It Cm dir
+directory
+.It Cm fifo
+fifo
+.It Cm file
+regular file
+.It Cm link
+symbolic link
+.It Cm socket
+socket
+.El
+.El
+.Pp
+The default set of keywords are
+.Cm gid ,
+.Cm link ,
+.Cm mode ,
+.Cm nlink ,
+.Cm size ,
+.Cm time ,
+and
+.Cm uid .
+.Pp
+There are four types of lines in a specification.
+.Pp
+The first type of line sets a global value for a keyword, and consists of
+the string ``/set'' followed by whitespace, followed by sets of keyword/value
+pairs, separated by whitespace.
+Keyword/value pairs consist of a keyword, followed by an equals sign
+(``=''), followed by a value, without whitespace characters.
+Once a keyword has been set, its value remains unchanged until either
+reset or unset.
+.Pp
+The second type of line unsets keywords and consists of the string
+``/unset'', followed by whitespace, followed by one or more keywords,
+separated by whitespace.
+.Pp
+The third type of line is a file specification and consists of a file
+name, followed by whitespace, followed by zero or more whitespace
+separated keyword/value pairs.
+The file name may be preceded by whitespace characters.
+The file name may contain any of the standard file name matching
+characters (``['', ``]'', ``?'' or ``*''), in which case files
+in the hierarchy will be associated with the first pattern that
+they match.
+.Pp
+Each of the keyword/value pairs consist of a keyword, followed by an
+equals sign (``=''), followed by the keyword's value, without
+whitespace characters.
+These values override, without changing, the global value of the
+corresponding keyword.
+.Pp
+All paths are relative.
+Specifying a directory will cause subsequent files to be searched
+for in that directory hierarchy.
+Which brings us to the last type of line in a specification: a line
+containing only the string
+.Dq Nm \&..
+causes the current directory
+path to ascend one level.
+.Pp
+Empty lines and lines whose first non-whitespace character is a hash
+mark (``#'') are ignored.
+.Pp
+The
+.Nm mtree
+utility exits with a status of 0 on success, 1 if any error occurred,
+and 2 if the file hierarchy did not match the specification.
+.Sh EXAMPLES
+To detect system binaries that have been ``trojan horsed'', it is recommended
+that
+.Nm mtree
+be run on the file systems, and a copy of the results stored on a different
+machine, or, at least, in encrypted form.
+The seed for the
+.Fl s
+option should not be an obvious value and the final checksum should not be
+stored on-line under any circumstances!
+Then, periodically,
+.Nm mtree
+should be run against the on-line specifications and the final checksum
+compared with the previous value.
+While it is possible for the bad guys to change the on-line specifications
+to conform to their modified binaries, it shouldn't be possible for them
+to make it produce the same final checksum value.
+If the final checksum value changes, the off-line copies of the specification
+can be used to detect which of the binaries have actually been modified.
+.Pp
+The
+.Fl d
+and
+.Fl u
+options can be used in combination to create directory hierarchies
+for distributions and other such things.
+.Sh FILES
+.Bl -tag -width /etc/mtree -compact
+.It Pa /etc/mtree
+system specification directory
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr chown 1 ,
+.Xr chgrp 1 ,
+.Xr cksum 1 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Sh HISTORY
+The
+.Nm mtree
+utility appeared in
+.Bx 4.3 Reno .
diff --git a/usr.sbin/mtree/mtree.c b/usr.sbin/mtree/mtree.c
new file mode 100644
index 00000000000..5f2de630a4d
--- /dev/null
+++ b/usr.sbin/mtree/mtree.c
@@ -0,0 +1,152 @@
+/* $NetBSD: mtree.c,v 1.5 1995/03/07 21:12:10 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 1990, 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) 1989, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: mtree.c,v 1.5 1995/03/07 21:12:10 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fts.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int crc_total;
+
+int ftsoptions = FTS_PHYSICAL;
+int cflag, dflag, eflag, rflag, sflag, uflag;
+u_short keys;
+char fullpath[MAXPATHLEN];
+
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int ch;
+ char *dir, *p;
+
+ dir = NULL;
+ keys = KEYDEFAULT;
+ while ((ch = getopt(argc, argv, "cdef:K:k:p:rs:ux")) != EOF)
+ switch((char)ch) {
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'f':
+ if (!(freopen(optarg, "r", stdin)))
+ err("%s: %s", optarg, strerror(errno));
+ break;
+ case 'K':
+ while ((p = strsep(&optarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ break;
+ case 'k':
+ keys = F_TYPE;
+ while ((p = strsep(&optarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ break;
+ case 'p':
+ dir = optarg;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ crc_total = ~strtol(optarg, &p, 0);
+ if (*p)
+ err("illegal seed value -- %s", optarg);
+ case 'u':
+ uflag = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc)
+ usage();
+
+ if (dir && chdir(dir))
+ err("%s: %s", dir, strerror(errno));
+
+ if ((cflag || sflag) && !getwd(fullpath))
+ err("%s", fullpath);
+
+ if (cflag) {
+ cwalk();
+ exit(0);
+ }
+ exit(verify());
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: mtree [-cderux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n");
+ exit(1);
+}
diff --git a/usr.sbin/mtree/mtree.h b/usr.sbin/mtree/mtree.h
new file mode 100644
index 00000000000..19e670d09dc
--- /dev/null
+++ b/usr.sbin/mtree/mtree.h
@@ -0,0 +1,91 @@
+/* $NetBSD: mtree.h,v 1.7 1995/03/07 21:26:27 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990, 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.
+ *
+ * @(#)mtree.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#define KEYDEFAULT \
+ (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID)
+
+#define MISMATCHEXIT 2
+
+typedef struct _node {
+ struct _node *parent, *child; /* up, down */
+ struct _node *prev, *next; /* left, right */
+ off_t st_size; /* size */
+ struct timespec st_mtimespec; /* last modification time */
+ u_long cksum; /* check sum */
+ char *slink; /* symbolic link reference */
+ uid_t st_uid; /* uid */
+ gid_t st_gid; /* gid */
+#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
+ mode_t st_mode; /* mode */
+ nlink_t st_nlink; /* link count */
+
+#define F_CKSUM 0x0001 /* check sum */
+#define F_DONE 0x0002 /* directory done */
+#define F_GID 0x0004 /* gid */
+#define F_GNAME 0x0008 /* group name */
+#define F_IGN 0x0010 /* ignore */
+#define F_MAGIC 0x0020 /* name has magic chars */
+#define F_MODE 0x0040 /* mode */
+#define F_NLINK 0x0080 /* number of links */
+#define F_OPT 0x0100 /* existence optional */
+#define F_SIZE 0x0200 /* size */
+#define F_SLINK 0x0400 /* link count */
+#define F_TIME 0x0800 /* modification time */
+#define F_TYPE 0x1000 /* file type */
+#define F_UID 0x2000 /* uid */
+#define F_UNAME 0x4000 /* user name */
+#define F_VISIT 0x8000 /* file visited */
+ u_short flags; /* items set */
+
+#define F_BLOCK 0x001 /* block special */
+#define F_CHAR 0x002 /* char special */
+#define F_DIR 0x004 /* directory */
+#define F_FIFO 0x008 /* fifo */
+#define F_FILE 0x010 /* regular file */
+#define F_LINK 0x020 /* symbolic link */
+#define F_SOCK 0x040 /* socket */
+ u_char type; /* file type */
+
+ char name[1]; /* file name (must be last) */
+} NODE;
+
+#define RP(p) \
+ ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
+ (p)->fts_path + 2 : (p)->fts_path)
diff --git a/usr.sbin/mtree/spec.c b/usr.sbin/mtree/spec.c
new file mode 100644
index 00000000000..7eaefbe4452
--- /dev/null
+++ b/usr.sbin/mtree/spec.c
@@ -0,0 +1,286 @@
+/* $NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 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
+#if 0
+static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "mtree.h"
+#include "extern.h"
+
+int lineno; /* Current spec line number. */
+
+static void set __P((char *, NODE *));
+static void unset __P((char *, NODE *));
+
+NODE *
+spec()
+{
+ register NODE *centry, *last;
+ register char *p;
+ NODE ginfo, *root;
+ int c_cur, c_next;
+ char buf[2048];
+
+ root = NULL;
+ bzero(&ginfo, sizeof(ginfo));
+ c_cur = c_next = 0;
+ for (lineno = 1; fgets(buf, sizeof(buf), stdin);
+ ++lineno, c_cur = c_next, c_next = 0) {
+ /* Skip empty lines. */
+ if (buf[0] == '\n')
+ continue;
+
+ /* Find end of line. */
+ if ((p = index(buf, '\n')) == NULL)
+ err("line %d too long", lineno);
+
+ /* See if next line is continuation line. */
+ if (p[-1] == '\\') {
+ --p;
+ c_next = 1;
+ }
+
+ /* Null-terminate the line. */
+ *p = '\0';
+
+ /* Skip leading whitespace. */
+ for (p = buf; *p && isspace(*p); ++p);
+
+ /* If nothing but whitespace or comment char, continue. */
+ if (!*p || *p == '#')
+ continue;
+
+#ifdef DEBUG
+ (void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
+#endif
+ if (c_cur) {
+ set(p, centry);
+ continue;
+ }
+
+ /* Grab file name, "$", "set", or "unset". */
+ if ((p = strtok(p, "\n\t ")) == NULL)
+ err("missing field");
+
+ if (p[0] == '/')
+ switch(p[1]) {
+ case 's':
+ if (strcmp(p + 1, "set"))
+ break;
+ set(NULL, &ginfo);
+ continue;
+ case 'u':
+ if (strcmp(p + 1, "unset"))
+ break;
+ unset(NULL, &ginfo);
+ continue;
+ }
+
+ if (index(p, '/'))
+ err("slash character in file name");
+
+ if (!strcmp(p, "..")) {
+ /* Don't go up, if haven't gone down. */
+ if (!root)
+ goto noparent;
+ if (last->type != F_DIR || last->flags & F_DONE) {
+ if (last == root)
+ goto noparent;
+ last = last->parent;
+ }
+ last->flags |= F_DONE;
+ continue;
+
+noparent: err("no parent node");
+ }
+
+ if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
+ err("%s", strerror(errno));
+ *centry = ginfo;
+ (void)strcpy(centry->name, p);
+#define MAGIC "?*["
+ if (strpbrk(p, MAGIC))
+ centry->flags |= F_MAGIC;
+ set(NULL, centry);
+
+ if (!root) {
+ last = root = centry;
+ root->parent = root;
+ } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
+ centry->parent = last;
+ last = last->child = centry;
+ } else {
+ centry->parent = last->parent;
+ centry->prev = last;
+ last = last->next = centry;
+ }
+ }
+ return (root);
+}
+
+static void
+set(t, ip)
+ char *t;
+ register NODE *ip;
+{
+ register int type;
+ register char *kw, *val;
+ struct group *gr;
+ struct passwd *pw;
+ mode_t *m;
+ int value;
+ char *ep;
+
+ for (; kw = strtok(t, "= \t\n"); t = NULL) {
+ ip->flags |= type = parsekey(kw, &value);
+ if (value && (val = strtok(NULL, " \t\n")) == NULL)
+ err("missing value");
+ switch(type) {
+ case F_CKSUM:
+ ip->cksum = strtoul(val, &ep, 10);
+ if (*ep)
+ err("invalid checksum %s", val);
+ break;
+ case F_GID:
+ ip->st_gid = strtoul(val, &ep, 10);
+ if (*ep)
+ err("invalid gid %s", val);
+ break;
+ case F_GNAME:
+ if ((gr = getgrnam(val)) == NULL)
+ err("unknown group %s", val);
+ ip->st_gid = gr->gr_gid;
+ break;
+ case F_IGN:
+ /* just set flag bit */
+ break;
+ case F_MODE:
+ if ((m = setmode(val)) == NULL)
+ err("invalid file mode %s", val);
+ ip->st_mode = getmode(m, 0);
+ break;
+ case F_NLINK:
+ ip->st_nlink = strtoul(val, &ep, 10);
+ if (*ep)
+ err("invalid link count %s", val);
+ break;
+ case F_SIZE:
+ ip->st_size = strtouq(val, &ep, 10);
+ if (*ep)
+ err("invalid size %s", val);
+ break;
+ case F_SLINK:
+ if ((ip->slink = strdup(val)) == NULL)
+ err("%s", strerror(errno));
+ break;
+ case F_TIME:
+ ip->st_mtimespec.ts_sec = strtoul(val, &ep, 10);
+ if (*ep != '.')
+ err("invalid time %s", val);
+ val = ep + 1;
+ ip->st_mtimespec.ts_nsec = strtoul(val, &ep, 10);
+ if (*ep)
+ err("invalid time %s", val);
+ break;
+ case F_TYPE:
+ switch(*val) {
+ case 'b':
+ if (!strcmp(val, "block"))
+ ip->type = F_BLOCK;
+ break;
+ case 'c':
+ if (!strcmp(val, "char"))
+ ip->type = F_CHAR;
+ break;
+ case 'd':
+ if (!strcmp(val, "dir"))
+ ip->type = F_DIR;
+ break;
+ case 'f':
+ if (!strcmp(val, "file"))
+ ip->type = F_FILE;
+ if (!strcmp(val, "fifo"))
+ ip->type = F_FIFO;
+ break;
+ case 'l':
+ if (!strcmp(val, "link"))
+ ip->type = F_LINK;
+ break;
+ case 's':
+ if (!strcmp(val, "socket"))
+ ip->type = F_SOCK;
+ break;
+ default:
+ err("unknown file type %s", val);
+ }
+ break;
+ case F_UID:
+ ip->st_uid = strtoul(val, &ep, 10);
+ if (*ep)
+ err("invalid uid %s", val);
+ break;
+ case F_UNAME:
+ if ((pw = getpwnam(val)) == NULL)
+ err("unknown user %s", val);
+ ip->st_uid = pw->pw_uid;
+ break;
+ }
+ }
+}
+
+static void
+unset(t, ip)
+ char *t;
+ register NODE *ip;
+{
+ register char *p;
+
+ while (p = strtok(t, "\n\t "))
+ ip->flags &= ~parsekey(p, NULL);
+}
diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c
new file mode 100644
index 00000000000..feaa75ed457
--- /dev/null
+++ b/usr.sbin/mtree/verify.c
@@ -0,0 +1,210 @@
+/* $NetBSD: verify.c,v 1.10 1995/03/07 21:26:28 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990, 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
+#if 0
+static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: verify.c,v 1.10 1995/03/07 21:26:28 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fts.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int crc_total, ftsoptions;
+extern int dflag, eflag, rflag, sflag, uflag;
+extern char fullpath[MAXPATHLEN];
+
+static NODE *root;
+static char path[MAXPATHLEN];
+
+static void miss __P((NODE *, char *));
+static int vwalk __P((void));
+
+int
+verify()
+{
+ int rval;
+
+ root = spec();
+ rval = vwalk();
+ miss(root, path);
+ return (rval);
+}
+
+static int
+vwalk()
+{
+ register FTS *t;
+ register FTSENT *p;
+ register NODE *ep, *level;
+ int ftsdepth, specdepth, rval;
+ char *argv[2];
+
+ argv[0] = ".";
+ argv[1] = NULL;
+ if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
+ err("fts_open: %s", strerror(errno));
+ level = root;
+ ftsdepth = specdepth = rval = 0;
+ while (p = fts_read(t)) {
+ switch(p->fts_info) {
+ case FTS_D:
+ ++ftsdepth;
+ break;
+ case FTS_DP:
+ --ftsdepth;
+ if (specdepth > ftsdepth) {
+ for (level = level->parent; level->prev;
+ level = level->prev);
+ --specdepth;
+ }
+ continue;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ (void)fprintf(stderr, "mtree: %s: %s\n",
+ RP(p), strerror(errno));
+ continue;
+ default:
+ if (dflag)
+ continue;
+ }
+
+ for (ep = level; ep; ep = ep->next)
+ if (ep->flags & F_MAGIC &&
+ !fnmatch(ep->name, p->fts_name, FNM_PATHNAME) ||
+ !strcmp(ep->name, p->fts_name)) {
+ ep->flags |= F_VISIT;
+ if (compare(ep->name, ep, p))
+ rval = MISMATCHEXIT;
+ if (ep->flags & F_IGN)
+ (void)fts_set(t, p, FTS_SKIP);
+ else if (ep->child && ep->type == F_DIR &&
+ p->fts_info == FTS_D) {
+ level = ep->child;
+ ++specdepth;
+ }
+ break;
+ }
+
+ if (ep)
+ continue;
+ if (!eflag) {
+ (void)printf("extra: %s", RP(p));
+ if (rflag) {
+ if (unlink(p->fts_accpath)) {
+ (void)printf(", not removed: %s",
+ strerror(errno));
+ } else
+ (void)printf(", removed");
+ }
+ (void)putchar('\n');
+ }
+ (void)fts_set(t, p, FTS_SKIP);
+ }
+ (void)fts_close(t);
+ if (sflag)
+ (void)fprintf(stderr,
+ "mtree: %s checksum: %lu\n", fullpath, crc_total);
+ return (rval);
+}
+
+static void
+miss(p, tail)
+ register NODE *p;
+ register char *tail;
+{
+ register int create;
+ register char *tp;
+
+ for (; p; p = p->next) {
+ if (p->flags & F_OPT && !(p->flags & F_VISIT))
+ continue;
+ if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
+ continue;
+ (void)strcpy(tail, p->name);
+ if (!(p->flags & F_VISIT))
+ (void)printf("missing: %s", path);
+ if (p->type != F_DIR) {
+ putchar('\n');
+ continue;
+ }
+
+ create = 0;
+ if (!(p->flags & F_VISIT) && uflag)
+ if (!(p->flags & (F_UID | F_UNAME)))
+ (void)printf(" (not created: user not specified)");
+ else if (!(p->flags & (F_GID | F_GNAME)))
+ (void)printf(" (not created: group not specified)");
+ else if (!(p->flags & F_MODE))
+ (void)printf(" (not created: mode not specified)");
+ else if (mkdir(path, S_IRWXU))
+ (void)printf(" (not created: %s)",
+ strerror(errno));
+ else {
+ create = 1;
+ (void)printf(" (created)");
+ }
+
+ if (!(p->flags & F_VISIT))
+ (void)putchar('\n');
+
+ for (tp = tail; *tp; ++tp);
+ *tp = '/';
+ miss(p->child, tp + 1);
+ *tp = '\0';
+
+ if (!create)
+ continue;
+ if (chown(path, p->st_uid, p->st_gid)) {
+ (void)printf("%s: user/group/mode not modified: %s\n",
+ path, strerror(errno));
+ continue;
+ }
+ if (chmod(path, p->st_mode))
+ (void)printf("%s: permissions not set: %s\n",
+ path, strerror(errno));
+ }
+}
diff --git a/usr.sbin/named/Makefile b/usr.sbin/named/Makefile
new file mode 100644
index 00000000000..ab237e35cbf
--- /dev/null
+++ b/usr.sbin/named/Makefile
@@ -0,0 +1,27 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $
+
+### -DALLOW_T_UNSPEC -Dmalloc=rt_malloc -Dfree=rt_free
+### ALLOC=storage.o
+PROG= named
+MAN= named.8
+CFLAGS+=-DDEBUG -DSTATS
+SRCS= db_dump.c db_glue.c db_load.c db_lookup.c db_reload.c db_save.c \
+ db_update.c ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c \
+ ns_resp.c ns_sort.c ns_stats.c
+OBJS+= version.o
+CLEANFILES+=version.c version.o
+SUBDIR= tools xfer
+
+version.c: ${.CURDIR}/Version.c
+ (u=$${USER-root} d=`pwd |sed -e 's|/obj/|/src/|'` \
+ h=`hostname` t=`date`; \
+ sed -e "s|%WHEN%|$${t}|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ < ${.CURDIR}/Version.c > version.c)
+
+afterinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/named.restart \
+ ${.CURDIR}/named.reload ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/Makefile.dist b/usr.sbin/named/Makefile.dist
new file mode 100644
index 00000000000..0e7eae0bcb4
--- /dev/null
+++ b/usr.sbin/named/Makefile.dist
@@ -0,0 +1,61 @@
+# from: @(#)Makefile.dist 5.5 (Berkeley) 8/23/90
+# $Id: Makefile.dist,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $
+
+STDDEF= -DDEBUG -DSTATS
+### -DSIG_FN=void -DALLOW_T_UNSPEC -Dmalloc=rt_malloc -Dfree=rt_free
+### ALLOC=storage.o
+CFLAGS= -O ${STDDEF} ${DEFINES}
+
+RES=
+LIBS= ${RES}
+#LIBC= /lib/libc.a
+
+SRCS= db_dump.c db_load.c db_lookup.c db_reload.c db_save.c db_update.c \
+ ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c ns_resp.c \
+ ns_sort.c ns_stats.c db_glue.c named-xfer.c
+HDRS= db.h ns.h
+OBJS= db_dump.o db_load.o db_lookup.o db_reload.o db_save.o db_update.o \
+ ns_forw.o ns_init.o ns_main.o ns_maint.o ns_req.o ns_resp.o \
+ ns_sort.o ns_stats.o db_glue.o $(ALLOC)
+XFEROBJ= named-xfer.o db_glue.o
+
+#MAN= named.0
+
+all: named named-xfer
+
+named: ${OBJS} ${LIBC} version.c
+ ${CC} -o $@ version.c ${OBJS} ${LIBS}
+
+version.c: Version.c
+ (u=$${USER-root} d=`pwd` h=`hostname` t=`date`; \
+ sed -e "s|%WHEN%|$${t}|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ < Version.c > version.c)
+
+named-xfer: ${XFEROBJ} ${LIBC}
+ ${CC} -o $@ ${XFEROBJ} ${LIBS}
+
+clean:
+ rm -f ${OBJS} ${XFEROBJ} core named named-xfer version.o version.c
+
+cleandir: clean
+ rm -f ${MAN} tags .depend
+
+depend .depend: ${SRCS}
+ mkdep ${CFLAGS} ${SRCS}
+
+install: ${MAN}
+ install -s -o bin -g bin -m 755 named ${DESTDIR}/etc/named
+ install -s -o bin -g bin -m 755 named-xfer ${DESTDIR}/etc/named-xfer
+# install -c -o bin -g bin -m 444 ${MAN} ${DESTDIR}/usr/man/cat8
+ install -c -o bin -g bin -m 755 named.restart ${DESTDIR}/etc
+ install -c -o bin -g bin -m 755 named.reload ${DESTDIR}/etc
+
+lint: ${SRCS} ${HDRS}
+ lint -Dlint ${CFLAGS} ${SRCS}
+
+tags: ${SRCS}
+ ctags -t ${SRCS} ${HDRS}
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/usr.sbin/named/Version.c b/usr.sbin/named/Version.c
new file mode 100644
index 00000000000..1daf932ba86
--- /dev/null
+++ b/usr.sbin/named/Version.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 1986, 1987, 1990 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.
+ *
+ * @(#)Version.c 4.10 (Berkeley) 4/24/91
+ */
+
+#ifndef lint
+/*char sccsid[] = "from: @(#)named 4.8.3 %WHEN% %WHOANDWHERE%\n";*/
+static char rcsid[] = "$Id: Version.c,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $";
+#endif /* not lint */
+
+char Version[] = "named 4.8.3 %WHEN%\n\t%WHOANDWHERE%\n";
+
+#ifdef COMMENT
+
+SCCS/s.Version.c:
+
+D 4.8.3 90/08/15 09:21:21 bloom 37 35 00031/00028/00079
+Version distributed with 4.3 Reno tape (June 1990)
+(with additional changes for backward compat. after Reno)
+
+D 4.8.2 89/09/18 13:57:11 bloom 35 34 00020/00014/00087
+Interim fixes release
+
+D 4.8.1 89/02/08 17:12:15 karels 34 33 00026/00017/00075
+branch for 4.8.1
+
+D 4.8 88/07/09 14:27:00 karels 33 28 00043/00031/00049
+4.8 is here!
+
+D 4.7 87/11/20 13:15:52 karels 25 24 00000/00000/00062
+4.7.3 beta
+
+D 4.6 87/07/21 12:15:52 karels 25 24 00000/00000/00062
+4.6 declared stillborn
+
+D 4.5 87/02/10 12:33:25 kjd 24 18 00000/00000/00062
+February 1987, Network Release. Child (bind) grows up, parent (kevin) leaves home.
+
+D 4.4 86/10/01 10:06:26 kjd 18 12 00020/00017/00042
+October 1, 1986 Network Distribution
+
+D 4.3 86/06/04 12:12:18 kjd 12 7 00015/00028/00044
+Version distributed with 4.3BSD
+
+D 4.2 86/04/30 20:57:16 kjd 7 1 00056/00000/00016
+Network distribution Freeze and one more version until 4.3BSD
+
+D 1.1 86/04/30 19:30:00 kjd 1 0 00016/00000/00000
+date and time created 86/04/30 19:30:00 by kjd
+
+code versions:
+
+Makefile
+ Makefile.dist 5.4 (Berkeley) 8/15/90
+Makefile.reno
+ Makefile 5.8 (Berkeley) 7/28/90
+Version.c
+ Version.c 4.9 (Berkeley) 7/21/90
+db.h
+ db.h 4.16 (Berkeley) 6/1/90
+db_dump.c
+ db_dump.c 4.30 (Berkeley) 6/1/90
+db_glue.c
+ db_glue.c 4.4 (Berkeley) 6/1/90
+db_load.c
+ db_load.c 4.37 (Berkeley) 6/1/90
+db_lookup.c
+ db_lookup.c 4.17 (Berkeley) 6/1/90
+db_reload.c
+ db_reload.c 4.21 (Berkeley) 6/1/90
+db_save.c
+ db_save.c 4.15 (Berkeley) 6/1/90
+db_update.c
+ db_update.c 4.26 (Berkeley) 6/1/90
+named-xfer.c
+ named-xfer.c 4.16 (Berkeley) 8/15/90
+named.reload
+ named.reload 5.1 (Berkeley) 2/8/89
+named.reload.reno
+ named.reload 5.2 (Berkeley) 6/27/89
+named.restart
+ named.restart 5.2 (Berkeley) 2/5/89
+named.restart.reno
+ named.restart 5.4 (Berkeley) 6/27/89
+ns.h
+ ns.h 4.32 (Berkeley) 8/15/90
+ns_forw.c
+ ns_forw.c 4.30 (Berkeley) 6/27/90
+ns_init.c
+ ns_init.c 4.35 (Berkeley) 6/27/90
+ns_main.c
+ ns_main.c 4.51 (Berkeley) 8/15/90
+ns_maint.c
+ ns_maint.c 4.38 (Berkeley) 8/15/90
+ns_req.c
+ ns_req.c 4.44 (Berkeley) 6/27/90
+ns_resp.c
+ ns_resp.c 4.63 (Berkeley) 6/1/90
+ns_sort.c
+ ns_sort.c 4.8 (Berkeley) 6/1/90
+ns_stats.c
+ ns_stats.c 4.10 (Berkeley) 6/27/90
+pathnames.h
+ pathnames.h 5.4 (Berkeley) 6/1/90
+
+#endif COMMENT
diff --git a/usr.sbin/named/Version.self b/usr.sbin/named/Version.self
new file mode 100644
index 00000000000..cd65debe7cd
--- /dev/null
+++ b/usr.sbin/named/Version.self
@@ -0,0 +1 @@
+D 4.8 %E% %U% karels 26 25 00000/00000/00062
diff --git a/usr.sbin/named/adb.scripts/databuf b/usr.sbin/named/adb.scripts/databuf
new file mode 100644
index 00000000000..d6f1e2cf260
--- /dev/null
+++ b/usr.sbin/named/adb.scripts/databuf
@@ -0,0 +1 @@
+./"next"16t"ttl"16t"flags"8t"zone"8t"class"8t"type"nXDx3dn"mark"8t"size"8t"nstime"nddD
diff --git a/usr.sbin/named/adb.scripts/databufs b/usr.sbin/named/adb.scripts/databufs
new file mode 100644
index 00000000000..c1f8938d725
--- /dev/null
+++ b/usr.sbin/named/adb.scripts/databufs
@@ -0,0 +1,2 @@
+./"next"16t"ttl"16t"flags"8t"zone"8t"class"8t"type"nXDx3dn"mark"8t"size"8t"nstime"nddD
+*.,<9-1$<databuf
diff --git a/usr.sbin/named/adb.scripts/namebuf b/usr.sbin/named/adb.scripts/namebuf
new file mode 100644
index 00000000000..f5170b63552
--- /dev/null
+++ b/usr.sbin/named/adb.scripts/namebuf
@@ -0,0 +1,2 @@
+./"dname"16t"hashval"16t"next"n3Xn"data"16t"parent"16t"hashbuf"n3X
+*./"name"16ts
diff --git a/usr.sbin/named/db.h b/usr.sbin/named/db.h
new file mode 100644
index 00000000000..c9af52bb76a
--- /dev/null
+++ b/usr.sbin/named/db.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1985, 1990 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.
+ *
+ * from: @(#)db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db.h,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $
+ */
+
+/*
+ * Global structures and variables for data base routines.
+ */
+
+#define INVBLKSZ 7 /* # of namebuf pointers per block */
+#define INVHASHSZ 919 /* size of inverse hash table */
+
+ /* max length of data in RR data field */
+#define MAXDATA 2048
+
+/*
+ * Hash table structures.
+ */
+struct databuf {
+ struct databuf *d_next; /* linked list */
+ u_long d_ttl; /* time to live */
+ short d_flags;
+ short d_zone; /* zone number */
+ short d_class; /* class number */
+ short d_type; /* type number */
+ short d_mark; /* place to mark data */
+ short d_size; /* size of data area */
+ u_long d_nstime; /* NS response time, milliseconds */
+ char d_data[1]; /* the data is malloc'ed to size */
+};
+#define DATASIZE(n) (sizeof(struct databuf) - 1 + n)
+
+/*
+ * d_flags definitions
+ */
+#define DB_F_HINT 0x01 /* databuf belongs to fcachetab */
+
+struct namebuf {
+ char *n_dname; /* domain name */
+ u_int n_hashval; /* hash value of n_dname */
+ struct namebuf *n_next; /* linked list */
+ struct databuf *n_data; /* data records */
+ struct namebuf *n_parent; /* parent domain */
+ struct hashbuf *n_hash; /* hash table for children */
+};
+
+struct invbuf {
+ struct invbuf *i_next; /* linked list */
+ struct namebuf *i_dname[INVBLKSZ]; /* domain name */
+};
+
+struct hashbuf {
+ int h_size; /* size of hash table */
+ int h_cnt; /* number of entries */
+ struct namebuf *h_tab[1]; /* malloc'ed as needed */
+};
+#define HASHSIZE(s) (s*sizeof(struct namebuf *) + 2*sizeof(int))
+
+#define HASHSHIFT 3
+#define HASHMASK 0x1f
+
+/*
+ * Flags to updatedb
+ */
+#define DB_NODATA 0x01 /* data should not exist */
+#define DB_MEXIST 0x02 /* data must exist */
+#define DB_DELETE 0x04 /* delete data if it exists */
+#define DB_NOTAUTH 0x08 /* must not update authoritative data */
+#define DB_NOHINTS 0x10 /* don't reflect update in fcachetab */
+
+#define DB_Z_CACHE (0) /* cache-zone-only db_dump() */
+#define DB_Z_ALL (-1) /* normal db_dump() */
+
+/*
+ * Error return codes
+ */
+#define OK 0
+#define NONAME -1
+#define NOCLASS -2
+#define NOTYPE -3
+#define NODATA -4
+#define DATAEXISTS -5
+#define NODBFILE -6
+#define TOOMANYZONES -7
+#define GOODDB -8
+#define NEWDB -9
+#define AUTH -10
+
+extern struct hashbuf *hashtab; /* root hash table */
+extern struct invbuf *invtab[]; /* inverse hash table */
+extern struct hashbuf *fcachetab; /* hash table for cache read from file*/
+
+extern struct namebuf *nlookup();
+extern struct namebuf *savename();
+extern struct databuf *savedata();
+extern struct databuf *rm_datum();
+extern struct hashbuf *savehash();
+extern struct invbuf *saveinv();
+extern char *savestr();
+extern char *malloc(), *realloc(), *calloc();
diff --git a/usr.sbin/named/db_dump.c b/usr.sbin/named/db_dump.c
new file mode 100644
index 00000000000..fe447db94d9
--- /dev/null
+++ b/usr.sbin/named/db_dump.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 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[] = "from: @(#)db_dump.c 4.33 (Berkeley) 3/3/91";*/
+static char rcsid[] = "$Id: db_dump.c,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ns.h"
+#include "db.h"
+#include "pathnames.h"
+
+#ifdef DUMPFILE
+char *dumpfile = DUMPFILE;
+#else
+char *dumpfile = _PATH_DUMPFILE;
+#endif
+
+extern char *cache_file;
+
+/*
+ * Dump current cache in a format similar to RFC 883.
+ *
+ * We try to be careful and determine whether the operation succeeded
+ * so that the new cache file can be installed.
+ */
+
+#define DB_ROOT_TIMBUF 3600
+
+doachkpt()
+{
+ extern int errno;
+ FILE *fp;
+ time_t dumptime;
+ char tmpcheckfile[256];
+
+ /* nowhere to checkpoint cache... */
+ if (cache_file == NULL) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(to where?)\n");
+#endif
+ return;
+ }
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt()\n");
+#endif
+
+ (void) sprintf(tmpcheckfile, "%s.chk", cache_file);
+ if ((fp = fopen(tmpcheckfile, "w")) == NULL) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(can't open %s for write)\n", tmpcheckfile);
+#endif
+ return;
+ }
+
+ (void) gettime(&tt);
+ dumptime = tt.tv_sec;
+ fprintf(fp, "; Dumped at %s", ctime(&dumptime));
+ fflush(fp);
+ if (ferror(fp)) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(write to checkpoint file failed)\n");
+#endif
+ return;
+ }
+
+ if (fcachetab != NULL) {
+ int n;
+ if ((n = scan_root(hashtab)) < MINROOTS) {
+ syslog(LOG_ERR, "%d root hints... (too low)", n);
+ fprintf(fp, "; ---- Root hint cache dump ----\n");
+ (void) db_dump(fcachetab, fp, DB_Z_CACHE, "");
+ }
+ }
+
+ if (hashtab != NULL) {
+ fprintf(fp, "; ---- Cache dump ----\n");
+ if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(checkpoint failed)\n");
+#endif
+ (void) fclose(fp);
+ return;
+ }
+ }
+
+ (void) fsync(fileno(fp));
+ if (fclose(fp) == EOF) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(close failed)\n");
+#endif
+ return;
+ }
+
+ if (rename(tmpcheckfile, cache_file)) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doachkpt(install %s to %s failed, %d)\n",
+ tmpcheckfile,cache_file, errno);
+#endif
+ }
+}
+
+/*
+ * What we do is scan the root hint cache to make sure there are at least
+ * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not
+ * lose the root. Failing this, all pointers are written out w/ TTL ~0
+ * (root pointers timed out and prime_cache() not done or failed).
+ */
+#define TIMBUF 300
+
+int
+scan_root(htp)
+ struct hashbuf *htp;
+{
+ register struct databuf *dp;
+ register struct namebuf *np;
+ struct timeval soon;
+ int roots = 0;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"scan_root(0x%x)\n", htp);
+#endif
+
+ /* metric by which we determine whether a root NS pointer is still */
+ /* valid (will be written out if we do a dump). we also add some */
+ /* time buffer for safety... */
+ (void) gettime(&soon);
+ soon.tv_sec += TIMBUF;
+
+ for (np = htp->h_tab[0]; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] == '\0') {
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (dp->d_type == T_NS &&
+ dp->d_ttl > soon.tv_sec) {
+ roots++;
+ if (roots >= MINROOTS)
+ return (roots);
+ }
+ dp = dp->d_next;
+ }
+ }
+ }
+ return (roots);
+}
+
+#ifdef notdef
+mark_cache(htp, ttl)
+ struct hashbuf *htp;
+ int ttl;
+{
+ register struct databuf *dp;
+ register struct namebuf *np;
+ struct namebuf **npp, **nppend;
+ struct timeval soon;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"mark_cache()\n");
+#endif
+
+ (void) gettime(&soon);
+ soon.tv_sec += TIMBUF;
+
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_data == NULL)
+ continue;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_ttl < soon.tv_sec)
+ dp->d_ttl = ttl;
+ }
+ }
+ }
+
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_hash == NULL)
+ continue;
+ mark_cache(np->n_hash, ttl);
+ }
+ }
+}
+#endif notdef
+
+/*
+ * Dump current data base in a format similar to RFC 883.
+ */
+
+doadump()
+{
+ FILE *fp;
+ time_t dumptime;
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doadump()\n");
+#endif
+
+ if ((fp = fopen(dumpfile, "w")) == NULL)
+ return;
+ gettime(&tt);
+ dumptime = tt.tv_sec;
+ fprintf(fp, "; Dumped at %s", ctime(&dumptime));
+ fprintf(fp, "; --- Cache & Data ---\n");
+ if (hashtab != NULL)
+ (void) db_dump(hashtab, fp, DB_Z_ALL, "");
+ fprintf(fp, "; --- Hints ---\n");
+ if (fcachetab != NULL)
+ (void) db_dump(fcachetab, fp, DB_Z_ALL, "");
+ (void) fclose(fp);
+}
+
+#ifdef ALLOW_UPDATES
+/* Create a disk database to back up zones
+ */
+zonedump(zp)
+ register struct zoneinfo *zp;
+{
+ FILE *fp;
+ char *fname;
+ struct hashbuf *htp;
+ char *op;
+ struct stat st;
+
+ /* Only dump zone if there is a cache specified */
+ if (zp->z_source && *(zp->z_source)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "zonedump(%s)\n", zp->z_source);
+#endif
+
+ if ((fp = fopen(zp->z_source, "w")) == NULL)
+ return;
+ if (op = index(zp->z_origin, '.'))
+ op++;
+ gettime(&tt);
+ htp = hashtab;
+ if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) {
+ db_dump(htp, fp, zp-zones, (op == NULL ? "" : op));
+#ifdef ALLOW_UPDATES
+ zp->hasChanged = 0; /* Checkpointed */
+#endif ALLOW_UPDATES
+ }
+ (void) fclose(fp);
+ if (stat(zp->z_source, &st) == 0)
+ zp->z_ftime = st.st_mtime;
+ }
+#ifdef DEBUG
+ else if (debug)
+ fprintf(ddt, "zonedump: no zone to dump\n");
+#endif
+}
+#endif
+
+int
+db_dump(htp, fp, zone, origin)
+ int zone;
+ struct hashbuf *htp;
+ FILE *fp;
+ char *origin;
+{
+ register struct databuf *dp;
+ register struct namebuf *np;
+ struct namebuf **npp, **nppend;
+ char dname[MAXDNAME];
+ u_long n;
+ u_long addr;
+ u_short i;
+ int j;
+ register u_char *cp;
+ u_char *end;
+ char *proto;
+ extern char *inet_ntoa(), *protocolname(), *servicename();
+ int found_data, tab, printed_origin = 0;
+
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_data == NULL)
+ continue;
+ /* Blecch - can't tell if there is data here for the
+ * right zone, so can't print name yet
+ */
+ found_data = 0;
+ /* we want a snapshot in time... */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ /* Is the data for this zone? */
+ if (zone != DB_Z_ALL && dp->d_zone != zone)
+ continue;
+ if (dp->d_zone == DB_Z_CACHE &&
+ dp->d_ttl <= tt.tv_sec &&
+ (dp->d_flags & DB_F_HINT) == 0)
+ continue;
+ if (!printed_origin) {
+ fprintf(fp, "$ORIGIN %s.\n", origin);
+ printed_origin++;
+ }
+ tab = 0;
+ if (!found_data) {
+ if (np->n_dname[0] == 0) {
+ if (origin[0] == 0)
+ fprintf(fp, ".\t");
+ else
+ fprintf(fp, ".%s.\t", origin); /* ??? */
+ } else
+ fprintf(fp, "%s\t", np->n_dname);
+ if (strlen(np->n_dname) < 8)
+ tab = 1;
+ found_data++;
+ } else {
+ (void) putc('\t', fp);
+ tab = 1;
+ }
+ if (dp->d_zone == DB_Z_CACHE) {
+ if (dp->d_flags & DB_F_HINT &&
+ (long)(dp->d_ttl - tt.tv_sec) < DB_ROOT_TIMBUF)
+ fprintf(fp, "%d\t", DB_ROOT_TIMBUF);
+ else
+ fprintf(fp, "%d\t",
+ (int)(dp->d_ttl - tt.tv_sec));
+ } else if (dp->d_ttl != 0 &&
+ dp->d_ttl != zones[dp->d_zone].z_minimum)
+ fprintf(fp, "%d\t", (int)dp->d_ttl);
+ else if (tab)
+ (void) putc('\t', fp);
+ fprintf(fp, "%s\t%s\t", p_class(dp->d_class),
+ p_type(dp->d_type));
+ cp = (u_char *)dp->d_data;
+ /*
+ * Print type specific data
+ */
+ switch (dp->d_type) {
+ case T_A:
+ switch (dp->d_class) {
+ case C_IN:
+ case C_HS:
+ GETLONG(n, cp);
+ n = htonl(n);
+ fprintf(fp, "%s",
+ inet_ntoa(*(struct in_addr *)&n));
+ break;
+ }
+ if (dp->d_nstime)
+ fprintf(fp, "\t; %d", dp->d_nstime);
+ fprintf(fp, "\n");
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ if (cp[0] == '\0')
+ fprintf(fp, ".\n");
+ else
+ fprintf(fp, "%s.\n", cp);
+ break;
+
+ case T_NS:
+ cp = (u_char *)dp->d_data;
+ if (cp[0] == '\0')
+ fprintf(fp, ".\t");
+ else
+ fprintf(fp, "%s.", cp);
+ if (dp->d_nstime)
+ fprintf(fp, "\t; %d???", dp->d_nstime);
+ fprintf(fp, "\n");
+ break;
+
+ case T_HINFO:
+ if (n = *cp++) {
+ fprintf(fp, "\"%.*s\"", (int)n, cp);
+ cp += n;
+ } else
+ fprintf(fp, "\"\"");
+ if (n = *cp++)
+ fprintf(fp, " \"%.*s\"", (int)n, cp);
+ else
+ fprintf(fp, " \"\"");
+ (void) putc('\n', fp);
+ break;
+
+ case T_SOA:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s. (\n", cp);
+ cp += strlen((char *)cp) + 1;
+ GETLONG(n, cp);
+ fprintf(fp, "\t\t%lu", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu )\n", n);
+ break;
+
+ case T_MX:
+ GETSHORT(n, cp);
+ fprintf(fp,"%lu", n);
+ fprintf(fp," %s.\n", cp);
+ break;
+
+ case T_TXT:
+ end = (u_char *)dp->d_data + dp->d_size;
+ (void) putc('"', fp);
+ while (cp < end) {
+ if (n = *cp++) {
+ for (j = n ; j > 0 && cp < end ; j--)
+ if (*cp == '\n') {
+ (void) putc('\\', fp);
+ (void) putc(*cp++, fp);
+ } else
+ (void) putc(*cp++, fp);
+ }
+ }
+ (void) fputs("\"\n", fp);
+ break;
+
+ case T_UINFO:
+ fprintf(fp, "\"%s\"\n", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dp->d_size == sizeof(u_long)) {
+ GETLONG(n, cp);
+ fprintf(fp, "%lu\n", n);
+ }
+ break;
+
+ case T_WKS:
+ GETLONG(addr, cp);
+ addr = htonl(addr);
+ fprintf(fp,"%s ",
+ inet_ntoa(*(struct in_addr *)&addr));
+ proto = protocolname(*cp);
+ cp += sizeof(char);
+ fprintf(fp, "%s ", proto);
+ i = 0;
+ while(cp < (u_char *)dp->d_data + dp->d_size) {
+ j = *cp++;
+ do {
+ if (j & 0200)
+ fprintf(fp," %s",
+ servicename(i, proto));
+ j <<= 1;
+ } while(++i & 07);
+ }
+ fprintf(fp,"\n");
+ break;
+
+ case T_MINFO:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s.\n", cp);
+ break;
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ /* Dump binary data out in an ASCII-encoded
+ format */
+ {
+ /* Allocate more than enough space:
+ * actually need 5/4 size + 20 or so
+ */
+ int TmpSize = 2 * dp->d_size + 30;
+ char *TmpBuf = (char *) malloc(TmpSize);
+ if (TmpBuf == NULL) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "Dump T_UNSPEC: malloc returned NULL\n");
+#endif DEBUG
+ syslog(LOG_ERR, "Dump T_UNSPEC: malloc: %m");
+ }
+ if (btoa(cp, dp->d_size, TmpBuf,
+ TmpSize) == CONV_OVERFLOW) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "Dump T_UNSPEC: Output buffer overflow\n");
+#endif DEBUG
+ syslog(LOG_ERR, "Dump T_UNSPEC: Output buffer overflow\n");
+ } else
+ fprintf(fp, "%s\n", TmpBuf);
+ }
+ break;
+#endif ALLOW_T_UNSPEC
+ default:
+ fprintf(fp, "???\n");
+ }
+ }
+ }
+ }
+ if (ferror(fp))
+ return(NODBFILE);
+
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_hash == NULL)
+ continue;
+ getname(np, dname, sizeof(dname));
+ if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE)
+ return(NODBFILE);
+ }
+ }
+ return(OK);
+}
+
+#ifdef ALLOW_T_UNSPEC
+/*
+ * Subroutines to convert between 8 bit binary bytes and printable ASCII.
+ * Computes the number of bytes, and three kinds of simple checksums.
+ * Incoming bytes are collected into 32-bit words, then printed in base 85:
+ * exp(85,5) > exp(2,32)
+ * The ASCII characters used are between '!' and 'u';
+ * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
+ *
+ * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
+ * the atob/btoa programs, released with the compress program, in mod.sources.
+ * Modified by Mike Schwartz 8/19/86 for use in BIND.
+ */
+
+/* Make sure global variable names are unique */
+#define Ceor T_UNSPEC_Ceor
+#define Csum T_UNSPEC_Csum
+#define Crot T_UNSPEC_Crot
+#define word T_UNSPEC_word
+#define bcount T_UNSPEC_bcount
+
+static long int Ceor, Csum, Crot, word, bcount;
+
+#define EN(c) ((int) ((c) + '!'))
+#define DE(c) ((c) - '!')
+#define AddToBuf(bufp, c) **bufp = c; (*bufp)++;
+#define streq(s0, s1) strcmp(s0, s1) == 0
+#define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x)
+
+
+/* Decode ASCII-encoded byte c into binary representation and
+ * place into *bufp, advancing bufp
+ */
+static int
+byte_atob(c, bufp)
+ register c;
+ char **bufp;
+{
+ if (c == 'z') {
+ if (bcount != 0)
+ return(CONV_BADFMT);
+ else {
+ putbyte(0, bufp);
+ putbyte(0, bufp);
+ putbyte(0, bufp);
+ putbyte(0, bufp);
+ }
+ } else if ((c >= '!') && (c < ('!' + 85))) {
+ if (bcount == 0) {
+ word = DE(c);
+ ++bcount;
+ } else if (bcount < 4) {
+ word = times85(word);
+ word += DE(c);
+ ++bcount;
+ } else {
+ word = times85(word) + DE(c);
+ putbyte((int)((word >> 24) & 255), bufp);
+ putbyte((int)((word >> 16) & 255), bufp);
+ putbyte((int)((word >> 8) & 255), bufp);
+ putbyte((int)(word & 255), bufp);
+ word = 0;
+ bcount = 0;
+ }
+ } else
+ return(CONV_BADFMT);
+ return(CONV_SUCCESS);
+}
+
+/* Compute checksum info and place c into *bufp, advancing bufp */
+static
+putbyte(c, bufp)
+ register c;
+ char **bufp;
+{
+ Ceor ^= c;
+ Csum += c;
+ Csum += 1;
+ if ((Crot & 0x80000000)) {
+ Crot <<= 1;
+ Crot += 1;
+ } else {
+ Crot <<= 1;
+ }
+ Crot += c;
+ AddToBuf(bufp, c);
+}
+
+/* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
+ it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
+ outbuflen must be divisible by 4. (Note: this is because outbuf is filled
+ in 4 bytes at a time. If the actual data doesn't end on an even 4-byte
+ boundary, there will be no problem...it will be padded with 0 bytes, and
+ numbytes will indicate the correct number of bytes. The main point is
+ that since the buffer is filled in 4 bytes at a time, even if there is
+ not a full 4 bytes of data at the end, there has to be room to 0-pad the
+ data, so the buffer must be of size divisible by 4). Place the number of
+ output bytes in numbytes, and return a failure/success status */
+int
+atob(inbuf, inbuflen, outbuf, outbuflen, numbytes)
+ char *inbuf;
+ int inbuflen;
+ char *outbuf;
+ int outbuflen;
+ int *numbytes;
+{
+ int inc, nb;
+ long int oeor, osum, orot;
+ char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen];
+
+ if ( (outbuflen % 4) != 0)
+ return(CONV_BADBUFLEN);
+ Ceor = Csum = Crot = word = bcount = 0;
+ for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
+ if (outp > endoutp)
+ return(CONV_OVERFLOW);
+ if (*inp == 'x') {
+ inp +=2;
+ break;
+ } else {
+ if (byte_atob(*inp, &outp) == CONV_BADFMT)
+ return(CONV_BADFMT);
+ }
+ }
+
+ /* Get byte count and checksum information from end of buffer */
+ if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4)
+ return(CONV_BADFMT);
+ if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
+ return(CONV_BADCKSUM);
+ return(CONV_SUCCESS);
+}
+
+/* Encode binary byte c into ASCII representation and place into *bufp,
+ advancing bufp */
+static
+byte_btoa(c, bufp)
+ register c;
+ char **bufp;
+{
+ Ceor ^= c;
+ Csum += c;
+ Csum += 1;
+ if ((Crot & 0x80000000)) {
+ Crot <<= 1;
+ Crot += 1;
+ } else {
+ Crot <<= 1;
+ }
+ Crot += c;
+
+ word <<= 8;
+ word |= c;
+ if (bcount == 3) {
+ if (word == 0) {
+ AddToBuf(bufp, 'z');
+ } else {
+ register int tmp = 0;
+ register long int tmpword = word;
+
+ if (tmpword < 0) {
+ /* Because some don't support unsigned long */
+ tmp = 32;
+ tmpword -= (long)(85 * 85 * 85 * 85 * 32);
+ }
+ if (tmpword < 0) {
+ tmp = 64;
+ tmpword -= (long)(85 * 85 * 85 * 85 * 32);
+ }
+ AddToBuf(bufp,
+ EN((tmpword / (long)(85 * 85 * 85 * 85)) + tmp));
+ tmpword %= (long)(85 * 85 * 85 * 85);
+ AddToBuf(bufp, EN(tmpword / (85 * 85 * 85)));
+ tmpword %= (85 * 85 * 85);
+ AddToBuf(bufp, EN(tmpword / (85 * 85)));
+ tmpword %= (85 * 85);
+ AddToBuf(bufp, EN(tmpword / 85));
+ tmpword %= 85;
+ AddToBuf(bufp, EN(tmpword));
+ }
+ bcount = 0;
+ } else {
+ bcount += 1;
+ }
+}
+
+
+/*
+ * Encode the binary data from inbuf, of length inbuflen, into a
+ * null-terminated ASCII representation in outbuf, not to exceed outbuflen
+ * bytes. Return success/failure status
+ */
+int
+btoa(inbuf, inbuflen, outbuf, outbuflen)
+ char *inbuf;
+ int inbuflen;
+ char *outbuf;
+ int outbuflen;
+{
+ long int inc, nb;
+ long int oeor, osum, orot;
+ char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1];
+
+ Ceor = Csum = Crot = word = bcount = 0;
+ for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
+ byte_btoa((unsigned char) (*inp), &outp);
+ if (outp >= endoutp)
+ return(CONV_OVERFLOW);
+ }
+ while (bcount != 0) {
+ byte_btoa(0, &outp);
+ if (outp >= endoutp)
+ return(CONV_OVERFLOW);
+ }
+ /* Put byte count and checksum information at end of buffer, delimited
+ by 'x' */
+ (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot);
+ if (&outp[strlen(outp) - 1] >= endoutp)
+ return(CONV_OVERFLOW);
+ else
+ return(CONV_SUCCESS);
+}
+#endif ALLOW_T_UNSPEC
diff --git a/usr.sbin/named/db_glue.c b/usr.sbin/named/db_glue.c
new file mode 100644
index 00000000000..5614f91c696
--- /dev/null
+++ b/usr.sbin/named/db_glue.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1986, 1988 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[] = "from: @(#)db_glue.c 4.4 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: db_glue.c,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "db.h"
+
+struct valuelist {
+ struct valuelist *next, *prev;
+ char *name;
+ char *proto;
+ short port;
+} *servicelist, *protolist;
+
+buildservicelist()
+{
+ struct servent *sp;
+ struct valuelist *slp;
+
+ setservent(1);
+ while (sp = getservent()) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ slp->name = savestr(sp->s_name);
+ slp->proto = savestr(sp->s_proto);
+ slp->port = ntohs((u_short)sp->s_port);
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+buildprotolist()
+{
+ struct protoent *pp;
+ struct valuelist *slp;
+
+ setprotoent(1);
+ while (pp = getprotoent()) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ slp->name = savestr(pp->p_name);
+ slp->port = pp->p_proto;
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+servicenumber(p)
+ char *p;
+{
+
+ return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+protocolnumber(p)
+ char *p;
+{
+
+ return (findservice(p, &protolist));
+}
+
+findservice(s, list)
+ register char *s;
+ register struct valuelist **list;
+{
+ register struct valuelist *lp = *list;
+ int n;
+
+ for (; lp != NULL; lp = lp->next)
+ if (strcasecmp(lp->name, s) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ return(lp->port);
+ }
+ if (sscanf(s, "%d", &n) != 1 || n <= 0)
+ n = -1;
+ return(n);
+}
+
+struct servent *
+cgetservbyport(port, proto)
+ u_short port;
+ char *proto;
+{
+ register struct valuelist **list = &servicelist;
+ register struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = htons(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != lp->port)
+ continue;
+ if (strcasecmp(lp->proto, proto) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ serv.s_name = lp->name;
+ serv.s_port = htons((u_short)lp->port);
+ serv.s_proto = lp->proto;
+ return(&serv);
+ }
+ }
+ return(0);
+}
+
+struct protoent *
+cgetprotobynumber(proto)
+ register int proto;
+{
+
+ register struct valuelist **list = &protolist;
+ register struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ prot.p_name = lp->name;
+ prot.p_proto = lp->port;
+ return(&prot);
+ }
+ return(0);
+}
+
+char *
+protocolname(num)
+ int num;
+{
+ static char number[8];
+ struct protoent *pp;
+
+ pp = cgetprotobynumber(num);
+ if(pp == 0) {
+ (void) sprintf(number, "%d", num);
+ return(number);
+ }
+ return(pp->p_name);
+}
+
+char *
+servicename(port, proto)
+ u_short port;
+ char *proto;
+{
+ static char number[8];
+ struct servent *ss;
+
+ ss = cgetservbyport(htons(port), proto);
+ if(ss == 0) {
+ (void) sprintf(number, "%d", port);
+ return(number);
+ }
+ return(ss->s_name);
+}
diff --git a/usr.sbin/named/db_load.c b/usr.sbin/named/db_load.c
new file mode 100644
index 00000000000..a0029eedcc4
--- /dev/null
+++ b/usr.sbin/named/db_load.c
@@ -0,0 +1,969 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 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[] = "from: @(#)db_load.c 4.38 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: db_load.c,v 1.1.1.1 1995/10/18 08:47:49 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Load data base from ascii backupfile. Format similar to RFC 883.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "db.h"
+
+extern char *index();
+extern int max_cache_ttl;
+
+/*
+ * Map class and type names to number
+ */
+struct map {
+ char token[8];
+ int val;
+};
+
+struct map m_class[] = {
+ "in", C_IN,
+#ifdef notdef
+ "any", C_ANY, /* any is a QCLASS, not CLASS */
+#endif
+ "chaos", C_CHAOS,
+ "hs", C_HS,
+};
+#define NCLASS (sizeof(m_class)/sizeof(struct map))
+
+struct map m_type[] = {
+ "a", T_A,
+ "ns", T_NS,
+ "cname", T_CNAME,
+ "soa", T_SOA,
+ "mb", T_MB,
+ "mg", T_MG,
+ "mr", T_MR,
+ "null", T_NULL,
+ "wks", T_WKS,
+ "ptr", T_PTR,
+ "hinfo", T_HINFO,
+ "minfo", T_MINFO,
+ "mx", T_MX,
+ "uinfo", T_UINFO,
+ "txt", T_TXT,
+ "uid", T_UID,
+ "gid", T_GID,
+#ifdef notdef
+ "any", T_ANY, /* any is a QTYPE, not TYPE */
+#endif
+#ifdef ALLOW_T_UNSPEC
+ "unspec", T_UNSPEC,
+#endif ALLOW_T_UNSPEC
+};
+#define NTYPE (sizeof(m_type)/sizeof(struct map))
+
+/*
+ * Parser token values
+ */
+#define CURRENT 1
+#define DOT 2
+#define AT 3
+#define DNAME 4
+#define INCLUDE 5
+#define ORIGIN 6
+#define ERROR 7
+
+int lineno; /* current line number */
+
+/*
+ * Load the database from 'filename'. Origin is appended to all domain
+ * names in the file.
+ */
+db_load(filename, in_origin, zp, doinginclude)
+ char *filename, *in_origin;
+ struct zoneinfo *zp;
+{
+ register u_char *cp;
+ register struct map *mp;
+ char domain[MAXDNAME];
+ char origin[MAXDNAME];
+ char tmporigin[MAXDNAME];
+ u_char buf[MAXDATA];
+ u_char data[MAXDATA];
+ u_char *cp1;
+ char *op;
+ int c;
+ int class, type, ttl, dbflags, dataflags;
+ int read_soa = 0; /* number of soa's read */
+ struct databuf *dp;
+ FILE *fp;
+ int slineno, i, errs = 0, didinclude = 0;
+ register u_long n;
+ struct stat sb;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"db_load(%s, %s, %d, %d)\n",
+ filename, in_origin, zp - zones, doinginclude);
+#endif
+
+ (void) strcpy(origin, in_origin);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", filename);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"db_load: error opening file %s\n", filename);
+#endif
+ return (-1);
+ }
+ if (zp->z_type == Z_CACHE) {
+ dbflags = DB_NODATA | DB_NOHINTS;
+ dataflags = DB_F_HINT;
+ } else {
+ dbflags = DB_NODATA;
+ dataflags = 0;
+ }
+ gettime(&tt);
+ if (fstat(fileno(fp), &sb) < 0) {
+ syslog(LOG_ERR, "%s: %m", filename);
+ sb.st_mtime = (int)tt.tv_sec;
+ }
+ slineno = lineno;
+ lineno = 1;
+ domain[0] = '\0';
+ class = C_IN;
+ zp->z_state &= ~(Z_INCLUDE|Z_DB_BAD);
+ while ((c = gettoken(fp)) != EOF) {
+ switch (c) {
+ case INCLUDE:
+ if (!getword(buf, sizeof(buf), fp)) /* file name */
+ break;
+ if (!getword(tmporigin, sizeof(tmporigin), fp))
+ strcpy(tmporigin, origin);
+ else {
+ makename(tmporigin, origin);
+ endline(fp);
+ }
+ didinclude = 1;
+ errs += db_load(buf, tmporigin, zp, 1);
+ continue;
+
+ case ORIGIN:
+ (void) strcpy((char *)buf, origin);
+ if (!getword(origin, sizeof(origin), fp))
+ break;
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"db_load: origin %s, buf %s\n",
+ origin, buf);
+#endif
+ makename(origin, buf);
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"db_load: origin now %s\n", origin);
+#endif
+ continue;
+
+ case DNAME:
+ if (!getword(domain, sizeof(domain), fp))
+ break;
+ n = strlen(domain) - 1;
+ if (domain[n] == '.')
+ domain[n] = '\0';
+ else if (*origin) {
+ (void) strcat(domain, ".");
+ (void) strcat(domain, origin);
+ }
+ goto gotdomain;
+
+ case AT:
+ (void) strcpy(domain, origin);
+ goto gotdomain;
+
+ case DOT:
+ domain[0] = '\0';
+ /* fall thru ... */
+ case CURRENT:
+ gotdomain:
+ if (!getword(buf, sizeof(buf), fp)) {
+ if (c == CURRENT)
+ continue;
+ break;
+ }
+ cp = buf;
+ ttl = 0;
+ if (isdigit(*cp)) {
+ n = 0;
+ do
+ n = n * 10 + (*cp++ - '0');
+ while (isdigit(*cp));
+ if (zp->z_type == Z_CACHE) {
+ /* this allows the cache entry to age */
+ /* while sitting on disk (powered off) */
+ if (n > max_cache_ttl)
+ n = max_cache_ttl;
+ n += sb.st_mtime;
+ }
+ ttl = n;
+ if (!getword(buf, sizeof(buf), fp))
+ break;
+ }
+ for (mp = m_class; mp < m_class+NCLASS; mp++)
+ if (!strcasecmp((char *)buf, mp->token)) {
+ class = mp->val;
+ (void) getword(buf, sizeof(buf), fp);
+ break;
+ }
+ for (mp = m_type; mp < m_type+NTYPE; mp++)
+ if (!strcasecmp((char *)buf, mp->token)) {
+ type = mp->val;
+ goto fndtype;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"Line %d: Unknown type: %s.\n",
+ lineno, buf);
+#endif
+ errs++;
+ syslog(LOG_ERR, "Line %d: Unknown type: %s.\n",
+ lineno, buf);
+ break;
+ fndtype:
+#ifdef ALLOW_T_UNSPEC
+ /* Don't do anything here for T_UNSPEC...
+ * read input separately later
+ */
+ if (type != T_UNSPEC) {
+#endif ALLOW_T_UNSPEC
+ if (!getword(buf, sizeof(buf), fp))
+ break;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,
+ "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n",
+ domain, class, type, ttl, buf);
+#endif
+#ifdef ALLOW_T_UNSPEC
+ }
+#endif ALLOW_T_UNSPEC
+ /*
+ * Convert the ascii data 'buf' to the proper format
+ * based on the type and pack into 'data'.
+ */
+ switch (type) {
+ case T_A:
+ n = ntohl((u_long)inet_addr((char *)buf));
+ cp = data;
+ PUTLONG(n, cp);
+ n = sizeof(u_long);
+ break;
+
+ case T_HINFO:
+ n = strlen((char *)buf);
+ if (n > 255) {
+ syslog(LOG_WARNING,
+ "%s: line %d: CPU type too long",
+ filename, lineno);
+ n = 255;
+ }
+ data[0] = n;
+ bcopy(buf, (char *)data + 1, (int)n);
+ n++;
+ if (!getword(buf, sizeof(buf), fp))
+ break;
+ i = strlen((char *)buf);
+ if (i > 255) {
+ syslog(LOG_WARNING,
+ "%s: line %d: OS type too long",
+ filename, lineno);
+ i = 255;
+ }
+ data[n] = i;
+ bcopy(buf, data + n + 1, i);
+ n += i + 1;
+ endline(fp);
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ (void) strcpy((char *)data, (char *)buf);
+ makename(data, origin);
+ cp = data + strlen((char *)data) + 1;
+ if (!getword(cp,
+ sizeof(data) - (cp - data),fp)) {
+ n = cp - data;
+ break;
+ }
+ makename(cp, origin);
+ cp += strlen((char *)cp) + 1;
+ if (type == T_MINFO) {
+ n = cp - data;
+ break;
+ }
+ if (getnonblank(fp) != '(')
+ goto err;
+ zp->z_serial = getnum(fp);
+ n = (u_long) zp->z_serial;
+ PUTLONG(n, cp);
+ zp->z_refresh = getnum(fp);
+ n = (u_long) zp->z_refresh;
+ PUTLONG(n, cp);
+ if (zp->z_type == Z_SECONDARY)
+ zp->z_time = sb.st_mtime + zp->z_refresh;
+ zp->z_retry = getnum(fp);
+ n = (u_long) zp->z_retry;
+ PUTLONG(n, cp);
+ zp->z_expire = getnum(fp);
+ n = (u_long) zp->z_expire;
+ PUTLONG (n, cp);
+ zp->z_minimum = getnum(fp);
+ n = (u_long) zp->z_minimum;
+ PUTLONG (n, cp);
+ n = cp - data;
+ if (getnonblank(fp) != ')')
+ goto err;
+ read_soa++;
+ endline(fp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ n = 0;
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ if (cp == buf)
+ goto err;
+ cp = data;
+ PUTLONG(n, cp);
+ n = sizeof(long);
+ break;
+
+ case T_WKS:
+ /* Address */
+ n = ntohl((u_long)inet_addr((char *)buf));
+ cp = data;
+ PUTLONG(n, cp);
+ *cp = getprotocol(fp, filename);
+ /* Protocol */
+ n = sizeof(u_long) + sizeof(char);
+ /* Services */
+ n = getservices((int)n, data, fp, filename);
+ break;
+
+ case T_NS:
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ (void) strcpy((char *)data, (char *)buf);
+ makename(data, origin);
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_UINFO:
+ cp = (u_char *)index((char *)buf, '&');
+ bzero(data, sizeof(data));
+ if ( cp != NULL) {
+ (void) strncpy((char *)data,
+ (char *)buf, cp - buf);
+ op = index(domain, '.');
+ if ( op != NULL)
+ (void) strncat((char *)data,
+ domain,op-domain);
+ else
+ (void) strcat((char *)data,
+ domain);
+ (void) strcat((char *)data,
+ (char *)++cp);
+ } else
+ (void) strcpy((char *)data,
+ (char *)buf);
+ n = strlen((char *)data) + 1;
+ break;
+ case T_MX:
+ n = 0;
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ /* catch bad values */
+ if ((cp == buf) || (n > 65535))
+ goto err;
+
+ cp = data;
+ PUTSHORT((u_short)n, cp);
+
+ if (!getword(buf, sizeof(buf), fp))
+ break;
+ (void) strcpy((char *)cp, (char *)buf);
+ makename(cp, origin);
+ /* get pointer to place in data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - data);
+ break;
+
+ case T_TXT:
+ i = strlen((char *)buf);
+ cp = data;
+ cp1 = buf;
+ /*
+ * there is expansion here so make sure we
+ * don't overflow data
+ */
+ if (i > sizeof(data) * 255 / 256) {
+ syslog(LOG_WARNING,
+ "%s: line %d: TXT record truncated",
+ filename, lineno);
+ i = sizeof(data) * 255 / 256;
+ }
+ while (i > 255) {
+ *cp++ = 255;
+ bcopy(cp1, cp, 255);
+ cp += 255;
+ cp1 += 255;
+ i -= 255;
+ }
+ *cp++ = i;
+ bcopy(cp1, cp, i);
+ cp += i;
+ n = cp - data;
+ endline(fp);
+ break;
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ {
+ int rcode;
+ fgets(buf, sizeof(buf), fp);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "loading T_UNSPEC\n");
+#endif DEBUG
+ if (rcode = atob(buf,
+ strlen((char *)buf), data,
+ sizeof(data), &n)) {
+ if (rcode == CONV_OVERFLOW) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "Load T_UNSPEC: input buffer overflow\n");
+#endif DEBUG
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: input buffer overflow");
+ } else {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "Load T_UNSPEC: Data in bad atob format\n");
+#endif DEBUG
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: Data in bad atob format");
+ }
+ }
+ }
+ break;
+#endif ALLOW_T_UNSPEC
+
+ default:
+ goto err;
+ }
+ dp = savedata(class, type, (u_long)ttl, data, (int)n);
+ dp->d_zone = zp - zones;
+ dp->d_flags = dataflags;
+ if ((c = db_update(domain, dp, dp, dbflags,
+ (zp->z_type == Z_CACHE)? fcachetab : hashtab)) < 0) {
+#ifdef DEBUG
+ if (debug && (c != DATAEXISTS))
+ fprintf(ddt,"update failed\n");
+#endif
+ }
+ continue;
+
+ case ERROR:
+ break;
+ }
+ err:
+ errs++;
+ syslog(LOG_ERR, "%s: line %d: database format error (%s)",
+ filename, lineno, buf);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"%s: line %d: database format error ('%s', %d)\n",
+ filename, lineno, buf, n);
+#endif
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ lineno++;
+ }
+ (void) fclose(fp);
+ lineno = slineno;
+ if (doinginclude == 0) {
+ if (didinclude) {
+ zp->z_state |= Z_INCLUDE;
+ zp->z_ftime = 0;
+ } else
+ zp->z_ftime = sb.st_mtime;
+ zp->z_lastupdate = sb.st_mtime;
+ if (zp->z_type != Z_CACHE && read_soa != 1) {
+ errs++;
+ if (read_soa == 0)
+ syslog(LOG_ERR, "%s: no SOA record", filename);
+ else
+ syslog(LOG_ERR, "%s: multiple SOA records",
+ filename);
+ }
+ }
+ if (errs)
+ zp->z_state |= Z_DB_BAD;
+ return (errs);
+}
+
+int gettoken(fp)
+ register FILE *fp;
+{
+ register int c;
+ char op[32];
+
+ for (;;) {
+ c = getc(fp);
+ top:
+ switch (c) {
+ case EOF:
+ return (EOF);
+
+ case '$':
+ if (getword(op, sizeof(op), fp)) {
+ if (!strcasecmp("include", op))
+ return (INCLUDE);
+ if (!strcasecmp("origin", op))
+ return (ORIGIN);
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"Line %d: Unknown $ option: $%s\n",
+ lineno, op);
+#endif
+ syslog(LOG_ERR,"Line %d: Unknown $ option: $%s\n",
+ lineno, op);
+ return (ERROR);
+
+ case ';':
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ goto top;
+
+ case ' ':
+ case '\t':
+ return (CURRENT);
+
+ case '.':
+ return (DOT);
+
+ case '@':
+ return (AT);
+
+ case '\n':
+ lineno++;
+ continue;
+
+ default:
+ (void) ungetc(c, fp);
+ return (DNAME);
+ }
+ }
+}
+
+/*
+ * Get next word, skipping blanks & comments.
+ */
+getword(buf, size, fp)
+ char *buf;
+ int size;
+ FILE *fp;
+{
+ register char *cp;
+ register int c;
+
+ for (cp = buf; (c = getc(fp)) != EOF; ) {
+ if (c == ';') {
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ c = '\n';
+ }
+ if (c == '\n') {
+ if (cp != buf)
+ ungetc(c, fp);
+ else
+ lineno++;
+ break;
+ }
+ if (isspace(c)) {
+ while (isspace(c = getc(fp)) && c != '\n')
+ ;
+ ungetc(c, fp);
+ if (cp != buf) /* Trailing whitespace */
+ break;
+ continue; /* Leading whitespace */
+ }
+ if (c == '"') {
+ while ((c = getc(fp)) != EOF && c != '"' && c != '\n') {
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (c == '\n')
+ lineno++;
+ }
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = c;
+ }
+ if (c == '\n') {
+ lineno++;
+ break;
+ }
+ continue;
+ }
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (c == '\n')
+ lineno++;
+ }
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = c;
+ }
+ *cp = '\0';
+ return (cp != buf);
+}
+
+getnum(fp)
+ FILE *fp;
+{
+ register int c, n;
+ int seendigit = 0;
+ int seendecimal = 0;
+
+ for (n = 0; (c = getc(fp)) != EOF; ) {
+ if (isspace(c)) {
+ if (c == '\n')
+ lineno++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (c == ';') {
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ lineno++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (void) ungetc(c, fp);
+ break;
+ }
+ if (seendecimal || c != '.') {
+ syslog(LOG_ERR, "line %d: expected a number",
+ lineno);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"line %d: expected a number",
+ lineno);
+#endif
+ exit(1); /* XXX why exit */
+ } else {
+ if (!seendigit)
+ n = 1;
+ n = n * 1000 ;
+ seendigit = 1;
+ seendecimal = 1;
+ }
+ continue;
+ }
+ n = n * 10 + (c - '0');
+ seendigit = 1;
+ }
+ return (n);
+}
+
+getnonblank(fp)
+ FILE *fp;
+{
+ register int c;
+
+ while ( (c = getc(fp)) != EOF ) {
+ if (isspace(c)) {
+ if (c == '\n')
+ lineno++;
+ continue;
+ }
+ if (c == ';') {
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ lineno++;
+ continue;
+ }
+ return(c);
+ }
+ syslog(LOG_ERR, "line %d: unexpected EOF", lineno);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "line %d: unexpected EOF", lineno);
+#endif
+ return (EOF);
+}
+
+/*
+ * Take name and fix it according to following rules:
+ * "." means root.
+ * "@" means current origin.
+ * "name." means no changes.
+ * "name" means append origin.
+ */
+makename(name, origin)
+ char *name, *origin;
+{
+ int n;
+
+ if (origin[0] == '.')
+ origin++;
+ n = strlen(name);
+ if (n == 1) {
+ if (name[0] == '.') {
+ name[0] = '\0';
+ return;
+ }
+ if (name[0] == '@') {
+ (void) strcpy(name, origin);
+ return;
+ }
+ }
+ if (n > 0) {
+ if (name[n - 1] == '.')
+ name[n - 1] = '\0';
+ else if (origin[0] != '\0') {
+ name[n] = '.';
+ (void) strcpy(name + n + 1, origin);
+ }
+ }
+}
+
+endline(fp)
+ register FILE *fp;
+{
+ register int c;
+ while (c = getc(fp))
+ if (c == '\n') {
+ (void) ungetc(c,fp);
+ break;
+ } else if (c == EOF)
+ break;
+}
+
+#define MAXPORT 256
+#define MAXLEN 24
+
+getprotocol(fp, src)
+ FILE *fp;
+ char *src;
+{
+ int k;
+ char b[MAXLEN];
+
+ (void) getword(b, sizeof(b), fp);
+
+ k = protocolnumber(b);
+ if(k == -1)
+ syslog(LOG_ERR, "%s: line %d: unknown protocol: %s.",
+ src, lineno, b);
+ return(k);
+}
+
+int
+getservices(n, data, fp, src)
+ int n;
+ char *data, *src;
+ FILE *fp;
+{
+ int j, ch;
+ int k;
+ int maxl;
+ int bracket;
+ char b[MAXLEN];
+ char bm[MAXPORT/8];
+
+ for (j = 0; j < MAXPORT/8; j++)
+ bm[j] = 0;
+ maxl = 0;
+ bracket = 0;
+ while (getword(b, sizeof(b), fp) || bracket) {
+ if (feof(fp) || ferror(fp))
+ break;
+ if (strlen(b) == 0)
+ continue;
+ if ( b[0] == '(') {
+ bracket++;
+ continue;
+ }
+ if ( b[0] == ')') {
+ bracket = 0;
+ while ((ch = getc(fp)) != EOF && ch != '\n')
+ ;
+ if (ch == '\n')
+ lineno++;
+ break;
+ }
+ k = servicenumber(b);
+ if (k == -1) {
+ syslog(LOG_WARNING, "%s: line %d: Unknown service '%s'",
+ src, lineno, b);
+ continue;
+ }
+ if ((k < MAXPORT) && (k)) {
+ bm[k/8] |= (0x80>>(k%8));
+ if (k > maxl)
+ maxl=k;
+ }
+ else {
+ syslog(LOG_WARNING,
+ "%s: line %d: port no. (%d) too big\n",
+ src, lineno, k);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "%s: line %d: port no. (%d) too big\n",
+ src, lineno, k);
+#endif
+ }
+ }
+ if (bracket)
+ syslog(LOG_WARNING, "%s: line %d: missing close paren\n",
+ src, lineno);
+ maxl = maxl/8+1;
+ bcopy(bm, data+n, maxl);
+ return(maxl+n);
+}
+
+get_sort_list(fp)
+ FILE *fp;
+{
+ extern struct netinfo **enettab;
+ register struct netinfo *ntp, **end = enettab;
+ extern struct netinfo *findnetinfo();
+ struct in_addr addr;
+ char buf[BUFSIZ];
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sortlist ");
+#endif
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt," %s",buf);
+#endif
+ addr.s_addr = inet_addr(buf);
+ if (addr.s_addr == (unsigned)-1) {
+ /* resolve name to address - XXX */
+ continue;
+ }
+ /* Check for duplicates, then add to linked list */
+ if (findnetinfo(addr))
+ continue;
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ ntp->my_addr = addr;
+ ntp->next = NULL;
+ ntp->mask = net_mask(ntp->my_addr);
+ ntp->net = ntp->my_addr.s_addr & ntp->mask;
+ if (ntp->net != addr.s_addr) {
+ struct in_addr tmpaddr;
+
+ tmpaddr.s_addr = ntp->net;
+ syslog(LOG_WARNING, "sortlist: addr %s != %s", buf,
+ inet_ntoa(tmpaddr));
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "\nsortlist: addr %s != %s\n", buf,
+ inet_ntoa(tmpaddr));
+#endif
+ }
+
+ *end = ntp;
+ end = &ntp->next;
+ }
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"\n");
+ if (debug > 2)
+ printnetinfo(*enettab);
+ if (debug > 4) {
+ extern struct netinfo *nettab;
+
+ fprintf(ddt, "\nFull sort list:\n");
+ printnetinfo(nettab);
+ }
+#endif
+}
+
+free_sort_list()
+{
+ extern struct netinfo **enettab;
+ register struct netinfo *ntp, *next;
+
+ for (ntp = *enettab; ntp != NULL; ntp = next) {
+ next = ntp->next;
+ free((char *)ntp);
+ }
+ *enettab = NULL;
+}
diff --git a/usr.sbin/named/db_lookup.c b/usr.sbin/named/db_lookup.c
new file mode 100644
index 00000000000..5747b3e47bf
--- /dev/null
+++ b/usr.sbin/named/db_lookup.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1986 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[] = "from: @(#)db_lookup.c 4.18 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: db_lookup.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Table lookup routines.
+ */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include "db.h"
+
+struct hashbuf *hashtab; /* root hash table */
+struct hashbuf *fcachetab; /* hash table of cache read from file */
+
+#ifdef DEBUG
+extern int debug;
+extern FILE *ddt;
+#endif
+
+/*
+ * Lookup 'name' and return a pointer to the namebuf;
+ * NULL otherwise. If 'insert', insert name into tables.
+ * Wildcard lookups are handled.
+ */
+struct namebuf *
+nlookup(name, htpp, fname, insert)
+ char *name;
+ struct hashbuf **htpp;
+ char **fname;
+ int insert;
+{
+ register struct namebuf *np;
+ register char *cp;
+ register int c;
+ register unsigned hval;
+ register struct hashbuf *htp;
+ struct namebuf *parent = NULL;
+
+ htp = *htpp;
+ hval = 0;
+ *fname = "???";
+ for (cp = name; c = *cp++; ) {
+ if (c == '.') {
+ parent = np = nlookup(cp, htpp, fname, insert);
+ if (np == NULL)
+ return (NULL);
+ if (*fname != cp)
+ return (np);
+ if ((htp = np->n_hash) == NULL) {
+ if (!insert) {
+ if (np->n_dname[0] == '*' &&
+ np->n_dname[1] == '\0')
+ *fname = name;
+ return (np);
+ }
+ htp = savehash((struct hashbuf *)NULL);
+ np->n_hash = htp;
+ }
+ *htpp = htp;
+ break;
+ }
+ hval <<= HASHSHIFT;
+ hval += c & HASHMASK;
+ }
+ c = *--cp;
+ *cp = '\0';
+ /*
+ * Lookup this label in current hash table.
+ */
+ for (np = htp->h_tab[hval % htp->h_size]; np != NULL; np = np->n_next) {
+ if (np->n_hashval == hval &&
+ strcasecmp(name, np->n_dname) == 0) {
+ *cp = c;
+ *fname = name;
+ return (np);
+ }
+ }
+ if (!insert) {
+ /*
+ * Look for wildcard in this hash table.
+ * Don't use a cached "*" name as a wildcard,
+ * only authoritative.
+ */
+ hval = ('*' & HASHMASK) % htp->h_size;
+ for (np = htp->h_tab[hval]; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] == '*' && np->n_dname[1] == '\0' &&
+ np->n_data && np->n_data->d_zone != 0) {
+ *cp = c;
+ *fname = name;
+ return (np);
+ }
+ }
+ *cp = c;
+ return (parent);
+ }
+ np = savename(name);
+ np->n_parent = parent;
+ np->n_hashval = hval;
+ hval %= htp->h_size;
+ np->n_next = htp->h_tab[hval];
+ htp->h_tab[hval] = np;
+ /* increase hash table size */
+ if (++htp->h_cnt > htp->h_size * 2) {
+ *htpp = savehash(htp);
+ if (parent == NULL) {
+ if (htp == hashtab)
+ hashtab = *htpp;
+ else
+ fcachetab = *htpp;
+ }
+ else
+ parent->n_hash = *htpp;
+ htp = *htpp;
+ }
+ *cp = c;
+ *fname = name;
+ return (np);
+}
+
+/*
+ * Does the data record match the class and type?
+ */
+match(dp, class, type)
+ register struct databuf *dp;
+ register int class, type;
+{
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"match(0x%x, %d, %d) %d, %d\n", dp, class, type,
+ dp->d_class, dp->d_type);
+#endif
+ if (dp->d_class != class && class != C_ANY)
+ return (0);
+ if (dp->d_type != type && type != T_ANY)
+ return (0);
+ return (1);
+}
diff --git a/usr.sbin/named/db_reload.c b/usr.sbin/named/db_reload.c
new file mode 100644
index 00000000000..26554c9dfb9
--- /dev/null
+++ b/usr.sbin/named/db_reload.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1986, 1988 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[] = "from: @(#)db_reload.c 4.22 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: db_reload.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include "ns.h"
+#include "db.h"
+
+extern time_t resettime;
+
+/*
+ * Flush and reload data base.
+ */
+
+db_reload()
+{
+ extern char *bootfile;
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"reload()\n");
+#endif
+ syslog(LOG_NOTICE, "reloading nameserver\n");
+
+ qflush();
+ sqflush();
+ fwdtab_free();
+ free_sort_list();
+ getnetconf();
+ ns_init(bootfile);
+ time(&resettime);
+}
+
+db_free(htp)
+ struct hashbuf *htp;
+{
+ register struct databuf *dp, *nextdp;
+ register struct namebuf *np, *nextnp;
+ struct namebuf **npp, **nppend;
+
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = nextnp) {
+ if (np->n_hash != NULL)
+ db_free(np->n_hash);
+ (void) free((char *)np->n_dname);
+ for (dp = np->n_data; dp != NULL; ) {
+ nextdp = dp->d_next;
+ (void) free((char *)dp);
+ dp = nextdp;
+ }
+ nextnp = np->n_next;
+ free((char *)np);
+ }
+ }
+ (void) free((char *)htp);
+}
+
+db_inv_free()
+{
+ register struct invbuf *ip;
+ register int i, j;
+
+ for (i = 0; i < INVHASHSZ; i++)
+ for (ip = invtab[i]; ip != NULL; ip = ip->i_next)
+ for (j = 0; j < INVBLKSZ; j++)
+ ip->i_dname[j] = NULL;
+}
+
+fwdtab_free()
+{
+ extern struct fwdinfo *fwdtab;
+ struct fwdinfo *fp, *nextfp;
+
+ for (fp = fwdtab; fp != NULL; fp = nextfp) {
+ nextfp = fp->next;
+ free((char *)fp);
+ }
+ fwdtab = NULL;
+}
diff --git a/usr.sbin/named/db_save.c b/usr.sbin/named/db_save.c
new file mode 100644
index 00000000000..39fd88b8bc7
--- /dev/null
+++ b/usr.sbin/named/db_save.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 1986 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[] = "from: @(#)db_save.c 4.16 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: db_save.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <string.h>
+#include "db.h"
+
+#ifdef DEBUG
+extern int debug;
+extern FILE *ddt;
+#endif
+
+/*
+ * Allocate a name buffer & save name.
+ */
+struct namebuf *
+savename(name)
+ char *name;
+{
+ register struct namebuf *np;
+
+ np = (struct namebuf *) malloc(sizeof(struct namebuf));
+ if (np == NULL) {
+ syslog(LOG_ERR, "savename: %m");
+ exit(1);
+ }
+ np->n_dname = savestr(name);
+ np->n_next = NULL;
+ np->n_data = NULL;
+ np->n_hash = NULL;
+ return (np);
+}
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct databuf *
+savedata(class, type, ttl, data, size)
+ int class, type;
+ u_long ttl;
+ char *data;
+ int size;
+{
+ register struct databuf *dp;
+
+ if (type == T_NS)
+ dp = (struct databuf *)
+ malloc((unsigned)DATASIZE(size)+sizeof(u_long));
+ else
+ dp = (struct databuf *) malloc((unsigned)DATASIZE(size));
+ if (dp == NULL) {
+ syslog(LOG_ERR, "savedata: %m");
+ exit(1);
+ }
+ dp->d_next = NULL;
+ dp->d_type = type;
+ dp->d_class = class;
+ dp->d_ttl = ttl;
+ dp->d_size = size;
+ dp->d_mark = 0;
+ dp->d_flags = 0;
+ dp->d_nstime = 0;
+ bcopy(data, dp->d_data, dp->d_size);
+ return (dp);
+}
+
+int hashsizes[] = { /* hashtable sizes */
+ 2,
+ 11,
+ 113,
+ 337,
+ 977,
+ 2053,
+ 4073,
+ 8011,
+ 16001,
+ 0
+};
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct hashbuf *
+savehash(oldhtp)
+ register struct hashbuf *oldhtp;
+{
+ register struct hashbuf *htp;
+ register struct namebuf *np, *nnp, **hp;
+ register int n;
+ int newsize;
+
+ if (oldhtp == NULL)
+ newsize = hashsizes[0];
+ else {
+ for (n = 0; newsize = hashsizes[n++]; )
+ if (oldhtp->h_size == newsize) {
+ newsize = hashsizes[n];
+ break;
+ }
+ if (newsize == 0)
+ newsize = oldhtp->h_size * 2 + 1;
+ }
+#ifdef DEBUG
+ if(debug > 3)
+ fprintf(ddt, "savehash GROWING to %d\n", newsize);
+#endif
+ htp = (struct hashbuf *) malloc((unsigned)HASHSIZE(newsize));
+ if (htp == NULL) {
+ syslog(LOG_ERR, "savehash: %m");
+ exit(1);
+ }
+ htp->h_size = newsize;
+ bzero((char *) htp->h_tab, newsize * sizeof(struct hashbuf *));
+ if (oldhtp == NULL) {
+ htp->h_cnt = 0;
+ return (htp);
+ }
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"savehash(%#x) cnt=%d, sz=%d, newsz=%d\n",
+ oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize);
+#endif
+ htp->h_cnt = oldhtp->h_cnt;
+ for (n = 0; n < oldhtp->h_size; n++) {
+ for (np = oldhtp->h_tab[n]; np != NULL; np = nnp) {
+ nnp = np->n_next;
+ hp = &htp->h_tab[np->n_hashval % htp->h_size];
+ np->n_next = *hp;
+ *hp = np;
+ }
+ }
+ free((char *) oldhtp);
+ return (htp);
+}
+
+/*
+ * Allocate an inverse query buffer.
+ */
+struct invbuf *
+saveinv()
+{
+ register struct invbuf *ip;
+
+ ip = (struct invbuf *) malloc(sizeof(struct invbuf));
+ if (ip == NULL) {
+ syslog(LOG_ERR, "saveinv: %m");
+ exit(1);
+ }
+ ip->i_next = NULL;
+ bzero((char *)ip->i_dname, sizeof(ip->i_dname));
+ return (ip);
+}
+
+/*
+ * Make a copy of a string and return a pointer to it.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *cp;
+
+ cp = malloc((unsigned)strlen(str) + 1);
+ if (cp == NULL) {
+ syslog(LOG_ERR, "savestr: %m");
+ exit(1);
+ }
+ (void) strcpy(cp, str);
+ return (cp);
+}
diff --git a/usr.sbin/named/db_update.c b/usr.sbin/named/db_update.c
new file mode 100644
index 00000000000..6c21ca5189c
--- /dev/null
+++ b/usr.sbin/named/db_update.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1986, 1990 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[] = "from: @(#)db_update.c 4.28 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: db_update.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include "ns.h"
+#include "db.h"
+
+extern struct timeval tt;
+extern FILE *ddt;
+extern struct sockaddr_in from_addr; /* Source addr of last packet */
+extern int needs_prime_cache;
+
+int max_cache_ttl = (7*24*60*60); /* ONE_WEEK maximum ttl */
+int min_cache_ttl = (5*60); /* 5 minute minimum ttl */
+
+/*
+ * Update data base. Flags control the action.
+ * Inverse query tables modified.
+ */
+db_update(name, odp, newdp, flags, htp)
+ char name[];
+ struct databuf *odp, *newdp;
+ int flags;
+ struct hashbuf *htp;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *pdp;
+ char *fname;
+ int foundRR = 0;
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"db_update(%s, 0x%x, 0x%x, 0%o, 0x%x)%s\n",
+ name, odp, newdp, flags, htp,
+ (odp && (odp->d_flags&DB_F_HINT)) ? " hint":"" );
+#endif
+ np = nlookup(name, &htp, &fname, newdp != NULL);
+ if (np == NULL || fname != name)
+ return (NONAME);
+
+ /* Reflect certain updates in hint cache also... */
+ /* Don't stick data we are authoritative for in hints. */
+ if (!(flags & DB_NOHINTS) && (odp != NULL) &&
+ (odp->d_zone <= 0) && !(odp->d_flags & DB_F_HINT) &&
+ ((name[0] == '\0' && odp->d_type == T_NS) ||
+ (odp->d_type == T_A)))
+ {
+ register struct databuf *dp;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"db_update: hint '%s' %d\n",
+ name, odp->d_ttl);
+#endif
+ dp = savedata(odp->d_class, odp->d_type, odp->d_ttl,
+ odp->d_data, odp->d_size);
+ dp->d_zone = DB_Z_CACHE;
+ dp->d_flags = DB_F_HINT;
+ if (db_update(name, dp,dp, (flags|DB_NOHINTS), fcachetab) != OK) {
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt, "db_update: hint %x freed\n", dp);
+#endif
+ (void) free((char *)dp);
+ }
+ }
+
+ if (odp != NULL) {
+ pdp = NULL;
+ for (dp = np->n_data; dp != NULL; ) {
+ if (!match(dp, odp->d_class, odp->d_type)) {
+ if ((dp->d_type == T_CNAME ||
+ odp->d_type == T_CNAME) &&
+ odp->d_mark == dp->d_mark &&
+ zones[odp->d_zone].z_type != Z_CACHE) {
+ syslog(LOG_ERR,
+ "%s has CNAME and other data (illegal)\n",
+ name);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "db_update: %s: CNAME and more (%d, %d)\n",
+ name, odp->d_type, dp->d_type);
+#endif
+ }
+ goto skip;
+ }
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"db_update: flags = %#x, sizes = %d, %d (%d)\n",
+ flags, odp->d_size, dp->d_size,
+ db_cmp(dp, odp));
+#endif
+ if (flags & DB_NOTAUTH && dp->d_zone) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "%s attempted update to auth zone %d '%s'\n",
+ inet_ntoa(from_addr.sin_addr),
+ dp->d_zone, zones[dp->d_zone].z_origin);
+#endif
+ return (AUTH);
+ }
+ if ((flags & DB_NODATA) && !db_cmp(dp, odp)) {
+ /* refresh ttl if cache entry */
+ if (dp->d_zone == 0) {
+ if (odp->d_zone != 0) { /* XXX */
+ /* changing cache->auth */
+ dp->d_zone = odp->d_zone;
+ dp->d_ttl = odp->d_ttl;
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,
+ "db_update: cache entry now in auth zone\n");
+#endif
+ return (DATAEXISTS);
+ }
+ fixttl(odp);
+ if (odp->d_ttl > dp->d_ttl)
+ dp->d_ttl = odp->d_ttl;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"db_update: new ttl %d, +%d\n",
+ dp->d_ttl, dp->d_ttl - tt.tv_sec);
+#endif
+ }
+ return (DATAEXISTS);
+ }
+ /*
+ * If the old databuf has some data, check that the
+ * data matches that in the new databuf (so UPDATED
+ * will delete only the matching RR)
+ */
+ if (odp->d_size > 0) {
+ if (db_cmp(dp, odp))
+ goto skip;
+ }
+ foundRR = 1;
+ if (flags & DB_DELETE)
+ dp = rm_datum(dp, np, pdp);
+ else {
+skip: pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+ if (!foundRR) {
+ if (flags & DB_DELETE)
+ return(NODATA);
+ if (flags & DB_MEXIST)
+ return(NODATA);
+ }
+ }
+ if (newdp == NULL)
+ return (OK);
+ fixttl(newdp);
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"db_update: adding%s %x\n",
+ (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp);
+#endif
+ if (!(newdp->d_flags & DB_F_HINT))
+ addinv(np, newdp); /* modify inverse query tables */
+
+ /* Add to end of list, generally preserving order */
+ newdp->d_next = NULL;
+ if ((dp = np->n_data) == NULL) {
+ np->n_data = newdp;
+ return (OK);
+ }
+ /* XXX: need to check for duplicate WKS records and flag error */
+ while (dp->d_next != NULL) {
+ if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
+ return (DATAEXISTS);
+ dp = dp->d_next;
+ }
+ if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
+ return (DATAEXISTS);
+ dp->d_next = newdp;
+ return (OK);
+}
+
+fixttl(dp)
+register struct databuf *dp;
+{
+ if (dp->d_zone == 0 && !(dp->d_flags & DB_F_HINT)) {
+ if (dp->d_ttl <= tt.tv_sec)
+ return;
+ else if (dp->d_ttl < tt.tv_sec+min_cache_ttl)
+ dp->d_ttl = tt.tv_sec+min_cache_ttl;
+ else if (dp->d_ttl > tt.tv_sec+max_cache_ttl)
+ dp->d_ttl = tt.tv_sec+max_cache_ttl;
+ }
+ return;
+}
+
+struct invbuf *invtab[INVHASHSZ]; /* Inverse query hash table */
+
+/*
+ * Add data 'dp' to inverse query tables for name 'np'.
+ */
+addinv(np, dp)
+ struct namebuf *np;
+ struct databuf *dp;
+{
+ register struct invbuf *ip;
+ register int hval, i;
+
+ switch (dp->d_type) {
+ case T_A:
+ case T_UID:
+ case T_GID:
+ break;
+
+ default:
+ return;
+ }
+
+ hval = dhash(dp->d_data, dp->d_size);
+ for (ip = invtab[hval]; ip != NULL; ip = ip->i_next)
+ for (i = 0; i < INVBLKSZ; i++)
+ if (ip->i_dname[i] == NULL) {
+ ip->i_dname[i] = np;
+ return;
+ }
+ ip = saveinv();
+ ip->i_next = invtab[hval];
+ invtab[hval] = ip;
+ ip->i_dname[0] = np;
+}
+
+/*
+ * Remove data 'odp' from inverse query table.
+ */
+rminv(odp)
+ struct databuf *odp;
+{
+ register struct invbuf *ip;
+ register struct databuf *dp;
+ struct namebuf *np;
+ register int i;
+
+ for (ip = invtab[dhash(odp->d_data, odp->d_size)]; ip != NULL;
+ ip = ip->i_next) {
+ for (i = 0; i < INVBLKSZ; i++) {
+ if ((np = ip->i_dname[i]) == NULL)
+ break;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, odp->d_class, odp->d_type))
+ continue;
+ if (db_cmp(dp, odp))
+ continue;
+ while (i < INVBLKSZ-1) {
+ ip->i_dname[i] = ip->i_dname[i+1];
+ i++;
+ }
+ ip->i_dname[i] = NULL;
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * Compute hash value from data.
+ */
+dhash(dp, dlen)
+ char *dp;
+ int dlen;
+{
+ register char *cp;
+ register unsigned hval;
+ register int n;
+
+ n = dlen;
+ if (n > 8)
+ n = 8;
+ hval = 0;
+ for (cp = dp; --n >= 0; ) {
+ hval <<= 1;
+ hval += *cp++;
+ }
+ return (hval % INVHASHSZ);
+}
+
+/*
+ * Compare type, class and data from databufs for equivalence.
+ * Must be case insensitive for some domain names.
+ * Return 0 if equivalent, nonzero otherwise.
+ */
+db_cmp(dp1, dp2)
+ register struct databuf *dp1, *dp2;
+
+{
+ register char *cp1, *cp2;
+ int len;
+
+ if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class)
+ return(1);
+ if (dp1->d_size != dp2->d_size)
+ return(1);
+ if (dp1->d_mark != dp2->d_mark)
+ return(1); /* old and new RR's are distinct */
+ switch (dp1->d_type) {
+
+ case T_A:
+ case T_UID:
+ case T_GID:
+ case T_WKS:
+ case T_NULL:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif ALLOW_T_UNSPEC
+ return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
+
+ case T_NS:
+ case T_CNAME:
+ case T_PTR:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_UINFO:
+ return(strcasecmp(dp1->d_data, dp2->d_data));
+
+ case T_HINFO:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ len = *cp1;
+ if (strncasecmp(++cp1, ++cp2, len))
+ return(1);
+ cp1 += len;
+ cp2 += len;
+ len = *cp1;
+ return(strncasecmp(++cp1, ++cp2, len));
+
+ case T_SOA:
+ case T_MINFO:
+ if (strcasecmp(dp1->d_data, dp2->d_data))
+ return(1);
+ cp1 = dp1->d_data + strlen(dp1->d_data) + 1;
+ cp2 = dp2->d_data + strlen(dp2->d_data) + 1;
+ if (dp1->d_type != T_SOA)
+ return(strcasecmp(cp1, cp2));
+ if (strcasecmp(cp1, cp2))
+ return(1);
+ cp1 += strlen(cp1) + 1;
+ cp2 += strlen(cp2) + 1;
+ return(bcmp(cp1, cp2, sizeof(u_long) * 5));
+
+ case T_MX:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
+ return(1);
+ return(strcasecmp(cp1, cp2));
+
+ case T_TXT:
+ if (dp1->d_size != dp2->d_size)
+ return(1);
+ return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
+
+ default:
+ return (1);
+ }
+}
diff --git a/usr.sbin/named/doc/rfc1032.lpr b/usr.sbin/named/doc/rfc1032.lpr
new file mode 100644
index 00000000000..0e82721cee7
--- /dev/null
+++ b/usr.sbin/named/doc/rfc1032.lpr
@@ -0,0 +1,781 @@
+Network Working Group M. Stahl
+Request for Comments: 1032 SRI International
+ November 1987
+
+
+ DOMAIN ADMINISTRATORS GUIDE
+
+
+STATUS OF THIS MEMO
+
+ This memo describes procedures for registering a domain with the
+ Network Information Center (NIC) of Defense Data Network (DDN), and
+ offers guidelines on the establishment and administration of a domain
+ in accordance with the requirements specified in RFC-920. It is
+ intended for use by domain administrators. This memo should be used
+ in conjunction with RFC-920, which is an official policy statement of
+ the Internet Activities Board (IAB) and the Defense Advanced Research
+ Projects Agency (DARPA). Distribution of this memo is unlimited.
+
+BACKGROUND
+
+ Domains are administrative entities that provide decentralized
+ management of host naming and addressing. The domain-naming system
+ is distributed and hierarchical.
+
+ The NIC is designated by the Defense Communications Agency (DCA) to
+ provide registry services for the domain-naming system on the DDN and
+ DARPA portions of the Internet.
+
+ As registrar of top-level and second-level domains, as well as
+ administrator of the root domain name servers on behalf of DARPA and
+ DDN, the NIC is responsible for maintaining the root server zone
+ files and their binary equivalents. In addition, the NIC is
+ responsible for administering the top-level domains of "ARPA," "COM,"
+ "EDU," "ORG," "GOV," and "MIL" on behalf of DCA and DARPA until it
+ becomes feasible for other appropriate organizations to assume those
+ responsibilities.
+
+ It is recommended that the guidelines described in this document be
+ used by domain administrators in the establishment and control of
+ second-level domains.
+
+THE DOMAIN ADMINISTRATOR
+
+ The role of the domain administrator (DA) is that of coordinator,
+ manager, and technician. If his domain is established at the second
+ level or lower in the tree, the DA must register by interacting with
+ the management of the domain directly above his, making certain that
+
+
+
+Stahl [Page 1]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ his domain satisfies all the requirements of the administration under
+ which his domain would be situated. To find out who has authority
+ over the name space he wishes to join, the DA can ask the NIC
+ Hostmaster. Information on contacts for the top-level and second-
+ level domains can also be found on line in the file NETINFO:DOMAIN-
+ CONTACTS.TXT, which is available from the NIC via anonymous FTP.
+
+ The DA should be technically competent; he should understand the
+ concepts and procedures for operating a domain server, as described
+ in RFC-1034, and make sure that the service provided is reliable and
+ uninterrupted. It is his responsibility or that of his delegate to
+ ensure that the data will be current at all times. As a manager, the
+ DA must be able to handle complaints about service provided by his
+ domain name server. He must be aware of the behavior of the hosts in
+ his domain, and take prompt action on reports of problems, such as
+ protocol violations or other serious misbehavior. The administrator
+ of a domain must be a responsible person who has the authority to
+ either enforce these actions himself or delegate them to someone
+ else.
+
+ Name assignments within a domain are controlled by the DA, who should
+ verify that names are unique within his domain and that they conform
+ to standard naming conventions. He furnishes access to names and
+ name-related information to users both inside and outside his domain.
+ He should work closely with the personnel he has designated as the
+ "technical and zone" contacts for his domain, for many administrative
+ decisions will be made on the basis of input from these people.
+
+THE DOMAIN TECHNICAL AND ZONE CONTACT
+
+ A zone consists of those contiguous parts of the domain tree for
+ which a domain server has complete information and over which it has
+ authority. A domain server may be authoritative for more than one
+ zone. The domain technical/zone contact is the person who tends to
+ the technical aspects of maintaining the domain's name server and
+ resolver software, and database files. He keeps the name server
+ running, and interacts with technical people in other domains and
+ zones to solve problems that affect his zone.
+
+POLICIES
+
+ Domain or host name choices and the allocation of domain name space
+ are considered to be local matters. In the event of conflicts, it is
+ the policy of the NIC not to get involved in local disputes or in the
+ local decision-making process. The NIC will not act as referee in
+ disputes over such matters as who has the "right" to register a
+ particular top-level or second-level domain for an organization. The
+ NIC considers this a private local matter that must be settled among
+
+
+
+Stahl [Page 2]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ the parties involved prior to their commencing the registration
+ process with the NIC. Therefore, it is assumed that the responsible
+ person for a domain will have resolved any local conflicts among the
+ members of his domain before registering that domain with the NIC.
+ The NIC will give guidance, if requested, by answering specific
+ technical questions, but will not provide arbitration in disputes at
+ the local level. This policy is also in keeping with the distributed
+ hierarchical nature of the domain-naming system in that it helps to
+ distribute the tasks of solving problems and handling questions.
+
+ Naming conventions for hosts should follow the rules specified in
+ RFC-952. From a technical standpoint, domain names can be very long.
+ Each segment of a domain name may contain up to 64 characters, but
+ the NIC strongly advises DAs to choose names that are 12 characters
+ or fewer, because behind every domain system there is a human being
+ who must keep track of the names, addresses, contacts, and other data
+ in a database. The longer the name, the more likely the data
+ maintainer is to make a mistake. Users also will appreciate shorter
+ names. Most people agree that short names are easier to remember and
+ type; most domain names registered so far are 12 characters or fewer.
+
+ Domain name assignments are made on a first-come-first-served basis.
+ The NIC has chosen not to register individual hosts directly under
+ the top-level domains it administers. One advantage of the domain
+ naming system is that administration and data maintenance can be
+ delegated down a hierarchical tree. Registration of hosts at the
+ same level in the tree as a second-level domain would dilute the
+ usefulness of this feature. In addition, the administrator of a
+ domain is responsible for the actions of hosts within his domain. We
+ would not want to find ourselves in the awkward position of policing
+ the actions of individual hosts. Rather, the subdomains registered
+ under these top-level domains retain the responsibility for this
+ function.
+
+ Countries that wish to be registered as top-level domains are
+ required to name themselves after the two-letter country code listed
+ in the international standard ISO-3166. In some cases, however, the
+ two-letter ISO country code is identical to a state code used by the
+ U.S. Postal Service. Requests made by countries to use the three-
+ letter form of country code specified in the ISO-3166 standard will
+ be considered in such cases so as to prevent possible conflicts and
+ confusion.
+
+
+
+
+
+
+
+
+
+Stahl [Page 3]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+HOW TO REGISTER
+
+ Obtain a domain questionnaire from the NIC hostmaster, or FTP the
+ file NETINFO:DOMAIN-TEMPLATE.TXT from host SRI-NIC.ARPA.
+
+ Fill out the questionnaire completely. Return it via electronic mail
+ to HOSTMASTER@SRI-NIC.ARPA.
+
+ The APPENDIX to this memo contains the application form for
+ registering a top-level or second-level domain with the NIC. It
+ supersedes the version of the questionnaire found in RFC-920. The
+ application should be submitted by the person administratively
+ responsible for the domain, and must be filled out completely before
+ the NIC will authorize establishment of a top-level or second-level
+ domain. The DA is responsible for keeping his domain's data current
+ with the NIC or with the registration agent with which his domain is
+ registered. For example, the CSNET and UUCP managements act as
+ domain filters, processing domain applications for their own
+ organizations. They pass pertinent information along periodically to
+ the NIC for incorporation into the domain database and root server
+ files. The online file NETINFO:ALTERNATE-DOMAIN-PROCEDURE.TXT
+ outlines this procedure. It is highly recommended that the DA review
+ this information periodically and provide any corrections or
+ additions. Corrections should be submitted via electronic mail.
+
+WHICH DOMAIN NAME?
+
+ The designers of the domain-naming system initiated several general
+ categories of names as top-level domain names, so that each could
+ accommodate a variety of organizations. The current top-level
+ domains registered with the DDN Network Information Center are ARPA,
+ COM, EDU, GOV, MIL, NET, and ORG, plus a number of top-level country
+ domains. To join one of these, a DA needs to be aware of the purpose
+ for which it was intended.
+
+ "ARPA" is a temporary domain. It is by default appended to the
+ names of hosts that have not yet joined a domain. When the system
+ was begun in 1984, the names of all hosts in the Official DoD
+ Internet Host Table maintained by the NIC were changed by adding
+ of the label ".ARPA" in order to accelerate a transition to the
+ domain-naming system. Another reason for the blanket name changes
+ was to force hosts to become accustomed to using the new style
+ names and to modify their network software, if necessary. This
+ was done on a network-wide basis and was directed by DCA in DDN
+ Management Bulletin No. 22. Hosts that fall into this domain will
+ eventually move to other branches of the domain tree.
+
+
+
+
+
+Stahl [Page 4]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ "COM" is meant to incorporate subdomains of companies and
+ businesses.
+
+ "EDU" was initiated to accommodate subdomains set up by
+ universities and other educational institutions.
+
+ "GOV" exists to act as parent domain for subdomains set up by
+ government agencies.
+
+ "MIL" was initiated to act as parent to subdomains that are
+ developed by military organizations.
+
+ "NET" was introduced as a parent domain for various network-type
+ organizations. Organizations that belong within this top-level
+ domain are generic or network-specific, such as network service
+ centers and consortia. "NET" also encompasses network
+ management-related organizations, such as information centers and
+ operations centers.
+
+ "ORG" exists as a parent to subdomains that do not clearly fall
+ within the other top-level domains. This may include technical-
+ support groups, professional societies, or similar organizations.
+
+ One of the guidelines in effect in the domain-naming system is that a
+ host should have only one name regardless of what networks it is
+ connected to. This implies, that, in general, domain names should
+ not include routing information or addresses. For example, a host
+ that has one network connection to the Internet and another to BITNET
+ should use the same name when talking to either network. For a
+ description of the syntax of domain names, please refer to Section 3
+ of RFC-1034.
+
+VERIFICATION OF DATA
+
+ The verification process can be accomplished in several ways. One of
+ these is through the NIC WHOIS server. If he has access to WHOIS,
+ the DA can type the command "whois domain <domain name><return>".
+ The reply from WHOIS will supply the following: the name and address
+ of the organization "owning" the domain; the name of the domain; its
+ administrative, technical, and zone contacts; the host names and
+ network addresses of sites providing name service for the domain.
+
+
+
+
+
+
+
+
+
+
+Stahl [Page 5]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ Example:
+
+ @whois domain rice.edu<Return>
+
+ Rice University (RICE-DOM)
+ Advanced Studies and Research
+ Houston, TX 77001
+
+ Domain Name: RICE.EDU
+
+ Administrative Contact:
+ Kennedy, Ken (KK28) Kennedy@LLL-CRG.ARPA (713) 527-4834
+ Technical Contact, Zone Contact:
+ Riffle, Vicky R. (VRR) rif@RICE.EDU
+ (713) 527-8101 ext 3844
+
+ Domain servers:
+
+ RICE.EDU 128.42.5.1
+ PENDRAGON.CS.PURDUE.EDU 128.10.2.5
+
+
+ Alternatively, the DA can send an electronic mail message to
+ SERVICE@SRI-NIC.ARPA. In the subject line of the message header, the
+ DA should type "whois domain <domain name>". The requested
+ information will be returned via electronic mail. This method is
+ convenient for sites that do not have access to the NIC WHOIS
+ service.
+
+ The initial application for domain authorization should be submitted
+ via electronic mail, if possible, to HOSTMASTER@SRI-NIC.ARPA. The
+ questionnaire described in the appendix may be used or a separate
+ application can be FTPed from host SRI-NIC.ARPA. The information
+ provided by the administrator will be reviewed by hostmaster
+ personnel for completeness. There will most likely be a few
+ exchanges of correspondence via electronic mail, the preferred method
+ of communication, prior to authorization of the domain.
+
+HOW TO GET MORE INFORMATION
+
+ An informational table of the top-level domains and their root
+ servers is contained in the file NETINFO:DOMAINS.TXT online at SRI-
+ NIC.ARPA. This table can be obtained by FTPing the file.
+ Alternatively, the information can be acquired by opening a TCP or
+ UDP connection to the NIC Host Name Server, port 101 on SRI-NIC.ARPA,
+ and invoking the command "ALL-DOM".
+
+
+
+
+
+Stahl [Page 6]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ The following online files, all available by FTP from SRI-NIC.ARPA,
+ contain pertinent domain information:
+
+ - NETINFO:DOMAINS.TXT, a table of all top-level domains and the
+ network addresses of the machines providing domain name
+ service for them. It is updated each time a new top-level
+ domain is approved.
+
+ - NETINFO:DOMAIN-INFO.TXT contains a concise list of all
+ top-level and second-level domain names registered with the
+ NIC and is updated monthly.
+
+ - NETINFO:DOMAIN-CONTACTS.TXT also contains a list of all the
+ top level and second-level domains, but includes the
+ administrative, technical and zone contacts for each as well.
+
+ - NETINFO:DOMAIN-TEMPLATE.TXT contains the questionnaire to be
+ completed before registering a top-level or second-level
+ domain.
+
+ For either general or specific information on the domain system, do
+ one or more of the following:
+
+ 1. Send electronic mail to HOSTMASTER@SRI-NIC.ARPA
+
+ 2. Call the toll-free NIC hotline at (800) 235-3155
+
+ 3. Use FTP to get background RFCs and other files maintained
+ online at the NIC. Some pertinent RFCs are listed below in
+ the REFERENCES section of this memo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Stahl [Page 7]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+REFERENCES
+
+ The references listed here provide important background information
+ on the domain-naming system. Path names of the online files
+ available via anonymous FTP from the SRI-NIC.ARPA host are noted in
+ brackets.
+
+ 1. Defense Communications Agency DDN Defense Communications
+ System, DDN Management Bulletin No. 22, Domain Names
+ Transition, March 1984.
+ [ DDN-NEWS:DDN-MGT-BULLETIN-22.TXT ]
+
+ 2. Defense Communications Agency DDN Defense Communications
+ System, DDN Management Bulletin No. 32, Phase I of the Domain
+ Name Implementation, January 1987.
+ [ DDN-NEWS:DDN-MGT-BULLETIN-32.TXT ]
+
+ 3. Harrenstien, K., M. Stahl, and E. Feinler, "Hostname
+ Server", RFC-953, DDN Network Information Center, SRI
+ International, October 1985. [ RFC:RFC953.TXT ]
+
+ 4. Harrenstien, K., M. Stahl, and E. Feinler, "Official DoD
+ Internet Host Table Specification", RFC-952, DDN Network
+ Information Center, SRI International, October 1985.
+ [ RFC:RFC952.TXT ]
+
+ 5. ISO, "Codes for the Representation of Names of Countries",
+ ISO-3166, International Standards Organization, May 1981.
+ [ Not online ]
+
+ 6. Lazear, W.D., "MILNET Name Domain Transition", RFC-1031,
+ Mitre Corporation, October 1987. [ RFC:RFC1031.TXT ]
+
+ 7. Lottor, M.K., "Domain Administrators Operations Guide",
+ RFC-1033, DDN Network Information Center, SRI International,
+ July 1987. [ RFC:RFC1033.TXT ]
+
+ 8. Mockapetris, P., "Domain Names - Concepts and Facilities",
+ RFC-1034, USC Information Sciences Institute, October 1987.
+ [ RFC:RFC1034.TXT ]
+
+ 9. Mockapetris, P., "Domain Names - Implementation and
+ Specification", RFC-1035, USC Information Sciences Institute,
+ October 1987. [ RFC:RFC1035.TXT ]
+
+ 10. Mockapetris, P., "The Domain Name System", Proceedings of the
+ IFIP 6.5 Working Conference on Computer Message Services,
+ Nottingham, England, May 1984. Also as ISI/RS-84-133, June
+
+
+
+Stahl [Page 8]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ 1984. [ Not online ]
+
+ 11. Mockapetris, P., J. Postel, and P. Kirton, "Name Server
+ Design for Distributed Systems", Proceedings of the Seventh
+ International Conference on Computer Communication, October
+ 30 to November 3 1984, Sidney, Australia. Also as
+ ISI/RS-84-132, June 1984. [ Not online ]
+
+ 12. Partridge, C., "Mail Routing and the Domain System", RFC-974,
+ CSNET-CIC, BBN Laboratories, January 1986.
+ [ RFC:RFC974.TXT ]
+
+ 13. Postel, J., "The Domain Names Plan and Schedule", RFC-881,
+ USC Information Sciences Institute, November 1983.
+ [ RFC:RFC881.TXT ]
+
+ 14. Reynolds, J., and Postel, J., "Assigned Numbers", RFC-1010
+ USC Information Sciences Institute, May 1986.
+ [ RFC:RFC1010.TXT ]
+
+ 15. Romano, S., and Stahl, M., "Internet Numbers", RFC-1020,
+ SRI, November 1987.
+ [ RFC:RFC1020.TXT ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Stahl [Page 9]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+APPENDIX
+
+ The following questionnaire may be FTPed from SRI-NIC.ARPA as
+ NETINFO:DOMAIN-TEMPLATE.TXT.
+
+ ---------------------------------------------------------------------
+
+ To establish a domain, the following information must be sent to the
+ NIC Domain Registrar (HOSTMASTER@SRI-NIC.ARPA):
+
+ NOTE: The key people must have electronic mailboxes and NIC
+ "handles," unique NIC database identifiers. If you have access to
+ "WHOIS", please check to see if you are registered and if so, make
+ sure the information is current. Include only your handle and any
+ changes (if any) that need to be made in your entry. If you do not
+ have access to "WHOIS", please provide all the information indicated
+ and a NIC handle will be assigned.
+
+ (1) The name of the top-level domain to join.
+
+ For example: COM
+
+ (2) The NIC handle of the administrative head of the organization.
+ Alternately, the person's name, title, mailing address, phone number,
+ organization, and network mailbox. This is the contact point for
+ administrative and policy questions about the domain. In the case of
+ a research project, this should be the principal investigator.
+
+ For example:
+
+ Administrator
+
+ Organization The NetWorthy Corporation
+ Name Penelope Q. Sassafrass
+ Title President
+ Mail Address The NetWorthy Corporation
+ 4676 Andrews Way, Suite 100
+ Santa Clara, CA 94302-1212
+ Phone Number (415) 123-4567
+ Net Mailbox Sassafrass@ECHO.TNC.COM
+ NIC Handle PQS
+
+ (3) The NIC handle of the technical contact for the domain.
+ Alternately, the person's name, title, mailing address, phone number,
+ organization, and network mailbox. This is the contact point for
+ problems concerning the domain or zone, as well as for updating
+ information about the domain or zone.
+
+
+
+
+Stahl [Page 10]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ For example:
+
+ Technical and Zone Contact
+
+ Organization The NetWorthy Corporation
+ Name Ansel A. Aardvark
+ Title Executive Director
+ Mail Address The NetWorthy Corporation
+ 4676 Andrews Way, Suite 100
+ Santa Clara, CA. 94302-1212
+ Phone Number (415) 123-6789
+ Net Mailbox Aardvark@ECHO.TNC.COM
+ NIC Handle AAA2
+
+ (4) The name of the domain (up to 12 characters). This is the name
+ that will be used in tables and lists associating the domain with the
+ domain server addresses. [While, from a technical standpoint, domain
+ names can be quite long (programmers beware), shorter names are
+ easier for people to cope with.]
+
+ For example: TNC
+
+ (5) A description of the servers that provide the domain service for
+ translating names to addresses for hosts in this domain, and the date
+ they will be operational.
+
+ A good way to answer this question is to say "Our server is
+ supplied by person or company X and does whatever their standard
+ issue server does."
+
+ For example: Our server is a copy of the one operated by
+ the NIC; it will be installed and made operational on
+ 1 November 1987.
+
+ (6) Domains must provide at least two independent servers for the
+ domain. Establishing the servers in physically separate locations
+ and on different PSNs is strongly recommended. A description of the
+ server machine and its backup, including
+
+
+
+
+
+
+
+
+
+
+
+
+
+Stahl [Page 11]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ (a) Hardware and software (using keywords from the Assigned
+ Numbers RFC).
+
+ (b) Host domain name and network addresses (which host on which
+ network for each connected network).
+
+ (c) Any domain-style nicknames (please limit your domain-style
+ nickname request to one)
+
+ For example:
+
+ - Hardware and software
+
+ VAX-11/750 and UNIX, or
+ IBM-PC and MS-DOS, or
+ DEC-1090 and TOPS-20
+
+ - Host domain names and network addresses
+
+ BAR.FOO.COM 10.9.0.193 on ARPANET
+
+ - Domain-style nickname
+
+ BR.FOO.COM (same as BAR.FOO.COM 10.9.0.13 on ARPANET)
+
+ (7) Planned mapping of names of any other network hosts, other than
+ the server machines, into the new domain's naming space.
+
+ For example:
+
+ BAR-FOO2.ARPA (10.8.0.193) -> FOO2.BAR.COM
+ BAR-FOO3.ARPA (10.7.0.193) -> FOO3.BAR.COM
+ BAR-FOO4.ARPA (10.6.0.193) -> FOO4.BAR.COM
+
+
+ (8) An estimate of the number of hosts that will be in the domain.
+
+ (a) Initially
+ (b) Within one year
+ (c) Two years
+ (d) Five years.
+
+ For example:
+
+ (a) Initially = 50
+ (b) One year = 100
+ (c) Two years = 200
+ (d) Five years = 500
+
+
+
+Stahl [Page 12]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ (9) The date you expect the fully qualified domain name to become
+ the official host name in HOSTS.TXT.
+
+ Please note: If changing to a fully qualified domain name (e.g.,
+ FOO.BAR.COM) causes a change in the official host name of an
+ ARPANET or MILNET host, DCA approval must be obtained beforehand.
+ Allow 10 working days for your requested changes to be processed.
+
+ ARPANET sites should contact ARPANETMGR@DDN1.ARPA. MILNET sites
+ should contact HOSTMASTER@SRI-NIC.ARPA, 800-235-3155, for
+ further instructions.
+
+ (10) Please describe your organization briefly.
+
+ For example: The NetWorthy Corporation is a consulting
+ organization of people working with UNIX and the C language in an
+ electronic networking environment. It sponsors two technical
+ conferences annually and distributes a bimonthly newsletter.
+
+ ---------------------------------------------------------------------
+
+ This example of a completed application corresponds to the examples
+ found in the companion document RFC-1033, "Domain Administrators
+ Operations Guide."
+
+ (1) The name of the top-level domain to join.
+
+ COM
+
+ (2) The NIC handle of the administrative contact person.
+
+ NIC Handle JAKE
+
+ (3) The NIC handle of the domain's technical and zone
+ contact person.
+
+ NIC Handle DLE6
+
+ (4) The name of the domain.
+
+ SRI
+
+ (5) A description of the servers.
+
+ Our server is the TOPS20 server JEEVES supplied by ISI; it
+ will be installed and made operational on 1 July 1987.
+
+
+
+
+
+Stahl [Page 13]
+
+RFC 1032 DOMAIN ADMINISTRATORS GUIDE November 1987
+
+
+ (6) A description of the server machine and its backup:
+
+ (a) Hardware and software
+
+ DEC-1090T and TOPS20
+ DEC-2065 and TOPS20
+
+ (b) Host domain name and network address
+
+ KL.SRI.COM 10.1.0.2 on ARPANET, 128.18.10.6 on SRINET
+ STRIPE.SRI.COM 10.4.0.2 on ARPANET, 128.18.10.4 on SRINET
+
+ (c) Domain-style nickname
+
+ None
+
+ (7) Planned mapping of names of any other network hosts, other than
+ the server machines, into the new domain's naming space.
+
+ SRI-Blackjack.ARPA (128.18.2.1) -> Blackjack.SRI.COM
+ SRI-CSL.ARPA (192.12.33.2) -> CSL.SRI.COM
+
+ (8) An estimate of the number of hosts that will be directly within
+ this domain.
+
+ (a) Initially = 50
+ (b) One year = 100
+ (c) Two years = 200
+ (d) Five years = 500
+
+ (9) A date when you expect the fully qualified domain name to become
+ the official host name in HOSTS.TXT.
+
+ 31 September 1987
+
+ (10) Brief description of organization.
+
+ SRI International is an independent, nonprofit, scientific
+ research organization. It performs basic and applied research
+ for government and commercial clients, and contributes to
+ worldwide economic, scientific, industrial, and social progress
+ through research and related services.
+
+
+
+
+
+
+
+
+
+Stahl [Page 14]
+
diff --git a/usr.sbin/named/doc/rfc1033.lpr b/usr.sbin/named/doc/rfc1033.lpr
new file mode 100644
index 00000000000..7db4bee839b
--- /dev/null
+++ b/usr.sbin/named/doc/rfc1033.lpr
@@ -0,0 +1,1229 @@
+Network Working Group M. Lottor
+Request For Comments: 1033 SRI International
+ November 1987
+
+
+ DOMAIN ADMINISTRATORS OPERATIONS GUIDE
+
+
+
+STATUS OF THIS MEMO
+
+ This RFC provides guidelines for domain administrators in operating a
+ domain server and maintaining their portion of the hierarchical
+ database. Familiarity with the domain system is assumed.
+ Distribution of this memo is unlimited.
+
+ACKNOWLEDGMENTS
+
+ This memo is a formatted collection of notes and excerpts from the
+ references listed at the end of this document. Of particular mention
+ are Paul Mockapetris and Kevin Dunlap.
+
+INTRODUCTION
+
+ A domain server requires a few files to get started. It will
+ normally have some number of boot/startup files (also known as the
+ "safety belt" files). One section will contain a list of possible
+ root servers that the server will use to find the up-to-date list of
+ root servers. Another section will list the zone files to be loaded
+ into the server for your local domain information. A zone file
+ typically contains all the data for a particular domain. This guide
+ describes the data formats that can be used in zone files and
+ suggested parameters to use for certain fields. If you are
+ attempting to do anything advanced or tricky, consult the appropriate
+ domain RFC's for more details.
+
+ Note: Each implementation of domain software may require different
+ files. Zone files are standardized but some servers may require
+ other startup files. See the appropriate documentation that comes
+ with your software. See the appendix for some specific examples.
+
+ZONES
+
+ A zone defines the contents of a contiguous section of the domain
+ space, usually bounded by administrative boundaries. There will
+ typically be a separate data file for each zone. The data contained
+ in a zone file is composed of entries called Resource Records (RRs).
+
+
+
+
+Lottor [Page 1]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ You may only put data in your domain server that you are
+ authoritative for. You must not add entries for domains other than
+ your own (except for the special case of "glue records").
+
+ A domain server will probably read a file on start-up that lists the
+ zones it should load into its database. The format of this file is
+ not standardized and is different for most domain server
+ implementations. For each zone it will normally contain the domain
+ name of the zone and the file name that contains the data to load for
+ the zone.
+
+ROOT SERVERS
+
+ A resolver will need to find the root servers when it first starts.
+ When the resolver boots, it will typically read a list of possible
+ root servers from a file.
+
+ The resolver will cycle through the list trying to contact each one.
+ When it finds a root server, it will ask it for the current list of
+ root servers. It will then discard the list of root servers it read
+ from the data file and replace it with the current list it received.
+
+ Root servers will not change very often. You can get the names of
+ current root servers from the NIC.
+
+ FTP the file NETINFO:ROOT-SERVERS.TXT or send a mail request to
+ NIC@SRI-NIC.ARPA.
+
+ As of this date (June 1987) they are:
+
+ SRI-NIC.ARPA 10.0.0.51 26.0.0.73
+ C.ISI.EDU 10.0.0.52
+ BRL-AOS.ARPA 192.5.25.82 192.5.22.82 128.20.1.2
+ A.ISI.EDU 26.3.0.103
+
+RESOURCE RECORDS
+
+ Records in the zone data files are called resource records (RRs).
+ They are specified in RFC-883 and RFC-973. An RR has a standard
+ format as shown:
+
+ <name> [<ttl>] [<class>] <type> <data>
+
+ The record is divided into fields which are separated by white space.
+
+ <name>
+
+ The name field defines what domain name applies to the given
+
+
+
+Lottor [Page 2]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ RR. In some cases the name field can be left blank and it will
+ default to the name field of the previous RR.
+
+ <ttl>
+
+ TTL stands for Time To Live. It specifies how long a domain
+ resolver should cache the RR before it throws it out and asks a
+ domain server again. See the section on TTL's. If you leave
+ the TTL field blank it will default to the minimum time
+ specified in the SOA record (described later).
+
+ <class>
+
+ The class field specifies the protocol group. If left blank it
+ will default to the last class specified.
+
+ <type>
+
+ The type field specifies what type of data is in the RR. See
+ the section on types.
+
+ <data>
+
+ The data field is defined differently for each type and class
+ of data. Popular RR data formats are described later.
+
+ The domain system does not guarantee to preserve the order of
+ resource records. Listing RRs (such as multiple address records) in
+ a certain order does not guarantee they will be used in that order.
+
+ Case is preserved in names and data fields when loaded into the name
+ server. All comparisons and lookups in the name server are case
+ insensitive.
+
+ Parenthesis ("(",")") are used to group data that crosses a line
+ boundary.
+
+ A semicolon (";") starts a comment; the remainder of the line is
+ ignored.
+
+ The asterisk ("*") is used for wildcarding.
+
+ The at-sign ("@") denotes the current default domain name.
+
+
+
+
+
+
+
+
+Lottor [Page 3]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+NAMES
+
+ A domain name is a sequence of labels separated by dots.
+
+ Domain names in the zone files can be one of two types, either
+ absolute or relative. An absolute name is the fully qualified domain
+ name and is terminated with a period. A relative name does not
+ terminate with a period, and the current default domain is appended
+ to it. The default domain is usually the name of the domain that was
+ specified in the boot file that loads each zone.
+
+ The domain system allows a label to contain any 8-bit character.
+ Although the domain system has no restrictions, other protocols such
+ as SMTP do have name restrictions. Because of other protocol
+ restrictions, only the following characters are recommended for use
+ in a host name (besides the dot separator):
+
+ "A-Z", "a-z", "0-9", dash and underscore
+
+TTL's (Time To Live)
+
+ It is important that TTLs are set to appropriate values. The TTL is
+ the time (in seconds) that a resolver will use the data it got from
+ your server before it asks your server again. If you set the value
+ too low, your server will get loaded down with lots of repeat
+ requests. If you set it too high, then information you change will
+ not get distributed in a reasonable amount of time. If you leave the
+ TTL field blank, it will default to what is specified in the SOA
+ record for the zone.
+
+ Most host information does not change much over long time periods. A
+ good way to set up your TTLs would be to set them at a high value,
+ and then lower the value if you know a change will be coming soon.
+ You might set most TTLs to anywhere between a day (86400) and a week
+ (604800). Then, if you know some data will be changing in the near
+ future, set the TTL for that RR down to a lower value (an hour to a
+ day) until the change takes place, and then put it back up to its
+ previous value.
+
+ Also, all RRs with the same name, class, and type should have the
+ same TTL value.
+
+CLASSES
+
+ The domain system was designed to be protocol independent. The class
+ field is used to identify the protocol group that each RR is in.
+
+ The class of interest to people using TCP/IP software is the class
+
+
+
+Lottor [Page 4]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ "Internet". Its standard designation is "IN".
+
+ A zone file should only contain RRs of the same class.
+
+TYPES
+
+ There are many defined RR types. For a complete list, see the domain
+ specification RFCs. Here is a list of current commonly used types.
+ The data for each type is described in the data section.
+
+ Designation Description
+ ==========================================
+ SOA Start Of Authority
+ NS Name Server
+
+ A Internet Address
+ CNAME Canonical Name (nickname pointer)
+ HINFO Host Information
+ WKS Well Known Services
+
+ MX Mail Exchanger
+
+ PTR Pointer
+
+SOA (Start Of Authority)
+
+ <name> [<ttl>] [<class>] SOA <origin> <person> (
+ <serial>
+ <refresh>
+ <retry>
+ <expire>
+ <minimum> )
+
+ The Start Of Authority record designates the start of a zone. The
+ zone ends at the next SOA record.
+
+ <name> is the name of the zone.
+
+ <origin> is the name of the host on which the master zone file
+ resides.
+
+ <person> is a mailbox for the person responsible for the zone. It is
+ formatted like a mailing address but the at-sign that normally
+ separates the user from the host name is replaced with a dot.
+
+ <serial> is the version number of the zone file. It should be
+ incremented anytime a change is made to data in the zone.
+
+
+
+
+Lottor [Page 5]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ <refresh> is how long, in seconds, a secondary name server is to
+ check with the primary name server to see if an update is needed. A
+ good value here would be one hour (3600).
+
+ <retry> is how long, in seconds, a secondary name server is to retry
+ after a failure to check for a refresh. A good value here would be
+ 10 minutes (600).
+
+ <expire> is the upper limit, in seconds, that a secondary name server
+ is to use the data before it expires for lack of getting a refresh.
+ You want this to be rather large, and a nice value is 3600000, about
+ 42 days.
+
+ <minimum> is the minimum number of seconds to be used for TTL values
+ in RRs. A minimum of at least a day is a good value here (86400).
+
+ There should only be one SOA record per zone. A sample SOA record
+ would look something like:
+
+ @ IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+ 45 ;serial
+ 3600 ;refresh
+ 600 ;retry
+ 3600000 ;expire
+ 86400 ) ;minimum
+
+
+NS (Name Server)
+
+ <domain> [<ttl>] [<class>] NS <server>
+
+ The NS record lists the name of a machine that provides domain
+ service for a particular domain. The name associated with the RR is
+ the domain name and the data portion is the name of a host that
+ provides the service. If machines SRI-NIC.ARPA and C.ISI.EDU provide
+ name lookup service for the domain COM then the following entries
+ would be used:
+
+ COM. NS SRI-NIC.ARPA.
+ NS C.ISI.EDU.
+
+ Note that the machines providing name service do not have to live in
+ the named domain. There should be one NS record for each server for
+ a domain. Also note that the name "COM" defaults for the second NS
+ record.
+
+ NS records for a domain exist in both the zone that delegates the
+ domain, and in the domain itself.
+
+
+
+Lottor [Page 6]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+GLUE RECORDS
+
+ If the name server host for a particular domain is itself inside the
+ domain, then a 'glue' record will be needed. A glue record is an A
+ (address) RR that specifies the address of the server. Glue records
+ are only needed in the server delegating the domain, not in the
+ domain itself. If for example the name server for domain SRI.COM was
+ KL.SRI.COM, then the NS record would look like this, but you will
+ also need to have the following A record.
+
+ SRI.COM. NS
+ KL.SRI.COM. KL.SRI.COM. A 10.1.0.2.
+
+
+A (Address)
+
+ <host> [<ttl>] [<class>] A <address>
+
+ The data for an A record is an internet address in dotted decimal
+ form. A sample A record might look like:
+
+ SRI-NIC.ARPA. A 10.0.0.51
+
+ There should be one A record for each address of a host.
+
+CNAME ( Canonical Name)
+
+ <nickname> [<ttl>] [<class>] CNAME <host>
+
+ The CNAME record is used for nicknames. The name associated with the
+ RR is the nickname. The data portion is the official name. For
+ example, a machine named SRI-NIC.ARPA may want to have the nickname
+ NIC.ARPA. In that case, the following RR would be used:
+
+ NIC.ARPA. CNAME SRI-NIC.ARPA.
+
+ There must not be any other RRs associated with a nickname of the
+ same class.
+
+ Nicknames are also useful when a host changes it's name. In that
+ case, it is usually a good idea to have a CNAME pointer so that
+ people still using the old name will get to the right place.
+
+
+
+
+
+
+
+
+
+Lottor [Page 7]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+HINFO (Host Info)
+
+ <host> [<ttl>] [<class>] HINFO <hardware> <software>
+
+ The HINFO record gives information about a particular host. The data
+ is two strings separated by whitespace. The first string is a
+ hardware description and the second is software. The hardware is
+ usually a manufacturer name followed by a dash and model designation.
+ The software string is usually the name of the operating system.
+
+ Official HINFO types can be found in the latest Assigned Numbers RFC,
+ the latest of which is RFC-1010. The Hardware type is called the
+ Machine name and the Software type is called the System name.
+
+ Some sample HINFO records:
+
+ SRI-NIC.ARPA. HINFO DEC-2060 TOPS20
+ UCBARPA.Berkeley.EDU. HINFO VAX-11/780 UNIX
+
+
+WKS (Well Known Services)
+
+ <host> [<ttl>] [<class>] WKS <address> <protocol> <services>
+
+ The WKS record is used to list Well Known Services a host provides.
+ WKS's are defined to be services on port numbers below 256. The WKS
+ record lists what services are available at a certain address using a
+ certain protocol. The common protocols are TCP or UDP. A sample WKS
+ record for a host offering the same services on all address would
+ look like:
+
+ Official protocol names can be found in the latest Assigned Numbers
+ RFC, the latest of which is RFC-1010.
+
+ SRI-NIC.ARPA. WKS 10.0.0.51 TCP TELNET FTP SMTP
+ WKS 10.0.0.51 UDP TIME
+ WKS 26.0.0.73 TCP TELNET FTP SMTP
+ WKS 26.0.0.73 UDP TIME
+
+MX (Mail Exchanger) (See RFC-974 for more details.)
+
+ <name> [<ttl>] [<class>] MX <preference> <host>
+
+ MX records specify where mail for a domain name should be delivered.
+ There may be multiple MX records for a particular name. The
+ preference value specifies the order a mailer should try multiple MX
+ records when delivering mail. Zero is the highest preference.
+ Multiple records for the same name may have the same preference.
+
+
+
+Lottor [Page 8]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ A host BAR.FOO.COM may want its mail to be delivered to the host
+ PO.FOO.COM and would then use the MX record:
+
+ BAR.FOO.COM. MX 10 PO.FOO.COM.
+
+ A host BAZ.FOO.COM may want its mail to be delivered to one of three
+ different machines, in the following order:
+
+ BAZ.FOO.COM. MX 10 PO1.FOO.COM.
+ MX 20 PO2.FOO.COM.
+ MX 30 PO3.FOO.COM.
+
+ An entire domain of hosts not connected to the Internet may want
+ their mail to go through a mail gateway that knows how to deliver
+ mail to them. If they would like mail addressed to any host in the
+ domain FOO.COM to go through the mail gateway they might use:
+
+ FOO.COM. MX 10 RELAY.CS.NET.
+ *.FOO.COM. MX 20 RELAY.CS.NET.
+
+ Note that you can specify a wildcard in the MX record to match on
+ anything in FOO.COM, but that it won't match a plain FOO.COM.
+
+IN-ADDR.ARPA
+
+ The structure of names in the domain system is set up in a
+ hierarchical way such that the address of a name can be found by
+ tracing down the domain tree contacting a server for each label of
+ the name. Because of this 'indexing' based on name, there is no easy
+ way to translate a host address back into its host name.
+
+ In order to do the reverse translation easily, a domain was created
+ that uses hosts' addresses as part of a name that then points to the
+ data for that host. In this way, there is now an 'index' to hosts'
+ RRs based on their address. This address mapping domain is called
+ IN-ADDR.ARPA. Within that domain are subdomains for each network,
+ based on network number. Also, for consistency and natural
+ groupings, the 4 octets of a host number are reversed.
+
+ For example, the ARPANET is net 10. That means there is a domain
+ called 10.IN-ADDR.ARPA. Within this domain there is a PTR RR at
+ 51.0.0.10.IN-ADDR that points to the RRs for the host SRI-NIC.ARPA
+ (who's address is 10.0.0.51). Since the NIC is also on the MILNET
+ (Net 26, address 26.0.0.73), there is also a PTR RR at 73.0.0.26.IN-
+ ADDR.ARPA that points to the same RR's for SRI-NIC.ARPA. The format
+ of these special pointers is defined below along with the examples
+ for the NIC.
+
+
+
+
+Lottor [Page 9]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+PTR
+
+ <special-name> [<ttl>] [<class>] PTR <name>
+
+ The PTR record is used to let special names point to some other
+ location in the domain tree. They are mainly used in the IN-
+ ADDR.ARPA records for translation of addresses to names. PTR's
+ should use official names and not aliases.
+
+ For example, host SRI-NIC.ARPA with addresses 10.0.0.51 and 26.0.0.73
+ would have the following records in the respective zone files for net
+ 10 and net 26:
+
+ 51.0.0.10.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+ 73.0.0.26.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+
+GATEWAY PTR's
+
+ The IN-ADDR tree is also used to locate gateways on a particular
+ network. Gateways have the same kind of PTR RRs as hosts (as above)
+ but in addition they have other PTRs used to locate them by network
+ number alone. These records have only 1, 2, or 3 octets as part of
+ the name depending on whether they are class A, B, or C networks,
+ respectively.
+
+ Lets take the SRI-CSL gateway for example. It connects 3 different
+ networks, one class A, one class B and one class C. It will have the
+ standard RR's for a host in the CSL.SRI.COM zone:
+
+ GW.CSL.SRI.COM. A 10.2.0.2
+ A 128.18.1.1
+ A 192.12.33.2
+
+ Also, in 3 different zones (one for each network), it will have one
+ of the following number to name translation pointers:
+
+ 2.0.2.10.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+ 1.1.18.128.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+ 1.33.12.192.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+
+ In addition, in each of the same 3 zones will be one of the following
+ gateway location pointers:
+
+ 10.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+ 18.128.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+ 33.12.192.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+
+
+
+
+
+Lottor [Page 10]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+INSTRUCTIONS
+
+ Adding a subdomain.
+
+ To add a new subdomain to your domain:
+
+ Setup the other domain server and/or the new zone file.
+
+ Add an NS record for each server of the new domain to the zone
+ file of the parent domain.
+
+ Add any necessary glue RRs.
+
+ Adding a host.
+
+ To add a new host to your zone files:
+
+ Edit the appropriate zone file for the domain the host is in.
+
+ Add an entry for each address of the host.
+
+ Optionally add CNAME, HINFO, WKS, and MX records.
+
+ Add the reverse IN-ADDR entry for each host address in the
+ appropriate zone files for each network the host in on.
+
+ Deleting a host.
+
+ To delete a host from the zone files:
+
+ Remove all the hosts' resource records from the zone file of
+ the domain the host is in.
+
+ Remove all the hosts' PTR records from the IN-ADDR zone files
+ for each network the host was on.
+
+ Adding gateways.
+
+ Follow instructions for adding a host.
+
+ Add the gateway location PTR records for each network the
+ gateway is on.
+
+ Deleting gateways.
+
+ Follow instructions for deleting a host.
+
+ Also delete the gateway location PTR records for each network
+
+
+
+Lottor [Page 11]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ the gateway was on.
+
+COMPLAINTS
+
+ These are the suggested steps you should take if you are having
+ problems that you believe are caused by someone else's name server:
+
+
+ 1. Complain privately to the responsible person for the domain. You
+ can find their mailing address in the SOA record for the domain.
+
+ 2. Complain publicly to the responsible person for the domain.
+
+ 3. Ask the NIC for the administrative person responsible for the
+ domain. Complain. You can also find domain contacts on the NIC in
+ the file NETINFO:DOMAIN-CONTACTS.TXT
+
+ 4. Complain to the parent domain authorities.
+
+ 5. Ask the parent authorities to excommunicate the domain.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 12]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+EXAMPLE DOMAIN SERVER DATABASE FILES
+
+ The following examples show how zone files are set up for a typical
+ organization. SRI will be used as the example organization. SRI has
+ decided to divided their domain SRI.COM into a few subdomains, one
+ for each group that wants one. The subdomains are CSL and ISTC.
+
+ Note the following interesting items:
+
+ There are both hosts and domains under SRI.COM.
+
+ CSL.SRI.COM is both a domain name and a host name.
+
+ All the domains are serviced by the same pair of domain servers.
+
+ All hosts at SRI are on net 128.18 except hosts in the CSL domain
+ which are on net 192.12.33. Note that a domain does not have to
+ correspond to a physical network.
+
+ The examples do not necessarily correspond to actual data in use
+ by the SRI domain.
+
+ SRI Domain Organization
+
+ +-------+
+ | COM |
+ +-------+
+ |
+ +-------+
+ | SRI |
+ +-------+
+ |
+ +----------++-----------+
+ | | |
+ +-------+ +------+ +-------+
+ | CSL | | ISTC | | Hosts |
+ +-------+ +------+ +-------+
+ | |
+ +-------+ +-------+
+ | Hosts | | Hosts |
+ +-------+ +-------+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 13]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "CONFIG.CMD". Since bootstrap files are not standardized, this
+ file is presented using a pseudo configuration file syntax.]
+
+ load root server list from file ROOT.SERVERS
+ load zone SRI.COM. from file SRI.ZONE
+ load zone CSL.SRI.COM. from file CSL.ZONE
+ load zone ISTC.SRI.COM. from file ISTC.ZONE
+ load zone 18.128.IN-ADDR.ARPA. from file SRINET.ZONE
+ load zone 33.12.192.IN-ADDR.ARPA. from file SRI-CSL-NET.ZONE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 14]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "ROOT.SERVERS". Again, the format of this file is not
+ standardized.]
+
+ ;list of possible root servers
+ SRI-NIC.ARPA 10.0.0.51 26.0.0.73
+ C.ISI.EDU 10.0.0.52
+ BRL-AOS.ARPA 192.5.25.82 192.5.22.82 128.20.1.2
+ A.ISI.EDU 26.3.0.103
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 15]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "SRI.ZONE"]
+
+ SRI.COM. IN SOA KL.SRI.COM. DLE.STRIPE.SRI.COM. (
+ 870407 ;serial
+ 1800 ;refresh every 30 minutes
+ 600 ;retry every 10 minutes
+ 604800 ;expire after a week
+ 86400 ;default of an hour
+ )
+
+ SRI.COM. NS KL.SRI.COM.
+ NS STRIPE.SRI.COM.
+ MX 10 KL.SRI.COM.
+
+ ;SRI.COM hosts
+
+ KL A 10.1.0.2
+ A 128.18.10.6
+ MX 10 KL.SRI.COM.
+
+ STRIPE A 10.4.0.2
+ STRIPE A 128.18.10.4
+ MX 10 STRIPE.SRI.COM.
+
+ NIC CNAME SRI-NIC.ARPA.
+
+ Blackjack A 128.18.2.1
+ HINFO VAX-11/780 UNIX
+ WKS 128.18.2.1 TCP TELNET FTP
+
+ CSL A 192.12.33.2
+ HINFO FOONLY-F4 TOPS20
+ WKS 192.12.33.2 TCP TELNET FTP SMTP FINGER
+ MX 10 CSL.SRI.COM.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 16]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "CSL.ZONE"]
+
+ CSL.SRI.COM. IN SOA KL.SRI.COM. DLE.STRIPE.SRI.COM. (
+ 870330 ;serial
+ 1800 ;refresh every 30 minutes
+ 600 ;retry every 10 minutes
+ 604800 ;expire after a week
+ 86400 ;default of a day
+ )
+
+ CSL.SRI.COM. NS KL.SRI.COM.
+ NS STRIPE.SRI.COM.
+ A 192.12.33.2
+
+ ;CSL.SRI.COM hosts
+
+ A CNAME CSL.SRI.COM.
+ B A 192.12.33.3
+ HINFO FOONLY-F4 TOPS20
+ WKS 192.12.33.3 TCP TELNET FTP SMTP
+ GW A 10.2.0.2
+ A 192.12.33.1
+ A 128.18.1.1
+ HINFO PDP-11/23 MOS
+ SMELLY A 192.12.33.4
+ HINFO IMAGEN IMAGEN
+ SQUIRREL A 192.12.33.5
+ HINFO XEROX-1100 INTERLISP
+ VENUS A 192.12.33.7
+ HINFO SYMBOLICS-3600 LISPM
+ HELIUM A 192.12.33.30
+ HINFO SUN-3/160 UNIX
+ ARGON A 192.12.33.31
+ HINFO SUN-3/75 UNIX
+ RADON A 192.12.33.32
+ HINFO SUN-3/75 UNIX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 17]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "ISTC.ZONE"]
+
+ ISTC.SRI.COM. IN SOA KL.SRI.COM. roemers.JOYCE.ISTC.SRI.COM. (
+ 870406 ;serial
+ 1800 ;refresh every 30 minutes
+ 600 ;retry every 10 minutes
+ 604800 ;expire after a week
+ 86400 ;default of a day
+ )
+
+ ISTC.SRI.COM. NS KL.SRI.COM.
+ NS STRIPE.SRI.COM.
+ MX 10 SPAM.ISTC.SRI.COM.
+
+ ; ISTC hosts
+
+ joyce A 128.18.4.2
+ HINFO VAX-11/750 UNIX
+ bozo A 128.18.0.6
+ HINFO SUN UNIX
+ sundae A 128.18.0.11
+ HINFO SUN UNIX
+ tsca A 128.18.0.201
+ A 10.3.0.2
+ HINFO VAX-11/750 UNIX
+ MX 10 TSCA.ISTC.SRI.COM.
+ tsc CNAME tsca
+ prmh A 128.18.0.203
+ A 10.2.0.51
+ HINFO PDP-11/44 UNIX
+ spam A 128.18.4.3
+ A 10.2.0.107
+ HINFO VAX-11/780 UNIX
+ MX 10 SPAM.ISTC.SRI.COM.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 18]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "SRINET.ZONE"]
+
+ 18.128.IN-ADDR.ARPA. IN SOA KL.SRI.COM DLE.STRIPE.SRI.COM. (
+ 870406 ;serial
+ 1800 ;refresh every 30 minutes
+ 600 ;retry every 10 minutes
+ 604800 ;expire after a week
+ 86400 ;default of a day
+ )
+
+ 18.128.IN-ADDR.ARPA. NS KL.SRI.COM.
+ NS STRIPE.SRI.COM.
+ PTR GW.CSL.SRI.COM.
+
+ ; SRINET [128.18.0.0] Address Translations
+
+ ; SRI.COM Hosts
+ 1.2.18.128.IN-ADDR.ARPA. PTR Blackjack.SRI.COM.
+
+ ; ISTC.SRI.COM Hosts
+ 2.4.18.128.IN-ADDR.ARPA. PTR joyce.ISTC.SRI.COM.
+ 6.0.18.128.IN-ADDR.ARPA. PTR bozo.ISTC.SRI.COM.
+ 11.0.18.128.IN-ADDR.ARPA. PTR sundae.ISTC.SRI.COM.
+ 201.0.18.128.IN-ADDR.ARPA. PTR tsca.ISTC.SRI.COM.
+ 203.0.18.128.IN-ADDR.ARPA. PTR prmh.ISTC.SRI.COM.
+ 3.4.18.128.IN-ADDR.ARPA. PTR spam.ISTC.SRI.COM.
+
+ ; CSL.SRI.COM Hosts
+ 1.1.18.128.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 19]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+ [File "SRI-CSL-NET.ZONE"]
+
+ 33.12.192.IN-ADDR.ARPA. IN SOA KL.SRI.COM DLE.STRIPE.SRI.COM. (
+ 870404 ;serial
+ 1800 ;refresh every 30 minutes
+ 600 ;retry every 10 minutes
+ 604800 ;expire after a week
+ 86400 ;default of a day
+ )
+
+ 33.12.192.IN-ADDR.ARPA. NS KL.SRI.COM.
+ NS STRIPE.SRI.COM.
+ PTR GW.CSL.SRI.COM.
+
+ ; SRI-CSL-NET [192.12.33.0] Address Translations
+
+ ; SRI.COM Hosts
+ 2.33.12.192.IN-ADDR.ARPA. PTR CSL.SRI.COM.
+
+ ; CSL.SRI.COM Hosts
+ 1.33.12.192.IN-ADDR.ARPA. PTR GW.CSL.SRI.COM.
+ 3.33.12.192.IN-ADDR.ARPA. PTR B.CSL.SRI.COM.
+ 4.33.12.192.IN-ADDR.ARPA. PTR SMELLY.CSL.SRI.COM.
+ 5.33.12.192.IN-ADDR.ARPA. PTR SQUIRREL.CSL.SRI.COM.
+ 7.33.12.192.IN-ADDR.ARPA. PTR VENUS.CSL.SRI.COM.
+ 30.33.12.192.IN-ADDR.ARPA. PTR HELIUM.CSL.SRI.COM.
+ 31.33.12.192.IN-ADDR.ARPA. PTR ARGON.CSL.SRI.COM.
+ 32.33.12.192.IN-ADDR.ARPA. PTR RADON.CSL.SRI.COM.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 20]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+APPENDIX
+
+ BIND (Berkeley Internet Name Domain server) distributed with 4.3 BSD
+ UNIX
+
+ This section describes two BIND implementation specific files; the
+ boot file and the cache file. BIND has other options, files, and
+ specifications that are not described here. See the Name Server
+ Operations Guide for BIND for details.
+
+ The boot file for BIND is usually called "named.boot". This
+ corresponds to file "CONFIG.CMD" in the example section.
+
+ --------------------------------------------------------
+ cache . named.ca
+ primary SRI.COM SRI.ZONE
+ primary CSL.SRI.COM CSL.ZONE
+ primary ISTC.SRI.COM ISTC.ZONE
+ primary 18.128.IN-ADDR.ARPA SRINET.ZONE
+ primary 33.12.192.IN-ADDR.ARPA SRI-CSL-NET.ZONE
+ --------------------------------------------------------
+
+ The cache file for BIND is usually called "named.ca". This
+ corresponds to file "ROOT.SERVERS" in the example section.
+
+ -------------------------------------------------
+ ;list of possible root servers
+ . 1 IN NS SRI-NIC.ARPA.
+ NS C.ISI.EDU.
+ NS BRL-AOS.ARPA.
+ NS C.ISI.EDU.
+ ;and their addresses
+ SRI-NIC.ARPA. A 10.0.0.51
+ A 26.0.0.73
+ C.ISI.EDU. A 10.0.0.52
+ BRL-AOS.ARPA. A 192.5.25.82
+ A 192.5.22.82
+ A 128.20.1.2
+ A.ISI.EDU. A 26.3.0.103
+ -------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 21]
+
+RFC 1033 DOMAIN OPERATIONS GUIDE November 1987
+
+
+REFERENCES
+
+ [1] Dunlap, K., "Name Server Operations Guide for BIND", CSRG,
+ Department of Electrical Engineering and Computer Sciences,
+ University of California, Berkeley, California.
+
+ [2] Partridge, C., "Mail Routing and the Domain System", RFC-974,
+ CSNET CIC BBN Laboratories, January 1986.
+
+ [3] Mockapetris, P., "Domains Names - Concepts and Facilities",
+ RFC-1034, USC/Information Sciences Institute, November 1987.
+
+ [4] Mockapetris, P., "Domain Names - Implementations Specification",
+ RFC-1035, USC/Information Sciences Institute, November 1987.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lottor [Page 22]
+
diff --git a/usr.sbin/named/doc/rfc1034.lpr b/usr.sbin/named/doc/rfc1034.lpr
new file mode 100644
index 00000000000..55cdb21fe65
--- /dev/null
+++ b/usr.sbin/named/doc/rfc1034.lpr
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1034 ISI
+Obsoletes: RFCs 882, 883, 973 November 1987
+
+
+ DOMAIN NAMES - CONCEPTS AND FACILITIES
+
+
+
+1. STATUS OF THIS MEMO
+
+This RFC is an introduction to the Domain Name System (DNS), and omits
+many details which can be found in a companion RFC, "Domain Names -
+Implementation and Specification" [RFC-1035]. That RFC assumes that the
+reader is familiar with the concepts discussed in this memo.
+
+A subset of DNS functions and data types constitute an official
+protocol. The official protocol includes standard queries and their
+responses and most of the Internet class data formats (e.g., host
+addresses).
+
+However, the domain system is intentionally extensible. Researchers are
+continuously proposing, implementing and experimenting with new data
+types, query types, classes, functions, etc. Thus while the components
+of the official protocol are expected to stay essentially unchanged and
+operate as a production service, experimental behavior should always be
+expected in extensions beyond the official protocol. Experimental or
+obsolete features are clearly marked in these RFCs, and such information
+should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+2. INTRODUCTION
+
+This RFC introduces domain style names, their use for Internet mail and
+host address support, and the protocols and servers used to implement
+domain name facilities.
+
+2.1. The history of domain names
+
+The impetus for the development of the domain system was growth in the
+Internet:
+
+ - Host name to address mappings were maintained by the Network
+ Information Center (NIC) in a single file (HOSTS.TXT) which
+ was FTPed by all hosts [RFC-952, RFC-953]. The total network
+
+
+
+Mockapetris [Page 1]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ bandwidth consumed in distributing a new version by this
+ scheme is proportional to the square of the number of hosts in
+ the network, and even when multiple levels of FTP are used,
+ the outgoing FTP load on the NIC host is considerable.
+ Explosive growth in the number of hosts didn't bode well for
+ the future.
+
+ - The network population was also changing in character. The
+ timeshared hosts that made up the original ARPANET were being
+ replaced with local networks of workstations. Local
+ organizations were administering their own names and
+ addresses, but had to wait for the NIC to change HOSTS.TXT to
+ make changes visible to the Internet at large. Organizations
+ also wanted some local structure on the name space.
+
+ - The applications on the Internet were getting more
+ sophisticated and creating a need for general purpose name
+ service.
+
+
+The result was several ideas about name spaces and their management
+[IEN-116, RFC-799, RFC-819, RFC-830]. The proposals varied, but a
+common thread was the idea of a hierarchical name space, with the
+hierarchy roughly corresponding to organizational structure, and names
+using "." as the character to mark the boundary between hierarchy
+levels. A design using a distributed database and generalized resources
+was described in [RFC-882, RFC-883]. Based on experience with several
+implementations, the system evolved into the scheme described in this
+memo.
+
+The terms "domain" or "domain name" are used in many contexts beyond the
+DNS described here. Very often, the term domain name is used to refer
+to a name with structure indicated by dots, but no relation to the DNS.
+This is particularly true in mail addressing [Quarterman 86].
+
+2.2. DNS design goals
+
+The design goals of the DNS influence its structure. They are:
+
+ - The primary goal is a consistent name space which will be used
+ for referring to resources. In order to avoid the problems
+ caused by ad hoc encodings, names should not be required to
+ contain network identifiers, addresses, routes, or similar
+ information as part of the name.
+
+ - The sheer size of the database and frequency of updates
+ suggest that it must be maintained in a distributed manner,
+ with local caching to improve performance. Approaches that
+
+
+
+Mockapetris [Page 2]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ attempt to collect a consistent copy of the entire database
+ will become more and more expensive and difficult, and hence
+ should be avoided. The same principle holds for the structure
+ of the name space, and in particular mechanisms for creating
+ and deleting names; these should also be distributed.
+
+ - Where there tradeoffs between the cost of acquiring data, the
+ speed of updates, and the accuracy of caches, the source of
+ the data should control the tradeoff.
+
+ - The costs of implementing such a facility dictate that it be
+ generally useful, and not restricted to a single application.
+ We should be able to use names to retrieve host addresses,
+ mailbox data, and other as yet undetermined information. All
+ data associated with a name is tagged with a type, and queries
+ can be limited to a single type.
+
+ - Because we want the name space to be useful in dissimilar
+ networks and applications, we provide the ability to use the
+ same name space with different protocol families or
+ management. For example, host address formats differ between
+ protocols, though all protocols have the notion of address.
+ The DNS tags all data with a class as well as the type, so
+ that we can allow parallel use of different formats for data
+ of type address.
+
+ - We want name server transactions to be independent of the
+ communications system that carries them. Some systems may
+ wish to use datagrams for queries and responses, and only
+ establish virtual circuits for transactions that need the
+ reliability (e.g., database updates, long transactions); other
+ systems will use virtual circuits exclusively.
+
+ - The system should be useful across a wide spectrum of host
+ capabilities. Both personal computers and large timeshared
+ hosts should be able to use the system, though perhaps in
+ different ways.
+
+2.3. Assumptions about usage
+
+The organization of the domain system derives from some assumptions
+about the needs and usage patterns of its user community and is designed
+to avoid many of the the complicated problems found in general purpose
+database systems.
+
+The assumptions are:
+
+ - The size of the total database will initially be proportional
+
+
+
+Mockapetris [Page 3]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ to the number of hosts using the system, but will eventually
+ grow to be proportional to the number of users on those hosts
+ as mailboxes and other information are added to the domain
+ system.
+
+ - Most of the data in the system will change very slowly (e.g.,
+ mailbox bindings, host addresses), but that the system should
+ be able to deal with subsets that change more rapidly (on the
+ order of seconds or minutes).
+
+ - The administrative boundaries used to distribute
+ responsibility for the database will usually correspond to
+ organizations that have one or more hosts. Each organization
+ that has responsibility for a particular set of domains will
+ provide redundant name servers, either on the organization's
+ own hosts or other hosts that the organization arranges to
+ use.
+
+ - Clients of the domain system should be able to identify
+ trusted name servers they prefer to use before accepting
+ referrals to name servers outside of this "trusted" set.
+
+ - Access to information is more critical than instantaneous
+ updates or guarantees of consistency. Hence the update
+ process allows updates to percolate out through the users of
+ the domain system rather than guaranteeing that all copies are
+ simultaneously updated. When updates are unavailable due to
+ network or host failure, the usual course is to believe old
+ information while continuing efforts to update it. The
+ general model is that copies are distributed with timeouts for
+ refreshing. The distributor sets the timeout value and the
+ recipient of the distribution is responsible for performing
+ the refresh. In special situations, very short intervals can
+ be specified, or the owner can prohibit copies.
+
+ - In any system that has a distributed database, a particular
+ name server may be presented with a query that can only be
+ answered by some other server. The two general approaches to
+ dealing with this problem are "recursive", in which the first
+ server pursues the query for the client at another server, and
+ "iterative", in which the server refers the client to another
+ server and lets the client pursue the query. Both approaches
+ have advantages and disadvantages, but the iterative approach
+ is preferred for the datagram style of access. The domain
+ system requires implementation of the iterative approach, but
+ allows the recursive approach as an option.
+
+
+
+
+
+Mockapetris [Page 4]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The domain system assumes that all data originates in master files
+scattered through the hosts that use the domain system. These master
+files are updated by local system administrators. Master files are text
+files that are read by a local name server, and hence become available
+through the name servers to users of the domain system. The user
+programs access name servers through standard programs called resolvers.
+
+The standard format of master files allows them to be exchanged between
+hosts (via FTP, mail, or some other mechanism); this facility is useful
+when an organization wants a domain, but doesn't want to support a name
+server. The organization can maintain the master files locally using a
+text editor, transfer them to a foreign host which runs a name server,
+and then arrange with the system administrator of the name server to get
+the files loaded.
+
+Each host's name servers and resolvers are configured by a local system
+administrator [RFC-1033]. For a name server, this configuration data
+includes the identity of local master files and instructions on which
+non-local master files are to be loaded from foreign servers. The name
+server uses the master files or copies to load its zones. For
+resolvers, the configuration data identifies the name servers which
+should be the primary sources of information.
+
+The domain system defines procedures for accessing the data and for
+referrals to other name servers. The domain system also defines
+procedures for caching retrieved data and for periodic refreshing of
+data defined by the system administrator.
+
+The system administrators provide:
+
+ - The definition of zone boundaries.
+
+ - Master files of data.
+
+ - Updates to master files.
+
+ - Statements of the refresh policies desired.
+
+The domain system provides:
+
+ - Standard formats for resource data.
+
+ - Standard methods for querying the database.
+
+ - Standard methods for name servers to refresh local data from
+ foreign name servers.
+
+
+
+
+
+Mockapetris [Page 5]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+2.4. Elements of the DNS
+
+The DNS has three major components:
+
+ - The DOMAIN NAME SPACE and RESOURCE RECORDS, which are
+ specifications for a tree structured name space and data
+ associated with the names. Conceptually, each node and leaf
+ of the domain name space tree names a set of information, and
+ query operations are attempts to extract specific types of
+ information from a particular set. A query names the domain
+ name of interest and describes the type of resource
+ information that is desired. For example, the Internet
+ uses some of its domain names to identify hosts; queries for
+ address resources return Internet host addresses.
+
+ - NAME SERVERS are server programs which hold information about
+ the domain tree's structure and set information. A name
+ server may cache structure or set information about any part
+ of the domain tree, but in general a particular name server
+ has complete information about a subset of the domain space,
+ and pointers to other name servers that can be used to lead to
+ information from any part of the domain tree. Name servers
+ know the parts of the domain tree for which they have complete
+ information; a name server is said to be an AUTHORITY for
+ these parts of the name space. Authoritative information is
+ organized into units called ZONEs, and these zones can be
+ automatically distributed to the name servers which provide
+ redundant service for the data in a zone.
+
+ - RESOLVERS are programs that extract information from name
+ servers in response to client requests. Resolvers must be
+ able to access at least one name server and use that name
+ server's information to answer a query directly, or pursue the
+ query using referrals to other name servers. A resolver will
+ typically be a system routine that is directly accessible to
+ user programs; hence no protocol is necessary between the
+ resolver and the user program.
+
+These three components roughly correspond to the three layers or views
+of the domain system:
+
+ - From the user's point of view, the domain system is accessed
+ through a simple procedure or OS call to a local resolver.
+ The domain space consists of a single tree and the user can
+ request information from any section of the tree.
+
+ - From the resolver's point of view, the domain system is
+ composed of an unknown number of name servers. Each name
+
+
+
+Mockapetris [Page 6]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ server has one or more pieces of the whole domain tree's data,
+ but the resolver views each of these databases as essentially
+ static.
+
+ - From a name server's point of view, the domain system consists
+ of separate sets of local information called zones. The name
+ server has local copies of some of the zones. The name server
+ must periodically refresh its zones from master copies in
+ local files or foreign name servers. The name server must
+ concurrently process queries that arrive from resolvers.
+
+In the interests of performance, implementations may couple these
+functions. For example, a resolver on the same machine as a name server
+might share a database consisting of the the zones managed by the name
+server and the cache managed by the resolver.
+
+3. DOMAIN NAME SPACE and RESOURCE RECORDS
+
+3.1. Name space specifications and terminology
+
+The domain name space is a tree structure. Each node and leaf on the
+tree corresponds to a resource set (which may be empty). The domain
+system makes no distinctions between the uses of the interior nodes and
+leaves, and this memo uses the term "node" to refer to both.
+
+Each node has a label, which is zero to 63 octets in length. Brother
+nodes may not have the same label, although the same label can be used
+for nodes which are not brothers. One label is reserved, and that is
+the null (i.e., zero length) label used for the root.
+
+The domain name of a node is the list of the labels on the path from the
+node to the root of the tree. By convention, the labels that compose a
+domain name are printed or read left to right, from the most specific
+(lowest, farthest from the root) to the least specific (highest, closest
+to the root).
+
+Internally, programs that manipulate domain names should represent them
+as sequences of labels, where each label is a length octet followed by
+an octet string. Because all domain names end at the root, which has a
+null string for a label, these internal representations can use a length
+byte of zero to terminate a domain name.
+
+By convention, domain names can be stored with arbitrary case, but
+domain name comparisons for all present domain functions are done in a
+case-insensitive manner, assuming an ASCII character set, and a high
+order zero bit. This means that you are free to create a node with
+label "A" or a node with label "a", but not both as brothers; you could
+refer to either using "a" or "A". When you receive a domain name or
+
+
+
+Mockapetris [Page 7]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+label, you should preserve its case. The rationale for this choice is
+that we may someday need to add full binary domain names for new
+services; existing services would not be changed.
+
+When a user needs to type a domain name, the length of each label is
+omitted and the labels are separated by dots ("."). Since a complete
+domain name ends with the root label, this leads to a printed form which
+ends in a dot. We use this property to distinguish between:
+
+ - a character string which represents a complete domain name
+ (often called "absolute"). For example, "poneria.ISI.EDU."
+
+ - a character string that represents the starting labels of a
+ domain name which is incomplete, and should be completed by
+ local software using knowledge of the local domain (often
+ called "relative"). For example, "poneria" used in the
+ ISI.EDU domain.
+
+Relative names are either taken relative to a well known origin, or to a
+list of domains used as a search list. Relative names appear mostly at
+the user interface, where their interpretation varies from
+implementation to implementation, and in master files, where they are
+relative to a single origin domain name. The most common interpretation
+uses the root "." as either the single origin or as one of the members
+of the search list, so a multi-label relative name is often one where
+the trailing dot has been omitted to save typing.
+
+To simplify implementations, the total number of octets that represent a
+domain name (i.e., the sum of all label octets and label lengths) is
+limited to 255.
+
+A domain is identified by a domain name, and consists of that part of
+the domain name space that is at or below the domain name which
+specifies the domain. A domain is a subdomain of another domain if it
+is contained within that domain. This relationship can be tested by
+seeing if the subdomain's name ends with the containing domain's name.
+For example, A.B.C.D is a subdomain of B.C.D, C.D, D, and " ".
+
+3.2. Administrative guidelines on use
+
+As a matter of policy, the DNS technical specifications do not mandate a
+particular tree structure or rules for selecting labels; its goal is to
+be as general as possible, so that it can be used to build arbitrary
+applications. In particular, the system was designed so that the name
+space did not have to be organized along the lines of network
+boundaries, name servers, etc. The rationale for this is not that the
+name space should have no implied semantics, but rather that the choice
+of implied semantics should be left open to be used for the problem at
+
+
+
+Mockapetris [Page 8]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+hand, and that different parts of the tree can have different implied
+semantics. For example, the IN-ADDR.ARPA domain is organized and
+distributed by network and host address because its role is to translate
+from network or host numbers to names; NetBIOS domains [RFC-1001, RFC-
+1002] are flat because that is appropriate for that application.
+
+However, there are some guidelines that apply to the "normal" parts of
+the name space used for hosts, mailboxes, etc., that will make the name
+space more uniform, provide for growth, and minimize problems as
+software is converted from the older host table. The political
+decisions about the top levels of the tree originated in RFC-920.
+Current policy for the top levels is discussed in [RFC-1032]. MILNET
+conversion issues are covered in [RFC-1031].
+
+Lower domains which will eventually be broken into multiple zones should
+provide branching at the top of the domain so that the eventual
+decomposition can be done without renaming. Node labels which use
+special characters, leading digits, etc., are likely to break older
+software which depends on more restrictive choices.
+
+3.3. Technical guidelines on use
+
+Before the DNS can be used to hold naming information for some kind of
+object, two needs must be met:
+
+ - A convention for mapping between object names and domain
+ names. This describes how information about an object is
+ accessed.
+
+ - RR types and data formats for describing the object.
+
+These rules can be quite simple or fairly complex. Very often, the
+designer must take into account existing formats and plan for upward
+compatibility for existing usage. Multiple mappings or levels of
+mapping may be required.
+
+For hosts, the mapping depends on the existing syntax for host names
+which is a subset of the usual text representation for domain names,
+together with RR formats for describing host addresses, etc. Because we
+need a reliable inverse mapping from address to host name, a special
+mapping for addresses into the IN-ADDR.ARPA domain is also defined.
+
+For mailboxes, the mapping is slightly more complex. The usual mail
+address <local-part>@<mail-domain> is mapped into a domain name by
+converting <local-part> into a single label (regardles of dots it
+contains), converting <mail-domain> into a domain name using the usual
+text format for domain names (dots denote label breaks), and
+concatenating the two to form a single domain name. Thus the mailbox
+
+
+
+Mockapetris [Page 9]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+HOSTMASTER@SRI-NIC.ARPA is represented as a domain name by
+HOSTMASTER.SRI-NIC.ARPA. An appreciation for the reasons behind this
+design also must take into account the scheme for mail exchanges [RFC-
+974].
+
+The typical user is not concerned with defining these rules, but should
+understand that they usually are the result of numerous compromises
+between desires for upward compatibility with old usage, interactions
+between different object definitions, and the inevitable urge to add new
+features when defining the rules. The way the DNS is used to support
+some object is often more crucial than the restrictions inherent in the
+DNS.
+
+3.4. Example name space
+
+The following figure shows a part of the current domain name space, and
+is used in many examples in this RFC. Note that the tree is a very
+small subset of the actual name space.
+
+ |
+ |
+ +---------------------+------------------+
+ | | |
+ MIL EDU ARPA
+ | | |
+ | | |
+ +-----+-----+ | +------+-----+-----+
+ | | | | | | |
+ BRL NOSC DARPA | IN-ADDR SRI-NIC ACC
+ |
+ +--------+------------------+---------------+--------+
+ | | | | |
+ UCI MIT | UDEL YALE
+ | ISI
+ | |
+ +---+---+ |
+ | | |
+ LCS ACHILLES +--+-----+-----+--------+
+ | | | | | |
+ XX A C VAXA VENERA Mockapetris
+
+In this example, the root domain has three immediate subdomains: MIL,
+EDU, and ARPA. The LCS.MIT.EDU domain has one immediate subdomain named
+XX.LCS.MIT.EDU. All of the leaves are also domains.
+
+3.5. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+
+
+
+Mockapetris [Page 10]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+3.6. Resource Records
+
+A domain name identifies a node. Each node has a set of resource
+
+
+
+Mockapetris [Page 11]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+information, which may be empty. The set of resource information
+associated with a particular name is composed of separate resource
+records (RRs). The order of RRs in a set is not significant, and need
+not be preserved by name servers, resolvers, or other parts of the DNS.
+
+When we talk about a specific RR, we assume it has the following:
+
+owner which is the domain name where the RR is found.
+
+type which is an encoded 16 bit value that specifies the type
+ of the resource in this resource record. Types refer to
+ abstract resources.
+
+ This memo uses the following types:
+
+ A a host address
+
+ CNAME identifies the canonical name of an
+ alias
+
+ HINFO identifies the CPU and OS used by a host
+
+ MX identifies a mail exchange for the
+ domain. See [RFC-974 for details.
+
+ NS
+ the authoritative name server for the domain
+
+ PTR
+ a pointer to another part of the domain name space
+
+ SOA
+ identifies the start of a zone of authority]
+
+class which is an encoded 16 bit value which identifies a
+ protocol family or instance of a protocol.
+
+ This memo uses the following classes:
+
+ IN the Internet system
+
+ CH the Chaos system
+
+TTL which is the time to live of the RR. This field is a 32
+ bit integer in units of seconds, an is primarily used by
+ resolvers when they cache RRs. The TTL describes how
+ long a RR can be cached before it should be discarded.
+
+
+
+
+Mockapetris [Page 12]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+RDATA which is the type and sometimes class dependent data
+ which describes the resource:
+
+ A For the IN class, a 32 bit IP address
+
+ For the CH class, a domain name followed
+ by a 16 bit octal Chaos address.
+
+ CNAME a domain name.
+
+ MX a 16 bit preference value (lower is
+ better) followed by a host name willing
+ to act as a mail exchange for the owner
+ domain.
+
+ NS a host name.
+
+ PTR a domain name.
+
+ SOA several fields.
+
+The owner name is often implicit, rather than forming an integral part
+of the RR. For example, many name servers internally form tree or hash
+structures for the name space, and chain RRs off nodes. The remaining
+RR parts are the fixed header (type, class, TTL) which is consistent for
+all RRs, and a variable part (RDATA) that fits the needs of the resource
+being described.
+
+The meaning of the TTL field is a time limit on how long an RR can be
+kept in a cache. This limit does not apply to authoritative data in
+zones; it is also timed out, but by the refreshing policies for the
+zone. The TTL is assigned by the administrator for the zone where the
+data originates. While short TTLs can be used to minimize caching, and
+a zero TTL prohibits caching, the realities of Internet performance
+suggest that these times should be on the order of days for the typical
+host. If a change can be anticipated, the TTL can be reduced prior to
+the change to minimize inconsistency during the change, and then
+increased back to its former value following the change.
+
+The data in the RDATA section of RRs is carried as a combination of
+binary strings and domain names. The domain names are frequently used
+as "pointers" to other data in the DNS.
+
+3.6.1. Textual expression of RRs
+
+RRs are represented in binary form in the packets of the DNS protocol,
+and are usually represented in highly encoded form when stored in a name
+server or resolver. In this memo, we adopt a style similar to that used
+
+
+
+Mockapetris [Page 13]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+in master files in order to show the contents of RRs. In this format,
+most RRs are shown on a single line, although continuation lines are
+possible using parentheses.
+
+The start of the line gives the owner of the RR. If a line begins with
+a blank, then the owner is assumed to be the same as that of the
+previous RR. Blank lines are often included for readability.
+
+Following the owner, we list the TTL, type, and class of the RR. Class
+and type use the mnemonics defined above, and TTL is an integer before
+the type field. In order to avoid ambiguity in parsing, type and class
+mnemonics are disjoint, TTLs are integers, and the type mnemonic is
+always last. The IN class and TTL values are often omitted from examples
+in the interests of clarity.
+
+The resource data or RDATA section of the RR are given using knowledge
+of the typical representation for the data.
+
+For example, we might show the RRs carried in a message as:
+
+ ISI.EDU. MX 10 VENERA.ISI.EDU.
+ MX 10 VAXA.ISI.EDU.
+ VENERA.ISI.EDU. A 128.9.0.32
+ A 10.1.0.52
+ VAXA.ISI.EDU. A 10.2.0.27
+ A 128.9.0.33
+
+The MX RRs have an RDATA section which consists of a 16 bit number
+followed by a domain name. The address RRs use a standard IP address
+format to contain a 32 bit internet address.
+
+This example shows six RRs, with two RRs at each of three domain names.
+
+Similarly we might see:
+
+ XX.LCS.MIT.EDU. IN A 10.0.0.44
+ CH A MIT.EDU. 2420
+
+This example shows two addresses for XX.LCS.MIT.EDU, each of a different
+class.
+
+3.6.2. Aliases and canonical names
+
+In existing systems, hosts and other resources often have several names
+that identify the same resource. For example, the names C.ISI.EDU and
+USC-ISIC.ARPA both identify the same host. Similarly, in the case of
+mailboxes, many organizations provide many names that actually go to the
+same mailbox; for example Mockapetris@C.ISI.EDU, Mockapetris@B.ISI.EDU,
+
+
+
+Mockapetris [Page 14]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+and PVM@ISI.EDU all go to the same mailbox (although the mechanism
+behind this is somewhat complicated).
+
+Most of these systems have a notion that one of the equivalent set of
+names is the canonical or primary name and all others are aliases.
+
+The domain system provides such a feature using the canonical name
+(CNAME) RR. A CNAME RR identifies its owner name as an alias, and
+specifies the corresponding canonical name in the RDATA section of the
+RR. If a CNAME RR is present at a node, no other data should be
+present; this ensures that the data for a canonical name and its aliases
+cannot be different. This rule also insures that a cached CNAME can be
+used without checking with an authoritative server for other RR types.
+
+CNAME RRs cause special action in DNS software. When a name server
+fails to find a desired RR in the resource set associated with the
+domain name, it checks to see if the resource set consists of a CNAME
+record with a matching class. If so, the name server includes the CNAME
+record in the response and restarts the query at the domain name
+specified in the data field of the CNAME record. The one exception to
+this rule is that queries which match the CNAME type are not restarted.
+
+For example, suppose a name server was processing a query with for USC-
+ISIC.ARPA, asking for type A information, and had the following resource
+records:
+
+ USC-ISIC.ARPA IN CNAME C.ISI.EDU
+
+ C.ISI.EDU IN A 10.0.0.52
+
+Both of these RRs would be returned in the response to the type A query,
+while a type CNAME or * query should return just the CNAME.
+
+Domain names in RRs which point at another name should always point at
+the primary name and not the alias. This avoids extra indirections in
+accessing information. For example, the address to name RR for the
+above host should be:
+
+ 52.0.0.10.IN-ADDR.ARPA IN PTR C.ISI.EDU
+
+rather than pointing at USC-ISIC.ARPA. Of course, by the robustness
+principle, domain software should not fail when presented with CNAME
+chains or loops; CNAME chains should be followed and CNAME loops
+signalled as an error.
+
+3.7. Queries
+
+Queries are messages which may be sent to a name server to provoke a
+
+
+
+Mockapetris [Page 15]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+response. In the Internet, queries are carried in UDP datagrams or over
+TCP connections. The response by the name server either answers the
+question posed in the query, refers the requester to another set of name
+servers, or signals some error condition.
+
+In general, the user does not generate queries directly, but instead
+makes a request to a resolver which in turn sends one or more queries to
+name servers and deals with the error conditions and referrals that may
+result. Of course, the possible questions which can be asked in a query
+does shape the kind of service a resolver can provide.
+
+DNS queries and responses are carried in a standard message format. The
+message format has a header containing a number of fixed fields which
+are always present, and four sections which carry query parameters and
+RRs.
+
+The most important field in the header is a four bit field called an
+opcode which separates different queries. Of the possible 16 values,
+one (standard query) is part of the official protocol, two (inverse
+query and status query) are options, one (completion) is obsolete, and
+the rest are unassigned.
+
+The four sections are:
+
+Question Carries the query name and other query parameters.
+
+Answer Carries RRs which directly answer the query.
+
+Authority Carries RRs which describe other authoritative servers.
+ May optionally carry the SOA RR for the authoritative
+ data in the answer section.
+
+Additional Carries RRs which may be helpful in using the RRs in the
+ other sections.
+
+Note that the content, but not the format, of these sections varies with
+header opcode.
+
+3.7.1. Standard queries
+
+A standard query specifies a target domain name (QNAME), query type
+(QTYPE), and query class (QCLASS) and asks for RRs which match. This
+type of query makes up such a vast majority of DNS queries that we use
+the term "query" to mean standard query unless otherwise specified. The
+QTYPE and QCLASS fields are each 16 bits long, and are a superset of
+defined types and classes.
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The QTYPE field may contain:
+
+<any type> matches just that type. (e.g., A, PTR).
+
+AXFR special zone transfer QTYPE.
+
+MAILB matches all mail box related RRs (e.g. MB and MG).
+
+* matches all RR types.
+
+The QCLASS field may contain:
+
+<any class> matches just that class (e.g., IN, CH).
+
+* matches aLL RR classes.
+
+Using the query domain name, QTYPE, and QCLASS, the name server looks
+for matching RRs. In addition to relevant records, the name server may
+return RRs that point toward a name server that has the desired
+information or RRs that are expected to be useful in interpreting the
+relevant RRs. For example, a name server that doesn't have the
+requested information may know a name server that does; a name server
+that returns a domain name in a relevant RR may also return the RR that
+binds that domain name to an address.
+
+For example, a mailer tying to send mail to Mockapetris@ISI.EDU might
+ask the resolver for mail information about ISI.EDU, resulting in a
+query for QNAME=ISI.EDU, QTYPE=MX, QCLASS=IN. The response's answer
+section would be:
+
+ ISI.EDU. MX 10 VENERA.ISI.EDU.
+ MX 10 VAXA.ISI.EDU.
+
+while the additional section might be:
+
+ VAXA.ISI.EDU. A 10.2.0.27
+ A 128.9.0.33
+ VENERA.ISI.EDU. A 10.1.0.52
+ A 128.9.0.32
+
+Because the server assumes that if the requester wants mail exchange
+information, it will probably want the addresses of the mail exchanges
+soon afterward.
+
+Note that the QCLASS=* construct requires special interpretation
+regarding authority. Since a particular name server may not know all of
+the classes available in the domain system, it can never know if it is
+authoritative for all classes. Hence responses to QCLASS=* queries can
+
+
+
+Mockapetris [Page 17]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+never be authoritative.
+
+3.7.2. Inverse queries (Optional)
+
+Name servers may also support inverse queries that map a particular
+resource to a domain name or domain names that have that resource. For
+example, while a standard query might map a domain name to a SOA RR, the
+corresponding inverse query might map the SOA RR back to the domain
+name.
+
+Implementation of this service is optional in a name server, but all
+name servers must at least be able to understand an inverse query
+message and return a not-implemented error response.
+
+The domain system cannot guarantee the completeness or uniqueness of
+inverse queries because the domain system is organized by domain name
+rather than by host address or any other resource type. Inverse queries
+are primarily useful for debugging and database maintenance activities.
+
+Inverse queries may not return the proper TTL, and do not indicate cases
+where the identified RR is one of a set (for example, one address for a
+host having multiple addresses). Therefore, the RRs returned in inverse
+queries should never be cached.
+
+Inverse queries are NOT an acceptable method for mapping host addresses
+to host names; use the IN-ADDR.ARPA domain instead.
+
+A detailed discussion of inverse queries is contained in [RFC-1035].
+
+3.8. Status queries (Experimental)
+
+To be defined.
+
+3.9. Completion queries (Obsolete)
+
+The optional completion services described in RFCs 882 and 883 have been
+deleted. Redesigned services may become available in the future, or the
+opcodes may be reclaimed for other use.
+
+4. NAME SERVERS
+
+4.1. Introduction
+
+Name servers are the repositories of information that make up the domain
+database. The database is divided up into sections called zones, which
+are distributed among the name servers. While name servers can have
+several optional functions and sources of data, the essential task of a
+name server is to answer queries using data in its zones. By design,
+
+
+
+Mockapetris [Page 18]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+name servers can answer queries in a simple manner; the response can
+always be generated using only local data, and either contains the
+answer to the question or a referral to other name servers "closer" to
+the desired information.
+
+A given zone will be available from several name servers to insure its
+availability in spite of host or communication link failure. By
+administrative fiat, we require every zone to be available on at least
+two servers, and many zones have more redundancy than that.
+
+A given name server will typically support one or more zones, but this
+gives it authoritative information about only a small section of the
+domain tree. It may also have some cached non-authoritative data about
+other parts of the tree. The name server marks its responses to queries
+so that the requester can tell whether the response comes from
+authoritative data or not.
+
+4.2. How the database is divided into zones
+
+The domain database is partitioned in two ways: by class, and by "cuts"
+made in the name space between nodes.
+
+The class partition is simple. The database for any class is organized,
+delegated, and maintained separately from all other classes. Since, by
+convention, the name spaces are the same for all classes, the separate
+classes can be thought of as an array of parallel namespace trees. Note
+that the data attached to nodes will be different for these different
+parallel classes. The most common reasons for creating a new class are
+the necessity for a new data format for existing types or a desire for a
+separately managed version of the existing name space.
+
+Within a class, "cuts" in the name space can be made between any two
+adjacent nodes. After all cuts are made, each group of connected name
+space is a separate zone. The zone is said to be authoritative for all
+names in the connected region. Note that the "cuts" in the name space
+may be in different places for different classes, the name servers may
+be different, etc.
+
+These rules mean that every zone has at least one node, and hence domain
+name, for which it is authoritative, and all of the nodes in a
+particular zone are connected. Given, the tree structure, every zone
+has a highest node which is closer to the root than any other node in
+the zone. The name of this node is often used to identify the zone.
+
+It would be possible, though not particularly useful, to partition the
+name space so that each domain name was in a separate zone or so that
+all nodes were in a single zone. Instead, the database is partitioned
+at points where a particular organization wants to take over control of
+
+
+
+Mockapetris [Page 19]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+a subtree. Once an organization controls its own zone it can
+unilaterally change the data in the zone, grow new tree sections
+connected to the zone, delete existing nodes, or delegate new subzones
+under its zone.
+
+If the organization has substructure, it may want to make further
+internal partitions to achieve nested delegations of name space control.
+In some cases, such divisions are made purely to make database
+maintenance more convenient.
+
+4.2.1. Technical considerations
+
+The data that describes a zone has four major parts:
+
+ - Authoritative data for all nodes within the zone.
+
+ - Data that defines the top node of the zone (can be thought of
+ as part of the authoritative data).
+
+ - Data that describes delegated subzones, i.e., cuts around the
+ bottom of the zone.
+
+ - Data that allows access to name servers for subzones
+ (sometimes called "glue" data).
+
+All of this data is expressed in the form of RRs, so a zone can be
+completely described in terms of a set of RRs. Whole zones can be
+transferred between name servers by transferring the RRs, either carried
+in a series of messages or by FTPing a master file which is a textual
+representation.
+
+The authoritative data for a zone is simply all of the RRs attached to
+all of the nodes from the top node of the zone down to leaf nodes or
+nodes above cuts around the bottom edge of the zone.
+
+Though logically part of the authoritative data, the RRs that describe
+the top node of the zone are especially important to the zone's
+management. These RRs are of two types: name server RRs that list, one
+per RR, all of the servers for the zone, and a single SOA RR that
+describes zone management parameters.
+
+The RRs that describe cuts around the bottom of the zone are NS RRs that
+name the servers for the subzones. Since the cuts are between nodes,
+these RRs are NOT part of the authoritative data of the zone, and should
+be exactly the same as the corresponding RRs in the top node of the
+subzone. Since name servers are always associated with zone boundaries,
+NS RRs are only found at nodes which are the top node of some zone. In
+the data that makes up a zone, NS RRs are found at the top node of the
+
+
+
+Mockapetris [Page 20]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+zone (and are authoritative) and at cuts around the bottom of the zone
+(where they are not authoritative), but never in between.
+
+One of the goals of the zone structure is that any zone have all the
+data required to set up communications with the name servers for any
+subzones. That is, parent zones have all the information needed to
+access servers for their children zones. The NS RRs that name the
+servers for subzones are often not enough for this task since they name
+the servers, but do not give their addresses. In particular, if the
+name of the name server is itself in the subzone, we could be faced with
+the situation where the NS RRs tell us that in order to learn a name
+server's address, we should contact the server using the address we wish
+to learn. To fix this problem, a zone contains "glue" RRs which are not
+part of the authoritative data, and are address RRs for the servers.
+These RRs are only necessary if the name server's name is "below" the
+cut, and are only used as part of a referral response.
+
+4.2.2. Administrative considerations
+
+When some organization wants to control its own domain, the first step
+is to identify the proper parent zone, and get the parent zone's owners
+to agree to the delegation of control. While there are no particular
+technical constraints dealing with where in the tree this can be done,
+there are some administrative groupings discussed in [RFC-1032] which
+deal with top level organization, and middle level zones are free to
+create their own rules. For example, one university might choose to use
+a single zone, while another might choose to organize by subzones
+dedicated to individual departments or schools. [RFC-1033] catalogs
+available DNS software an discusses administration procedures.
+
+Once the proper name for the new subzone is selected, the new owners
+should be required to demonstrate redundant name server support. Note
+that there is no requirement that the servers for a zone reside in a
+host which has a name in that domain. In many cases, a zone will be
+more accessible to the internet at large if its servers are widely
+distributed rather than being within the physical facilities controlled
+by the same organization that manages the zone. For example, in the
+current DNS, one of the name servers for the United Kingdom, or UK
+domain, is found in the US. This allows US hosts to get UK data without
+using limited transatlantic bandwidth.
+
+As the last installation step, the delegation NS RRs and glue RRs
+necessary to make the delegation effective should be added to the parent
+zone. The administrators of both zones should insure that the NS and
+glue RRs which mark both sides of the cut are consistent and remain so.
+
+4.3. Name server internals
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.1. Queries and responses
+
+The principal activity of name servers is to answer standard queries.
+Both the query and its response are carried in a standard message format
+which is described in [RFC-1035]. The query contains a QTYPE, QCLASS,
+and QNAME, which describe the types and classes of desired information
+and the name of interest.
+
+The way that the name server answers the query depends upon whether it
+is operating in recursive mode or not:
+
+ - The simplest mode for the server is non-recursive, since it
+ can answer queries using only local information: the response
+ contains an error, the answer, or a referral to some other
+ server "closer" to the answer. All name servers must
+ implement non-recursive queries.
+
+ - The simplest mode for the client is recursive, since in this
+ mode the name server acts in the role of a resolver and
+ returns either an error or the answer, but never referrals.
+ This service is optional in a name server, and the name server
+ may also choose to restrict the clients which can use
+ recursive mode.
+
+Recursive service is helpful in several situations:
+
+ - a relatively simple requester that lacks the ability to use
+ anything other than a direct answer to the question.
+
+ - a request that needs to cross protocol or other boundaries and
+ can be sent to a server which can act as intermediary.
+
+ - a network where we want to concentrate the cache rather than
+ having a separate cache for each client.
+
+Non-recursive service is appropriate if the requester is capable of
+pursuing referrals and interested in information which will aid future
+requests.
+
+The use of recursive mode is limited to cases where both the client and
+the name server agree to its use. The agreement is negotiated through
+the use of two bits in query and response messages:
+
+ - The recursion available, or RA bit, is set or cleared by a
+ name server in all responses. The bit is true if the name
+ server is willing to provide recursive service for the client,
+ regardless of whether the client requested recursive service.
+ That is, RA signals availability rather than use.
+
+
+
+Mockapetris [Page 22]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ - Queries contain a bit called recursion desired or RD. This
+ bit specifies specifies whether the requester wants recursive
+ service for this query. Clients may request recursive service
+ from any name server, though they should depend upon receiving
+ it only from servers which have previously sent an RA, or
+ servers which have agreed to provide service through private
+ agreement or some other means outside of the DNS protocol.
+
+The recursive mode occurs when a query with RD set arrives at a server
+which is willing to provide recursive service; the client can verify
+that recursive mode was used by checking that both RA and RD are set in
+the reply. Note that the name server should never perform recursive
+service unless asked via RD, since this interferes with trouble shooting
+of name servers and their databases.
+
+If recursive service is requested and available, the recursive response
+to a query will be one of the following:
+
+ - The answer to the query, possibly preface by one or more CNAME
+ RRs that specify aliases encountered on the way to an answer.
+
+ - A name error indicating that the name does not exist. This
+ may include CNAME RRs that indicate that the original query
+ name was an alias for a name which does not exist.
+
+ - A temporary error indication.
+
+If recursive service is not requested or is not available, the non-
+recursive response will be one of the following:
+
+ - An authoritative name error indicating that the name does not
+ exist.
+
+ - A temporary error indication.
+
+ - Some combination of:
+
+ RRs that answer the question, together with an indication
+ whether the data comes from a zone or is cached.
+
+ A referral to name servers which have zones which are closer
+ ancestors to the name than the server sending the reply.
+
+ - RRs that the name server thinks will prove useful to the
+ requester.
+
+
+
+
+
+
+Mockapetris [Page 23]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.2. Algorithm
+
+The actual algorithm used by the name server will depend on the local OS
+and data structures used to store RRs. The following algorithm assumes
+that the RRs are organized in several tree structures, one for each
+zone, and another for the cache:
+
+ 1. Set or clear the value of recursion available in the response
+ depending on whether the name server is willing to provide
+ recursive service. If recursive service is available and
+ requested via the RD bit in the query, go to step 5,
+ otherwise step 2.
+
+ 2. Search the available zones for the zone which is the nearest
+ ancestor to QNAME. If such a zone is found, go to step 3,
+ otherwise step 4.
+
+ 3. Start matching down, label by label, in the zone. The
+ matching process can terminate several ways:
+
+ a. If the whole of QNAME is matched, we have found the
+ node.
+
+ If the data at the node is a CNAME, and QTYPE doesn't
+ match CNAME, copy the CNAME RR into the answer section
+ of the response, change QNAME to the canonical name in
+ the CNAME RR, and go back to step 1.
+
+ Otherwise, copy all RRs which match QTYPE into the
+ answer section and go to step 6.
+
+ b. If a match would take us out of the authoritative data,
+ we have a referral. This happens when we encounter a
+ node with NS RRs marking cuts along the bottom of a
+ zone.
+
+ Copy the NS RRs for the subzone into the authority
+ section of the reply. Put whatever addresses are
+ available into the additional section, using glue RRs
+ if the addresses are not available from authoritative
+ data or the cache. Go to step 4.
+
+ c. If at some label, a match is impossible (i.e., the
+ corresponding label does not exist), look to see if a
+ the "*" label exists.
+
+ If the "*" label does not exist, check whether the name
+ we are looking for is the original QNAME in the query
+
+
+
+Mockapetris [Page 24]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ or a name we have followed due to a CNAME. If the name
+ is original, set an authoritative name error in the
+ response and exit. Otherwise just exit.
+
+ If the "*" label does exist, match RRs at that node
+ against QTYPE. If any match, copy them into the answer
+ section, but set the owner of the RR to be QNAME, and
+ not the node with the "*" label. Go to step 6.
+
+ 4. Start matching down in the cache. If QNAME is found in the
+ cache, copy all RRs attached to it that match QTYPE into the
+ answer section. If there was no delegation from
+ authoritative data, look for the best one from the cache, and
+ put it in the authority section. Go to step 6.
+
+ 5. Using the local resolver or a copy of its algorithm (see
+ resolver section of this memo) to answer the query. Store
+ the results, including any intermediate CNAMEs, in the answer
+ section of the response.
+
+ 6. Using local data only, attempt to add other RRs which may be
+ useful to the additional section of the query. Exit.
+
+4.3.3. Wildcards
+
+In the previous algorithm, special treatment was given to RRs with owner
+names starting with the label "*". Such RRs are called wildcards.
+Wildcard RRs can be thought of as instructions for synthesizing RRs.
+When the appropriate conditions are met, the name server creates RRs
+with an owner name equal to the query name and contents taken from the
+wildcard RRs.
+
+This facility is most often used to create a zone which will be used to
+forward mail from the Internet to some other mail system. The general
+idea is that any name in that zone which is presented to server in a
+query will be assumed to exist, with certain properties, unless explicit
+evidence exists to the contrary. Note that the use of the term zone
+here, instead of domain, is intentional; such defaults do not propagate
+across zone boundaries, although a subzone may choose to achieve that
+appearance by setting up similar defaults.
+
+The contents of the wildcard RRs follows the usual rules and formats for
+RRs. The wildcards in the zone have an owner name that controls the
+query names they will match. The owner name of the wildcard RRs is of
+the form "*.<anydomain>", where <anydomain> is any domain name.
+<anydomain> should not contain other * labels, and should be in the
+authoritative data of the zone. The wildcards potentially apply to
+descendants of <anydomain>, but not to <anydomain> itself. Another way
+
+
+
+Mockapetris [Page 25]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+to look at this is that the "*" label always matches at least one whole
+label and sometimes more, but always whole labels.
+
+Wildcard RRs do not apply:
+
+ - When the query is in another zone. That is, delegation cancels
+ the wildcard defaults.
+
+ - When the query name or a name between the wildcard domain and
+ the query name is know to exist. For example, if a wildcard
+ RR has an owner name of "*.X", and the zone also contains RRs
+ attached to B.X, the wildcards would apply to queries for name
+ Z.X (presuming there is no explicit information for Z.X), but
+ not to B.X, A.B.X, or X.
+
+A * label appearing in a query name has no special effect, but can be
+used to test for wildcards in an authoritative zone; such a query is the
+only way to get a response containing RRs with an owner name with * in
+it. The result of such a query should not be cached.
+
+Note that the contents of the wildcard RRs are not modified when used to
+synthesize RRs.
+
+To illustrate the use of wildcard RRs, suppose a large company with a
+large, non-IP/TCP, network wanted to create a mail gateway. If the
+company was called X.COM, and IP/TCP capable gateway machine was called
+A.X.COM, the following RRs might be entered into the COM zone:
+
+ X.COM MX 10 A.X.COM
+
+ *.X.COM MX 10 A.X.COM
+
+ A.X.COM A 1.2.3.4
+ A.X.COM MX 10 A.X.COM
+
+ *.A.X.COM MX 10 A.X.COM
+
+This would cause any MX query for any domain name ending in X.COM to
+return an MX RR pointing at A.X.COM. Two wildcard RRs are required
+since the effect of the wildcard at *.X.COM is inhibited in the A.X.COM
+subtree by the explicit data for A.X.COM. Note also that the explicit
+MX data at X.COM and A.X.COM is required, and that none of the RRs above
+would match a query name of XX.COM.
+
+4.3.4. Negative response caching (Optional)
+
+The DNS provides an optional service which allows name servers to
+distribute, and resolvers to cache, negative results with TTLs. For
+
+
+
+Mockapetris [Page 26]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+example, a name server can distribute a TTL along with a name error
+indication, and a resolver receiving such information is allowed to
+assume that the name does not exist during the TTL period without
+consulting authoritative data. Similarly, a resolver can make a query
+with a QTYPE which matches multiple types, and cache the fact that some
+of the types are not present.
+
+This feature can be particularly important in a system which implements
+naming shorthands that use search lists beacuse a popular shorthand,
+which happens to require a suffix toward the end of the search list,
+will generate multiple name errors whenever it is used.
+
+The method is that a name server may add an SOA RR to the additional
+section of a response when that response is authoritative. The SOA must
+be that of the zone which was the source of the authoritative data in
+the answer section, or name error if applicable. The MINIMUM field of
+the SOA controls the length of time that the negative result may be
+cached.
+
+Note that in some circumstances, the answer section may contain multiple
+owner names. In this case, the SOA mechanism should only be used for
+the data which matches QNAME, which is the only authoritative data in
+this section.
+
+Name servers and resolvers should never attempt to add SOAs to the
+additional section of a non-authoritative response, or attempt to infer
+results which are not directly stated in an authoritative response.
+There are several reasons for this, including: cached information isn't
+usually enough to match up RRs and their zone names, SOA RRs may be
+cached due to direct SOA queries, and name servers are not required to
+output the SOAs in the authority section.
+
+This feature is optional, although a refined version is expected to
+become part of the standard protocol in the future. Name servers are
+not required to add the SOA RRs in all authoritative responses, nor are
+resolvers required to cache negative results. Both are recommended.
+All resolvers and recursive name servers are required to at least be
+able to ignore the SOA RR when it is present in a response.
+
+Some experiments have also been proposed which will use this feature.
+The idea is that if cached data is known to come from a particular zone,
+and if an authoritative copy of the zone's SOA is obtained, and if the
+zone's SERIAL has not changed since the data was cached, then the TTL of
+the cached data can be reset to the zone MINIMUM value if it is smaller.
+This usage is mentioned for planning purposes only, and is not
+recommended as yet.
+
+
+
+
+
+Mockapetris [Page 27]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.5. Zone maintenance and transfers
+
+Part of the job of a zone administrator is to maintain the zones at all
+of the name servers which are authoritative for the zone. When the
+inevitable changes are made, they must be distributed to all of the name
+servers. While this distribution can be accomplished using FTP or some
+other ad hoc procedure, the preferred method is the zone transfer part
+of the DNS protocol.
+
+The general model of automatic zone transfer or refreshing is that one
+of the name servers is the master or primary for the zone. Changes are
+coordinated at the primary, typically by editing a master file for the
+zone. After editing, the administrator signals the master server to
+load the new zone. The other non-master or secondary servers for the
+zone periodically check for changes (at a selectable interval) and
+obtain new zone copies when changes have been made.
+
+To detect changes, secondaries just check the SERIAL field of the SOA
+for the zone. In addition to whatever other changes are made, the
+SERIAL field in the SOA of the zone is always advanced whenever any
+change is made to the zone. The advancing can be a simple increment, or
+could be based on the write date and time of the master file, etc. The
+purpose is to make it possible to determine which of two copies of a
+zone is more recent by comparing serial numbers. Serial number advances
+and comparisons use sequence space arithmetic, so there is a theoretic
+limit on how fast a zone can be updated, basically that old copies must
+die out before the serial number covers half of its 32 bit range. In
+practice, the only concern is that the compare operation deals properly
+with comparisons around the boundary between the most positive and most
+negative 32 bit numbers.
+
+The periodic polling of the secondary servers is controlled by
+parameters in the SOA RR for the zone, which set the minimum acceptable
+polling intervals. The parameters are called REFRESH, RETRY, and
+EXPIRE. Whenever a new zone is loaded in a secondary, the secondary
+waits REFRESH seconds before checking with the primary for a new serial.
+If this check cannot be completed, new checks are started every RETRY
+seconds. The check is a simple query to the primary for the SOA RR of
+the zone. If the serial field in the secondary's zone copy is equal to
+the serial returned by the primary, then no changes have occurred, and
+the REFRESH interval wait is restarted. If the secondary finds it
+impossible to perform a serial check for the EXPIRE interval, it must
+assume that its copy of the zone is obsolete an discard it.
+
+When the poll shows that the zone has changed, then the secondary server
+must request a zone transfer via an AXFR request for the zone. The AXFR
+may cause an error, such as refused, but normally is answered by a
+sequence of response messages. The first and last messages must contain
+
+
+
+Mockapetris [Page 28]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+the data for the top authoritative node of the zone. Intermediate
+messages carry all of the other RRs from the zone, including both
+authoritative and non-authoritative RRs. The stream of messages allows
+the secondary to construct a copy of the zone. Because accuracy is
+essential, TCP or some other reliable protocol must be used for AXFR
+requests.
+
+Each secondary server is required to perform the following operations
+against the master, but may also optionally perform these operations
+against other secondary servers. This strategy can improve the transfer
+process when the primary is unavailable due to host downtime or network
+problems, or when a secondary server has better network access to an
+"intermediate" secondary than to the primary.
+
+5. RESOLVERS
+
+5.1. Introduction
+
+Resolvers are programs that interface user programs to domain name
+servers. In the simplest case, a resolver receives a request from a
+user program (e.g., mail programs, TELNET, FTP) in the form of a
+subroutine call, system call etc., and returns the desired information
+in a form compatible with the local host's data formats.
+
+The resolver is located on the same machine as the program that requests
+the resolver's services, but it may need to consult name servers on
+other hosts. Because a resolver may need to consult several name
+servers, or may have the requested information in a local cache, the
+amount of time that a resolver will take to complete can vary quite a
+bit, from milliseconds to several seconds.
+
+A very important goal of the resolver is to eliminate network delay and
+name server load from most requests by answering them from its cache of
+prior results. It follows that caches which are shared by multiple
+processes, users, machines, etc., are more efficient than non-shared
+caches.
+
+5.2. Client-resolver interface
+
+5.2.1. Typical functions
+
+The client interface to the resolver is influenced by the local host's
+conventions, but the typical resolver-client interface has three
+functions:
+
+ 1. Host name to host address translation.
+
+ This function is often defined to mimic a previous HOSTS.TXT
+
+
+
+Mockapetris [Page 29]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ based function. Given a character string, the caller wants
+ one or more 32 bit IP addresses. Under the DNS, it
+ translates into a request for type A RRs. Since the DNS does
+ not preserve the order of RRs, this function may choose to
+ sort the returned addresses or select the "best" address if
+ the service returns only one choice to the client. Note that
+ a multiple address return is recommended, but a single
+ address may be the only way to emulate prior HOSTS.TXT
+ services.
+
+ 2. Host address to host name translation
+
+ This function will often follow the form of previous
+ functions. Given a 32 bit IP address, the caller wants a
+ character string. The octets of the IP address are reversed,
+ used as name components, and suffixed with "IN-ADDR.ARPA". A
+ type PTR query is used to get the RR with the primary name of
+ the host. For example, a request for the host name
+ corresponding to IP address 1.2.3.4 looks for PTR RRs for
+ domain name "4.3.2.1.IN-ADDR.ARPA".
+
+ 3. General lookup function
+
+ This function retrieves arbitrary information from the DNS,
+ and has no counterpart in previous systems. The caller
+ supplies a QNAME, QTYPE, and QCLASS, and wants all of the
+ matching RRs. This function will often use the DNS format
+ for all RR data instead of the local host's, and returns all
+ RR content (e.g., TTL) instead of a processed form with local
+ quoting conventions.
+
+When the resolver performs the indicated function, it usually has one of
+the following results to pass back to the client:
+
+ - One or more RRs giving the requested data.
+
+ In this case the resolver returns the answer in the
+ appropriate format.
+
+ - A name error (NE).
+
+ This happens when the referenced name does not exist. For
+ example, a user may have mistyped a host name.
+
+ - A data not found error.
+
+ This happens when the referenced name exists, but data of the
+ appropriate type does not. For example, a host address
+
+
+
+Mockapetris [Page 30]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ function applied to a mailbox name would return this error
+ since the name exists, but no address RR is present.
+
+It is important to note that the functions for translating between host
+names and addresses may combine the "name error" and "data not found"
+error conditions into a single type of error return, but the general
+function should not. One reason for this is that applications may ask
+first for one type of information about a name followed by a second
+request to the same name for some other type of information; if the two
+errors are combined, then useless queries may slow the application.
+
+5.2.2. Aliases
+
+While attempting to resolve a particular request, the resolver may find
+that the name in question is an alias. For example, the resolver might
+find that the name given for host name to address translation is an
+alias when it finds the CNAME RR. If possible, the alias condition
+should be signalled back from the resolver to the client.
+
+In most cases a resolver simply restarts the query at the new name when
+it encounters a CNAME. However, when performing the general function,
+the resolver should not pursue aliases when the CNAME RR matches the
+query type. This allows queries which ask whether an alias is present.
+For example, if the query type is CNAME, the user is interested in the
+CNAME RR itself, and not the RRs at the name it points to.
+
+Several special conditions can occur with aliases. Multiple levels of
+aliases should be avoided due to their lack of efficiency, but should
+not be signalled as an error. Alias loops and aliases which point to
+non-existent names should be caught and an error condition passed back
+to the client.
+
+5.2.3. Temporary failures
+
+In a less than perfect world, all resolvers will occasionally be unable
+to resolve a particular request. This condition can be caused by a
+resolver which becomes separated from the rest of the network due to a
+link failure or gateway problem, or less often by coincident failure or
+unavailability of all servers for a particular domain.
+
+It is essential that this sort of condition should not be signalled as a
+name or data not present error to applications. This sort of behavior
+is annoying to humans, and can wreak havoc when mail systems use the
+DNS.
+
+While in some cases it is possible to deal with such a temporary problem
+by blocking the request indefinitely, this is usually not a good choice,
+particularly when the client is a server process that could move on to
+
+
+
+Mockapetris [Page 31]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+other tasks. The recommended solution is to always have temporary
+failure as one of the possible results of a resolver function, even
+though this may make emulation of existing HOSTS.TXT functions more
+difficult.
+
+5.3. Resolver internals
+
+Every resolver implementation uses slightly different algorithms, and
+typically spends much more logic dealing with errors of various sorts
+than typical occurances. This section outlines a recommended basic
+strategy for resolver operation, but leaves details to [RFC-1035].
+
+5.3.1. Stub resolvers
+
+One option for implementing a resolver is to move the resolution
+function out of the local machine and into a name server which supports
+recursive queries. This can provide an easy method of providing domain
+service in a PC which lacks the resources to perform the resolver
+function, or can centralize the cache for a whole local network or
+organization.
+
+All that the remaining stub needs is a list of name server addresses
+that will perform the recursive requests. This type of resolver
+presumably needs the information in a configuration file, since it
+probably lacks the sophistication to locate it in the domain database.
+The user also needs to verify that the listed servers will perform the
+recursive service; a name server is free to refuse to perform recursive
+services for any or all clients. The user should consult the local
+system administrator to find name servers willing to perform the
+service.
+
+This type of service suffers from some drawbacks. Since the recursive
+requests may take an arbitrary amount of time to perform, the stub may
+have difficulty optimizing retransmission intervals to deal with both
+lost UDP packets and dead servers; the name server can be easily
+overloaded by too zealous a stub if it interprets retransmissions as new
+requests. Use of TCP may be an answer, but TCP may well place burdens
+on the host's capabilities which are similar to those of a real
+resolver.
+
+5.3.2. Resources
+
+In addition to its own resources, the resolver may also have shared
+access to zones maintained by a local name server. This gives the
+resolver the advantage of more rapid access, but the resolver must be
+careful to never let cached information override zone data. In this
+discussion the term "local information" is meant to mean the union of
+the cache and such shared zones, with the understanding that
+
+
+
+Mockapetris [Page 32]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+authoritative data is always used in preference to cached data when both
+are present.
+
+The following resolver algorithm assumes that all functions have been
+converted to a general lookup function, and uses the following data
+structures to represent the state of a request in progress in the
+resolver:
+
+SNAME the domain name we are searching for.
+
+STYPE the QTYPE of the search request.
+
+SCLASS the QCLASS of the search request.
+
+SLIST a structure which describes the name servers and the
+ zone which the resolver is currently trying to query.
+ This structure keeps track of the resolver's current
+ best guess about which name servers hold the desired
+ information; it is updated when arriving information
+ changes the guess. This structure includes the
+ equivalent of a zone name, the known name servers for
+ the zone, the known addresses for the name servers, and
+ history information which can be used to suggest which
+ server is likely to be the best one to try next. The
+ zone name equivalent is a match count of the number of
+ labels from the root down which SNAME has in common with
+ the zone being queried; this is used as a measure of how
+ "close" the resolver is to SNAME.
+
+SBELT a "safety belt" structure of the same form as SLIST,
+ which is initialized from a configuration file, and
+ lists servers which should be used when the resolver
+ doesn't have any local information to guide name server
+ selection. The match count will be -1 to indicate that
+ no labels are known to match.
+
+CACHE A structure which stores the results from previous
+ responses. Since resolvers are responsible for
+ discarding old RRs whose TTL has expired, most
+ implementations convert the interval specified in
+ arriving RRs to some sort of absolute time when the RR
+ is stored in the cache. Instead of counting the TTLs
+ down individually, the resolver just ignores or discards
+ old RRs when it runs across them in the course of a
+ search, or discards them during periodic sweeps to
+ reclaim the memory consumed by old RRs.
+
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+5.3.3. Algorithm
+
+The top level algorithm has four steps:
+
+ 1. See if the answer is in local information, and if so return
+ it to the client.
+
+ 2. Find the best servers to ask.
+
+ 3. Send them queries until one returns a response.
+
+ 4. Analyze the response, either:
+
+ a. if the response answers the question or contains a name
+ error, cache the data as well as returning it back to
+ the client.
+
+ b. if the response contains a better delegation to other
+ servers, cache the delegation information, and go to
+ step 2.
+
+ c. if the response shows a CNAME and that is not the
+ answer itself, cache the CNAME, change the SNAME to the
+ canonical name in the CNAME RR and go to step 1.
+
+ d. if the response shows a servers failure or other
+ bizarre contents, delete the server from the SLIST and
+ go back to step 3.
+
+Step 1 searches the cache for the desired data. If the data is in the
+cache, it is assumed to be good enough for normal use. Some resolvers
+have an option at the user interface which will force the resolver to
+ignore the cached data and consult with an authoritative server. This
+is not recommended as the default. If the resolver has direct access to
+a name server's zones, it should check to see if the desired data is
+present in authoritative form, and if so, use the authoritative data in
+preference to cached data.
+
+Step 2 looks for a name server to ask for the required data. The
+general strategy is to look for locally-available name server RRs,
+starting at SNAME, then the parent domain name of SNAME, the
+grandparent, and so on toward the root. Thus if SNAME were
+Mockapetris.ISI.EDU, this step would look for NS RRs for
+Mockapetris.ISI.EDU, then ISI.EDU, then EDU, and then . (the root).
+These NS RRs list the names of hosts for a zone at or above SNAME. Copy
+the names into SLIST. Set up their addresses using local data. It may
+be the case that the addresses are not available. The resolver has many
+choices here; the best is to start parallel resolver processes looking
+
+
+
+Mockapetris [Page 34]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+for the addresses while continuing onward with the addresses which are
+available. Obviously, the design choices and options are complicated
+and a function of the local host's capabilities. The recommended
+priorities for the resolver designer are:
+
+ 1. Bound the amount of work (packets sent, parallel processes
+ started) so that a request can't get into an infinite loop or
+ start off a chain reaction of requests or queries with other
+ implementations EVEN IF SOMEONE HAS INCORRECTLY CONFIGURED
+ SOME DATA.
+
+ 2. Get back an answer if at all possible.
+
+ 3. Avoid unnecessary transmissions.
+
+ 4. Get the answer as quickly as possible.
+
+If the search for NS RRs fails, then the resolver initializes SLIST from
+the safety belt SBELT. The basic idea is that when the resolver has no
+idea what servers to ask, it should use information from a configuration
+file that lists several servers which are expected to be helpful.
+Although there are special situations, the usual choice is two of the
+root servers and two of the servers for the host's domain. The reason
+for two of each is for redundancy. The root servers will provide
+eventual access to all of the domain space. The two local servers will
+allow the resolver to continue to resolve local names if the local
+network becomes isolated from the internet due to gateway or link
+failure.
+
+In addition to the names and addresses of the servers, the SLIST data
+structure can be sorted to use the best servers first, and to insure
+that all addresses of all servers are used in a round-robin manner. The
+sorting can be a simple function of preferring addresses on the local
+network over others, or may involve statistics from past events, such as
+previous response times and batting averages.
+
+Step 3 sends out queries until a response is received. The strategy is
+to cycle around all of the addresses for all of the servers with a
+timeout between each transmission. In practice it is important to use
+all addresses of a multihomed host, and too aggressive a retransmission
+policy actually slows response when used by multiple resolvers
+contending for the same name server and even occasionally for a single
+resolver. SLIST typically contains data values to control the timeouts
+and keep track of previous transmissions.
+
+Step 4 involves analyzing responses. The resolver should be highly
+paranoid in its parsing of responses. It should also check that the
+response matches the query it sent using the ID field in the response.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The ideal answer is one from a server authoritative for the query which
+either gives the required data or a name error. The data is passed back
+to the user and entered in the cache for future use if its TTL is
+greater than zero.
+
+If the response shows a delegation, the resolver should check to see
+that the delegation is "closer" to the answer than the servers in SLIST
+are. This can be done by comparing the match count in SLIST with that
+computed from SNAME and the NS RRs in the delegation. If not, the reply
+is bogus and should be ignored. If the delegation is valid the NS
+delegation RRs and any address RRs for the servers should be cached.
+The name servers are entered in the SLIST, and the search is restarted.
+
+If the response contains a CNAME, the search is restarted at the CNAME
+unless the response has the data for the canonical name or if the CNAME
+is the answer itself.
+
+Details and implementation hints can be found in [RFC-1035].
+
+6. A SCENARIO
+
+In our sample domain space, suppose we wanted separate administrative
+control for the root, MIL, EDU, MIT.EDU and ISI.EDU zones. We might
+allocate name servers as follows:
+
+
+ |(C.ISI.EDU,SRI-NIC.ARPA
+ | A.ISI.EDU)
+ +---------------------+------------------+
+ | | |
+ MIL EDU ARPA
+ |(SRI-NIC.ARPA, |(SRI-NIC.ARPA, |
+ | A.ISI.EDU | C.ISI.EDU) |
+ +-----+-----+ | +------+-----+-----+
+ | | | | | | |
+ BRL NOSC DARPA | IN-ADDR SRI-NIC ACC
+ |
+ +--------+------------------+---------------+--------+
+ | | | | |
+ UCI MIT | UDEL YALE
+ |(XX.LCS.MIT.EDU, ISI
+ |ACHILLES.MIT.EDU) |(VAXA.ISI.EDU,VENERA.ISI.EDU,
+ +---+---+ | A.ISI.EDU)
+ | | |
+ LCS ACHILLES +--+-----+-----+--------+
+ | | | | | |
+ XX A C VAXA VENERA Mockapetris
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+In this example, the authoritative name server is shown in parentheses
+at the point in the domain tree at which is assumes control.
+
+Thus the root name servers are on C.ISI.EDU, SRI-NIC.ARPA, and
+A.ISI.EDU. The MIL domain is served by SRI-NIC.ARPA and A.ISI.EDU. The
+EDU domain is served by SRI-NIC.ARPA. and C.ISI.EDU. Note that servers
+may have zones which are contiguous or disjoint. In this scenario,
+C.ISI.EDU has contiguous zones at the root and EDU domains. A.ISI.EDU
+has contiguous zones at the root and MIL domains, but also has a non-
+contiguous zone at ISI.EDU.
+
+6.1. C.ISI.EDU name server
+
+C.ISI.EDU is a name server for the root, MIL, and EDU domains of the IN
+class, and would have zones for these domains. The zone data for the
+root domain might be:
+
+ . IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+ 870611 ;serial
+ 1800 ;refresh every 30 min
+ 300 ;retry every 5 min
+ 604800 ;expire after a week
+ 86400) ;minimum of a day
+ NS A.ISI.EDU.
+ NS C.ISI.EDU.
+ NS SRI-NIC.ARPA.
+
+ MIL. 86400 NS SRI-NIC.ARPA.
+ 86400 NS A.ISI.EDU.
+
+ EDU. 86400 NS SRI-NIC.ARPA.
+ 86400 NS C.ISI.EDU.
+
+ SRI-NIC.ARPA. A 26.0.0.73
+ A 10.0.0.51
+ MX 0 SRI-NIC.ARPA.
+ HINFO DEC-2060 TOPS20
+
+ ACC.ARPA. A 26.6.0.65
+ HINFO PDP-11/70 UNIX
+ MX 10 ACC.ARPA.
+
+ USC-ISIC.ARPA. CNAME C.ISI.EDU.
+
+ 73.0.0.26.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+ 65.0.6.26.IN-ADDR.ARPA. PTR ACC.ARPA.
+ 51.0.0.10.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+ 52.0.0.10.IN-ADDR.ARPA. PTR C.ISI.EDU.
+
+
+
+Mockapetris [Page 37]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+
+ A.ISI.EDU. 86400 A 26.3.0.103
+ C.ISI.EDU. 86400 A 10.0.0.52
+
+This data is represented as it would be in a master file. Most RRs are
+single line entries; the sole exception here is the SOA RR, which uses
+"(" to start a multi-line RR and ")" to show the end of a multi-line RR.
+Since the class of all RRs in a zone must be the same, only the first RR
+in a zone need specify the class. When a name server loads a zone, it
+forces the TTL of all authoritative RRs to be at least the MINIMUM field
+of the SOA, here 86400 seconds, or one day. The NS RRs marking
+delegation of the MIL and EDU domains, together with the glue RRs for
+the servers host addresses, are not part of the authoritative data in
+the zone, and hence have explicit TTLs.
+
+Four RRs are attached to the root node: the SOA which describes the root
+zone and the 3 NS RRs which list the name servers for the root. The
+data in the SOA RR describes the management of the zone. The zone data
+is maintained on host SRI-NIC.ARPA, and the responsible party for the
+zone is HOSTMASTER@SRI-NIC.ARPA. A key item in the SOA is the 86400
+second minimum TTL, which means that all authoritative data in the zone
+has at least that TTL, although higher values may be explicitly
+specified.
+
+The NS RRs for the MIL and EDU domains mark the boundary between the
+root zone and the MIL and EDU zones. Note that in this example, the
+lower zones happen to be supported by name servers which also support
+the root zone.
+
+The master file for the EDU zone might be stated relative to the origin
+EDU. The zone data for the EDU domain might be:
+
+ EDU. IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+ 870729 ;serial
+ 1800 ;refresh every 30 minutes
+ 300 ;retry every 5 minutes
+ 604800 ;expire after a week
+ 86400 ;minimum of a day
+ )
+ NS SRI-NIC.ARPA.
+ NS C.ISI.EDU.
+
+ UCI 172800 NS ICS.UCI
+ 172800 NS ROME.UCI
+ ICS.UCI 172800 A 192.5.19.1
+ ROME.UCI 172800 A 192.5.19.31
+
+
+
+
+Mockapetris [Page 38]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ ISI 172800 NS VAXA.ISI
+ 172800 NS A.ISI
+ 172800 NS VENERA.ISI.EDU.
+ VAXA.ISI 172800 A 10.2.0.27
+ 172800 A 128.9.0.33
+ VENERA.ISI.EDU. 172800 A 10.1.0.52
+ 172800 A 128.9.0.32
+ A.ISI 172800 A 26.3.0.103
+
+ UDEL.EDU. 172800 NS LOUIE.UDEL.EDU.
+ 172800 NS UMN-REI-UC.ARPA.
+ LOUIE.UDEL.EDU. 172800 A 10.0.0.96
+ 172800 A 192.5.39.3
+
+ YALE.EDU. 172800 NS YALE.ARPA.
+ YALE.EDU. 172800 NS YALE-BULLDOG.ARPA.
+
+ MIT.EDU. 43200 NS XX.LCS.MIT.EDU.
+ 43200 NS ACHILLES.MIT.EDU.
+ XX.LCS.MIT.EDU. 43200 A 10.0.0.44
+ ACHILLES.MIT.EDU. 43200 A 18.72.0.8
+
+Note the use of relative names here. The owner name for the ISI.EDU. is
+stated using a relative name, as are two of the name server RR contents.
+Relative and absolute domain names may be freely intermixed in a master
+
+6.2. Example standard queries
+
+The following queries and responses illustrate name server behavior.
+Unless otherwise noted, the queries do not have recursion desired (RD)
+in the header. Note that the answers to non-recursive queries do depend
+on the server being asked, but do not depend on the identity of the
+requester.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 39]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.1. QNAME=SRI-NIC.ARPA, QTYPE=A
+
+The query would look like:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The response from C.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | 86400 IN A 10.0.0.51 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The header of the response looks like the header of the query, except
+that the RESPONSE bit is set, indicating that this message is a
+response, not a query, and the Authoritative Answer (AA) bit is set
+indicating that the address RRs in the answer section are from
+authoritative data. The question section of the response matches the
+question section of the query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 40]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+If the same query was sent to some other server which was not
+authoritative for SRI-NIC.ARPA, the response might be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY,RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 1777 IN A 10.0.0.51 |
+ | 1777 IN A 26.0.0.73 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+This response is different from the previous one in two ways: the header
+does not have AA set, and the TTLs are different. The inference is that
+the data did not come from a zone, but from a cache. The difference
+between the authoritative TTL and the TTL here is due to aging of the
+data in a cache. The difference in ordering of the RRs in the answer
+section is not significant.
+
+6.2.2. QNAME=SRI-NIC.ARPA, QTYPE=*
+
+A query similar to the previous one, but using a QTYPE of *, would
+receive the following response from C.ISI.EDU:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ | MX 0 SRI-NIC.ARPA. |
+ | HINFO DEC-2060 TOPS20 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+If a similar query was directed to two name servers which are not
+authoritative for SRI-NIC.ARPA, the responses might be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 12345 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+and
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 1290 IN HINFO DEC-2060 TOPS20 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Neither of these answers have AA set, so neither response comes from
+authoritative data. The different contents and different TTLs suggest
+that the two servers cached data at different times, and that the first
+server cached the response to a QTYPE=A query and the second cached the
+response to a HINFO query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.3. QNAME=SRI-NIC.ARPA, QTYPE=MX
+
+This type of query might be result from a mailer trying to look up
+routing information for the mail destination HOSTMASTER@SRI-NIC.ARPA.
+The response from C.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN MX 0 SRI-NIC.ARPA.|
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+
+This response contains the MX RR in the answer section of the response.
+The additional section contains the address RRs because the name server
+at C.ISI.EDU guesses that the requester will need the addresses in order
+to properly use the information carried by the MX.
+
+6.2.4. QNAME=SRI-NIC.ARPA, QTYPE=NS
+
+C.ISI.EDU would reply to this query with:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=NS |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The only difference between the response and the query is the AA and
+RESPONSE bits in the header. The interpretation of this response is
+that the server is authoritative for the name, and the name exists, but
+no RRs of type NS are present there.
+
+6.2.5. QNAME=SIR-NIC.ARPA, QTYPE=A
+
+If a user mistyped a host name, we might see this type of query.
+
+
+
+Mockapetris [Page 43]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+C.ISI.EDU would answer it with:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA, RCODE=NE |
+ +---------------------------------------------------+
+ Question | QNAME=SIR-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | . SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. |
+ | 870611 1800 300 604800 86400 |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+This response states that the name does not exist. This condition is
+signalled in the response code (RCODE) section of the header.
+
+The SOA RR in the authority section is the optional negative caching
+information which allows the resolver using this response to assume that
+the name will not exist for the SOA MINIMUM (86400) seconds.
+
+6.2.6. QNAME=BRL.MIL, QTYPE=A
+
+If this query is sent to C.ISI.EDU, the reply would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=BRL.MIL, QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | MIL. 86400 IN NS SRI-NIC.ARPA. |
+ | 86400 NS A.ISI.EDU. |
+ +---------------------------------------------------+
+ Additional | A.ISI.EDU. A 26.3.0.103 |
+ | SRI-NIC.ARPA. A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+
+This response has an empty answer section, but is not authoritative, so
+it is a referral. The name server on C.ISI.EDU, realizing that it is
+not authoritative for the MIL domain, has referred the requester to
+servers on A.ISI.EDU and SRI-NIC.ARPA, which it knows are authoritative
+for the MIL domain.
+
+
+
+
+
+Mockapetris [Page 44]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.7. QNAME=USC-ISIC.ARPA, QTYPE=A
+
+The response to this query from A.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ | C.ISI.EDU. 86400 IN A 10.0.0.52 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Note that the AA bit in the header guarantees that the data matching
+QNAME is authoritative, but does not say anything about whether the data
+for C.ISI.EDU is authoritative. This complete reply is possible because
+A.ISI.EDU happens to be authoritative for both the ARPA domain where
+USC-ISIC.ARPA is found and the ISI.EDU domain where C.ISI.EDU data is
+found.
+
+If the same query was sent to C.ISI.EDU, its response might be the same
+as shown above if it had its own address in its cache, but might also
+be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | ISI.EDU. 172800 IN NS VAXA.ISI.EDU. |
+ | NS A.ISI.EDU. |
+ | NS VENERA.ISI.EDU. |
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ | A.ISI.EDU. 172800 A 26.3.0.103 |
+ +---------------------------------------------------+
+
+This reply contains an authoritative reply for the alias USC-ISIC.ARPA,
+plus a referral to the name servers for ISI.EDU. This sort of reply
+isn't very likely given that the query is for the host name of the name
+server being asked, but would be common for other aliases.
+
+6.2.8. QNAME=USC-ISIC.ARPA, QTYPE=CNAME
+
+If this query is sent to either A.ISI.EDU or C.ISI.EDU, the reply would
+be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Because QTYPE=CNAME, the CNAME RR itself answers the query, and the name
+server doesn't attempt to look up anything for C.ISI.EDU. (Except
+possibly for the additional section.)
+
+6.3. Example resolution
+
+The following examples illustrate the operations a resolver must perform
+for its client. We assume that the resolver is starting without a
+
+
+
+Mockapetris [Page 46]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+cache, as might be the case after system boot. We further assume that
+the system is not one of the hosts in the data and that the host is
+located somewhere on net 26, and that its safety belt (SBELT) data
+structure has the following information:
+
+ Match count = -1
+ SRI-NIC.ARPA. 26.0.0.73 10.0.0.51
+ A.ISI.EDU. 26.3.0.103
+
+This information specifies servers to try, their addresses, and a match
+count of -1, which says that the servers aren't very close to the
+target. Note that the -1 isn't supposed to be an accurate closeness
+measure, just a value so that later stages of the algorithm will work.
+
+The following examples illustrate the use of a cache, so each example
+assumes that previous requests have completed.
+
+6.3.1. Resolve MX for ISI.EDU.
+
+Suppose the first request to the resolver comes from the local mailer,
+which has mail for PVM@ISI.EDU. The mailer might then ask for type MX
+RRs for the domain name ISI.EDU.
+
+The resolver would look in its cache for MX RRs at ISI.EDU, but the
+empty cache wouldn't be helpful. The resolver would recognize that it
+needed to query foreign servers and try to determine the best servers to
+query. This search would look for NS RRs for the domains ISI.EDU, EDU,
+and the root. These searches of the cache would also fail. As a last
+resort, the resolver would use the information from the SBELT, copying
+it into its SLIST structure.
+
+At this point the resolver would need to pick one of the three available
+addresses to try. Given that the resolver is on net 26, it should
+choose either 26.0.0.73 or 26.3.0.103 as its first choice. It would
+then send off a query of the form:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The resolver would then wait for a response to its query or a timeout.
+If the timeout occurs, it would try different servers, then different
+addresses of the same servers, lastly retrying addresses already tried.
+It might eventually receive a reply from SRI-NIC.ARPA:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | ISI.EDU. 172800 IN NS VAXA.ISI.EDU. |
+ | NS A.ISI.EDU. |
+ | NS VENERA.ISI.EDU.|
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ | A.ISI.EDU. 172800 A 26.3.0.103 |
+ +---------------------------------------------------+
+
+The resolver would notice that the information in the response gave a
+closer delegation to ISI.EDU than its existing SLIST (since it matches
+three labels). The resolver would then cache the information in this
+response and use it to set up a new SLIST:
+
+ Match count = 3
+ A.ISI.EDU. 26.3.0.103
+ VAXA.ISI.EDU. 10.2.0.27 128.9.0.33
+ VENERA.ISI.EDU. 10.1.0.52 128.9.0.32
+
+A.ISI.EDU appears on this list as well as the previous one, but that is
+purely coincidental. The resolver would again start transmitting and
+waiting for responses. Eventually it would get an answer:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | ISI.EDU. MX 10 VENERA.ISI.EDU. |
+ | MX 20 VAXA.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ +---------------------------------------------------+
+
+The resolver would add this information to its cache, and return the MX
+RRs to its client.
+
+6.3.2. Get the host name for address 26.6.0.65
+
+The resolver would translate this into a request for PTR RRs for
+65.0.6.26.IN-ADDR.ARPA. This information is not in the cache, so the
+resolver would look for foreign servers to ask. No servers would match,
+so it would use SBELT again. (Note that the servers for the ISI.EDU
+domain are in the cache, but ISI.EDU is not an ancestor of
+65.0.6.26.IN-ADDR.ARPA, so the SBELT is used.)
+
+Since this request is within the authoritative data of both servers in
+SBELT, eventually one would return:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 49]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR |
+ +---------------------------------------------------+
+ Answer | 65.0.6.26.IN-ADDR.ARPA. PTR ACC.ARPA. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+6.3.3. Get the host address of poneria.ISI.EDU
+
+This request would translate into a type A request for poneria.ISI.EDU.
+The resolver would not find any cached data for this name, but would
+find the NS RRs in the cache for ISI.EDU when it looks for foreign
+servers to ask. Using this data, it would construct a SLIST of the
+form:
+
+ Match count = 3
+
+ A.ISI.EDU. 26.3.0.103
+ VAXA.ISI.EDU. 10.2.0.27 128.9.0.33
+ VENERA.ISI.EDU. 10.1.0.52
+
+A.ISI.EDU is listed first on the assumption that the resolver orders its
+choices by preference, and A.ISI.EDU is on the same network.
+
+One of these servers would answer the query.
+
+7. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] Dyer, S., and F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+
+
+
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[Quarterman 86] Quarterman, J., and J. Hoskins, "Notable Computer
+ Networks",Communications of the ACM, October 1986,
+ volume 29, number 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them. Now obsolete.
+
+
+
+
+
+Mockapetris [Page 52]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. K. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. K. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+Index
+
+ A 12
+ Absolute names 8
+ Aliases 14, 31
+ Authority 6
+ AXFR 17
+
+ Case of characters 7
+ CH 12
+ CNAME 12, 13, 31
+ Completion queries 18
+
+ Domain name 6, 7
+
+ Glue RRs 20
+
+ HINFO 12
+
+ IN 12
+ Inverse queries 16
+ Iterative 4
+
+ Label 7
+
+ Mailbox names 9
+ MX 12
+
+ Name error 27, 36
+ Name servers 5, 17
+ NE 30
+ Negative caching 44
+ NS 12
+
+ Opcode 16
+
+ PTR 12
+
+ QCLASS 16
+ QTYPE 16
+
+ RDATA 13
+ Recursive 4
+ Recursive service 22
+ Relative names 7
+ Resolvers 6
+ RR 12
+
+
+
+
+Mockapetris [Page 54]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ Safety belt 33
+ Sections 16
+ SOA 12
+ Standard queries 22
+
+ Status queries 18
+ Stub resolvers 32
+
+ TTL 12, 13
+
+ Wildcards 25
+
+ Zone transfers 28
+ Zones 19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
diff --git a/usr.sbin/named/doc/rfc1035.lpr b/usr.sbin/named/doc/rfc1035.lpr
new file mode 100644
index 00000000000..b1a9bf5a94b
--- /dev/null
+++ b/usr.sbin/named/doc/rfc1035.lpr
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1035 ISI
+ November 1987
+Obsoletes: RFCs 882, 883, 973
+
+ DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental. Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol. The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses). Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+ Table of Contents
+
+ 1. STATUS OF THIS MEMO 1
+ 2. INTRODUCTION 3
+ 2.1. Overview 3
+ 2.2. Common configurations 4
+ 2.3. Conventions 7
+ 2.3.1. Preferred name syntax 7
+ 2.3.2. Data Transmission Order 8
+ 2.3.3. Character Case 9
+ 2.3.4. Size limits 10
+ 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10
+ 3.1. Name space definitions 10
+ 3.2. RR definitions 11
+ 3.2.1. Format 11
+ 3.2.2. TYPE values 12
+ 3.2.3. QTYPE values 12
+ 3.2.4. CLASS values 13
+
+
+
+Mockapetris [Page 1]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 3.2.5. QCLASS values 13
+ 3.3. Standard RRs 13
+ 3.3.1. CNAME RDATA format 14
+ 3.3.2. HINFO RDATA format 14
+ 3.3.3. MB RDATA format (EXPERIMENTAL) 14
+ 3.3.4. MD RDATA format (Obsolete) 15
+ 3.3.5. MF RDATA format (Obsolete) 15
+ 3.3.6. MG RDATA format (EXPERIMENTAL) 16
+ 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16
+ 3.3.8. MR RDATA format (EXPERIMENTAL) 17
+ 3.3.9. MX RDATA format 17
+ 3.3.10. NULL RDATA format (EXPERIMENTAL) 17
+ 3.3.11. NS RDATA format 18
+ 3.3.12. PTR RDATA format 18
+ 3.3.13. SOA RDATA format 19
+ 3.3.14. TXT RDATA format 20
+ 3.4. ARPA Internet specific RRs 20
+ 3.4.1. A RDATA format 20
+ 3.4.2. WKS RDATA format 21
+ 3.5. IN-ADDR.ARPA domain 22
+ 3.6. Defining new types, classes, and special namespaces 24
+ 4. MESSAGES 25
+ 4.1. Format 25
+ 4.1.1. Header section format 26
+ 4.1.2. Question section format 28
+ 4.1.3. Resource record format 29
+ 4.1.4. Message compression 30
+ 4.2. Transport 32
+ 4.2.1. UDP usage 32
+ 4.2.2. TCP usage 32
+ 5. MASTER FILES 33
+ 5.1. Format 33
+ 5.2. Use of master files to define zones 35
+ 5.3. Master file example 36
+ 6. NAME SERVER IMPLEMENTATION 37
+ 6.1. Architecture 37
+ 6.1.1. Control 37
+ 6.1.2. Database 37
+ 6.1.3. Time 39
+ 6.2. Standard query processing 39
+ 6.3. Zone refresh and reload processing 39
+ 6.4. Inverse queries (Optional) 40
+ 6.4.1. The contents of inverse queries and responses 40
+ 6.4.2. Inverse query and response example 41
+ 6.4.3. Inverse query processing 42
+
+
+
+
+
+
+Mockapetris [Page 2]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 6.5. Completion queries and responses 42
+ 7. RESOLVER IMPLEMENTATION 43
+ 7.1. Transforming a user request into a query 43
+ 7.2. Sending the queries 44
+ 7.3. Processing responses 46
+ 7.4. Using the cache 47
+ 8. MAIL SUPPORT 47
+ 8.1. Mail exchange binding 48
+ 8.2. Mailbox binding (Experimental) 48
+ 9. REFERENCES and BIBLIOGRAPHY 50
+ Index 54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name. Thus a user might ask for the host address or
+mail information associated with a particular domain name. To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name. To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers. Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers. The
+resolver starts with knowledge of at least one name server. When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server. Using these
+referrals, resolvers learn the identities and contents of other name
+servers. Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data. The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space. This data is called
+authoritative. A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris [Page 3]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+from master files stored locally or in another name server. The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed. Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions. The simplest, and
+perhaps most typical, configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | cache | |
+ +----------+ |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system. User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system. Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time. The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris [Page 4]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host. A simple configuration might be:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server. Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS. This configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed. The messages sent for
+
+
+
+Mockapetris [Page 5]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | Shared | |
+ | database | |
+ +----------+ |
+ A | |
+ +---------+ refreshes | | references |
+ / /| | V |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+The shared database holds domain space data for the local name server
+and resolver. The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests. The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris [Page 6]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities. Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required. This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio. In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+ Local Hosts | Foreign
+ |
+ +---------+ |
+ | | responses |
+ | Stub |<--------------------+ |
+ | Resolver| | |
+ | |----------------+ | |
+ +---------+ recursive | | |
+ queries | | |
+ V | |
+ +---------+ recursive +----------+ | +--------+
+ | | queries | |queries | | |
+ | Stub |-------------->| Recursive|---------|->|Foreign |
+ | Resolver| | Server | | | Name |
+ | |<--------------| |<--------|--| Server |
+ +---------+ responses | |responses| | |
+ +----------+ | +--------+
+ | Central | |
+ | cache | |
+ +----------+ |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues. While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris [Page 7]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level. Whenever a diagram shows a
+
+
+
+Mockapetris [Page 8]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English. For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+ 0 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | 2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | 4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 5 | 6 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit. That is, the bit
+labeled 0 is the most significant bit. For example, the following
+diagram represents the value 170 (decimal).
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |1 0 1 0 1 0 1 0|
+ +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit. When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner. At present, this rule is in
+force throughout the domain system without exception. However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible. In certain circumstances this cannot be
+done. For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved. The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris [Page 9]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Loss of case sensitive data must be minimized. Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X. In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive. The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits. They are
+listed below. Some could be easily changed, others are more
+fundamental.
+
+labels 63 octets or less
+
+names 255 octets or less
+
+TTL positive values of a signed 32 bit number.
+
+UDP messages 512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets. Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero. The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions. Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity. Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris [Page 10]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+
+
+Mockapetris [Page 11]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records. Note that these types are a
+subset of QTYPEs.
+
+TYPE value and meaning
+
+A 1 a host address
+
+NS 2 an authoritative name server
+
+MD 3 a mail destination (Obsolete - use MX)
+
+MF 4 a mail forwarder (Obsolete - use MX)
+
+CNAME 5 the canonical name for an alias
+
+SOA 6 marks the start of a zone of authority
+
+MB 7 a mailbox domain name (EXPERIMENTAL)
+
+MG 8 a mail group member (EXPERIMENTAL)
+
+MR 9 a mail rename domain name (EXPERIMENTAL)
+
+NULL 10 a null RR (EXPERIMENTAL)
+
+WKS 11 a well known service description
+
+PTR 12 a domain name pointer
+
+HINFO 13 host information
+
+MINFO 14 mailbox or mail list information
+
+MX 15 mail exchange
+
+TXT 16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query. QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris [Page 12]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+AXFR 252 A request for a transfer of an entire zone
+
+MAILB 253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA 254 A request for mail agent RRs (Obsolete - see MX)
+
+* 255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records. The following CLASS mnemonics
+and values are defined:
+
+IN 1 the Internet
+
+CS 2 the CSNET class (Obsolete - used only for examples in
+ some obsolete RFCs)
+
+CH 3 the CHAOS class
+
+HS 4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query. QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS. In
+addition to CLASS values, the following QCLASSes are defined:
+
+* 255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes. In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length. <character-string> is a single
+length octet followed by that number of characters. <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.1. CNAME RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME A <domain-name> which specifies the canonical or primary
+ name for the owner. The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases. See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CPU /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / OS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU A <character-string> which specifies the CPU type.
+
+OS A <character-string> which specifies the operating
+ system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host. The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has the
+ specified mailbox.
+
+
+
+Mockapetris [Page 14]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which should be able to deliver
+ mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete. See the definition of MX and [RFC-974] for details of
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which will accept mail for
+ forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete. See the definition of MX and [RFC-974] for details ofw
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris [Page 15]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MGMNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME A <domain-name> which specifies a mailbox which is a
+ member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX A <domain-name> which specifies a mailbox which is
+ responsible for the mailing list or mailbox. If this
+ domain name names the root, the owner of the MINFO RR is
+ responsible for itself. Note that many existing mailing
+ lists use a mailbox X-request for the RMAILBX field of
+ mailing list X, e.g., Msgroup-request for Msgroup. This
+ field provides a more general mechanism.
+
+
+EMAILBX A <domain-name> which specifies a mailbox which is to
+ receive error messages related to the mailing list or
+ mailbox specified by the owner of the MINFO RR (similar
+ to the ERRORS-TO: field which has been proposed). If
+ this domain name names the root, errors should be
+ returned to the sender of the message.
+
+MINFO records cause no additional section processing. Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NEWNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME A <domain-name> which specifies a mailbox which is the
+ proper rename of the specified mailbox.
+
+MR records cause no additional section processing. The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE A 16 bit integer which specifies the preference given to
+ this RR among others at the same owner. Lower values
+ are preferred.
+
+EXCHANGE A <domain-name> which specifies a host willing to act as
+ a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE. The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / <anything> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris [Page 17]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+NULL records cause no additional section processing. NULL RRs are not
+allowed in master files. NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME A <domain-name> which specifies a host which should be
+ authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class. Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint. For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME A <domain-name> which points to some location in the
+ domain name space.
+
+PTR records cause no additional section processing. These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases. See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris [Page 18]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.13. SOA RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME The <domain-name> of the name server that was the
+ original or primary source of data for this zone.
+
+RNAME A <domain-name> which specifies the mailbox of the
+ person responsible for this zone.
+
+SERIAL The unsigned 32 bit version number of the original copy
+ of the zone. Zone transfers preserve this value. This
+ value wraps and should be compared using sequence space
+ arithmetic.
+
+REFRESH A 32 bit time interval before the zone should be
+ refreshed.
+
+RETRY A 32 bit time interval that should elapse before a
+ failed refresh should be retried.
+
+EXPIRE A 32 bit time value that specifies the upper limit on
+ the time interval that can elapse before the zone is no
+ longer authoritative.
+
+
+
+
+
+Mockapetris [Page 19]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MINIMUM The unsigned 32 bit minimum TTL field that should be
+ exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations. However, MINIMUM is used in all query operations that
+retrieve RRs from a zone. Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone. Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer. The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text. The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris [Page 20]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+A records cause no additional section processing. The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any imbedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PROTOCOL | |
+ +--+--+--+--+--+--+--+--+ |
+ | |
+ / <BIT MAP> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS An 32 bit Internet address
+
+PROTOCOL An 8 bit IP protocol number
+
+<BIT MAP> A variable length bit map. The bit map must be a
+ multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address. The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol. The first bit corresponds to port 0,
+the second to port 1, etc. If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero. The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP. If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping. Other classes may employ a similar
+strategy in other domains. The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix. Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified. Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA. The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space. For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET. Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets. Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network. Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it. Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris [Page 22]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU. Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 22.0.2.10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 103.0.0.26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 77.0.0.10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 4.0.10.18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA. It
+would receive two RRs in response:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+ - Since the IN-ADDR.ARPA special domain and the normal domain
+ for a particular host or gateway will be in different zones,
+ the possibility exists that that the data may be inconsistent.
+
+ - Gateways will often have two names in separate domains, only
+ one of which can be primary.
+
+ - Systems that use the domain database to initialize their
+ routing tables must start with enough gateway information to
+ guarantee that they can access the appropriate name server.
+
+ - The gateway data only reflects the existence of a gateway in a
+ manner equivalent to the current HOSTS.TXT file. It doesn't
+ replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris [Page 23]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo. New definitions should be expected. This section
+makes some recommendations to designers considering additions to the
+existing facilities. The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object. Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information. New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR. This is less efficient for most applications, but does keep
+RRs shorter. The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency. Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address. This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used. This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF). The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both). The redesigned
+
+
+
+Mockapetris [Page 24]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs. However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message. The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+
+The header section is always present. The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries. The question section contains fields that describe a
+question to a name server. These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME). The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs). The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 25]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+
+
+Mockapetris [Page 26]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+
+
+Mockapetris [Page 27]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked. The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+QTYPE a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.
+
+
+
+Mockapetris [Page 28]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+QCLASS a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME a domain name to which this resource record pertains.
+
+TYPE two octets containing one of the RR type codes. This
+ field specifies the meaning of the data in the RDATA
+ field.
+
+CLASS two octets which specify the class of the data in the
+ RDATA field.
+
+TTL a 32 bit unsigned integer that specifies the time
+ interval (in seconds) that the resource record may be
+ cached before it should be discarded. Zero values are
+ interpreted to mean that the RR can only be used for the
+ transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris [Page 29]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ For example, the if the TYPE is A and the CLASS is IN,
+ the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message. In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurance
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones. This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less. (The 10 and 01 combinations
+are reserved for future use.) The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header). A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+ - a sequence of labels ending in a zero octet
+
+ - a pointer
+
+ - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurances of a domain name where the
+format is not class specific. If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris [Page 30]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
+message, these domain names might be represented as:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 20 | 1 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 22 | 3 | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 24 | S | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 26 | 4 | A |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 28 | R | P |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 30 | A | 0 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 40 | 3 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 42 | O | O |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 44 | 1 1| 20 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 64 | 1 1| 26 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 92 | 0 | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20. The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA. The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20. The root domain name is
+
+
+
+Mockapetris [Page 31]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit. While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance. Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers). Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet. Queries sent using UDP may be
+lost, and hence a retransmission strategy is required. Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+ - The client should try other servers and server addresses
+ before repeating a query to a specific address of a server.
+
+ - The retransmission interval should be based on prior
+ statistics if possible. Too aggressive retransmission can
+ easily slow responses for the community at large. Depending
+ on how well connected the client is to its expected servers,
+ the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal). The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris [Page 32]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+length, excluding the two byte length field. This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+ - The server should not block other activities waiting for TCP
+ data.
+
+ - The server should support multiple connections.
+
+ - The server should assume that the client will initiate
+ connection closing, and should delay closing its end of the
+ connection until all outstanding client requests have been
+ satisfied.
+
+ - If the server needs to close a dormant connection to reclaim
+ resources, it should wait until the connection has been idle
+ for a period on the order of two minutes. In particular, the
+ server should allow the SOA and AXFR request sequence (which
+ begins a refresh operation) to be made on a single connection.
+ Since the server would be unable to answer queries anyway, a
+ unilateral close or reset may be used instead of a graceful
+ close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form. Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents. Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries. Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text. Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry. The end of
+any line in the master file can end with a comment. The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+ <blank>[<comment>]
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ $ORIGIN <domain-name> [<comment>]
+
+ $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+ <domain-name><rr> [<comment>]
+
+ <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE. $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name. $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file. $INCLUDE may also
+have a comment. Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs. If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner. If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+ [<TTL>] [<class>] <type> <RDATA>
+
+ [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class. Class and type use the
+standard mnemonics, TTL is a decimal integer. Omitted class and TTL
+values are default to the last explicitly stated values. Since type and
+class mnemonics are disjoint, the parse is unique. (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots. Quoting conventions allow arbitrary characters to be
+stored in domain names. Domain names that end in a dot are called
+absolute, and are taken as complete. Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine. A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris [Page 34]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ". Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded. In particular:
+
+ of the root.
+
+@ A free standing @ is used to denote the current origin.
+
+\X where X is any character other than a digit (0-9), is
+ used to quote that character so that its special meaning
+ does not apply. For example, "\." can be used to place
+ a dot character in a label.
+
+\DDD where each D is a digit is the octet corresponding to
+ the decimal number described by DDD. The resulting
+ octet is assumed to be text and is not checked for
+ special meaning.
+
+( ) Parentheses are used to group data that crosses a line
+ boundary. In effect, line terminations are not
+ recognized within parentheses.
+
+; Semicolon is used to start a comment; the remainder of
+ the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file. The
+rationale for this is that a single error can have widespread
+consequences. For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+ 1. All RRs in the file should have the same class.
+
+ 2. Exactly one SOA RR should be present at the top of the zone.
+
+ 3. If delegations are present and glue information is required,
+ it should be present.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 4. Information present outside of the authoritative nodes in the
+ zone should be glue information, rather than the result of an
+ origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@ IN SOA VENERA Action\.domains (
+ 20 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 3600000; EXPIRE
+ 60) ; MINIMUM
+
+ NS A.ISI.EDU.
+ NS VENERA
+ NS VAXA
+ MX 10 VENERA
+ MX 20 VAXA
+
+A A 26.3.0.103
+
+VENERA A 10.1.0.52
+ A 128.9.0.32
+
+VAXA A 10.2.0.27
+ A 128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+ MOE MB A.ISI.EDU.
+ LARRY MB A.ISI.EDU.
+ CURLEY MB A.ISI.EDU.
+ STOOGES MG MOE
+ MG LARRY
+ MG CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains@E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver. This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program. It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities. Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates. A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+ - A "catalog" data structure which lists the zones available to
+ this server, and a "pointer" to the zone data structure. The
+ main purpose of this structure is to find the nearest ancestor
+ zone, if any, for arriving standard queries.
+
+ - Separate data structures for each of the zones held by the
+ name server.
+
+ - A data structure for cached data. (or perhaps separate caches
+ for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs. In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris [Page 37]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case. The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded. In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+ - The catalog structure can be an almost static structure that
+ need change only when the system administrator changes the
+ zones supported by the server. This structure can also be
+ used to store parameters used to control refreshing
+ activities.
+
+ - The individual data structures for zones allow a zone to be
+ replaced simply by changing a pointer in the catalog. Zone
+ refresh operations can build a new structure and, when
+ complete, splice it into the database via a simple pointer
+ replacement. It is very important that when a zone is
+ refreshed, queries should not use old and new data
+ simultaneously.
+
+ - With the proper search procedures, authoritative data in zones
+ will always "hide", and hence take precedence over, cached
+ data.
+
+ - Errors in zone definitions that cause overlapping zones, etc.,
+ may cause erroneous responses to queries, but problem
+ determination is simplified, and the contents of one "bad"
+ zone can't corrupt another.
+
+ - Since the cache is most frequently updated, it is most
+ vulnerable to corruption during system restarts. It can also
+ become full of expired RR data. In either case, it can easily
+ be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host. State
+information which a name server should save across system crashes
+
+
+
+Mockapetris [Page 38]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds. Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways: as
+a relative increment and as an absolute time. One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other. The RRs in zones use relative times; the refresh timers and
+cache data use absolute times. Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query. When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram. Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone. This floor function should be done when
+the data is copied into a response. This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter. In this case, the name server
+
+
+
+Mockapetris [Page 39]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible. In any case, it should never send part of one version and
+part of another. If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS. Name servers are not
+required to support any form of inverse queries. If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header. While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name. For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section. The owner name of the
+query RR and its TTL are not significant. The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS. Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete. Thus inverse queries are primarily useful for database
+management and debugging activities. Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries. Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix". However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+ 1. zero, one, or multiple domain names for the specified
+ resource as QNAMEs in the question section
+
+
+
+Mockapetris [Page 40]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 2. an error code indicating that the name server doesn't support
+ inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries. One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear. For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+ +-----------------------------------------+
+ Header | OPCODE=IQUERY, ID=997 |
+ +-----------------------------------------+
+ Question | <empty> |
+ +-----------------------------------------+
+ Answer | <anyname> A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52. Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored). A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message. The TTL of the RR is not significant. The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ +-----------------------------------------+
+ Header | OPCODE=RESPONSE, ID=997 |
+ +-----------------------------------------+
+ Question |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+ +-----------------------------------------+
+ Answer | VENERA.ISI.EDU A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query. Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique. If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases. An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone. When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted. Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034]. This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler. The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source. If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information. This state block will
+typically contain:
+
+ - A timestamp indicating the time the request began.
+ The timestamp is used to decide whether RRs in the database
+ can be used or are out of date. This timestamp uses the
+ absolute time format previously discussed for RR storage in
+ zones and caches. Note that when an RRs TTL indicates a
+ relative time, the RR must be timely, since it is part of a
+ zone. When the RR has an absolute time, it is part of a
+ cache, and the TTL of the RR is compared against the timestamp
+ for the start of the request.
+
+ Note that using the timestamp is superior to using a current
+ time, since it allows RRs with TTLs of zero to be entered in
+ the cache in the usual manner, but still used by the current
+ request, even after intervals of many seconds due to system
+ load, query retransmission timeouts, etc.
+
+ - Some sort of parameters to limit the amount of work which will
+ be performed for this request.
+
+ The amount of work which a resolver will do in response to a
+ client request must be limited to guard against errors in the
+ database, such as circular CNAME references, and operational
+ problems, such as network partition which prevents the
+
+
+
+Mockapetris [Page 43]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ resolver from accessing the name servers it needs. While
+ local limits on the number of times a resolver will retransmit
+ a particular query to a particular name server address are
+ essential, the resolver should have a global per-request
+ counter to limit work on a single request. The counter should
+ be set to some initial value and decremented whenever the
+ resolver performs any action (retransmission timeout,
+ retransmission, etc.) If the counter passes zero, the request
+ is terminated with a temporary error.
+
+ Note that if the resolver structure allows one request to
+ start others in parallel, such as when the need to access a
+ name server for one request causes a parallel resolve for the
+ name server's addresses, the spawned request should be started
+ with a lower counter. This prevents circular references in
+ the database from starting a chain reaction of resolver
+ activity.
+
+ - The SLIST data structure discussed in [RFC-1034].
+
+ This structure keeps track of the state of a request if it
+ must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information. The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information. In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated. Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions. The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive. The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris [Page 44]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about. To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate. The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST. This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request). Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address. Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses. Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses. Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried. The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+ - The resolver may encounter a situation where no addresses are
+ available for any of the name servers named in SLIST, and
+ where the servers in the list are precisely those which would
+ normally be used to look up their own addresses. This
+ situation typically occurs when the glue address RRs have a
+ smaller TTL than the NS RRs marking delegation, or when the
+ resolver caches the result of a NS search. The resolver
+ should detect this condition and restart the search at the
+ next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ - If a resolver gets a server error or other bizarre response
+ from a name server, it should remove it from SLIST, and may
+ wish to schedule an immediate transmission to the next
+ candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response. This procedure should include:
+
+ - Check the header for reasonableness. Discard datagrams which
+ are queries when responses are expected.
+
+ - Parse the sections of the message, and insure that all RRs are
+ correctly formatted.
+
+ - As an optional step, check the TTLs of arriving data looking
+ for RRs with excessively long TTLs. If a RR has an
+ excessively long TTL, say greater than 1 week, either discard
+ the whole response, or limit all TTLs in the response to 1
+ week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired. This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort. This step has several fine points:
+
+ - Some name servers send their responses from different
+ addresses than the one used to receive the query. That is, a
+ resolver cannot rely that a response will come from the same
+ address which it sent the corresponding query to. This name
+ server bug is typically encountered in UNIX systems.
+
+ - If the resolver retransmits a particular request to a name
+ server it should be able to use a response from any of the
+ transmissions. However, if it is using the response to sample
+ the round trip time to access the name server, it must be able
+ to determine which transmission matches the response (and keep
+ transmission times for each outgoing message), or only
+ calculate round trip times based on initial transmissions.
+
+ - A name server will occasionally not have a current copy of a
+ zone which it should have according to some NS RRs. The
+ resolver should simply remove the name server from the current
+ SLIST, and continue.
+
+
+
+
+Mockapetris [Page 46]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+ - When several RRs of the same type are available for a
+ particular owner name, the resolver should either cache them
+ all or none at all. When a response is truncated, and a
+ resolver doesn't know whether it has a complete set, it should
+ not cache a possibly partial set of RRs.
+
+ - Cached data should never be used in preference to
+ authoritative data, so if caching would cause this to happen
+ the data should not be cached.
+
+ - The results of an inverse query should not be cached.
+
+ - The results of standard queries where the QNAME contains "*"
+ labels if the data might be used to construct wildcards. The
+ reason is that the cache does not necessarily contain existing
+ RRs or zone boundary information which is necessary to
+ restrict the application of the wildcard RRs.
+
+ - RR data in responses of dubious reliability. When a resolver
+ receives unsolicited responses or RR data other than that
+ requested, it should discard it without caching it. The basic
+ implication is that all sanity checks on a packet should be
+ performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs. Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined. If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information. The first method is called mail exchange binding
+and the other method is mailbox binding. The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet. Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>". While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name. The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox. Thus the mailbox HOSTMASTER@SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA. If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded. For
+example, the mailbox Action.domains@ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent. The <local-part>
+is not even consulted. [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function. However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU. If a mailer had a message for Mockapetris@ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU. The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name. The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 1. The query can return a name error indicating that the mailbox
+ does not exist as a domain name.
+
+ In the long term, this would indicate that the specified
+ mailbox doesn't exist. However, until the use of mailbox
+ binding is universal, this error condition should be
+ interpreted to mean that the organization identified by the
+ global part does not support mailbox binding. The
+ appropriate procedure is to revert to exchange binding at
+ this point.
+
+ 2. The query can return a Mail Rename (MR) RR.
+
+ The MR RR carries new mailbox specification in its RDATA
+ field. The mailer should replace the old mailbox with the
+ new one and retry the operation.
+
+ 3. The query can return a MB RR.
+
+ The MB RR carries a domain name for a host in its RDATA
+ field. The mailer should deliver the message to that host
+ via whatever protocol is applicable, e.g., b,SMTP.
+
+ 4. The query can return one or more Mail Group (MG) RRs.
+
+ This condition means that the mailbox was actually a mailing
+ list or mail group, rather than a single mailbox. Each MG RR
+ has a RDATA field that identifies a mailbox that is a member
+ of the group. The mailer should deliver a copy of the
+ message to each member.
+
+ 5. The query can return a MB RR as well as one or more MG RRs.
+
+ This condition means the the mailbox was actually a mailing
+ list. The mailer can either deliver the message to the host
+ specified by the MB RR, which will in turn do the delivery to
+ all members, or the mailer can use the MG RRs to do the
+ expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR. This RR is usually associated with a mail group, but is
+legal with a MB. The MINFO RR identifies two mailboxes. One of these
+identifies a responsible person for the original mailbox name. This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures. This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris [Page 49]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] S. Dyer, F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+ Communications of the ACM, October 1986, volume 29, number
+ 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute,
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them.
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987.
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris [Page 52]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Index
+
+ * 13
+
+ ; 33, 35
+
+ <character-string> 35
+ <domain-name> 34
+
+ @ 35
+
+ \ 35
+
+ A 12
+
+ Byte order 8
+
+ CH 13
+ Character case 9
+ CLASS 11
+ CNAME 12
+ Completion 42
+ CS 13
+
+ Hesiod 13
+ HINFO 12
+ HS 13
+
+ IN 13
+ IN-ADDR.ARPA domain 22
+ Inverse queries 40
+
+ Mailbox names 47
+ MB 12
+ MD 12
+ MF 12
+ MG 12
+ MINFO 12
+ MINIMUM 20
+ MR 12
+ MX 12
+
+ NS 12
+ NULL 12
+
+ Port numbers 32
+ Primary server 5
+ PTR 12, 18
+
+
+
+Mockapetris [Page 54]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ QCLASS 13
+ QTYPE 12
+
+ RDATA 12
+ RDLENGTH 11
+
+ Secondary server 5
+ SOA 12
+ Stub resolvers 7
+
+ TCP 32
+ TXT 12
+ TYPE 11
+
+ UDP 32
+
+ WKS 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
diff --git a/usr.sbin/named/doc/rfc1101.lpr b/usr.sbin/named/doc/rfc1101.lpr
new file mode 100644
index 00000000000..66c9d8b813b
--- /dev/null
+++ b/usr.sbin/named/doc/rfc1101.lpr
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Working Group P. Mockapetris
+Request for Comments: 1101 ISI
+Updates: RFCs 1034, 1035 April 1989
+
+
+ DNS Encoding of Network Names and Other Types
+
+
+1. STATUS OF THIS MEMO
+
+ This RFC proposes two extensions to the Domain Name System:
+
+ - A specific method for entering and retrieving RRs which map
+ between network names and numbers.
+
+ - Ideas for a general method for describing mappings between
+ arbitrary identifiers and numbers.
+
+ The method for mapping between network names and addresses is a
+ proposed standard, the ideas for a general method are experimental.
+
+ This RFC assumes that the reader is familiar with the DNS [RFC 1034,
+ RFC 1035] and its use. The data shown is for pedagogical use and
+ does not necessarily reflect the real Internet.
+
+ Distribution of this memo is unlimited.
+
+2. INTRODUCTION
+
+ The DNS is extensible and can be used for a virtually unlimited
+ number of data types, name spaces, etc. New type definitions are
+ occasionally necessary as are revisions or deletions of old types
+ (e.g., MX replacement of MD and MF [RFC 974]), and changes described
+ in [RFC 973]. This RFC describes changes due to the general need to
+ map between identifiers and values, and a specific need for network
+ name support.
+
+ Users wish to be able to use the DNS to map between network names and
+ numbers. This need is the only capability found in HOSTS.TXT which
+ is not available from the DNS. In designing a method to do this,
+ there were two major areas of concern:
+
+ - Several tradeoffs involving control of network names, the
+ syntax of network names, backward compatibility, etc.
+
+ - A desire to create a method which would be sufficiently
+ general to set a good precedent for future mappings,
+ for example, between TCP-port names and numbers,
+
+
+
+Mockapetris [Page 1]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ autonomous system names and numbers, X.500 Relative
+ Distinguished Names (RDNs) and their servers, or whatever.
+
+ It was impossible to reconcile these two areas of concern for network
+ names because of the desire to unify network number support within
+ existing IP address to host name support. The existing support is
+ the IN-ADDR.ARPA section of the DNS name space. As a result this RFC
+ describes one structure for network names which builds on the
+ existing support for host names, and another family of structures for
+ future yellow pages (YP) functions such as conversions between TCP-
+ port numbers and mnemonics.
+
+ Both structures are described in following sections. Each structure
+ has a discussion of design issues and specific structure
+ recommendations.
+
+ We wish to avoid defining structures and methods which can work but
+ do not because of indifference or errors on the part of system
+ administrators when maintaining the database. The WKS RR is an
+ example. Thus, while we favor distribution as a general method, we
+ also recognize that centrally maintained tables (such as HOSTS.TXT)
+ are usually more consistent though less maintainable and timely.
+ Hence we recommend both specific methods for mapping network names,
+ addresses, and subnets, as well as an instance of the general method
+ for mapping between allocated network numbers and network names.
+ (Allocation is centrally performed by the SRI Network Information
+ Center, aka the NIC).
+
+3. NETWORK NAME ISSUES AND DISCUSSION
+
+ The issues involved in the design were the definition of network name
+ syntax, the mappings to be provided, and possible support for similar
+ functions at the subnet level.
+
+3.1. Network name syntax
+
+ The current syntax for network names, as defined by [RFC 952] is an
+ alphanumeric string of up to 24 characters, which begins with an
+ alpha, and may include "." and "-" except as first and last
+ characters. This is the format which was also used for host names
+ before the DNS. Upward compatibility with existing names might be a
+ goal of any new scheme.
+
+ However, the present syntax has been used to define a flat name
+ space, and hence would prohibit the same distributed name allocation
+ method used for host names. There is some sentiment for allowing the
+ NIC to continue to allocate and regulate network names, much as it
+ allocates numbers, but the majority opinion favors local control of
+
+
+
+Mockapetris [Page 2]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ network names. Although it would be possible to provide a flat space
+ or a name space in which, for example, the last label of a domain
+ name captured the old-style network name, any such approach would add
+ complexity to the method and create different rules for network names
+ and host names.
+
+ For these reasons, we assume that the syntax of network names will be
+ the same as the expanded syntax for host names permitted in [HR].
+ The new syntax expands the set of names to allow leading digits, so
+ long as the resulting representations do not conflict with IP
+ addresses in decimal octet form. For example, 3Com.COM and 3M.COM
+ are now legal, although 26.0.0.73.COM is not. See [HR] for details.
+
+ The price is that network names will get as complicated as host
+ names. An administrator will be able to create network names in any
+ domain under his control, and also create network number to name
+ entries in IN-ADDR.ARPA domains under his control. Thus, the name
+ for the ARPANET might become NET.ARPA, ARPANET.ARPA or Arpa-
+ network.MIL., depending on the preferences of the owner.
+
+3.2. Mappings
+
+ The desired mappings, ranked by priority with most important first,
+ are:
+
+ - Mapping a IP address or network number to a network name.
+
+ This mapping is for use in debugging tools and status displays
+ of various sorts. The conversion from IP address to network
+ number is well known for class A, B, and C IP addresses, and
+ involves a simple mask operation. The needs of other classes
+ are not yet defined and are ignored for the rest of this RFC.
+
+ - Mapping a network name to a network address.
+
+ This facility is of less obvious application, but a
+ symmetrical mapping seems desirable.
+
+ - Mapping an organization to its network names and numbers.
+
+ This facility is useful because it may not always be possible
+ to guess the local choice for network names, but the
+ organization name is often well known.
+
+ - Similar mappings for subnets, even when nested.
+
+ The primary application is to be able to identify all of the
+ subnets involved in a particular IP address. A secondary
+
+
+
+Mockapetris [Page 3]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ requirement is to retrieve address mask information.
+
+3.3. Network address section of the name space
+
+ The network name syntax discussed above can provide domain names
+ which will contain mappings from network names to various quantities,
+ but we also need a section of the name space, organized by network
+ and subnet number to hold the inverse mappings.
+
+ The choices include:
+
+ - The same network number slots already assigned and delegated
+ in the IN-ADDR.ARPA section of the name space.
+
+ For example, 10.IN-ADDR.ARPA for class A net 10,
+ 2.128.IN-ADDR.ARPA for class B net 128.2, etc.
+
+ - Host-zero addresses in the IN-ADDR.ARPA tree. (A host field
+ of all zero in an IP address is prohibited because of
+ confusion related to broadcast addresses, et al.)
+
+ For example, 0.0.0.10.IN-ADDR.ARPA for class A net 10,
+ 0.0.2.128.IN-ADDR.arpa for class B net 128.2, etc. Like the
+ first scheme, it uses in-place name space delegations to
+ distribute control.
+
+ The main advantage of this scheme over the first is that it
+ allows convenient names for subnets as well as networks. A
+ secondary advantage is that it uses names which are not in use
+ already, and hence it is possible to test whether an
+ organization has entered this information in its domain
+ database.
+
+ - Some new section of the name space.
+
+ While this option provides the most opportunities, it creates
+ a need to delegate a whole new name space. Since the IP
+ address space is so closely related to the network number
+ space, most believe that the overhead of creating such a new
+ space is overwhelming and would lead to the WKS syndrome. (As
+ of February, 1989, approximately 400 sections of the
+ IN-ADDR.ARPA tree are already delegated, usually at network
+ boundaries.)
+
+
+
+
+
+
+
+
+Mockapetris [Page 4]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+4. SPECIFICS FOR NETWORK NAME MAPPINGS
+
+ The proposed solution uses information stored at:
+
+ - Names in the IN-ADDR.ARPA tree that correspond to host-zero IP
+ addresses. The same method is used for subnets in a nested
+ fashion. For example, 0.0.0.10.IN-ADDR.ARPA. for net 10.
+
+ Two types of information are stored here: PTR RRs which point
+ to the network name in their data sections, and A RRs, which
+ are present if the network (or subnet) is subnetted further.
+ If a type A RR is present, then it has the address mask as its
+ data. The general form is:
+
+ <reversed-host-zero-number>.IN-ADDR.ARPA. PTR <network-name>
+ <reversed-host-zero-number>.IN-ADDR.ARPA. A <subnet-mask>
+
+ For example:
+
+ 0.0.0.10.IN-ADDR.ARPA. PTR ARPANET.ARPA.
+
+ or
+
+ 0.0.2.128.IN-ADDR.ARPA. PTR cmu-net.cmu.edu.
+ A 255.255.255.0
+
+ In general, this information will be added to an existing
+ master file for some IN-ADDR.ARPA domain for each network
+ involved. Similar RRs can be used at host-zero subnet
+ entries.
+
+ - Names which are network names.
+
+ The data stored here is PTR RRs pointing at the host-zero
+ entries. The general form is:
+
+ <network-name> ptr <reversed-host-zero-number>.IN-ADDR.ARPA
+
+ For example:
+
+ ARPANET.ARPA. PTR 0.0.0.10.IN-ADDR.ARPA.
+
+ or
+
+ isi-net.isi.edu. PTR 0.0.9.128.IN-ADDR.ARPA.
+
+ In general, this information will be inserted in the master
+ file for the domain name of the organization; this is a
+
+
+
+Mockapetris [Page 5]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ different file from that which holds the information below
+ IN-ADDR.ARPA. Similar PTR RRs can be used at subnet names.
+
+ - Names corresponding to organizations.
+
+ The data here is one or more PTR RRs pointing at the
+ IN-ADDR.ARPA names corresponding to host-zero entries for
+ networks.
+
+ For example:
+
+ ISI.EDU. PTR 0.0.9.128.IN-ADDR.ARPA.
+
+ MCC.COM. PTR 0.167.5.192.IN-ADDR.ARPA.
+ PTR 0.168.5.192.IN-ADDR.ARPA.
+ PTR 0.169.5.192.IN-ADDR.ARPA.
+ PTR 0.0.62.128.IN-ADDR.ARPA.
+
+4.1. A simple example
+
+ The ARPANET is a Class A network without subnets. The RRs which
+ would be added, assuming the ARPANET.ARPA was selected as a network
+ name, would be:
+
+ ARPA. PTR 0.0.0.10.IN-ADDR.ARPA.
+
+ ARPANET.ARPA. PTR 0.0.0.10.IN-ADDR.ARPA.
+
+ 0.0.0.10.IN-ADDR.ARPA. PTR ARPANET.ARPA.
+
+ The first RR states that the organization named ARPA owns net 10 (It
+ might also own more network numbers, and these would be represented
+ with an additional RR per net.) The second states that the network
+ name ARPANET.ARPA. maps to net 10. The last states that net 10 is
+ named ARPANET.ARPA.
+
+ Note that all of the usual host and corresponding IN-ADDR.ARPA
+ entries would still be required.
+
+4.2. A complicated, subnetted example
+
+ The ISI network is 128.9, a class B number. Suppose the ISI network
+ was organized into two levels of subnet, with the first level using
+ an additional 8 bits of address, and the second level using 4 bits,
+ for address masks of x'FFFFFF00' and X'FFFFFFF0'.
+
+ Then the following RRs would be entered in ISI's master file for the
+ ISI.EDU zone:
+
+
+
+Mockapetris [Page 6]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ ; Define network entry
+ isi-net.isi.edu. PTR 0.0.9.128.IN-ADDR.ARPA.
+
+ ; Define first level subnets
+ div1-subnet.isi.edu. PTR 0.1.9.128.IN-ADDR.ARPA.
+ div2-subnet.isi.edu. PTR 0.2.9.128.IN-ADDR.ARPA.
+
+ ; Define second level subnets
+ inc-subsubnet.isi.edu. PTR 16.2.9.128.IN-ADDR.ARPA.
+
+ in the 9.128.IN-ADDR.ARPA zone:
+
+ ; Define network number and address mask
+ 0.0.9.128.IN-ADDR.ARPA. PTR isi-net.isi.edu.
+ A 255.255.255.0 ;aka X'FFFFFF00'
+
+ ; Define one of the first level subnet numbers and masks
+ 0.1.9.128.IN-ADDR.ARPA. PTR div1-subnet.isi.edu.
+ A 255.255.255.240 ;aka X'FFFFFFF0'
+
+ ; Define another first level subnet number and mask
+ 0.2.9.128.IN-ADDR.ARPA. PTR div2-subnet.isi.edu.
+ A 255.255.255.240 ;aka X'FFFFFFF0'
+
+ ; Define second level subnet number
+ 16.2.9.128.IN-ADDR.ARPA. PTR inc-subsubnet.isi.edu.
+
+ This assumes that the ISI network is named isi-net.isi.edu., first
+ level subnets are named div1-subnet.isi.edu. and div2-
+ subnet.isi.edu., and a second level subnet is called inc-
+ subsubnet.isi.edu. (In a real system as complicated as this there
+ would be more first and second level subnets defined, but we have
+ shown enough to illustrate the ideas.)
+
+4.3. Procedure for using an IP address to get network name
+
+ Depending on whether the IP address is class A, B, or C, mask off the
+ high one, two, or three bytes, respectively. Reverse the octets,
+ suffix IN-ADDR.ARPA, and do a PTR query.
+
+ For example, suppose the IP address is 10.0.0.51.
+
+ 1. Since this is a class A address, use a mask x'FF000000' and
+ get 10.0.0.0.
+
+ 2. Construct the name 0.0.0.10.IN-ADDR.ARPA.
+
+ 3. Do a PTR query. Get back
+
+
+
+Mockapetris [Page 7]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ 0.0.0.10.IN-ADDR.ARPA. PTR ARPANET.ARPA.
+
+ 4. Conclude that the network name is "ARPANET.ARPA."
+
+ Suppose that the IP address is 128.9.2.17.
+
+ 1. Since this is a class B address, use a mask of x'FFFF0000'
+ and get 128.9.0.0.
+
+ 2. Construct the name 0.0.9.128.IN-ADDR.ARPA.
+
+ 3. Do a PTR query. Get back
+
+ 0.0.9.128.IN-ADDR.ARPA. PTR isi-net.isi.edu
+
+ 4. Conclude that the network name is "isi-net.isi.edu."
+
+4.4. Procedure for finding all subnets involved with an IP address
+
+ This is a simple extension of the IP address to network name method.
+ When the network entry is located, do a lookup for a possible A RR.
+ If the A RR is found, look up the next level of subnet using the
+ original IP address and the mask in the A RR. Repeat this procedure
+ until no A RR is found.
+
+ For example, repeating the use of 128.9.2.17.
+
+ 1. As before construct a query for 0.0.9.128.IN-ADDR.ARPA.
+ Retrieve:
+
+ 0.0.9.128.IN-ADDR.ARPA. PTR isi-net.isi.edu.
+ A 255.255.255.0
+
+ 2. Since an A RR was found, repeat using mask from RR
+ (255.255.255.0), constructing a query for
+ 0.2.9.128.IN-ADDR.ARPA. Retrieve:
+
+ 0.2.9.128.IN-ADDR.ARPA. PTR div2-subnet.isi.edu.
+ A 255.255.255.240
+
+ 3. Since another A RR was found, repeat using mask
+ 255.255.255.240 (x'FFFFFFF0'). constructing a query for
+ 16.2.9.128.IN-ADDR.ARPA. Retrieve:
+
+ 16.2.9.128.IN-ADDR.ARPA. PTR inc-subsubnet.isi.edu.
+
+ 4. Since no A RR is present at 16.2.9.128.IN-ADDR.ARPA., there
+ are no more subnet levels.
+
+
+
+Mockapetris [Page 8]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+5. YP ISSUES AND DISCUSSION
+
+ The term "Yellow Pages" is used in almost as many ways as the term
+ "domain", so it is useful to define what is meant herein by YP. The
+ general problem to be solved is to create a method for creating
+ mappings from one kind of identifier to another, often with an
+ inverse capability. The traditional methods are to search or use a
+ precomputed index of some kind.
+
+ Searching is impractical when the search is too large, and
+ precomputed indexes are possible only when it is possible to specify
+ search criteria in advance, and pay for the resources necessary to
+ build the index. For example, it is impractical to search the entire
+ domain tree to find a particular address RR, so we build the IN-
+ ADDR.ARPA YP. Similarly, we could never build an Internet-wide index
+ of "hosts with a load average of less than 2" in less time than it
+ would take for the data to change, so indexes are a useless approach
+ for that problem.
+
+ Such a precomputed index is what we mean by YP, and we regard the
+ IN-ADDR.ARPA domain as the first instance of a YP in the DNS.
+ Although a single, centrally-managed YP for well-known values such as
+ TCP-port is desirable, we regard organization-specific YPs for, say,
+ locally defined TCP ports as a natural extension, as are combinations
+ of YPs using search lists to merge the two.
+
+ In examining Internet Numbers [RFC 997] and Assigned Numbers [RFC
+ 1010], it is clear that there are several mappings which might be of
+ value. For example:
+
+ <assigned-network-name> <==> <IP-address>
+ <autonomous-system-id> <==> <number>
+ <protocol-id> <==> <number>
+ <port-id> <==> <number>
+ <ethernet-type> <==> <number>
+ <public-data-net> <==> <IP-address>
+
+ Following the IN-ADDR example, the YP takes the form of a domain tree
+ organized to optimize retrieval by search key and distribution via
+ normal DNS rules. The name used as a key must include:
+
+ 1. A well known origin. For example, IN-ADDR.ARPA is the
+ current IP-address to host name YP.
+
+ 2. A "from" data type. This identifies the input type of the
+ mapping. This is necessary because we may be mapping
+ something as anonymous as a number to any number of
+ mnemonics, etc.
+
+
+
+Mockapetris [Page 9]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ 3. A "to" data type. Since we assume several symmetrical
+ mnemonic <==> number mappings, this is also necessary.
+
+ This ordering reflects the natural scoping of control, and hence the
+ order of the components in a domain name. Thus domain names would be
+ of the form:
+
+ <from-value>.<to-data-type>.<from-data-type>.<YP-origin>
+
+ To make this work, we need to define well-know strings for each of
+ these metavariables, as well as encoding rules for converting a
+ <from-value> into a domain name. We might define:
+
+ <YP-origin> :=YP
+ <from-data-type>:=TCP-port | IN-ADDR | Number |
+ Assigned-network-number | Name
+ <to-data-type> :=<from-data-type>
+
+ Note that "YP" is NOT a valid country code under [ISO 3166] (although
+ we may want to worry about the future), and the existence of a
+ syntactically valid <to-data-type>.<from-data-type> pair does not
+ imply that a meaningful mapping exists, or is even possible.
+
+ The encoding rules might be:
+
+ TCP-port Six character alphanumeric
+
+ IN-ADDR Reversed 4-octet decimal string
+
+ Number decimal integer
+
+ Assigned-network-number
+ Reversed 4-octet decimal string
+
+ Name Domain name
+
+6. SPECIFICS FOR YP MAPPINGS
+
+6.1. TCP-PORT
+
+ $origin Number.TCP-port.YP.
+
+ 23 PTR TELNET.TCP-port.Number.YP.
+ 25 PTR SMTP.TCP-port.Number.YP.
+
+ $origin TCP-port.Number.YP.
+
+ TELNET PTR 23.Number.TCP-port.YP.
+
+
+
+Mockapetris [Page 10]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ SMTP PTR 25.Number.TCP-port.YP.
+
+ Thus the mapping between 23 and TELNET is represented by a pair of
+ PTR RRs, one for each direction of the mapping.
+
+6.2. Assigned networks
+
+ Network numbers are assigned by the NIC and reported in "Internet
+ Numbers" RFCs. To create a YP, the NIC would set up two domains:
+
+ Name.Assigned-network-number.YP and Assigned-network-number.YP
+
+ The first would contain entries of the form:
+
+ $origin Name.Assigned-network-number.YP.
+
+ 0.0.0.4 PTR SATNET.Assigned-network-number.Name.YP.
+ 0.0.0.10 PTR ARPANET.Assigned-network-number.Name.YP.
+
+ The second would contain entries of the form:
+
+ $origin Assigned-network-number.Name.YP.
+
+ SATNET. PTR 0.0.0.4.Name.Assigned-network-number.YP.
+ ARPANET. PTR 0.0.0.10.Name.Assigned-network-number.YP.
+
+ These YPs are not in conflict with the network name support described
+ in the first half of this RFC since they map between ASSIGNED network
+ names and numbers, not those allocated by the organizations
+ themselves. That is, they document the NIC's decisions about
+ allocating network numbers but do not automatically track any
+ renaming performed by the new owners.
+
+ As a practical matter, we might want to create both of these domains
+ to enable users on the Internet to experiment with centrally
+ maintained support as well as the distributed version, or might want
+ to implement only the allocated number to name mapping and request
+ organizations to convert their allocated network names to the network
+ names described in the distributed model.
+
+6.3. Operational improvements
+
+ We could imagine that all conversion routines using these YPs might
+ be instructed to use "YP.<local-domain>" followed by "YP." as a
+ search list. Thus, if the organization ISI.EDU wished to define
+ locally meaningful TCP-PORT, it would define the domains:
+
+ <TCP-port.Number.YP.ISI.EDU> and <Number.TCP-port.YP.ISI.EDU>.
+
+
+
+Mockapetris [Page 11]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ We could add another level of indirection in the YP lookup, defining
+ the <to-data-type>.<from-data-type>.<YP-origin> nodes to point to the
+ YP tree, rather than being the YP tree directly. This would enable
+ entries of the form:
+
+ IN-ADDR.Netname.YP. PTR IN-ADDR.ARPA.
+
+ to splice in YPs from other origins or existing spaces.
+
+ Another possibility would be to shorten the RDATA section of the RRs
+ which map back and forth by deleting the origin. This could be done
+ either by allowing the domain name in the RDATA portion to not
+ identify a real domain name, or by defining a new RR which used a
+ simple text string rather than a domain name.
+
+ Thus, we might replace
+
+ $origin Assigned-network-number.Name.YP.
+
+ SATNET. PTR 0.0.0.4.Name.Assigned-network-number.YP.
+ ARPANET. PTR 0.0.0.10.Name.Assigned-network-number.YP.
+
+ with
+
+ $origin Assigned-network-number.Name.YP.
+
+ SATNET. PTR 0.0.0.4.
+ ARPANET. PTR 0.0.0.10.
+
+ or
+
+ $origin Assigned-network-number.Name.YP.
+
+ SATNET. PTT "0.0.0.4"
+ ARPANET. PTT "0.0.0.10"
+
+ where PTT is a new type whose RDATA section is a text string.
+
+7. ACKNOWLEDGMENTS
+
+ Drew Perkins, Mark Lottor, and Rob Austein contributed several of the
+ ideas in this RFC. Numerous contributions, criticisms, and
+ compromises were produced in the IETF Domain working group and the
+ NAMEDROPPERS mailing list.
+
+
+
+
+
+
+
+Mockapetris [Page 12]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+8. REFERENCES
+
+ [HR] Braden, B., editor, "Requirements for Internet Hosts",
+ RFC in preparation.
+
+ [ISO 3166] ISO, "Codes for the Representation of Names of
+ Countries", 1981.
+
+ [RFC 882] Mockapetris, P., "Domain names - Concepts and
+ Facilities", RFC 882, USC/Information Sciences Institute,
+ November 1983.
+
+ Superseded by RFC 1034.
+
+ [RFC 883] Mockapetris, P.,"Domain names - Implementation and
+ Specification", RFC 883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by RFC 1035.
+
+ [RFC 920] Postel, J. and J. Reynolds, "Domain Requirements", RFC
+ 920, October 1984.
+
+ Explains the naming scheme for top level domains.
+
+ [RFC 952] Harrenstien, K., M. Stahl, and E. Feinler, "DoD Internet
+ Host Table Specification", RFC 952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address table
+ replaced by the DNS
+
+ [RFC 973] Mockapetris, P., "Domain System Changes and
+ Observations", RFC 973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFCs 882 and 883 and reasons for
+ them.
+
+ [RFC 974] Partridge, C., "Mail routing and the domain system", RFC
+ 974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+
+RFC 1101 DNS Encoding of Network Names and Other Types April 1989
+
+
+ [RFC 997] Reynolds, J., and J. Postel, "Internet Numbers", RFC 997,
+ USC/Information Sciences Institute, March 1987
+
+ Contains network numbers, autonomous system numbers, etc.
+
+ [RFC 1010] Reynolds, J., and J. Postel, "Assigned Numbers", RFC
+ 1010, USC/Information Sciences Institute, May 1987
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+
+ [RFC 1034] Mockapetris, P., "Domain names - Concepts and
+ Facilities", RFC 1034, USC/Information Sciences
+ Institute, November 1987.
+
+ Introduction/overview of the DNS.
+
+ [RFC 1035] Mockapetris, P., "Domain names - Implementation and
+ Specification", RFC 1035, USC/Information Sciences
+ Institute, November 1987.
+
+ DNS implementation instructions.
+
+Author's Address:
+
+ Paul Mockapetris
+ USC/Information Sciences Institute
+ 4676 Admiralty Way
+ Marina del Rey, CA 90292
+
+ Phone: (213) 822-1511
+
+ Email: PVM@ISI.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 14]
+ \ No newline at end of file
diff --git a/usr.sbin/named/doc/rfc920.lpr b/usr.sbin/named/doc/rfc920.lpr
new file mode 100644
index 00000000000..661b8301006
--- /dev/null
+++ b/usr.sbin/named/doc/rfc920.lpr
@@ -0,0 +1,798 @@
+
+
+Network Working Group J. Postel
+Request for Comments: 920 J. Reynolds
+ ISI
+ October 1984
+
+ Domain Requirements
+
+
+Status of this Memo
+
+ This memo is a policy statement on the requirements of establishing a
+ new domain in the ARPA-Internet and the DARPA research community.
+ This is an official policy statement of the IAB and the DARPA.
+ Distribution of this memo is unlimited.
+
+Introduction
+
+ This memo restates and refines the requirements on establishing a
+ Domain first described in RFC-881 [1]. It adds considerable detail
+ to that discussion, and introduces the limited set of top level
+ domains.
+
+The Purpose of Domains
+
+ Domains are administrative entities. The purpose and expected use of
+ domains is to divide the name management required of a central
+ administration and assign it to sub-administrations. There are no
+ geographical, topological, or technological constraints on a domain.
+ The hosts in a domain need not have common hardware or software, nor
+ even common protocols. Most of the requirements and limitations on
+ domains are designed to ensure responsible administration.
+
+ The domain system is a tree-structured global name space that has a
+ few top level domains. The top level domains are subdivided into
+ second level domains. The second level domains may be subdivided
+ into third level domains, and so on.
+
+ The administration of a domain requires controlling the assignment of
+ names within that domain and providing access to the names and name
+ related information (such as addresses) to users both inside and
+ outside the domain.
+
+
+
+
+
+
+
+
+
+
+
+
+Postel & Reynolds [Page 1]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+General Purpose Domains
+
+ While the initial domain name "ARPA" arises from the history of the
+ development of this system and environment, in the future most of the
+ top level names will be very general categories like "government",
+ "education", or "commercial". The motivation is to provide an
+ organization name that is free of undesirable semantics.
+
+ After a short period of initial experimentation, all current
+ ARPA-Internet hosts will select some domain other than ARPA for their
+ future use. The use of ARPA as a top level domain will eventually
+ cease.
+
+Initial Set of Top Level Domains
+
+ The initial top level domain names are:
+
+ Temporary
+
+ ARPA = The current ARPA-Internet hosts.
+
+ Categories
+
+ GOV = Government, any government related domains meeting the
+ second level requirements.
+
+ EDU = Education, any education related domains meeting the
+ second level requirements.
+
+ COM = Commercial, any commercial related domains meeting the
+ second level requirements.
+
+ MIL = Military, any military related domains meeting the
+ second level requirements.
+
+ ORG = Organization, any other domains meeting the second
+ level requirements.
+
+ Countries
+
+ The English two letter code (alpha-2) identifying a country
+ according the the ISO Standard for "Codes for the
+ Representation of Names of Countries" [5].
+
+
+
+
+
+
+Postel & Reynolds [Page 2]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ Multiorganizations
+
+ A multiorganization may be a top level domain if it is large,
+ and is composed of other organizations; particularly if the
+ multiorganization can not be easily classified into one of the
+ categories and is international in scope.
+
+Possible Examples of Domains
+
+ The following examples are fictions of the authors' creation, any
+ similarity to the real world is coincidental.
+
+ The UC Domain
+
+ It might be that a large state wide university with, say, nine
+ campuses and several laboratories may want to form a domain. Each
+ campus or major off-campus laboratory might then be a subdomain,
+ and within each subdomain, each department could be further
+ distinguished. This university might be a second level domain in
+ the education category.
+
+ One might see domain style names for hosts in this domain like
+ these:
+
+ LOCUS.CS.LA.UC.EDU
+ CCN.OAC.LA.UC.EDU
+ ERNIE.CS.CAL.UC.EDU
+ A.S1.LLNL.UC.EDU
+ A.LAND.LANL.UC.EDU
+ NMM.LBL.CAL.UC.EDU
+
+ The MIT Domain
+
+ Another large university may have many hosts using a variety of
+ machine types, some even using several families of protocols.
+ However, the administrators at this university may see no need for
+ the outside world to be aware of these internal differences. This
+ university might be a second level domain in the education
+ category.
+
+ One might see domain style names for hosts in this domain like
+ these:
+
+ APIARY-1.MIT.EDU
+ BABY-BLUE.MIT.EDU
+ CEZANNE.MIT.EDU
+ DASH.MIT.EDU
+
+
+Postel & Reynolds [Page 3]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ MULTICS.MIT.EDU
+ TAC.MIT.EDU
+ XX.MIT.EDU
+
+ The CSNET Domain
+
+ There may be a consortium of universities and industry research
+ laboratories called, say, "CSNET". This CSNET is not a network
+ per se, but rather a computer mail exchange using a variety of
+ protocols and network systems. Therefore, CSNET is not a network
+ in the sense of the ARPANET, or an Ethernet, or even the
+ ARPA-Internet, but rather a community. Yet it does, in fact, have
+ the key property needed to form a domain; it has a responsible
+ administration. This consortium might be large enough and might
+ have membership that cuts across the categories in such a way that
+ it qualifies under the "multiorganization rule" to be a top level
+ domain.
+
+ One might see domain style names for hosts in this domain like
+ these:
+
+ CIC.CSNET
+ EMORY.CSNET
+ GATECH.CSNET
+ HP-LABS.CSNET
+ SJ.IBM.CSNET
+ UDEL.CSNET
+ UWISC.CSNET
+
+General Requirements on a Domain
+
+ There are several requirements that must be met to establish a
+ domain. In general, it must be responsibly managed. There must be a
+ responsible person to serve as an authoritative coordinator for
+ domain related questions. There must be a robust domain name lookup
+ service, it must be of at least a minimum size, and the domain must
+ be registered with the central domain administrator (the Network
+ Information Center (NIC) Domain Registrar).
+
+ Responsible Person:
+
+ An individual must be identified who has authority for the
+ administration of the names within the domain, and who seriously
+ takes on the responsibility for the behavior of the hosts in the
+ domain, plus their interactions with hosts outside the domain.
+ This person must have some technical expertise and the authority
+ within the domain to see that problems are fixed.
+
+
+Postel & Reynolds [Page 4]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ If a host in a given domain somehow misbehaves in its interactions
+ with hosts outside the domain (e.g., consistently violates
+ protocols), the responsible person for the domain must be
+ competent and available to receive reports of problems, take
+ action on the reported problems, and follow through to eliminate
+ the problems.
+
+ Domain Servers:
+
+ A robust and reliable domain server must be provided. One way of
+ meeting this requirement is to provide at least two independent
+ domain servers for the domain. The database can, of course, be
+ the same. The database can be prepared and copied to each domain
+ server. But, the servers should be in separate machines on
+ independent power supplies, et cetera; basically as physically
+ independent as can be. They should have no common point of
+ failure.
+
+ Some domains may find that providing a robust domain service can
+ most easily be done by cooperating with another domain where each
+ domain provides an additional server for the other.
+
+ In other situations, it may be desirable for a domain to arrange
+ for domain service to be provided by a third party, perhaps on
+ hosts located outside the domain.
+
+ One of the difficult problems in operating a domain server is the
+ acquisition and maintenance of the data. In this case, the data
+ are the host names and addresses. In some environments this
+ information changes fairly rapidly and keeping up-to-date data may
+ be difficult. This is one motivation for sub-domains. One may
+ wish to create sub-domains until the rate of change of the data in
+ a sub-domain domain server database is easily managed.
+
+ In the technical language of the domain server implementation the
+ data is divided into zones. Domains and zones are not necessarily
+ one-to-one. It may be reasonable for two or more domains to
+ combine their data in a single zone.
+
+ The responsible person or an identified technical assistant must
+ understand in detail the procedures for operating a domain server,
+ including the management of master files and zones.
+
+ The operation of a domain server should not be taken on lightly.
+ There are some difficult problems in providing an adequate
+ service, primarily the problems in keeping the database up to
+ date, and keeping the service operating.
+
+
+Postel & Reynolds [Page 5]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ The concepts and implementation details of the domain server are
+ given in RFC-882 [2] and RFC-883 [3].
+
+ Minimum Size:
+
+ The domain must be of at least a minimum size. There is no
+ requirement to form a domain because some set of hosts is above
+ the minimum size.
+
+ Top level domains must be specially authorized. In general, they
+ will only be authorized for domains expected to have over 500
+ hosts.
+
+ The general guideline for a second level domain is that it have
+ over 50 hosts. This is a very soft "requirement". It makes sense
+ that any major organization, such as a university or corporation,
+ be allowed as a second level domain -- even if it has just a few
+ hosts.
+
+ Registration:
+
+ Top level domains must be specially authorized and registered with
+ the NIC domain registrar.
+
+ The administrator of a level N domain must register with the
+ registrar (or responsible person) of the level N-1 domain. This
+ upper level authority must be satisfied that the requirements are
+ met before authorization for the domain is granted.
+
+ The registration procedure involves answering specific questions
+ about the prospective domain. A prototype of what the NIC Domain
+ Registrar may ask for the registration of a second level domain is
+ shown below. These questions may change from time to time. It is
+ the responsibility of domain administrators to keep this
+ information current.
+
+ The administrator of a domain is required to make sure that host
+ and sub-domain names within that jurisdiction conform to the
+ standard name conventions and are unique within that domain.
+
+ If sub-domains are set up, the administrator may wish to pass
+ along some of his authority and responsibility to a sub-domain
+ administrator. Even if sub-domains are established, the
+ responsible person for the top-level domain is ultimately
+ responsible for the whole tree of sub-domains and hosts.
+
+ This does not mean that a domain administrator has to know the
+
+
+Postel & Reynolds [Page 6]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ details of all the sub-domains and hosts to the Nth degree, but
+ simply that if a problem occurs he can get it fixed by calling on
+ the administrator of the sub-domain containing the problem.
+
+Top Level Domain Requirements
+
+ There are very few top level domains, each of these may have many
+ second level domains.
+
+ An initial set of top level names has been identified. Each of these
+ has an administrator and an agent.
+
+ The top level domains:
+
+ ARPA = The ARPA-Internet *** TEMPORARY ***
+
+ Administrator: DARPA
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+ GOV = Government
+
+ Administrator: DARPA
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+ EDU = Education
+
+ Administrator: DARPA
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+ COM = Commercial
+
+ Administrator: DARPA
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+ MIL = Military
+
+ Administrator: DDN-PMO
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+
+
+
+
+
+Postel & Reynolds [Page 7]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ ORG = Organization
+
+ Administrator: DARPA
+ Agent: The Network Information Center
+ Mailbox: HOSTMASTER@SRI-NIC.ARPA
+
+ Countries
+
+ The English two letter code (alpha-2) identifying a country
+ according the the ISO Standard for "Codes for the
+ Representation of Names of Countries" [5].
+
+ As yet no country domains have been established. As they are
+ established information about the administrators and agents
+ will be made public, and will be listed in subsequent editions
+ of this memo.
+
+ Multiorganizations
+
+ A multiorganization may be a top level domain if it is large,
+ and is composed of other organizations; particularly if the
+ multiorganization can not be easily classified into one of the
+ categories and is international in scope.
+
+ As yet no multiorganization domains have been established. As
+ they are established information about the administrators and
+ agents will be made public, and will be listed in subsequent
+ editions of this memo.
+
+ Note: The NIC is listed as the agent and registrar for all the
+ currently allowed top level domains. If there are other entities
+ that would be more appropriate agents and registrars for some or
+ all of these domains then it would be desirable to reassign the
+ responsibility.
+
+Second Level Domain Requirements
+
+ Each top level domain may have many second level domains. Every
+ second level domain must meet the general requirements on a domain
+ specified above, and be registered with a top level domain
+ administrator.
+
+
+
+
+
+
+
+
+Postel & Reynolds [Page 8]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+Third through Nth Level Domain Requirements
+
+ Each second level domain may have many third level domains, etc.
+ Every third level domain (through Nth level domain) must meet the
+ requirements set by the administrator of the immediately higher level
+ domain. Note that these may be more or less strict than the general
+ requirements. One would expect the minimum size requirements to
+ decrease at each level.
+
+The ARPA Domain
+
+ At the time the implementation of the domain concept was begun it was
+ thought that the set of hosts under the administrative authority of
+ DARPA would make up a domain. Thus the initial domain selected was
+ called ARPA. Now it is seen that there is no strong motivation for
+ there to be a top level ARPA domain. The plan is for the current
+ ARPA domain to go out of business as soon as possible. Hosts that
+ are currently members of the ARPA domain should make arrangements to
+ join another domain. It is likely that for experimental purposes
+ there will be a second level domain called ARPA in the ORG domain
+ (i.e., there will probably be an ARPA.ORG domain).
+
+The DDN Hosts
+
+ DDN hosts that do not desire to participate in this domain naming
+ system will continue to use the HOSTS.TXT data file maintained by the
+ NIC for name to address translations. This file will be kept up to
+ date for the DDN hosts. However, all DDN hosts will change their
+ names from "host.ARPA" to (for example) "host.DDN.MIL" some time in
+ the future. The schedule for changes required in DDN hosts will be
+ established by the DDN-PMO.
+
+Impact on Hosts
+
+ What is a host administrator to do about all this?
+
+ For existing hosts already operating in the ARPA-Internet, the
+ best advice is to sit tight for now. Take a few months to
+ consider the options, then select a domain to join. Plan
+ carefully for the impact that changing your host name will have on
+ both your local users and on their remote correspondents.
+
+ For a new host, careful thought should be given (as discussed
+ below). Some guidance can be obtained by comparing notes on what
+ other hosts with similar administrative properties have done.
+
+ The owner of a host may decide which domain to join, and the
+
+
+Postel & Reynolds [Page 9]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ administrator of a domain may decide which hosts to accept into his
+ domain. Thus the owner of a host and a domain administrator must
+ come to an understanding about the host being in the domain. This is
+ the foundation of responsible administration.
+
+ For example, a host "XYZ" at MIT might possible be considered as a
+ candidate for becoming any of XYZ.ARPA.ORG, XYZ.CSNET, or
+ XYZ.MIT.EDU.
+
+ The owner of host XYZ may choose which domain to join,
+ depending on which domain administrators are willing to have
+ him.
+
+ The domain is part of the host name. Thus if USC-ISIA.ARPA changes
+ its domain affiliation to DDN.MIL to become USC-ISIA.DDN.MIL, it has
+ changed its name. This means that any previous references to
+ USC-ISIA.ARPA are now out of date. Such old references may include
+ private host name to address tables, and any recorded information
+ about mailboxes such as mailing lists, the headers of old messages,
+ printed directories, and peoples' memories.
+
+ The experience of the DARPA community suggests that changing the name
+ of a host is somewhat painful. It is recommended that careful
+ thought be given to choosing a new name for a host - which includes
+ selecting its place in the domain hierarchy.
+
+The Roles of the Network Information Center
+
+ The NIC plays two types of roles in the administration of domains.
+ First, the NIC is the registrar of all top level domains. Second
+ the NIC is the administrator of several top level domains (and the
+ registrar for second level domains in these).
+
+ Top Level Domain Registrar
+
+ As the registrar for top level domains, the NIC is the contact
+ point for investigating the possibility of establishing a new top
+ level domain.
+
+ Top Level Domain Administrator
+
+ For the top level domains designated so far, the NIC is the
+ administrator of each of these domains. This means the NIC is
+ responsible for the management of these domains and the
+ registration of the second level domains or hosts (if at the
+ second level) in these domains.
+
+
+
+Postel & Reynolds [Page 10]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ It may be reasonable for the administration of some of these
+ domains to be taken on by other authorities in the future. It is
+ certainly not desired that the NIC be the administrator of all top
+ level domains forever.
+
+Prototypical Questions
+
+ To establish a domain, the following information must be provided to
+ the NIC Domain Registrar (HOSTMASTER@SRI-NIC.ARPA):
+
+ Note: The key people must have computer mail mailboxes and
+ NIC-Idents. If they do not at present, please remedy the
+ situation at once. A NIC-Ident may be established by contacting
+ NIC@SRI-NIC.ARPA.
+
+ 1) The name of the top level domain to join.
+
+ For example: EDU
+
+ 2) The name, title, mailing address, phone number, and organization
+ of the administrative head of the organization. This is the contact
+ point for administrative and policy questions about the domain. In
+ the case of a research project, this should be the Principal
+ Investigator. The online mailbox and NIC-Ident of this person should
+ also be included.
+
+ For example:
+
+ Administrator
+
+ Organization USC/Information Sciences Institute
+ Name Keith Uncapher
+ Title Executive Director
+ Mail Address USC/ISI
+ 4676 Admiralty Way, Suite 1001
+ Marina del Rey, CA. 90292-6695
+ Phone Number 213-822-1511
+ Net Mailbox Uncapher@USC-ISIB.ARPA
+ NIC-Ident KU
+
+ 3) The name, title, mailing address, phone number, and organization
+ of the domain technical contact. The online mailbox and NIC-Ident of
+ the domain technical contact should also be included. This is the
+ contact point for problems with the domain and for updating
+ information about the domain. Also, the domain technical contact may
+ be responsible for hosts in this domain.
+
+
+
+Postel & Reynolds [Page 11]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ For example:
+
+ Technical Contact
+
+ Organization USC/Information Sciences Institute
+ Name Craig Milo Rogers
+ Title Researcher
+ Mail Address USC/ISI
+ 4676 Admiralty Way, Suite 1001
+ Marina del Rey, CA. 90292-6695
+ Phone Number 213-822-1511
+ Net Mailbox Rogers@USC-ISIB.ARPA
+ NIC-Ident CMR
+
+ 4) The name, title, mailing address, phone number, and organization
+ of the zone technical contact. The online mailbox and NIC-Ident of
+ the zone technical contact should also be included. This is the
+ contact point for problems with the zone and for updating information
+ about the zone. In many cases the zone technical contact and the
+ domain technical contact will be the same person.
+
+ For example:
+
+ Technical Contact
+
+ Organization USC/Information Sciences Institute
+ Name Craig Milo Rogers
+ Title Researcher
+ Mail Address USC/ISI
+ 4676 Admiralty Way, Suite 1001
+ Marina del Rey, CA. 90292-6695
+ Phone Number 213-822-1511
+ Net Mailbox Rogers@USC-ISIB.ARPA
+ NIC-Ident CMR
+
+ 5) The name of the domain (up to 12 characters). This is the name
+ that will be used in tables and lists associating the domain and the
+ domain server addresses. [While technically domain names can be
+ quite long (programmers beware), shorter names are easier for people
+ to cope with.]
+
+ For example: ALPHA-BETA
+
+ 6) A description of the servers that provides the domain service for
+ translating name to address for hosts in this domain, and the date
+ they will be operational.
+
+
+
+Postel & Reynolds [Page 12]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+ A good way to answer this question is to say "Our server is
+ supplied by person or company X and does whatever their standard
+ issue server does".
+
+ For example: Our server is a copy of the server operated by
+ the NIC, and will be installed and made operational on
+ 1-November-84.
+
+ 7) A description of the server machines, including:
+
+ (a) hardware and software (using keywords from the Assigned
+ Numbers)
+
+ (b) addresses (what host on what net for each connected net)
+
+ For example:
+
+ (a) hardware and software
+
+ VAX-11/750 and UNIX, or
+ IBM-PC and MS-DOS, or
+ DEC-1090 and TOPS-20
+
+ (b) address
+
+ 10.9.0.193 on ARPANET
+
+ 8) An estimate of the number of hosts that will be in the domain.
+
+ (a) initially,
+ (b) within one year,
+ (c) two years, and
+ (d) five years.
+
+ For example:
+
+ (a) initially = 50
+ (b) one year = 100
+ (c) two years = 200
+ (d) five years = 500
+
+
+
+
+
+
+
+
+
+Postel & Reynolds [Page 13]
+
+
+
+RFC 920 October 1984
+Domain Requirements
+
+
+Acknowledgment
+
+ We would like to thank the many people who contributed to this memo,
+ including the participants in the Namedroppers Group, the ICCB, the
+ PCCB, and especially the staff of the Network Information Center,
+ particularly J. Feinler and K. Harrenstien.
+
+References
+
+ [1] Postel, J., "The Domain Names Plan and Schedule", RFC-881, USC
+ Information Sciences Institute, November 1983.
+
+ [2] Mockapetris, P., "Domain Names - Concepts and Facilities",
+ RFC-882, USC Information Sciences Institute, November 1983.
+
+ [3] Mockapetris, P., "Domain Names - Implementation and
+ Specification", RFC-883, USC Information Sciences Institute,
+ November 1983.
+
+ [4] Postel, J., "Domain Name System Implementation Schedule",
+ RFC-897, USC Information Sciences Institute, February 1984.
+
+ [5] ISO, "Codes for the Representation of Names of Countries",
+ ISO-3166, International Standards Organization, May 1981.
+
+ [6] Postel, J., "Domain Name System Implementation Schedule -
+ Revised", RFC-921, USC Information Sciences Institute, October
+ 1984.
+
+ [7] Mockapetris, P., "The Domain Name System", Proceedings of the
+ IFIP 6.5 Working Conference on Computer Message Services,
+ Nottingham, England, May 1984. Also as ISI/RS-84-133,
+ June 1984.
+
+ [8] Mockapetris, P., J. Postel, and P. Kirton, "Name Server Design
+ for Distributed Systems", Proceedings of the Seventh
+ International Conference on Computer Communication, October 30
+ to November 3 1984, Sidney, Australia. Also as ISI/RS-84-132,
+ June 1984.
+
+
+
+
+
+
+
+
+
+
+Postel & Reynolds [Page 14]
+
diff --git a/usr.sbin/named/doc/rfc974.lpr b/usr.sbin/named/doc/rfc974.lpr
new file mode 100644
index 00000000000..97d79a4fa4c
--- /dev/null
+++ b/usr.sbin/named/doc/rfc974.lpr
@@ -0,0 +1,399 @@
+
+
+Network Working Group Craig Partridge
+Request for Comments: 974 CSNET CIC BBN Laboratories Inc
+ January 1986
+
+ MAIL ROUTING AND THE DOMAIN SYSTEM
+
+
+Status of this Memo
+
+ This RFC presents a description of how mail systems on the Internet
+ are expected to route messages based on information from the domain
+ system described in RFCs 882, 883 and 973. Distribution of this memo
+ is unlimited.
+
+Introduction
+
+ The purpose of this memo is to explain how mailers are to decide how
+ to route a message addressed to a given Internet domain name. This
+ involves a discussion of how mailers interpret MX RRs, which are used
+ for message routing. Note that this memo makes no statement about
+ how mailers are to deal with MB and MG RRs, which are used for
+ interpreting mailbox names.
+
+ Under RFC-882 and RFC-883 certain assumptions about mail addresses
+ have been changed. Up to now, one could usually assume that if a
+ message was addressed to a mailbox, for example, at LOKI.BBN.COM,
+ that one could just open an SMTP connection to LOKI.BBN.COM and pass
+ the message along. This system broke down in certain situations,
+ such as for certain UUCP and CSNET hosts which were not directly
+ attached to the Internet, but these hosts could be handled as special
+ cases in configuration files (for example, most mailers were set up
+ to automatically forward mail addressed to a CSNET host to
+ CSNET-RELAY.ARPA).
+
+ Under domains, one cannot simply open a connection to LOKI.BBN.COM,
+ but must instead ask the domain system where messages to LOKI.BBN.COM
+ are to be delivered. And the domain system may direct a mailer to
+ deliver messages to an entirely different host, such as SH.CS.NET.
+ Or, in a more complicated case, the mailer may learn that it has a
+ choice of routes to LOKI.BBN.COM. This memo is essentially a set of
+ guidelines on how mailers should behave in this more complex world.
+
+ Readers are expected to be familiar with RFCs 882, 883, and the
+ updates to them (e.g., RFC-973).
+
+
+
+
+
+
+
+
+
+Partridge [Page 1]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+What the Domain Servers Know
+
+ The domain servers store information as a series of resource records
+ (RRs), each of which contains a particular piece of information about
+ a given domain name (which is usually, but not always, a host). The
+ simplest way to think of a RR is as a typed pair of datum, a domain
+ name matched with relevant data, and stored with some additional type
+ information to help systems determine when the RR is relevant. For
+ the purposes of message routing, the system stores RRs known as MX
+ RRs. Each MX matches a domain name with two pieces of data, a
+ preference value (an unsigned 16-bit integer), and the name of a
+ host. The preference number is used to indicate in what order the
+ mailer should attempt deliver to the MX hosts, with the lowest
+ numbered MX being the one to try first. Multiple MXs with the same
+ preference are permitted and have the same priority.
+
+ In addition to mail information, the servers store certain other
+ types of RR's which mailers may encounter or choose to use. These
+ are: the canonical name (CNAME) RR, which simply states that the
+ domain name queried for is actually an alias for another domain name,
+ which is the proper, or canonical, name; and the Well Known Service
+ (WKS) RR, which stores information about network services (such as
+ SMTP) a given domain name supports.
+
+General Routing Guidelines
+
+ Before delving into a detailed discussion of how mailers are expected
+ to do mail routing, it would seem to make sense to give a brief
+ overview of how this memo is approaching the problems that routing
+ poses.
+
+ The first major principle is derived from the definition of the
+ preference field in MX records, and is intended to prevent mail
+ looping. If the mailer is on a host which is listed as an MX for the
+ destination host, the mailer may only deliver to an MX which has a
+ lower preference count than its own host.
+
+ It is also possible to cause mail looping because routing information
+ is out of date or incomplete. Out of date information is only a
+ problem when domain tables are changed. The changes will not be
+ known to all affected hosts until their resolver caches time out.
+ There is no way to ensure that this will not happen short of
+ requiring mailers and their resolvers to always send their queries to
+ an authoritative server, and never use data stored in a cache. This
+ is an impractical solution, since eliminating resolver caching would
+ make mailing inordinately expensive. What is more, the out-of-date
+ RR problem should not happen if, when a domain table is changed,
+
+
+Partridge [Page 2]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+ affected hosts (those in the list of MXs) have their resolver caches
+ flushed. In other words, given proper precautions, mail looping as a
+ result of domain information should be avoidable, without requiring
+ mailers to query authoritative servers. (The appropriate precaution
+ is to check with a host's administrator before adding that host to a
+ list of MXs).
+
+ The incomplete data problem also requires some care when handling
+ domain queries. If the answer section of a query is incomplete
+ critical MX RRs may be left out. This may result in mail looping, or
+ in a message being mistakenly labelled undeliverable. As a result,
+ mailers may only accept responses from the domain system which have
+ complete answer sections. Note that this entire problem can be
+ avoided by only using virtual circuits for queries, but since this
+ situation is likely to be very rare and datagrams are the preferred
+ way to interact with the domain system, implementors should probably
+ just ensure that their mailer will repeat a query with virtual
+ circuits should the truncation bit ever be set.
+
+Determining Where to Send a Message
+
+ The explanation of how mailers should decide how to route a message
+ is discussed in terms of the problem of a mailer on a host with
+ domain name LOCAL trying to deliver a message addressed to the domain
+ name REMOTE. Both LOCAL and REMOTE are assumed to be syntactically
+ correct domain names. Furthermore, LOCAL is assumed to be the
+ official name for the host on which the mailer resides (i.e., it is
+ not a alias).
+
+Issuing a Query
+
+ The first step for the mailer at LOCAL is to issue a query for MX RRs
+ for REMOTE. It is strongly urged that this step be taken every time
+ a mailer attempts to send the message. The hope is that changes in
+ the domain database will rapidly be used by mailers, and thus domain
+ administrators will be able to re-route in-transit messages for
+ defective hosts by simply changing their domain databases.
+
+ Certain responses to the query are considered errors:
+
+ Getting no response to the query. The domain server the mailer
+ queried never sends anything back. (This is distinct from an
+ answer which contains no answers to the query, which is not an
+ error).
+
+ Getting a response in which the truncation field of the header is
+
+
+
+Partridge [Page 3]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+ set. (Recall discussion of incomplete queries above). Mailers
+ may not use responses of this type, and should repeat the query
+ using virtual circuits instead of datagrams.
+
+ Getting a response in which the response code is non-zero.
+
+ Mailers are expected to do something reasonable in the face of an
+ error. The behaviour for each type of error is not specified here,
+ but implementors should note that different types of errors should
+ probably be treated differently. For example, a response code of
+ "non-existent domain" should probably cause the message to be
+ returned to the sender as invalid, while a response code of "server
+ failure" should probably cause the message to be retried later.
+
+ There is one other special case. If the response contains an answer
+ which is a CNAME RR, it indicates that REMOTE is actually an alias
+ for some other domain name. The query should be repeated with the
+ canonical domain name.
+
+ If the response does not contain an error response, and does not
+ contain aliases, its answer section should be a (possibly zero
+ length) list of MX RRs for domain name REMOTE (or REMOTE's true
+ domain name if REMOTE was a alias). The next section describes how
+ this list is interpreted.
+
+Interpreting the List of MX RRs
+
+ NOTE: This section only discusses how mailers choose which names to
+ try to deliver a message to, working from a list of RR's. It does
+ not discuss how the mailers actually make delivery. Where ever
+ delivering a message is mentioned, all that is meant is that the
+ mailer should do whatever it needs to do to transfer a message to a
+ remote site, given a domain name for that site. (For example, an
+ SMTP mailer will try to get an address for the domain name, which
+ involves another query to the domain system, and then, if it gets an
+ address, connect to the SMTP TCP port). The mechanics of actually
+ transferring the message over the network to the address associated
+ with a given domain name is not within the scope of this memo.
+
+ It is possible that the list of MXs in the response to the query will
+ be empty. This is a special case. If the list is empty, mailers
+ should treat it as if it contained one RR, an MX RR with a preference
+ value of 0, and a host name of REMOTE. (I.e., REMOTE is its only
+ MX). In addition, the mailer should do no further processing on the
+ list, but should attempt to deliver the message to REMOTE. The idea
+
+
+
+
+Partridge [Page 4]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+ here is that if a domain fails to advertise any information about a
+ particular name we will give it the benefit of the doubt and attempt
+ delivery.
+
+ If the list is not empty, the mailer should remove irrelevant RR's
+ from the list according to the following steps. Note that the order
+ is significant.
+
+ For each MX, a WKS query should be issued to see if the domain
+ name listed actually supports the mail service desired. MX RRs
+ which list domain names which do not support the service should be
+ discarded. This step is optional, but strongly encouraged.
+
+ If the domain name LOCAL is listed as an MX RR, all MX RRs with a
+ preference value greater than or equal to that of LOCAL's must be
+ discarded.
+
+ After removing irrelevant RRs, the list can again be empty. This is
+ now an error condition and can occur in several ways. The simplest
+ case is that the WKS queries have discovered that none of the hosts
+ listed supports the mail service desired. The message is thus deemed
+ undeliverable, though extremely persistent mail systems might want to
+ try a delivery to REMOTE's address (if it exists) before returning
+ the message. Another, more dangerous, possibility is that the domain
+ system believes that LOCAL is handling message for REMOTE, but the
+ mailer on LOCAL is not set up to handle mail for REMOTE. For
+ example, if the domain system lists LOCAL as the only MX for REMOTE,
+ LOCAL will delete all the entries in the list. But LOCAL is
+ presumably querying the domain system because it didn't know what to
+ do with a message addressed to REMOTE. Clearly something is wrong.
+ How a mailer chooses to handle these situations is to some extent
+ implementation dependent, and is thus left to the implementor's
+ discretion.
+
+ If the list of MX RRs is not empty, the mailer should try to deliver
+ the message to the MXs in order (lowest preference value tried
+ first). The mailer is required to attempt delivery to the lowest
+ valued MX. Implementors are encouraged to write mailers so that they
+ try the MXs in order until one of the MXs accepts the message, or all
+ the MXs have been tried. A somewhat less demanding system, in which
+ a fixed number of MXs is tried, is also reasonable. Note that
+ multiple MXs may have the same preference value. In this case, all
+ MXs at with a given value must be tried before any of a higher value
+ are tried. In addition, in the special case in which there are
+ several MXs with the lowest preference value, all of them should be
+ tried before a message is deemed undeliverable.
+
+
+
+Partridge [Page 5]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+Minor Special Issues
+
+ There are a couple of special issues left out of the preceding
+ section because they complicated the discussion. They are treated
+ here in no particular order.
+
+ Wildcard names, those containing the character '*' in them, may be
+ used for mail routing. There are likely to be servers on the network
+ which simply state that any mail to a domain is to be routed through
+ a relay. For example, at the time that this RFC is being written, all
+ mail to hosts in the domain IL is routed through RELAY.CS.NET. This
+ is done by creating a wildcard RR, which states that *.IL has an MX
+ of RELAY.CS.NET. This should be transparent to the mailer since the
+ domain servers will hide this wildcard match. (If it matches *.IL
+ with HUJI.IL for example, a domain server will return an RR
+ containing HUJI.IL, not *.IL). If by some accident a mailer receives
+ an RR with a wildcard domain name in its name or data section it
+ should discard the RR.
+
+ Note that the algorithm to delete irrelevant RRs breaks if LOCAL has
+ a alias and the alias is listed in the MX records for REMOTE. (E.g.
+ REMOTE has an MX of ALIAS, where ALIAS has a CNAME of LOCAL). This
+ can be avoided if aliases are never used in the data section of MX
+ RRs.
+
+ Implementors should understand that the query and interpretation of
+ the query is only performed for REMOTE. It is not repeated for the
+ MX RRs listed for REMOTE. You cannot try to support more extravagant
+ mail routing by building a chain of MXs. (E.g. UNIX.BBN.COM is an MX
+ for RELAY.CS.NET and RELAY.CS.NET is an MX for all the hosts in .IL,
+ but this does not mean that UNIX.BBN.COM accepts any responsibility
+ for mail for .IL).
+
+ Finally, it should be noted that this is a standard for routing on
+ the Internet. Mailers serving hosts which lie on multiple networks
+ will presumably have to make some decisions about which network to
+ route through. This decision making is outside the scope of this
+ memo, although mailers may well use the domain system to help them
+ decide. However, once a mailer decides to deliver a message via the
+ Internet it must apply these rules to route the message.
+
+
+
+
+
+
+
+
+
+Partridge [Page 6]
+
+
+
+RFC 974 January 1986
+Mail Routing and the Domain System
+
+
+Examples
+
+ To illustrate the discussion above, here are three examples of how
+ mailers should route messages. All examples work with the following
+ database:
+
+ A.EXAMPLE.ORG IN MX 10 A.EXAMPLE.ORG
+ A.EXAMPLE.ORG IN MX 15 B.EXAMPLE.ORG
+ A.EXAMPLE.ORG IN MX 20 C.EXAMPLE.ORG
+ A.EXAMPLE.ORG IN WKS 10.0.0.1 TCP SMTP
+
+ B.EXAMPLE.ORG IN MX 0 B.EXAMPLE.ORG
+ B.EXAMPLE.ORG IN MX 10 C.EXAMPLE.ORG
+ B.EXAMPLE.ORG IN WKS 10.0.0.2 TCP SMTP
+
+ C.EXAMPLE.ORG IN MX 0 C.EXAMPLE.ORG
+ C.EXAMPLE.ORG IN WKS 10.0.0.3 TCP SMTP
+
+ D.EXAMPLE.ORG IN MX 0 D.EXAMPLE.ORG
+ D.EXAMPLE.ORG IN MX 0 C.EXAMPLE.ORG
+ D.EXAMPLE.ORG IN WKS 10.0.0.4 TCP SMTP
+
+ In the first example, an SMTP mailer on D.EXAMPLE.ORG is trying to
+ deliver a message addressed to A.EXAMPLE.ORG. From the answer to its
+ query, it learns that A.EXAMPLE.ORG has three MX RRs. D.EXAMPLE.ORG
+ is not one of the MX RRs and all three MXs support SMTP mail
+ (determined from the WKS entries), so none of the MXs are eliminated.
+ The mailer is obliged to try to deliver to A.EXAMPLE.ORG as the
+ lowest valued MX. If it cannot reach A.EXAMPLE.ORG it can (but is
+ not required to) try B.EXAMPLE.ORG. and if B.EXAMPLE.ORG is not
+ responding, it can try C.EXAMPLE.ORG.
+
+ In the second example, the mailer is on B.EXAMPLE.ORG, and is again
+ trying to deliver a message addressed to A.EXAMPLE.ORG. There are
+ once again three MX RRs for A.EXAMPLE.ORG, but in this case the
+ mailer must discard the RRs for itself and C.EXAMPLE.ORG (because the
+ MX RR for C.EXAMPLE.ORG has a higher preference value than the RR for
+ B.EXAMPLE.ORG). It is left only with the RR for A.EXAMPLE.ORG, and
+ can only try delivery to A.EXAMPLE.ORG.
+
+ In the third example, consider a mailer on A.EXAMPLE.ORG trying to
+ deliver a message to D.EXAMPLE.ORG. In this case there are only two
+ MX RRs, both with the same preference value. Either MX will accept
+ messages for D.EXAMPLE.ORG. The mailer should try one MX first (which
+ one is up to the mailer, though D.EXAMPLE.ORG seems most reasonable),
+ and if that delivery fails should try the other MX (e.g.
+ C.EXAMPLE.ORG).
+
+
+Partridge [Page 7]
+
diff --git a/usr.sbin/named/named.8 b/usr.sbin/named/named.8
new file mode 100644
index 00000000000..fbe326d267d
--- /dev/null
+++ b/usr.sbin/named/named.8
@@ -0,0 +1,440 @@
+.\" Copyright (c) 1985, 1991 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.
+.\"
+.\" from: @(#)named.8 6.9 (Berkeley) 3/16/91
+.\" $Id: named.8,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt NAMED 8
+.Os BSD 4
+.Sh NAME
+.Nm named
+.Nd Internet domain name server
+.Sh SYNOPSIS
+.Nm named
+.Op Fl d Ar debuglevel
+.Op Fl p Ar port#
+.Oo Op Fl b
+.Ar bootfile Oc
+.Sh DESCRIPTION
+.Nm Named
+is the Internet domain name server.
+See
+.%T RFC883
+for more information on the Internet name-domain system.
+Without any arguments,
+.Nm named
+will read the default boot file
+.Pa /etc/named.boot ,
+read any initial data and listen for queries.
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl d
+Print debugging information.
+A number after the
+.Fl d
+determines the level of
+messages printed.
+.It Fl p
+Use a different port number. The default is the standard port number
+as listed in
+.Pa /etc/services .
+.It Fl b
+Use an alternate boot file. This is optional and allows you to
+specify a file with a leading dash.
+.El
+.Pp
+Any additional argument is taken as the name of the boot file.
+The boot file contains information about where the name server is to get
+its initial data. If multiple boot files are specified, only the last
+is used.
+Lines in the boot file cannot be continued on subsequent lines.
+The following is a small example:
+.Bd -literal
+;
+; boot file for name server
+;
+directory /etc/namedb
+
+; type domain source host/file backup file
+
+cache . root.cache
+primary Berkeley.EDU berkeley.edu.zone
+primary 32.128.IN-ADDR.ARPA ucbhosts.rev
+secondary CC.Berkeley.EDU 128.32.137.8 128.32.137.3 cc.zone.bak
+secondary 6.32.128.IN-ADDR.ARPA 128.32.137.8 128.32.137.3 cc.rev.bak
+primary 0.0.127.IN-ADDR.ARPA localhost.rev
+forwarders 10.0.0.78 10.2.0.78
+; slave
+.Ed
+.Pp
+The ``directory'' line causes the server to change its
+working directory to the directory specified. This can
+be important for the correct processing of
+.Li $INCLUDE
+files
+in primary zone files.
+.Pp
+The
+.Dq cache
+line specifies that data in
+.Dq Pa root.cache
+is to be
+placed in the backup cache.
+Its main use is to specify data such as locations of root domain servers.
+This cache is not used during normal operation,
+but is used as
+.Dq hints
+to find the current root servers.
+The file
+.Dq Pa root.cache
+is in the same format as
+.Dq Pa berkeley.edu.zone .
+There can be more than one
+.Dq cache
+file specified.
+.\"The first such file will be updated under certain conditions to snapshot the
+.\"cache (see
+.\" .Dv SIGQUIT
+.\" below).
+.\"The cache line can also have an optional interval argument after
+.\"the filename.
+.\"If an interval is listed,
+.\"it requests the nameserver to dump the cache contents
+.\"at that interval (in seconds).
+.\"The example above requests the nameserver to dump the cache content
+.\"every 3600 seconds (once an hour).
+.\"The use of automatic cache file updates is not currently recommended
+.\"because of the way the cache is currently managed by the server;
+.\"although the entire cache will be dumped for later reloading,
+.\"most of the cache contents will be ignored when reloaded.
+.\"The exact dump interval will vary
+.\"based on the minimum maintence interval time which is typically about
+.\"5 minutes.
+The cache files are processed in such a way as to preserve the
+time-to-live's
+of data dumped out. Data for the root nameservers is kept artificially
+valid if necessary.
+.Pp
+The first
+.Dq primary
+line states that the file
+.Dq Pa berkeley.edu.zone
+contains
+authoritative data for the
+.Dq Berkeley. Ns Em EDU
+zone.
+The file
+.Dq Pa berkeley.edu.zone
+contains data in the master file format described in
+.%T RFC883 .
+All domain names are relative to the origin, in this
+case,
+.Dq Berkeley. Ns Em EDU
+(see below for a more detailed description).
+The second
+.Dq primary
+line states that the file
+.Dq Pa ucbhosts.rev
+contains
+authoritative data for the domain
+.Dq 32.128.IN-ADDR.ARPA ,
+which is used
+to translate addresses in network 128.32 to hostnames.
+Each master file should begin with an
+.Tn SOA
+record for the zone
+(see below).
+.Pp
+The first ``secondary'' line specifies that all authoritative data
+under
+.Dq CC.Berkeley. Ns Em EDU
+is to be transferred from the name server
+at 128.32.137.8. If the transfer fails it will try 128.32.137.3 and
+continue trying the addresses, up to 10, listed on this line.
+The secondary copy is also authoritative for the specified domain.
+The first non-dotted-quad address on this line will be taken
+as a filename in which to backup the transfered zone.
+The name server will load the zone from this backup file if it exists
+when it boots, providing a complete copy even if the master servers
+are unreachable.
+Whenever a new copy of the domain is received by automatic zone transfer
+from one of the master servers, this file will be updated.
+The second
+.Dq secondary
+line states that the address-to-hostname
+mapping for the subnet 128.32.136 should be obtained from the same list
+of master servers as the previous zone.
+.Pp
+The
+.Dq forwarders
+line specifies the addresses of sitewide servers
+that will accept recursive queries from other servers.
+If the boot file specifies one or more forwarders, then the
+server will send all queries for data not in the cache to the forwarders first.
+Each forwarder will be asked in turn until an answer is returned
+or the list is exhausted. If no answer is forthcoming from a
+forwarder, the server will continue as it would have without
+the forwarders line unless it is in ``slave'' mode.
+The forwarding facility is useful
+to cause a large sitewide cache to be generated on a master,
+and to reduce traffic over links to outside servers.
+It can also be used to allow servers to run that do not have
+access directly to the Internet, but wish to act as though
+they do.
+.Pp
+The ``slave'' line (shown commented out) is used to put the server
+in slave mode. In this mode, the server will only make queries to
+forwarders. This option is normally used on machine that wish to
+run a server but for physical or administrative reasons cannot
+be given access to the Internet, but have access to a host that
+does have access.
+.Pp
+The ``sortlist'' line can be used to indicate networks that are to be
+preferred over other, unlisted networks.
+Queries for host addresses from hosts on the same network as the server
+will receive responses with local network addresses listed first,
+then addresses on the sort list, then other addresses.
+This line is only acted on at initial startup.
+When reloading the nameserver with
+a
+.Dv SIGHUP ,
+this line will be ignored.
+.Pp
+The master file consists of control information
+and a list of resource records for objects in the zone
+of the forms:
+.Bd -literal
+$INCLUDE <filename> <opt_domain>
+$ORIGIN <domain>
+<domain> <opt_ttl> <opt_class> <type> <resource_record_data>
+.Ed
+.Pp
+where
+.Em domain
+is
+.Ql \&.
+for root,
+.Ql \&@
+for the current origin, or a standard domain
+name. If
+.Em domain
+is a standard domain name that does not end with
+.Ql \&. ,
+the current origin
+is appended to the domain. Domain names ending with
+.Ql \&.
+are
+unmodified.
+The
+.Em opt_domain
+field is used to define an origin for the data in an included file.
+It is equivalent to placing a
+.Li $ORIGIN
+statement before the first
+line of the included file. The field is optional.
+Neither the
+.Em opt_domain
+field nor
+.Li $ORIGIN
+statements in the included file modify the current origin
+for this file.
+The
+.Em opt_ttl
+field is an optional integer number for the time-to-live field.
+It defaults to zero, meaning the minimum value specified in the
+SOA record for the zone.
+The
+.Em opt_class
+field is the object address type; currently only one type is supported,
+.Sy IN ,
+for objects connected to the
+.Tn DARPA
+Internet.
+The
+.Em type
+field contains one of the following tokens; the data expected in the
+.Em resource_record_data
+field is in parentheses.
+.Bl -tag -width Fl
+.It A
+a host address (dotted quad)
+.It \&NS
+an authoritative name server (domain)
+.It \&MX
+a mail exchanger (domain)
+.It CNAME
+the canonical name for an alias (domain)
+.It SOA
+marks the start of a zone of authority (domain of originating host,
+domain address of maintainer, a serial number and the following
+parameters in seconds: refresh, retry, expire and minimum TTL
+(see
+.%T RFC883 ) )
+.It \&MB
+a mailbox domain name (domain)
+.It \&MG
+a mail group member (domain)
+.It \&MR
+a mail rename domain name (domain)
+.It NULL
+ra null resource record (no format or data)
+.It \&WKS
+a well know service description (not implemented yet)
+.It \&PTR
+a domain name pointer (domain)
+.It HINFO
+host information (cpu_type OS_type )
+.It MINFO
+mailbox or mail list information (request_domain error_domain)
+.El
+.Pp
+Resource records normally end at the end of a line,
+but may be continued across lines between opening and closing parentheses.
+Comments are introduced by semicolons and continue to the end of the line.
+.Pp
+Each master zone file should begin with an SOA
+record for the zone.
+An example SOA
+record is as follows:
+.Bd -literal
+@ IN SOA ucbvax.Berkeley.EDU. rwh.ucbvax.Berkeley.EDU. (
+ 2.89 ; serial
+ 10800 ; refresh
+ 3600 ; retry
+ 3600000 ; expire
+ 86400 ) ; minimum
+.Ed
+.Pp
+The SOA
+lists a serial number, which should be changed each time the master
+file is changed.
+Secondary servers check the serial number at intervals specified by the refresh
+time in seconds; if the serial number changes, a zone transfer will be done
+to load the new data.
+If a master server cannot be contacted when a refresh is due, the retry time
+specifies the interval at which refreshes should be attempted until successful.
+If a master server cannot be contacted within the interval given by the
+expire time, all data from the zone is discarded by secondary servers.
+The minimum value is the time-to-live used by records in the file
+with no explicit time-to-live value.
+.Sh NOTES
+The boot file directives ``domain'' and ``suffixes'' have been
+obsoleted by a more useful resolver based implementation of
+suffixing for partially qualified domain names. The prior mechanisms
+could fail under a number of situations, especially when then local
+nameserver did not have complete information.
+.Pp
+The following signals have the specified effect when sent to the
+server process using the
+.Xr kill 1
+command.
+.Bl -tag -width Fl
+.It Dv SIGHUP
+Causes server to read
+.Pa named.boot
+and reload database.
+.It Dv SIGINT
+Dumps current data base and cache to
+.Pa /var/tmp/named_dump.db
+.\".IP
+.\" .Dv SIGQUIT
+.\"Causes the server to checkpoint the cache into the first ``cache'' file.
+.It Dv SIGIOT
+Dumps statistics data into
+.Pa /var/tmp/named.stats
+if the server is
+compiled
+.Dv \-DSTATS .
+Statistics data is appended to the file.
+.It Dv SIGSYS
+Dumps the profiling data in
+.Pa /var/tmp
+if the server is compiled
+with profiling (server forks, chdirs and exits).
+.It Dv SIGTERM
+Dumps the primary and secondary database files.
+Used to save modified data on shutdown if the
+server is compiled with dynamic updating enabled.
+.It Dv SIGUSR1
+Turns on debugging; each
+.Dv SIGUSR1
+increments debug level.
+.Pf ( Dv SIGEMT
+on older systems without
+.Dv SIGUSR1 )
+.It Dv SIGUSR2
+Turns off debugging completely.
+.Pf ( Dv SIGFPE
+on older systems without
+.Dv SIGUSR2 )
+.El
+.Sh FILES
+.Bl -tag -width /var/tmp/named_dump.db -compact
+.It Pa /etc/named.boot
+name server configuration boot file
+.It Pa /var/run/named.pid
+the process id
+.It Pa /var/tmp/named.run
+debug output
+.It Pa /var/tmp/named_dump.db
+dump of the name server database
+.It Pa /var/tmp/named.stats
+nameserver statistics data
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr gethostbyname 3 ,
+.Xr signal 3 ,
+.Xr resolver 3 ,
+.Xr resolv.conf 5 ,
+.Xr hostname 7 ,
+.Rs
+.%T RFC882
+.Re
+.Rs
+.%T RFC883
+.Re
+.Rs
+.%T RFC973
+.Re
+.Rs
+.%T RFC974
+.Re
+.Rs
+.%T "Name Server Operations Guide for BIND"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/named/named.reload b/usr.sbin/named/named.reload
new file mode 100644
index 00000000000..d0c45eb9cfb
--- /dev/null
+++ b/usr.sbin/named/named.reload
@@ -0,0 +1,6 @@
+#!/bin/sh -
+#
+# @(#)named.reload 5.2 (Berkeley) 6/27/89
+#
+
+kill -s HUP `cat /var/run/named.pid`
diff --git a/usr.sbin/named/named.restart b/usr.sbin/named/named.restart
new file mode 100644
index 00000000000..dc215fd1926
--- /dev/null
+++ b/usr.sbin/named/named.restart
@@ -0,0 +1,9 @@
+#!/bin/sh -
+#
+# @(#)named.restart 5.4 (Berkeley) 6/27/89
+#
+
+PATH=/bin:/sbin:/usr/sbin:/usr/bin
+
+kill -s KILL `cat /var/run/named.pid`
+named
diff --git a/usr.sbin/named/ns.h b/usr.sbin/named/ns.h
new file mode 100644
index 00000000000..a6d7e30779d
--- /dev/null
+++ b/usr.sbin/named/ns.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1985, 1990 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.
+ *
+ * from: @(#)ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns.h,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $
+ */
+
+/*
+ * Global definitions and variables for the name server.
+ */
+
+#include <arpa/inet.h>
+#include <string.h>
+
+/*
+ * Timeout time should be around 1 minute or so. Using the
+ * the current simplistic backoff strategy, the sequence
+ * retrys after 4, 8, and 16 seconds. With 3 servers, this
+ * dies out in a little more than a minute.
+ * (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY)
+ */
+#define MINROOTS 2 /* min number of root hints */
+#define NSMAX 16 /* max number of NS addrs to try */
+#define RETRYBASE 4 /* base time between retries */
+#define MAXRETRY 3 /* max number of retries per addr */
+#define MAXCNAMES 8 /* max # of CNAMES tried per addr */
+#define MAXQUERIES 20 /* max # of queries to be made */
+ /* (prevent "recursive" loops) */
+#define INIT_REFRESH 600 /* retry time for initial secondary */
+ /* contact (10 minutes) */
+
+#define ALPHA 0.7 /* How much to preserver of old response time */
+#define BETA 1.2 /* How much to penalize response time on failure */
+#define GAMMA 0.98 /* How much to decay unused response times */
+
+struct zoneinfo {
+ int z_type; /* type of zone */
+ int z_auth; /* zone is authoritative */
+ char *z_origin; /* root domain name of zone */
+ time_t z_time; /* time for next refresh */
+ time_t z_lastupdate; /* time of last refresh */
+ u_long z_refresh; /* refresh interval */
+ u_long z_retry; /* refresh retry interval */
+ u_long z_expire; /* expiration time for cached info */
+ u_long z_minimum; /* minimum TTL value */
+ u_long z_serial; /* changes if zone modified */
+ char *z_source; /* source location of data */
+ time_t z_ftime; /* modification time of source file */
+ int z_addrcnt; /* address count */
+ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */
+ int z_state; /* state bits; see below */
+ u_short z_xferpid; /* xfer child pid */
+#ifdef ALLOW_UPDATES
+ int hasChanged; /* non-zero if zone has been updated
+ * since last checkpoint
+ */
+#endif ALLOW_UPDATES
+};
+
+ /* zone types (z_type) */
+#define Z_PRIMARY 1
+#define Z_SECONDARY 2
+#define Z_CACHE 3
+
+ /* zone state bits */
+#define Z_AUTH 0x01 /* should replace z_auth */
+#define Z_NEED_XFER 0x02 /* waiting to do xfer */
+#define Z_XFER_RUNNING 0x04 /* asynch. xfer is running */
+#define Z_NEED_RELOAD 0x08 /* waiting to do reload */
+#define Z_SYSLOGGED 0x10 /* have logged timeout */
+#define Z_CHANGED 0x20 /* should replace hasChanged */
+#define Z_FOUND 0x40 /* found in boot file when reloading */
+#define Z_INCLUDE 0x80 /* set if include used in file */
+#define Z_DB_BAD 0x100 /* errors when loading file */
+#define Z_TMP_FILE 0x200 /* backup file for xfer is temporary */
+#ifdef ALLOW_UPDATES
+#define Z_DYNAMIC 0x400 /* allow dynamic updates */
+#define Z_DYNADDONLY 0x800 /* dynamic mode: add new data only */
+#endif ALLOW_UPDATES
+
+ /* xfer exit codes */
+#define XFER_UPTODATE 0 /* zone is up-to-date */
+#define XFER_SUCCESS 1 /* performed transfer successfully */
+#define XFER_TIMEOUT 2 /* no server reachable/xfer timeout */
+#define XFER_FAIL 3 /* other failure, has been logged */
+
+/*
+ * Structure for recording info on forwarded queries.
+ */
+struct qinfo {
+ u_short q_id; /* id of query */
+ u_short q_nsid; /* id of forwarded query */
+ int q_dfd; /* UDP file descriptor */
+ struct sockaddr_in q_from; /* requestor's address */
+ char *q_msg; /* the message */
+ int q_msglen; /* len of message */
+ int q_naddr; /* number of addr's in q_addr */
+ int q_curaddr; /* last addr sent to */
+ struct fwdinfo *q_fwd; /* last forwarder used */
+ time_t q_time; /* time to retry */
+ struct qinfo *q_next; /* rexmit list (sorted by time) */
+ struct qinfo *q_link; /* storage list (random order) */
+ struct qserv {
+ struct sockaddr_in ns_addr; /* addresses of NS's */
+ struct databuf *ns; /* databuf for NS record */
+ struct databuf *nsdata; /* databuf for server address */
+ struct timeval stime; /* time first query started */
+ int nretry; /* # of times addr retried */
+ } q_addr[NSMAX]; /* addresses of NS's */
+ struct databuf *q_usedns[NSMAX]; /* databuf for NS that we've tried */
+ int q_nusedns;
+ int q_cname; /* # of cnames found */
+ int q_nqueries; /* # of queries required */
+ char *q_cmsg; /* the cname message */
+ int q_cmsglen; /* len of cname message */
+ struct qstream *q_stream; /* TCP stream, null if UDP */
+ int q_system; /* boolean, system query */
+};
+
+#define Q_NEXTADDR(qp,n) \
+ (((qp)->q_fwd == (struct fwdinfo *)0) ? \
+ &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr)
+
+#define PRIMING_CACHE 42
+#define QINFO_NULL ((struct qinfo *)0)
+
+#ifndef XFER
+extern struct qinfo *qfindid();
+extern struct qinfo *qnew();
+extern struct qinfo *retryqp; /* next query to retry */
+#endif /* XFER */
+
+/*
+ * Return codes from ns_forw:
+ */
+#define FW_OK 0
+#define FW_DUP 1
+#define FW_NOSERVER 2
+#define FW_SERVFAIL 3
+
+struct qstream {
+ int s_rfd; /* stream file descriptor */
+ int s_size; /* expected amount of data to recive */
+ int s_bufsize; /* amount of data recived in s_buf */
+ char *s_buf; /* buffer of recived data */
+ char *s_bufp; /* pointer into s_buf of recived data */
+ struct qstream *s_next; /* next stream */
+ struct sockaddr_in s_from; /* address query came from */
+ u_long s_time; /* time stamp of last transaction */
+ int s_refcnt; /* number of outstanding queries */
+ u_short s_tempsize; /* temporary for size from net */
+};
+
+#define QSTREAM_NULL ((struct qstream *)0)
+extern struct qstream *streamq; /* stream queue */
+
+struct qdatagram {
+ int dq_dfd; /* datagram file descriptor */
+ struct qdatagram *dq_next; /* next datagram */
+ struct in_addr dq_addr; /* address of interface */
+};
+
+#define QDATAGRAM_NULL ((struct qdatagram *)0)
+extern struct qdatagram *datagramq; /* datagram queue */
+
+struct netinfo {
+ struct netinfo *next;
+ u_long net;
+ u_long mask;
+ struct in_addr my_addr;
+};
+
+struct fwdinfo {
+ struct fwdinfo *next;
+ struct sockaddr_in fwdaddr;
+};
+
+struct nets {
+ char *name;
+ long net;
+ struct nets *next;
+};
+
+/*
+ * Statistics Defines
+ */
+struct stats {
+ unsigned long cnt;
+ char *description;
+};
+
+/* gross count of UDP packets in and out */
+#define S_INPKTS 0
+#define S_OUTPKTS 1
+/* gross count of queries and inverse queries received */
+#define S_QUERIES 2
+#define S_IQUERIES 3
+#define S_DUPQUERIES 4
+#define S_RESPONSES 5
+#define S_DUPRESP 6
+#define S_RESPOK 7
+#define S_RESPFAIL 8
+#define S_RESPFORMERR 9
+#define S_SYSQUERIES 10
+#define S_PRIMECACHE 11
+#define S_CHECKNS 12
+#define S_BADRESPONSES 13
+#define S_MARTIANS 14
+#define S_NSTATS 15 /* Careful! */
+#ifdef STATS
+extern struct stats stats[S_NSTATS];
+extern unsigned long typestats[T_ANY+1];
+#endif
+
+/*
+ * Attempt to configure for type of function returned by signal-catching
+ * functions (which signal and sigvec.sv_handler take a pointer to).
+ * This can guess for BSD; otherwise, define SIG_FN externally.
+ */
+#ifndef SIG_FN
+#ifdef BSD
+#if BSD >= 199006
+#define SIG_FN void /* signal-catching functions return void */
+#else
+#define SIG_FN int /* signal-catching functions return int */
+#endif
+#else /* BSD */
+#define SIG_FN void /* signal-catching functions return void */
+#endif /* BSD */
+#endif
+
+
+#ifdef DEBUG
+extern int debug; /* debug flag */
+extern FILE *ddt; /* debug file discriptor */
+#endif
+#ifndef XFER
+extern int ds; /* datagram socket */
+extern struct qdatagram *dqp;
+extern struct timeval tt; /* place to store time */
+
+extern struct itimerval ival; /* maintenance interval */
+extern struct zoneinfo *zones; /* zone information */
+extern int nzones; /* number of zones in use */
+
+extern int forward_only; /* true on slave server */
+#endif /* XFER */
+
+#define MAX_XFER_TIME 60 * 60 * 2 /* max seconds for an xfer */
+#define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */
+
+#ifndef XFER
+extern int xfer_running_cnt; /* number of xfers running */
+extern int xfer_deferred_cnt; /* number of deferred xfers */
+#define MAX_XFERS_RUNNING 4 /* max value of xfer_running_cnt */
+#endif /* XFER */
diff --git a/usr.sbin/named/ns_forw.c b/usr.sbin/named/ns_forw.c
new file mode 100644
index 00000000000..7c5d8af0444
--- /dev/null
+++ b/usr.sbin/named/ns_forw.c
@@ -0,0 +1,579 @@
+/*-
+ * Copyright (c) 1986 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[] = "from: @(#)ns_forw.c 4.32 (Berkeley) 3/3/91";*/
+static char rcsid[] = "$Id: ns_forw.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "ns.h"
+#include "db.h"
+
+struct qinfo *qhead = QINFO_NULL; /* head of allocated queries */
+struct qinfo *retryqp = QINFO_NULL; /* list of queries to retry */
+struct fwdinfo *fwdtab; /* list of forwarding hosts */
+
+int nsid; /* next forwarded query id */
+extern int forward_only; /* you are only a slave */
+extern int errno;
+extern u_short ns_port;
+
+time_t retrytime();
+
+/*
+ * Forward the query to get the answer since its not in the database.
+ * Returns FW_OK if a request struct is allocated and the query sent.
+ * Returns FW_DUP if this is a duplicate of a pending request.
+ * Returns FW_NOSERVER if there were no addresses for the nameservers.
+ * Returns FW_SERVFAIL on malloc error.
+ * (no action is taken on errors and qpp is not filled in.)
+ */
+ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
+ struct databuf *nsp[];
+ char *msg;
+ int msglen;
+ struct sockaddr_in *fp;
+ struct qstream *qsp;
+ int dfd;
+ struct qinfo **qpp;
+{
+ register struct qinfo *qp;
+ HEADER *hp;
+ u_short id;
+ extern char *calloc();
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"ns_forw()\n");
+#endif
+
+ /* Don't forward if we're already working on it. */
+ hp = (HEADER *) msg;
+ id = hp->id;
+ /* Look at them all */
+ for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+ if (qp->q_id == id &&
+ bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
+ ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
+ bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
+ (qp->q_cmsglen == msglen &&
+ bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
+#endif
+#ifdef STATS
+ stats[S_DUPQUERIES].cnt++;
+#endif
+ return (FW_DUP);
+ }
+ }
+
+ qp = qnew();
+ if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"forw: no nameservers found\n");
+#endif
+ qfree(qp);
+ return (FW_NOSERVER);
+ }
+ qp->q_stream = qsp;
+ qp->q_curaddr = 0;
+ qp->q_fwd = fwdtab;
+ qp->q_dfd = dfd;
+ qp->q_id = id;
+ hp->id = qp->q_nsid = htons((u_short)++nsid);
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ qp->q_from = *fp;
+ if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
+ syslog(LOG_ERR, "forw: %m");
+ qfree(qp);
+ return (FW_SERVFAIL);
+ }
+ bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
+ if (!qp->q_fwd) {
+ hp->rd = 0;
+ qp->q_addr[0].stime = tt;
+ }
+
+ schedretry(qp, retrytime(qp));
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "forw: forw -> %s %d (%d) nsid=%d id=%d %dms retry %d sec\n",
+ inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+ ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_addr[0].nsdata->d_nstime,
+ qp->q_time - tt.tv_sec);
+ if ( debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0),
+ sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"error returning msg errno=%d\n",errno);
+#endif
+ }
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+ if (qpp)
+ *qpp = qp;
+ hp->rd = 1;
+ return (0);
+}
+
+/*
+ * Lookup the address for each nameserver in `nsp' and add it to
+ * the list saved in the qinfo structure.
+ */
+nslookup(nsp, qp)
+ struct databuf *nsp[];
+ register struct qinfo *qp;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *nsdp;
+ register struct qserv *qs;
+ register int n, i;
+ struct hashbuf *tmphtp;
+ char *dname, *fname;
+ int oldn, naddr, class, found_arr;
+ time_t curtime;
+ int qcomp();
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp);
+#endif
+
+ naddr = n = qp->q_naddr;
+ curtime = (u_long) tt.tv_sec;
+ while ((nsdp = *nsp++) != NULL) {
+ class = nsdp->d_class;
+ dname = nsdp->d_data;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n",
+ dname, class, nsdp->d_type, nsdp->d_flags);
+#endif
+ /* don't put in people we have tried */
+ for (i = 0; i < qp->q_nusedns; i++)
+ if (qp->q_usedns[i] == nsdp) {
+#ifdef DEBUG
+ if (debug >= 2)
+fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data);
+#endif DEBUG
+ goto skipserver;
+ }
+
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL || fname != dname) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"%s: not found %s %x\n",dname,fname,np);
+#endif
+ continue;
+ }
+ found_arr = 0;
+ oldn = n;
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+ /*
+ * Don't use records that may become invalid to
+ * reference later when we do the rtt computation.
+ * Never delete our safety-belt information!
+ */
+ if ((dp->d_zone == 0) &&
+ (dp->d_ttl < (curtime+900)) &&
+ !(dp->d_flags & DB_F_HINT) )
+ {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"nslookup: stale entry '%s'\n",
+ np->n_dname);
+#endif
+ /* Cache invalidate the NS RR's */
+ if (dp->d_ttl < curtime)
+ delete_all(np, class, T_A);
+ n = oldn;
+ break;
+ }
+
+ found_arr++;
+ /* don't put in duplicates */
+ qs = qp->q_addr;
+ for (i = 0; i < n; i++, qs++)
+ if (bcmp((char *)&qs->ns_addr.sin_addr,
+ dp->d_data, sizeof(struct in_addr)) == 0)
+ goto skipaddr;
+ qs->ns_addr.sin_family = AF_INET;
+ qs->ns_addr.sin_port = ns_port;
+ qs->ns_addr.sin_addr =
+ *(struct in_addr *)dp->d_data;
+ qs->ns = nsdp;
+ qs->nsdata = dp;
+ qp->q_addr[n].nretry = 0;
+ n++;
+ if (n >= NSMAX)
+ goto out;
+ skipaddr: ;
+ }
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"nslookup: %d ns addrs\n", n);
+#endif
+ if (found_arr == 0 && qp->q_system == 0)
+ (void) sysquery(dname, class, T_A);
+skipserver: ;
+ }
+out:
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"nslookup: %d ns addrs total\n", n);
+#endif
+ qp->q_naddr = n;
+ if (n > 1)
+ qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp);
+ return (n - naddr);
+}
+
+qcomp(qs1, qs2)
+ struct qserv *qs1, *qs2;
+{
+
+ return (qs1->nsdata->d_nstime - qs2->nsdata->d_nstime);
+}
+
+/*
+ * Arrange that forwarded query (qp) is retried after t seconds.
+ */
+schedretry(qp, t)
+ struct qinfo *qp;
+ time_t t;
+{
+ register struct qinfo *qp1, *qp2;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt,"schedretry(%#x, %dsec)\n", qp, t);
+ if (qp->q_time)
+ fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time);
+ }
+#endif
+ t += (u_long) tt.tv_sec;
+ qp->q_time = t;
+
+ if ((qp1 = retryqp) == NULL) {
+ retryqp = qp;
+ qp->q_next = NULL;
+ return;
+ }
+ if (t < qp1->q_time) {
+ qp->q_next = qp1;
+ retryqp = qp;
+ return;
+ }
+ while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
+ qp1 = qp2;
+ qp1->q_next = qp;
+ qp->q_next = qp2;
+}
+
+/*
+ * Unsched is called to remove a forwarded query entry.
+ */
+unsched(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
+ }
+#endif
+ if( retryqp == qp ) {
+ retryqp = qp->q_next;
+ } else {
+ for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
+ if( np->q_next != qp)
+ continue;
+ np->q_next = qp->q_next; /* dequeue */
+ break;
+ }
+ }
+ qp->q_next = QINFO_NULL; /* sanity check */
+ qp->q_time = 0;
+}
+
+/*
+ * Retry is called to retransmit query 'qp'.
+ */
+retry(qp)
+ register struct qinfo *qp;
+{
+ register int n;
+ register HEADER *hp;
+
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
+#endif
+ if((HEADER *)qp->q_msg == NULL) { /*** XXX ***/
+ qremove(qp);
+ return;
+ } /*** XXX ***/
+
+ /* try next address */
+ n = qp->q_curaddr;
+ if (qp->q_fwd) {
+ qp->q_fwd = qp->q_fwd->next;
+ if (qp->q_fwd)
+ goto found;
+ /* out of forwarders, try direct queries */
+ } else
+ ++qp->q_addr[n].nretry;
+ if (!forward_only) {
+ do {
+ if (++n >= qp->q_naddr)
+ n = 0;
+ if (qp->q_addr[n].nretry < MAXRETRY)
+ goto found;
+ } while (n != qp->q_curaddr);
+ }
+ /*
+ * Give up. Can't reach destination.
+ */
+ hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
+ if (qp->q_system == PRIMING_CACHE) {
+ /* Can't give up priming */
+ unsched(qp);
+ schedretry(qp, (time_t)60*60); /* 1 hour */
+ hp->rcode = NOERROR; /* Lets be safe, reset the query */
+ hp->qr = hp->aa = 0;
+ qp->q_fwd = fwdtab;
+ for (n = 0; n < qp->q_naddr; n++)
+ qp->q_addr[n].nretry = 0;
+ return;
+ }
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"give up\n");
+#endif
+ n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
+ hp->id = qp->q_id;
+ hp->qr = 1;
+ hp->ra = 1;
+ hp->rd = 1;
+ hp->rcode = SERVFAIL;
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ if (send_msg((char *)hp, n, qp)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
+ qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
+#endif
+ }
+ qremove(qp);
+ return;
+
+found:
+ if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
+ qp->q_addr[n].stime = tt;
+ qp->q_curaddr = n;
+ hp = (HEADER *)qp->q_msg;
+ hp->rd = (qp->q_fwd ? 1 : 0);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
+ (qp->q_fwd ? "reforw" : "resend"),
+ n, qp->q_addr[n].nretry,
+ inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
+ ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_addr[n].nsdata->d_nstime);
+ if ( debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ /* NOSTRICT */
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)Q_NEXTADDR(qp,n),
+ sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"error resending msg errno=%d\n",errno);
+#endif
+ }
+ hp->rd = 1; /* leave set to 1 for dup detection */
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+ unsched(qp);
+ schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
+}
+
+/*
+ * Compute retry time for the next server for a query.
+ * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
+ * service time; * back off exponentially on retries, but place a 45-sec.
+ * ceiling on retry times for now. (This is because we don't hold a reference
+ * on servers or their addresses, and we have to finish before they time out.)
+ */
+time_t
+retrytime(qp)
+register struct qinfo *qp;
+{
+ time_t t;
+ struct qserv *ns = &qp->q_addr[qp->q_curaddr];
+
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"retrytime: nstime %dms.\n",
+ ns->nsdata->d_nstime / 1000);
+#endif
+ t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
+ t <<= ns->nretry;
+ t = MIN(t, 45); /* max. retry timeout for now */
+#ifdef notdef
+ if (qp->q_system)
+ return ((2 * t) + 5); /* system queries can wait. */
+#endif
+ return (t);
+}
+
+qflush()
+{
+ while (qhead)
+ qremove(qhead);
+ qhead = QINFO_NULL;
+}
+
+qremove(qp)
+register struct qinfo *qp;
+{
+#ifdef DEBUG
+ if(debug > 3)
+ fprintf(ddt,"qremove(x%x)\n", qp);
+#endif
+ unsched(qp); /* get off queue first */
+ qfree(qp);
+}
+
+struct qinfo *
+qfindid(id)
+register u_short id;
+{
+ register struct qinfo *qp;
+
+#ifdef DEBUG
+ if(debug > 3)
+ fprintf(ddt,"qfindid(%d)\n", ntohs(id));
+#endif
+ for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+ if (qp->q_nsid == id)
+ return(qp);
+ }
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"qp not found\n");
+#endif
+ return(NULL);
+}
+
+struct qinfo *
+qnew()
+{
+ register struct qinfo *qp;
+
+ if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"qnew: calloc error\n");
+#endif
+ syslog(LOG_ERR, "forw: %m");
+ exit(12);
+ }
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"qnew(x%x)\n", qp);
+#endif
+ qp->q_link = qhead;
+ qhead = qp;
+ return( qp );
+}
+
+qfree(qp)
+struct qinfo *qp;
+{
+ register struct qinfo *np;
+
+#ifdef DEBUG
+ if(debug > 3)
+ fprintf(ddt,"qfree( x%x )\n", qp);
+ if(debug && qp->q_next)
+ fprintf(ddt,"WARNING: qfree of linked ptr x%x\n", qp);
+#endif
+ if (qp->q_msg)
+ free(qp->q_msg);
+ if (qp->q_cmsg)
+ free(qp->q_cmsg);
+ if( qhead == qp ) {
+ qhead = qp->q_link;
+ } else {
+ for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link ) {
+ if( np->q_link != qp ) continue;
+ np->q_link = qp->q_link; /* dequeue */
+ break;
+ }
+ }
+ (void)free((char *)qp);
+}
diff --git a/usr.sbin/named/ns_init.c b/usr.sbin/named/ns_init.c
new file mode 100644
index 00000000000..0050a0c8b1f
--- /dev/null
+++ b/usr.sbin/named/ns_init.c
@@ -0,0 +1,704 @@
+/*-
+ * Copyright (c) 1986, 1990 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[] = "from: @(#)ns_init.c 4.38 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: ns_init.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <signal.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#undef nsaddr
+#include "pathnames.h"
+#include "ns.h"
+#include "db.h"
+
+struct zoneinfo *zones; /* zone information */
+int nzones; /* number of zones in use */
+int forward_only = 0; /* run only as a slave */
+char *cache_file;
+char *localdomain; /* "default" for non-dotted names */
+int maint_interval = 15*60; /* minimum ns_maint() interval */
+
+extern int lineno;
+
+
+/*
+ * Read boot file for configuration info.
+ */
+
+ns_init(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ struct zoneinfo *find_zone();
+ char buf[BUFSIZ], obuf[BUFSIZ], *source;
+ extern char *calloc();
+ FILE *fp;
+ int type;
+ extern int needmaint;
+ struct stat f_time;
+ static int loads = 0; /* number of times loaded */
+ static int tmpnum = 0; /* unique number for tmp zone files */
+#ifdef ALLOW_UPDATES
+ char *cp, *flag;
+#endif
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"\nns_init(%s)\n", bootfile);
+#endif
+ gettime(&tt);
+
+ if ((fp = fopen(bootfile, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", bootfile);
+ exit(1);
+ }
+ lineno = 0;
+ if (loads == 0) {
+ if ((zones =
+ (struct zoneinfo *)calloc(64, sizeof(struct zoneinfo)))
+ == NULL) {
+ syslog(LOG_ERR,
+ "Not enough memory to allocate initial zones array");
+ exit(1);
+ }
+ nzones = 1; /* zone zero is cache data */
+ /* allocate cache hash table, formerly the root hash table. */
+ hashtab = savehash((struct hashbuf *)NULL);
+
+ /* allocate root-hints/file-cache hash table */
+ fcachetab = savehash((struct hashbuf *)NULL);
+ /* init zone data */
+ zones[0].z_type = Z_CACHE;
+ } else {
+ /* Mark previous zones as not yet found in boot file. */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ zp->z_state &= ~Z_FOUND;
+ if (localdomain)
+ free(localdomain);
+ localdomain = NULL;
+ free_forwarders();
+ forward_only = 0;
+ }
+
+#ifdef DEBUG
+ if (debug >= 3) {
+ fprintf(ddt,"\n content of zones before loading \n");
+ content_zone(nzones - 1);
+ }
+#endif
+ while (!feof(fp) && !ferror(fp)) {
+ if (!getword(buf, sizeof(buf), fp))
+ continue;
+ /* read named.boot keyword and process args */
+ if (strcasecmp(buf, "directory") == 0) {
+ (void) getword(buf, sizeof(buf), fp);
+ if (chdir(buf) < 0) {
+ syslog(LOG_CRIT, "directory %s: %m\n",
+ buf);
+ exit(1);
+ }
+ continue;
+ } else if (strcasecmp(buf, "sortlist") == 0) {
+ get_sort_list(fp);
+ continue;
+ } else if (strcasecmp(buf, "forwarders") == 0) {
+ get_forwarders(fp);
+ continue;
+ } else if (strcasecmp(buf, "slave") == 0) {
+ forward_only++;
+ endline(fp);
+ continue;
+ } else if (strcasecmp(buf, "domain") == 0) {
+ if (getword(buf, sizeof(buf), fp))
+ localdomain = savestr(buf);
+ endline(fp);
+ continue;
+ } else if (strcasecmp(buf, "cache") == 0)
+ type = Z_CACHE;
+ else if (strcasecmp(buf, "primary") == 0)
+ type = Z_PRIMARY;
+ else if (strcasecmp(buf, "secondary") == 0)
+ type = Z_SECONDARY;
+ else {
+ syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
+ bootfile, lineno, buf);
+ endline(fp);
+ continue;
+ }
+
+ /*
+ * read zone origin
+ */
+ if (!getword(obuf, sizeof(obuf), fp)) {
+ syslog(LOG_ERR, "%s: line %d: missing origin\n",
+ bootfile, lineno);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "zone origin %s", obuf);
+#endif
+ if (obuf[0] == '.' && obuf[1] == '\0')
+ obuf[0] = '\0';
+ /*
+ * read source file or host address
+ */
+ if (!getword(buf, sizeof(buf), fp)) {
+ syslog(LOG_ERR,
+ "%s: line %d: missing source or addr\n",
+ bootfile, lineno);
+ continue;
+ }
+
+ /* check for previous instance of this zone (reload) */
+ if ((zp = find_zone(obuf, type)) == 0) {
+ if (type == Z_CACHE) {
+ zp = &zones[0];
+ zp->z_origin = "";
+ goto gotzone;
+ }
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == 0)
+ goto gotzone;
+ /*
+ * this code assume that nzones never decreases
+ */
+ if (nzones % 64 == 0) {
+#ifdef DEBUG
+ if (debug > 1)
+ fprintf(ddt, "Reallocating zones structure\n");
+#endif DEBUG
+ /*
+ * Realloc() not used since it might damage zones
+ * if an error occurs
+ */
+ if ((zp = (struct zoneinfo *)
+ malloc((64 + nzones) * sizeof(struct zoneinfo)))
+ == NULL) {
+ syslog(LOG_ERR, "no memory for more zones");
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "Out of memory for new zones\n");
+#endif DEBUG
+ endline(fp);
+ continue;
+ }
+ bcopy((char *)zones, (char *)zp,
+ nzones * sizeof(struct zoneinfo));
+ bzero((char *)&zp[nzones],
+ 64 * sizeof(struct zoneinfo));
+ free(zones);
+ zones = zp;
+ }
+ zp = &zones[nzones++];
+ gotzone:
+ zp->z_origin = savestr(obuf);
+ zp->z_type = type;
+ }
+ zp->z_addrcnt = 0;
+
+ switch (type) {
+ case Z_CACHE:
+ source = savestr(buf);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,", source = %s\n", source);
+#endif
+ zp->z_refresh = 0; /* by default, no dumping */
+ if (getword(buf, sizeof(buf), fp)) {
+#ifdef notyet
+ zp->z_refresh = atoi(buf);
+ if (zp->z_refresh <= 0) {
+ syslog(LOG_ERR,
+ "%s: line %d: bad refresh time '%s', ignored\n",
+ bootfile, lineno, buf);
+ zp->z_refresh = 0;
+ } else if (cache_file == NULL)
+ cache_file = source;
+#else
+ syslog(LOG_WARNING,
+ "%s: line %d: cache refresh ignored\n",
+ bootfile, lineno);
+#endif
+ endline(fp);
+ }
+ /*
+ * If we've loaded this file, and the file has
+ * not been modified and contains no $include,
+ * then there's no need to reload.
+ */
+ if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
+ (zp->z_state & Z_INCLUDE) == 0 &&
+ stat(zp->z_source, &f_time) == 0 &&
+ zp->z_ftime == f_time.st_mtime) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "cache is up to date\n");
+#endif
+ break; /* zone is already up to date */
+ }
+
+ /* file has changed, or hasn't been loaded yet */
+ if (zp->z_source) {
+ free(zp->z_source);
+ remove_zone(fcachetab, 0);
+ }
+ zp->z_source = source;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "reloading zone\n");
+#endif
+ (void) db_load(zp->z_source, zp->z_origin, zp, 0);
+ break;
+
+ case Z_PRIMARY:
+ source = savestr(buf);
+#ifdef ALLOW_UPDATES
+ if (getword(buf, sizeof(buf), fp)) {
+ endline(fp);
+ flag = buf;
+ while (flag) {
+ cp = index(flag, ',');
+ if (cp)
+ *cp++ = 0;
+ if (strcasecmp(flag, "dynamic") == 0)
+ zp->z_state |= Z_DYNAMIC;
+ else if (strcasecmp(flag, "addonly") == 0)
+ zp->z_state |= Z_DYNADDONLY;
+ else {
+ syslog(LOG_ERR,
+ "%s: line %d: bad flag '%s'\n",
+ bootfile, lineno, flag);
+ }
+ flag = cp;
+ }
+ }
+#else ALLOW_UPDATES
+ endline(fp);
+#endif
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,", source = %s\n", source);
+#endif
+ /*
+ * If we've loaded this file, and the file has
+ * not been modified and contains no $include,
+ * then there's no need to reload.
+ */
+ if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
+ (zp->z_state & Z_INCLUDE) == 0 &&
+ stat(zp->z_source, &f_time) == 0 &&
+ zp->z_ftime == f_time.st_mtime) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "zone is up to date\n");
+#endif
+ break; /* zone is already up to date */
+ }
+ if (zp->z_source) {
+ free(zp->z_source);
+ remove_zone(hashtab, zp - zones);
+ }
+ zp->z_source = source;
+ zp->z_auth = 0;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "reloading zone\n");
+#endif
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_auth = 1;
+#ifdef ALLOW_UPDATES
+ /* Guarantee calls to ns_maint() */
+ zp->z_refresh = maint_interval;
+#else ALLOW_UPDATES
+ zp->z_refresh = 0; /* no maintenance needed */
+ zp->z_time = 0;
+#endif ALLOW_UPDATES
+ break;
+
+ case Z_SECONDARY:
+ source = 0;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"\n\taddrs: ");
+#endif
+ do {
+ zp->z_addr[zp->z_addrcnt].s_addr =
+ inet_addr(buf);
+ if (zp->z_addr[zp->z_addrcnt].s_addr ==
+ (u_long)-1) {
+ source = savestr(buf);
+ endline(fp);
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"%s, ",buf);
+#endif
+ if (++zp->z_addrcnt > NSMAX - 1) {
+ zp->z_addrcnt = NSMAX - 1;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "\nns.h NSMAX reached\n");
+#endif
+ }
+ } while (getword(buf, sizeof(buf), fp));
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt);
+#endif
+ if (source == 0) {
+ /*
+ * We will always transfer this zone again
+ * after a reload.
+ */
+ sprintf(buf, "/%s/NsTmp%d", _PATH_TMPDIR,
+ tmpnum++);
+ source = savestr(buf);
+ zp->z_state |= Z_TMP_FILE;
+ } else
+ zp->z_state &= ~Z_TMP_FILE;
+ /*
+ * If we had a backup file name, and it was changed,
+ * free old zone and start over. If we don't have
+ * current zone contents, try again now in case
+ * we have a new server on the list.
+ */
+ if (zp->z_source && strcmp(source, zp->z_source)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"backup file changed\n");
+#endif
+ free(zp->z_source);
+ zp->z_source = 0;
+ zp->z_auth = 0;
+ zp->z_serial = 0; /* force xfer */
+ remove_zone(hashtab, zp - zones);
+ }
+ if (zp->z_source)
+ free(source);
+ else
+ zp->z_source = source;
+ if (zp->z_auth == 0)
+ zoneinit(zp);
+ break;
+
+ }
+ zp->z_state |= Z_FOUND;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"zone[%d] type %d: '%s'",
+ zp-zones, type,
+ *(zp->z_origin) == '\0' ? "." : zp->z_origin);
+#endif
+ if (zp->z_refresh && zp->z_time == 0)
+ zp->z_time = zp->z_refresh + tt.tv_sec;
+ if (zp->z_time <= tt.tv_sec)
+ needmaint = 1;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, " z_time %d, z_refresh %d\n",
+ zp->z_time, zp->z_refresh);
+#endif
+ }
+ (void) fclose(fp);
+ /* erase all old zones that were not found */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type && (zp->z_state & Z_FOUND) == 0) {
+ remove_zone(hashtab, zp - zones);
+ bzero((char *) zp, sizeof(*zp));
+#ifdef DEBUG
+ if(debug >=2)
+ fprintf(ddt,"\n zone no %d was removed \n", zp - zones);
+#endif
+ }
+#ifdef DEBUG
+ if(debug >= 2) {
+ fprintf(ddt,"\n content of zones after loading \n");
+ content_zone(nzones-1);
+ }
+#endif
+
+ /*
+ * Schedule calls to ns_maint().
+ */
+ if (needmaint == 0)
+ sched_maint();
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"exit ns_init()%s\n", needmaint ?
+ ", need maintenance immediately" : "");
+#endif
+ loads++;
+}
+
+zoneinit(zp)
+ register struct zoneinfo *zp;
+{
+ extern int needmaint;
+ struct stat sb;
+
+ /*
+ * Try to load zone from backup file,
+ * if one was specified and it exists.
+ * If not, or if the data are out of date,
+ * we will refresh the zone from a primary
+ * immediately.
+ */
+ if (zp->z_source == NULL)
+ return;
+ if (stat(zp->z_source, &sb) == -1 ||
+ db_load(zp->z_source, zp->z_origin, zp, 0) != 0) {
+ /*
+ * Set zone to be refreshed immediately.
+ */
+ zp->z_refresh = INIT_REFRESH;
+ zp->z_retry = INIT_REFRESH;
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ } else
+ zp->z_auth = 1;
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Look for the authoritative zone with the longest matching RHS of dname
+ * and return its zone # or zero if not found.
+ */
+findzone(dname, class)
+ char *dname;
+ int class;
+{
+ char *dZoneName, *zoneName, *index();
+ int dZoneNameLen, zoneNameLen;
+ int maxMatchLen = 0;
+ int maxMatchZoneNum = 0;
+ int zoneNum;
+
+#ifdef DEBUG
+ if (debug >= 4)
+ fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class);
+ if (debug >= 5) {
+ fprintf(ddt, "zone dump:\n");
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++)
+ printzoneinfo(zoneNum);
+ }
+#endif DEBUG
+
+ dZoneName = index(dname, '.');
+ if (dZoneName == NULL)
+ dZoneName = ""; /* root */
+ else
+ dZoneName++; /* There is a '.' in dname, so use remainder of
+ string as the zone name */
+ dZoneNameLen = strlen(dZoneName);
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
+ zoneName = (zones[zoneNum]).z_origin;
+ zoneNameLen = strlen(zoneName);
+ /* The zone name may or may not end with a '.' */
+ if (zoneName[zoneNameLen - 1] == '.')
+ zoneNameLen--;
+ if (dZoneNameLen != zoneNameLen)
+ continue;
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n",
+ dZoneName, zoneName, dZoneNameLen);
+#endif
+ if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt, "match\n");
+#endif
+ /*
+ * See if this is as long a match as any so far.
+ * Check if "<=" instead of just "<" so that if
+ * root domain (whose name length is 0) matches,
+ * we use it's zone number instead of just 0
+ */
+ if (maxMatchLen <= zoneNameLen) {
+ maxMatchZoneNum = zoneNum;
+ maxMatchLen = zoneNameLen;
+ }
+ }
+#ifdef DEBUG
+ else
+ if (debug >= 5)
+ fprintf(ddt, "no match\n");
+#endif
+ }
+#ifdef DEBUG
+ if (debug >= 4)
+ fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum);
+#endif DEBUG
+ return (maxMatchZoneNum);
+}
+#endif ALLOW_UPDATES
+
+soa_zinfo(zp, cp, eom)
+ register struct zoneinfo *zp;
+ register u_char *cp;
+ u_char *eom;
+{
+ cp += 3 * sizeof(u_short);
+ cp += sizeof(u_long);
+ cp += dn_skipname(cp, eom);
+ cp += dn_skipname(cp, eom);
+ GETLONG(zp->z_serial, cp);
+ GETLONG(zp->z_refresh, cp);
+ gettime(&tt);
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ GETLONG(zp->z_retry, cp);
+ GETLONG(zp->z_expire, cp);
+ GETLONG(zp->z_minimum, cp);
+}
+
+get_forwarders(fp)
+ FILE *fp;
+{
+ char buf[BUFSIZ];
+ register struct fwdinfo *fip = NULL, *ftp = NULL;
+ extern struct sockaddr_in nsaddr;
+ extern struct fwdinfo *fwdtab;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"forwarders ");
+#endif
+
+ /* on mulitple forwarder lines, move to end of the list */
+ if (fwdtab != NULL)
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next)
+ ;
+
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt," %s",buf);
+#endif
+ if (ftp == NULL)
+ ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+ if (isdigit(buf[0]) &&
+ (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf)) !=
+ (u_long)-1) {
+ ftp->fwdaddr.sin_port = nsaddr.sin_port;
+ ftp->fwdaddr.sin_family = AF_INET;
+ } else {
+ syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt," (ignored, NOT dotted quad)");
+#endif
+ continue;
+ }
+ ftp->next = NULL;
+ if (fwdtab == NULL)
+ fwdtab = ftp; /* First time only */
+ else
+ fip->next = ftp;
+ fip = ftp;
+ ftp = NULL;
+ }
+ if (ftp)
+ free((char *)ftp);
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"\n");
+ if (debug > 2)
+ for (ftp = fwdtab; ftp != NULL; ftp = ftp->next)
+ fprintf(ddt,"ftp x%x %s next x%x\n", ftp,
+ inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next);
+#endif
+}
+
+free_forwarders()
+{
+ extern struct fwdinfo *fwdtab;
+ register struct fwdinfo *ftp, *fnext;
+
+ for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+ fnext = ftp->next;
+ free((char *)ftp);
+ }
+ fwdtab = NULL;
+}
+
+struct zoneinfo *
+find_zone(name, type)
+ char *name;
+ int type;
+{
+ register struct zoneinfo *zp;
+
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == type && strcasecmp(name, zp->z_origin) == 0) {
+#ifdef DEBUG
+ if (debug > 1)
+ fprintf(ddt, ", old zone (%d)", zp - zones);
+#endif
+ return (zp);
+ }
+#ifdef DEBUG
+ if(debug > 1)
+ fprintf(ddt, ", new zone");
+#endif
+ return ((struct zoneinfo *)NULL);
+}
+
+/* prints out the content of zones */
+content_zone(end)
+ int end;
+{
+ int i;
+ for (i = 1; i <= end; i++)
+ printzoneinfo(i);
+}
diff --git a/usr.sbin/named/ns_main.c b/usr.sbin/named/ns_main.c
new file mode 100644
index 00000000000..67679302f2f
--- /dev/null
+++ b/usr.sbin/named/ns_main.c
@@ -0,0 +1,1301 @@
+/*
+ * Copyright (c) 1986, 1989, 1990 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
+char copyright[] =
+"@(#) Copyright (c) 1986, 1989, 1990 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)ns_main.c 4.55 (Berkeley) 7/1/91";*/
+static char rcsid[] = "$Id: ns_main.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+/*
+* Internet Name server (see rfc883 & others).
+*/
+
+#include <sys/param.h>
+#if defined(SYSV)
+#include <fcntl.h>
+#endif SYSV
+#include <sys/file.h>
+#include <sys/time.h>
+#if !defined(SYSV)
+#include <sys/wait.h>
+#endif !SYSV
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#undef nsaddr /* XXX */
+#include "ns.h"
+#include "db.h"
+#include "pathnames.h"
+
+#ifdef BOOTFILE /* default boot file */
+char *bootfile = BOOTFILE;
+#else
+char *bootfile = _PATH_BOOT;
+#endif
+
+#ifdef DEBUGFILE /* default debug output file */
+char *debugfile = DEBUGFILE;
+#else
+char *debugfile = _PATH_DEBUG;
+#endif
+
+#ifdef PIDFILE /* file to store current named PID */
+char *PidFile = PIDFILE;
+#else
+char *PidFile = _PATH_PIDFILE;
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SETSIZE 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+#endif
+
+FILE *fp; /* file descriptor for pid file */
+
+#ifdef DEBUG
+FILE *ddt;
+#endif
+
+int debug = 0; /* debugging flag */
+int ds; /* datagram socket */
+int needreload = 0; /* received SIGHUP, need to reload db */
+int needmaint = 0; /* need to call ns_maint()*/
+int needzoneload = 0; /* need to reload secondary zone(s) */
+int needToDoadump = 0; /* need to dump database */
+int needToChkpt = 0; /* need to checkpoint cache */
+int needStatsDump = 0; /* need to dump statistics */
+#ifdef ALLOW_UPDATES
+int needToExit = 0; /* need to exit (may need to doadump
+ * first, if database has changed since
+ * it was last dumped/booted). Gets
+ * set by shutdown signal handler
+ * (onintr)
+ */
+#endif ALLOW_UPDATES
+
+int priming = 0; /* is cache being primed */
+
+#ifdef SO_RCVBUF
+int rbufsize = 8 * 1024; /* UDP recive buffer size */
+#endif
+
+struct qstream *streamq = QSTREAM_NULL; /* list of open streams */
+struct qdatagram *datagramq = QDATAGRAM_NULL; /* list of datagram interfaces */
+struct sockaddr_in nsaddr;
+struct timeval tt;
+/*
+ * We keep a list of favored networks headed by nettab.
+ * There are three (possibly empty) parts to this list, in this order:
+ * 1. directly attached (sub)nets.
+ * 2. logical networks for directly attached subnetted networks.
+ * 3. networks from the sort list.
+ * The value (*elocal) points at the first entry in the second part of the list,
+ * if any, while (*enettab) points at the first entry in the sort list.
+ */
+struct netinfo *nettab = NULL;
+struct netinfo **elocal = &nettab;
+struct netinfo **enettab = &nettab;
+struct netinfo netloop;
+struct netinfo *findnetinfo();
+u_long net_mask();
+u_short ns_port;
+struct sockaddr_in from_addr; /* Source addr of last packet */
+int from_len; /* Source addr size of last packet */
+time_t boottime, resettime; /* Used by ns_stats */
+static fd_set mask; /* select mask of open descriptors */
+static int nfds; /* number of fds for select */
+static int vs; /* listening TCP socket */
+
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArg = NULL; /* end of argv */
+
+extern int errno;
+
+#if defined(SYSV)
+getdtablesize()
+{
+ return(FD_SETSIZE);
+}
+#endif SYSV
+
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ register int n, udpcnt;
+ register char *arg;
+ register struct qstream *sp;
+ register struct qdatagram *dqp;
+ struct qstream *nextsp;
+ int on = 1;
+ int rfd, size;
+ u_long lasttime, maxctime;
+ char buf[BUFSIZ];
+#ifndef SYSV
+ struct sigvec vec;
+#endif
+
+ fd_set tmpmask;
+
+ struct timeval t, *tp;
+ struct qstream *candidate = QSTREAM_NULL;
+ extern SIG_FN onintr(), maint_alarm(), endxfer();
+ extern SIG_FN setdumpflg(), onhup();
+ extern SIG_FN setIncrDbgFlg(), setNoDbgFlg(), sigprof();
+ extern SIG_FN setchkptflg(), setstatsflg();
+ extern int loadxfer();
+ extern struct qstream *sqadd();
+ extern struct qinfo *qhead;
+ extern char Version[];
+
+ ns_port = htons(NAMESERVER_PORT);
+
+ /*
+ ** Save start and extent of argv for setproctitle.
+ */
+
+ Argv = argv;
+ if (envp == 0 || *envp == 0)
+ envp = argv;
+ while (*envp)
+ envp++;
+ LastArg = envp[-1] + strlen(envp[-1]);
+
+ (void) umask(022);
+ while (--argc > 0) {
+ arg = *++argv;
+ if (*arg == '-') {
+ while (*++arg)
+ switch (*arg) {
+ case 'b':
+ if (--argc <= 0)
+ usage();
+ bootfile = *++argv;
+ break;
+
+ case 'd':
+ ++argv;
+
+ if (*argv != 0) {
+ if (**argv == '-') {
+ argv--;
+ break;
+ }
+ debug = atoi(*argv);
+ --argc;
+ }
+ if (debug <= 0)
+ debug = 1;
+ setdebug(1);
+ break;
+
+ case 'p':
+ if (--argc <= 0)
+ usage();
+ ns_port = htons((u_short)atoi(*++argv));
+ break;
+
+ default:
+ usage();
+ }
+ } else
+ bootfile = *argv;
+ }
+
+ if (!debug)
+ for (n = getdtablesize() - 1; n > 2; n--)
+ (void) close(n);
+#ifdef DEBUG
+ else {
+ fprintf(ddt,"Debug turned ON, Level %d\n",debug);
+ fprintf(ddt,"Version = %s\t",Version);
+ fprintf(ddt,"bootfile = %s\n",bootfile);
+ }
+#endif
+
+#ifdef LOG_DAEMON
+ openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY, LOG_DAEMON);
+#else
+ openlog("named", LOG_PID);
+#endif
+
+ /* tuck my process id away */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+ syslog(LOG_NOTICE, "restarted\n");
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
+ nsaddr.sin_family = AF_INET;
+ nsaddr.sin_addr.s_addr = INADDR_ANY;
+ nsaddr.sin_port = ns_port;
+
+ /*
+ ** Open stream port.
+ */
+ if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
+ exit(1);
+ }
+ (void)setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
+ if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
+ syslog(LOG_ERR, "bind(vs, %s[%d]): %m",
+ inet_ntoa(nsaddr.sin_addr), ntohs(nsaddr.sin_port));
+ exit(1);
+ }
+ (void) listen(vs, 5);
+
+ /*
+ * Get list of local addresses and set up datagram sockets.
+ */
+ getnetconf();
+
+ /*
+ ** Initialize and load database.
+ */
+ gettime(&tt);
+ buildservicelist();
+ buildprotolist();
+ ns_init(bootfile);
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt, "Network and sort list:\n");
+ printnetinfo(nettab);
+ }
+#endif DEBUG
+
+ time(&boottime);
+ resettime = boottime;
+
+ (void) signal(SIGHUP, onhup);
+#if defined(SYSV)
+ (void) signal(SIGCLD, endxfer);
+ (void) signal(SIGALRM, maint_alarm);
+#else
+ bzero((char *)&vec, sizeof(vec));
+ vec.sv_handler = maint_alarm;
+ vec.sv_mask = sigmask(SIGCHLD);
+ (void) sigvec(SIGALRM, &vec, (struct sigvec *)NULL);
+
+ vec.sv_handler = endxfer;
+ vec.sv_mask = sigmask(SIGALRM);
+ (void) sigvec(SIGCHLD, &vec, (struct sigvec *)NULL);
+#endif SYSV
+ (void) signal(SIGPIPE, SIG_IGN);
+ (void) signal(SIGSYS, sigprof);
+ (void) signal(SIGINT, setdumpflg);
+ (void) signal(SIGQUIT, setchkptflg);
+ (void) signal(SIGIOT, setstatsflg);
+
+#ifdef ALLOW_UPDATES
+ /* Catch SIGTERM so we can dump the database upon shutdown if it
+ has changed since it was last dumped/booted */
+ (void) signal(SIGTERM, onintr);
+#endif ALLOW_UPDATES
+
+#if defined(SIGUSR1) && defined(SIGUSR2)
+ (void) signal(SIGUSR1, setIncrDbgFlg);
+ (void) signal(SIGUSR2, setNoDbgFlg);
+#else SIGUSR1&&SIGUSR2
+ (void) signal(SIGEMT, setIncrDbgFlg);
+ (void) signal(SIGFPE, setNoDbgFlg);
+#endif SIGUSR1&&SIGUSR2
+
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt,"database initialized\n");
+ }
+#endif
+
+ t.tv_usec = 0;
+
+ /*
+ * Fork and go into background now that
+ * we've done any slow initialization
+ * and are ready to answer queries.
+ */
+ if (!debug) {
+#if defined(BSD) && BSD >= 199006
+ daemon(1, 0);
+#else
+ if (fork() > 0)
+ exit(0);
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) close(n);
+#ifdef SYSV
+ setpgrp();
+#else
+ {
+ struct itimerval ival;
+
+ /*
+ * The open below may hang on pseudo ttys if the person
+ * who starts named logs out before this point.
+ *
+ * needmaint may get set inapropriately if the open
+ * hangs, but all that will happen is we will see that
+ * no maintenance is required.
+ */
+ bzero((char *)&ival, sizeof(ival));
+ ival.it_value.tv_sec = 120;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ n = open(_PATH_TTY, O_RDWR);
+ ival.it_value.tv_sec = 0;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ if (n > 0) {
+ (void) ioctl(n, TIOCNOTTY, (char *)NULL);
+ (void) close(n);
+ }
+ }
+#endif /* SYSV */
+#endif /* BSD > 199006 */
+ }
+ /* tuck my process id away again */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"Ready to answer queries.\n");
+#endif
+ prime_cache();
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ if (vs >= nfds)
+ nfds = vs + 1;
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) {
+ FD_SET(dqp->dq_dfd, &mask);
+ if (dqp->dq_dfd >= nfds)
+ nfds = dqp->dq_dfd + 1;
+ }
+ for (;;) {
+#ifdef DEBUG
+ if (ddt && debug == 0) {
+ fprintf(ddt,"Debug turned OFF\n");
+ (void) fclose(ddt);
+ ddt = 0;
+ }
+#endif
+#ifdef ALLOW_UPDATES
+ if (needToExit) {
+ struct zoneinfo *zp;
+ sigblock(~0); /*
+ * Block all blockable signals
+ * to ensure a consistant
+ * state during final dump
+ */
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "Received shutdown signal\n");
+#endif DEBUG
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->hasChanged)
+ zonedump(zp);
+ }
+ exit(0);
+ }
+#endif ALLOW_UPDATES
+ if (needreload) {
+ needreload = 0;
+ db_reload();
+ }
+#ifdef STATS
+ if (needStatsDump) {
+ needStatsDump = 0;
+ ns_stats();
+ }
+#endif STATS
+ if (needzoneload) {
+ needzoneload = 0;
+ loadxfer();
+ }
+ if (needmaint) {
+ needmaint = 0;
+ ns_maint();
+ }
+ if(needToChkpt) {
+ needToChkpt = 0;
+ doachkpt();
+ }
+ if(needToDoadump) {
+ needToDoadump = 0;
+ doadump();
+ }
+ /*
+ ** Wait until a query arrives
+ */
+ if (retryqp != NULL) {
+ gettime(&tt);
+ t.tv_sec = (long) retryqp->q_time - tt.tv_sec;
+ if (t.tv_sec <= 0) {
+ retry(retryqp);
+ continue;
+ }
+ tp = &t;
+ } else
+ tp = NULL;
+ tmpmask = mask;
+ n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"select error\n");
+#endif
+ ;
+ }
+ if (n == 0)
+ continue;
+
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL;
+ dqp = dqp->dq_next) {
+ if (FD_ISSET(dqp->dq_dfd, &tmpmask))
+ for(udpcnt = 0; udpcnt < 25; udpcnt++) {
+ from_len = sizeof(from_addr);
+ if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from_addr, &from_len)) < 0)
+ {
+ if ((n == -1) && (errno == EWOULDBLOCK))
+ break;
+ syslog(LOG_WARNING, "recvfrom: %m");
+ break;
+ }
+#ifdef STATS
+ stats[S_INPKTS].cnt++;
+#endif
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "\ndatagram from %s port %d, fd %d, len %d\n",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port), dqp->dq_dfd, n);
+ if (debug >= 10)
+ fp_query(buf, ddt);
+#endif
+ /*
+ * Consult database to get the answer.
+ */
+ gettime(&tt);
+ ns_req(buf, n, PACKETSZ, QSTREAM_NULL, &from_addr,
+ dqp->dq_dfd);
+ }
+ }
+ /*
+ ** Process stream connection
+ */
+ if (FD_ISSET(vs, &tmpmask)) {
+ from_len = sizeof(from_addr);
+ rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
+ gettime(&tt);
+ if (rfd < 0 && errno == EMFILE && streamq != NULL) {
+ maxctime = 0;
+ candidate = QSTREAM_NULL;
+ for (sp = streamq; sp != QSTREAM_NULL;
+ sp = nextsp) {
+ nextsp = sp->s_next;
+ if (sp->s_refcnt != 0)
+ continue;
+ lasttime = tt.tv_sec - sp->s_time;
+ if (lasttime >= 900)
+ sqrm(sp);
+ else if (lasttime > maxctime) {
+ candidate = sp;
+ maxctime = lasttime;
+ }
+ }
+ rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
+ if ((rfd < 0) && (errno == EMFILE) &&
+ candidate != QSTREAM_NULL) {
+ sqrm(candidate);
+ rfd = accept(vs, (struct sockaddr *)&from_addr, &from_len);
+ }
+ }
+ if (rfd < 0) {
+ syslog(LOG_WARNING, "accept: %m");
+ continue;
+ }
+ (void) fcntl(rfd, F_SETFL, O_NONBLOCK);
+ (void) setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on));
+ if ((sp = sqadd()) == QSTREAM_NULL) {
+ (void) close(rfd);
+ continue;
+ }
+ sp->s_rfd = rfd; /* stream file descriptor */
+ sp->s_size = -1; /* amount of data to receive */
+ gettime(&tt);
+ sp->s_time = tt.tv_sec; /* last transaction time */
+ sp->s_from = from_addr; /* address to respond to */
+ sp->s_bufp = (char *)&sp->s_tempsize;
+ FD_SET(rfd, &mask);
+ FD_SET(rfd, &tmpmask);
+ if (rfd >= nfds)
+ nfds = rfd + 1;
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt,
+ "\nTCP connection from %s port %d (fd %d)\n",
+ inet_ntoa(sp->s_from.sin_addr),
+ ntohs(sp->s_from.sin_port), rfd);
+ }
+#endif
+ }
+#ifdef DEBUG
+ if (debug > 2 && streamq)
+ fprintf(ddt,"streamq = x%x\n",streamq);
+#endif
+ if (streamq != NULL) {
+ for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (FD_ISSET(sp->s_rfd, &tmpmask)) {
+#ifdef DEBUG
+ if (debug > 5) {
+ fprintf(ddt,
+ "sp x%x rfd %d size %d time %d ",
+ sp, sp->s_rfd, sp->s_size,
+ sp->s_time );
+ fprintf(ddt," next x%x \n", sp->s_next );
+ fprintf(ddt,"\tbufsize %d",sp->s_bufsize);
+ fprintf(ddt," buf x%x ",sp->s_buf);
+ fprintf(ddt," bufp x%x\n",sp->s_bufp);
+ }
+#endif DEBUG
+ if (sp->s_size < 0) {
+ size = sizeof(u_short) -
+ (sp->s_bufp - (char *)&sp->s_tempsize);
+ while (size > 0 &&
+ (n = read(sp->s_rfd, sp->s_bufp, size)) > 0){
+ sp->s_bufp += n;
+ size -= n;
+ }
+ if ((n == -1) && (errno == EWOULDBLOCK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ if ((sp->s_bufp - (char *)&sp->s_tempsize) ==
+ sizeof(u_short)) {
+ sp->s_size = htons(sp->s_tempsize);
+ if (sp->s_bufsize == 0) {
+ if ( (sp->s_buf = malloc(BUFSIZ))
+ == NULL) {
+ sp->s_buf = buf;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = BUFSIZ;
+ }
+ }
+ if (sp->s_size > sp->s_bufsize &&
+ sp->s_bufsize != 0) {
+ if ((sp->s_buf = realloc(
+ (char *)sp->s_buf,
+ (unsigned)sp->s_size)) == NULL){
+ sp->s_buf = buf;
+ sp->s_bufsize = 0;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = sp->s_size;
+ }
+ }
+ sp->s_bufp = sp->s_buf;
+ }
+ }
+ gettime(&tt);
+ sp->s_time = tt.tv_sec;
+ while (sp->s_size > 0 &&
+ (n = read(sp->s_rfd, sp->s_bufp, sp->s_size)) > 0)
+ {
+ sp->s_bufp += n;
+ sp->s_size -= n;
+ }
+ /*
+ * we don't have enough memory for the query.
+ * if we have a query id, then we will send an
+ * error back to the user.
+ */
+ if (sp->s_bufsize == 0 &&
+ (sp->s_bufp - sp->s_buf > sizeof(u_short))) {
+ HEADER *hp;
+
+ hp = (HEADER *)sp->s_buf;
+ hp->qr = 1;
+ hp->ra = 1;
+ hp->ancount = 0;
+ hp->qdcount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = SERVFAIL;
+ (void) writemsg(sp->s_rfd, sp->s_buf,
+ sizeof(HEADER));
+ continue;
+ }
+ if ((n == -1) && (errno == EWOULDBLOCK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ /*
+ * Consult database to get the answer.
+ */
+ if (sp->s_size == 0) {
+ sq_query(sp);
+ ns_req(sp->s_buf,
+ sp->s_bufp - sp->s_buf,
+ sp->s_bufsize, sp,
+ &sp->s_from, -1);
+ sp->s_bufp = (char *)&sp->s_tempsize;
+ sp->s_size = -1;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+usage()
+{
+ fprintf(stderr, "Usage: named [-d #] [-p port] [{-b} bootfile]\n");
+ exit(1);
+}
+
+getnetconf()
+{
+ register struct netinfo *ntp;
+ struct netinfo *ontp;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct qdatagram *dqp;
+ static int first = 1;
+ char buf[BUFSIZ], *cp, *cplim;
+ u_long nm;
+
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "get interface configuration: %m");
+ exit(1);
+ }
+ ntp = NULL;
+#ifdef AF_LINK
+#define max(a, b) (a > b ? a : b)
+#define size(p) max((p).sa_len, sizeof(p))
+#else
+#define size(p) (sizeof (p))
+#endif
+ cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+ for (cp = buf; cp < cplim;
+ cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+#undef size
+ ifr = (struct ifreq *)cp;
+ if (ifr->ifr_addr.sa_family != AF_INET ||
+ ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == 0)
+ continue;
+ ifreq = *ifr;
+ /*
+ * Don't test IFF_UP, packets may still be received at this
+ * address if any other interface is up.
+ */
+ if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get interface addr: %m");
+ continue;
+ }
+ /* build datagram queue */
+ /*
+ * look for an already existing source interface address.
+ * This happens mostly when reinitializing. Also, if
+ * the machine has multiple point to point interfaces, then
+ * the local address may appear more than once.
+ */
+ for (dqp=datagramq; dqp != NULL; dqp = dqp->dq_next)
+ if (((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr
+ == dqp->dq_addr.s_addr) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "dup interface address %s on %s\n",
+ inet_ntoa(dqp->dq_addr), ifreq.ifr_name);
+#endif
+ break;
+ }
+ if (dqp != NULL)
+ continue;
+
+ if ((dqp = (struct qdatagram *)calloc(1,
+ sizeof(struct qdatagram))) == NULL) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"getnetconf: malloc error\n");
+#endif
+ syslog(LOG_ERR, "getnetconf: Out Of Memory");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+ opensocket(dqp);
+
+ /*
+ * Add interface to list of directly-attached (sub)nets
+ * for use in sorting addresses.
+ */
+ if (ntp == NULL)
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ ntp->my_addr =
+ ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+#ifdef SIOCGIFNETMASK
+ if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get netmask: %m");
+ ntp->mask = net_mask(ntp->my_addr);
+ } else
+ ntp->mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+#else
+ /* 4.2 does not support subnets */
+ ntp->mask = net_mask(ntp->my_addr);
+#endif
+ if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get interface flags: %m");
+ continue;
+ }
+#ifdef IFF_LOOPBACK
+ if (ifreq.ifr_flags & IFF_LOOPBACK)
+#else
+ /* test against 127.0.0.1 (yuck!!) */
+ if (ntp->my_addr.s_addr == htonl(0x7F000001))
+#endif
+ {
+ if (netloop.my_addr.s_addr == 0) {
+ netloop.my_addr = ntp->my_addr;
+ netloop.mask = 0xffffffff;
+ netloop.net = ntp->my_addr.s_addr;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"loopback address: x%lx\n",
+ netloop.my_addr.s_addr);
+#endif DEBUG
+ }
+ continue;
+ } else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
+ if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get dst addr: %m");
+ continue;
+ }
+ ntp->mask = 0xffffffff;
+ ntp->net = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ } else {
+ ntp->net = ntp->mask & ntp->my_addr.s_addr;
+ }
+ /*
+ * Place on end of list of locally-attached (sub)nets,
+ * but before logical nets for subnetted nets.
+ */
+ ntp->next = *elocal;
+ *elocal = ntp;
+ if (elocal == enettab)
+ enettab = &ntp->next;
+ elocal = &ntp->next;
+ ntp = NULL;
+ }
+ if (ntp)
+ (void) free((char *)ntp);
+
+ /*
+ * Create separate qdatagram structure for socket
+ * wildcard address.
+ */
+ if (first) {
+ if ((dqp = (struct qdatagram *)calloc(1, sizeof(*dqp))) == NULL) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"getnetconf: malloc error\n");
+#endif
+ syslog(LOG_ERR, "getnetconf: Out Of Memory");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr.s_addr = INADDR_ANY;
+ opensocket(dqp);
+ ds = dqp->dq_dfd; /* used externally */
+ }
+
+ /*
+ * Compute logical networks to which we're connected
+ * based on attached subnets;
+ * used for sorting based on network configuration.
+ */
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ nm = net_mask(ntp->my_addr);
+ if (nm != ntp->mask) {
+ if (findnetinfo(ntp->my_addr))
+ continue;
+ ontp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ if (ontp == NULL) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"getnetconf: malloc error\n");
+#endif
+ syslog(LOG_ERR, "getnetconf: Out Of Memory");
+ exit(12);
+ }
+ ontp->my_addr = ntp->my_addr;
+ ontp->mask = nm;
+ ontp->net = ontp->my_addr.s_addr & nm;
+ ontp->next = *enettab;
+ *enettab = ontp;
+ enettab = &ontp->next;
+ }
+ }
+ first = 0;
+}
+
+/*
+ * Find netinfo structure for logical network implied by address "addr",
+ * if it's on list of local/favored networks.
+ */
+struct netinfo *
+findnetinfo(addr)
+ struct in_addr addr;
+{
+ register struct netinfo *ntp;
+ u_long net, mask;
+
+ mask = net_mask(addr);
+ net = addr.s_addr & mask;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if (ntp->net == net && ntp->mask == mask)
+ return (ntp);
+ return ((struct netinfo *) NULL);
+}
+
+#ifdef DEBUG
+printnetinfo(ntp)
+ register struct netinfo *ntp;
+{
+ for ( ; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt,"net x%lx mask x%lx", ntp->net, ntp->mask);
+ fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr);
+ fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr));
+ }
+}
+#endif
+
+opensocket(dqp)
+ register struct qdatagram *dqp;
+{
+ int on = 1;
+
+ /*
+ * Open datagram sockets bound to interface address.
+ */
+ if ((dqp->dq_dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_DGRAM): %m");
+ exit(1);
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"dqp->dq_addr %s d_dfd %d\n",
+ inet_ntoa(dqp->dq_addr), dqp->dq_dfd);
+#endif DEBUG
+ (void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on));
+#ifdef SO_RCVBUF
+ (void)setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&rbufsize, sizeof(rbufsize));
+#endif SO_RCVBUF
+ (void) fcntl(dqp->dq_dfd, F_SETFL, O_NONBLOCK);
+ /*
+ * NOTE: Some versions of SunOS have problems with the following
+ * call to bind. Bind still seems to function on these systems
+ * if you comment out the exit inside the if. This may cause
+ * Suns with multiple interfaces to reply strangely.
+ */
+ nsaddr.sin_addr = dqp->dq_addr;
+ if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
+ syslog(LOG_ERR, "bind(dfd %d, %s[%d]): %m",
+ dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+#if !defined(sun)
+ exit(1);
+#endif
+ }
+}
+
+/*
+** Set flag saying to reload database upon receiving SIGHUP.
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+SIG_FN
+onhup()
+{
+#if defined(SYSV)
+ (void)signal(SIGHUP, onhup);
+#endif SYSV
+ needreload = 1;
+}
+
+/*
+** Set flag saying to call ns_maint()
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+SIG_FN
+maint_alarm()
+{
+#if defined(SYSV)
+ (void)signal(SIGALRM, maint_alarm);
+#endif SYSV
+ needmaint = 1;
+ }
+
+
+#ifdef ALLOW_UPDATES
+/*
+ * Signal handler to schedule shutdown. Just set flag, to ensure a consistent
+ * state during dump.
+ */
+SIG_FN
+onintr()
+{
+ needToExit = 1;
+}
+#endif ALLOW_UPDATES
+
+/*
+ * Signal handler to schedule a data base dump. Do this instead of dumping the
+ * data base immediately, to avoid seeing it in a possibly inconsistent state
+ * (due to updates), and to avoid long disk I/O delays at signal-handler
+ * level
+ */
+SIG_FN
+setdumpflg()
+{
+#if defined(SYSV)
+ (void)signal(SIGINT, setdumpflg);
+#endif SYSV
+ needToDoadump = 1;
+}
+
+/*
+** Turn on or off debuging by open or closeing the debug file
+*/
+
+setdebug(code)
+int code;
+{
+#if defined(lint) && !defined(DEBUG)
+ code = code;
+#endif
+#ifdef DEBUG
+
+ if (code) {
+ ddt = freopen(debugfile, "w+", stderr);
+ if ( ddt == NULL) {
+ syslog(LOG_WARNING, "can't open debug file %s: %m",
+ debugfile);
+ debug = 0;
+ } else {
+#if defined(SYSV)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ (void) fcntl(fileno(ddt), F_SETFL, FAPPEND);
+ }
+ } else
+ debug = 0;
+ /* delay closing ddt, we might interrupt someone */
+#endif
+}
+
+/*
+** Catch a special signal and set debug level.
+**
+** If debuging is off then turn on debuging else increment the level.
+**
+** Handy for looking in on long running name servers.
+*/
+
+SIG_FN
+setIncrDbgFlg()
+{
+#if defined(SYSV)
+ (void)signal(SIGUSR1, setIncrDbgFlg);
+#endif SYSV
+#ifdef DEBUG
+ if (debug == 0) {
+ debug++;
+ setdebug(1);
+ }
+ else {
+ debug++;
+ }
+ fprintf(ddt,"Debug turned ON, Level %d\n",debug);
+#endif
+}
+
+/*
+** Catch a special signal to turn off debugging
+*/
+
+SIG_FN
+setNoDbgFlg()
+{
+#if defined(SYSV)
+ (void)signal(SIGUSR2, setNoDbgFlg);
+#endif SYSV
+ setdebug(0);
+}
+
+/*
+** Set flag for statistics dump
+*/
+SIG_FN
+setstatsflg()
+{
+#if defined(SYSV)
+ (void)signal(SIGIOT, setstatsflg);
+#endif SYSV
+ needStatsDump = 1;
+}
+
+SIG_FN
+setchkptflg()
+{
+#if defined(SYSV)
+ (void)signal(SIGQUIT, setchkptflg);
+#endif SYSV
+ needToChkpt = 1;
+}
+
+/*
+** Catch a special signal SIGSYS
+**
+** this is setup to fork and exit to drop to /usr/tmp/gmon.out
+** and keep the server running
+*/
+
+SIG_FN
+sigprof()
+{
+#if defined(SYSV)
+ (void)signal(SIGSYS, sigprof);
+#endif SYSV
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sigprof()\n");
+#endif
+ if ( fork() == 0)
+ {
+ (void) chdir(_PATH_TMPDIR);
+ exit(1);
+ }
+}
+
+/*
+** Routines for managing stream queue
+*/
+
+struct qstream *
+sqadd()
+{
+ register struct qstream *sqp;
+
+ if ((sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))
+ == NULL ) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"sqadd: malloc error\n");
+#endif
+ syslog(LOG_ERR, "sqadd: Out Of Memory");
+ return(QSTREAM_NULL);
+ }
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"sqadd(x%x)\n", sqp);
+#endif
+
+ sqp->s_next = streamq;
+ streamq = sqp;
+ return(sqp);
+}
+
+/*
+ * Remove stream queue structure.
+ * No current queries may refer to this stream when it is removed.
+ */
+sqrm(qp)
+ register struct qstream *qp;
+{
+ register struct qstream *qsp;
+
+#ifdef DEBUG
+ if (debug > 1) {
+ fprintf(ddt,"sqrm(%#x, %d ) rfcnt=%d\n",
+ qp, qp->s_rfd, qp->s_refcnt);
+ }
+#endif
+
+ if (qp->s_bufsize != 0)
+ (void) free(qp->s_buf);
+ FD_CLR(qp->s_rfd, &mask);
+ (void) close(qp->s_rfd);
+ if (qp == streamq) {
+ streamq = qp->s_next;
+ } else {
+ for (qsp = streamq; qsp->s_next != qp; qsp = qsp->s_next)
+ ;
+ qsp->s_next = qp->s_next;
+ }
+ (void)free((char *)qp);
+}
+
+sqflush()
+{
+ register struct qstream *sp, *spnext;
+
+ for (sp = streamq; sp != QSTREAM_NULL; sp = spnext) {
+ spnext = sp->s_next;
+ sqrm(sp);
+ }
+}
+
+/*
+ * Initiate query on stream;
+ * mark as referenced and stop selecting for input.
+ */
+sq_query(sp)
+ register struct qstream *sp;
+{
+ sp->s_refcnt++;
+ FD_CLR(sp->s_rfd, &mask);
+}
+
+/*
+ * Note that the current request on a stream has completed,
+ * and that we should continue looking for requests on the stream.
+ */
+sq_done(sp)
+ register struct qstream *sp;
+{
+
+ sp->s_refcnt = 0;
+ sp->s_time = tt.tv_sec;
+ FD_SET(sp->s_rfd, &mask);
+}
+
+setproctitle(a, s)
+ char *a;
+ int s;
+{
+ int size;
+ register char *cp;
+ struct sockaddr_in sin;
+ char buf[80];
+
+ cp = Argv[0];
+ size = sizeof(sin);
+ if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
+ (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
+ else {
+ syslog(LOG_DEBUG, "getpeername: %m");
+ (void) sprintf(buf, "-%s", a);
+ }
+ (void) strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = ' ';
+}
+
+u_long
+net_mask(in)
+struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ else
+ return (htonl(IN_CLASSC_NET));
+}
+
+gettime(ttp)
+struct timeval *ttp;
+{
+ if (gettimeofday(ttp, (struct timezone *)0) < 0)
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return;
+}
diff --git a/usr.sbin/named/ns_maint.c b/usr.sbin/named/ns_maint.c
new file mode 100644
index 00000000000..e697716d16f
--- /dev/null
+++ b/usr.sbin/named/ns_maint.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 1986, 1988 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[] = "from: @(#)ns_maint.c 4.39 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: ns_maint.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#if defined(SYSV)
+#include <unistd.h>
+#endif SYSV
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <sys/wait.h>
+#include "ns.h"
+#include "db.h"
+#include "pathnames.h"
+
+extern int errno;
+extern int maint_interval;
+extern int needzoneload;
+extern u_short ns_port;
+extern char *ctime();
+
+int xfers_running; /* number of xfers running */
+int xfers_deferred; /* number of needed xfers not run yet */
+static int alarm_pending;
+
+
+/*
+ * Invoked at regular intervals by signal interrupt; refresh all secondary
+ * zones from primary name server and remove old cache entries. Also,
+ * ifdef'd ALLOW_UPDATES, dump database if it has changed since last
+ * dump/bootup.
+ */
+ns_maint()
+{
+ register struct zoneinfo *zp;
+ struct itimerval ival;
+ time_t next_refresh = 0;
+ int zonenum;
+
+ gettime(&tt);
+
+#ifdef DEBUG
+ if (debug) {
+ time_t now;
+
+ now = tt.tv_sec;
+ fprintf(ddt,"\nns_maint(); now %s", ctime(&now));
+ }
+#endif
+
+ xfers_deferred = 0;
+ alarm_pending = 0;
+ for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) {
+#ifdef DEBUG
+ if (debug >= 2)
+ printzoneinfo(zonenum);
+#endif
+ if (tt.tv_sec >= zp->z_time && zp->z_refresh > 0) {
+ /*
+ * Set default time for next action first,
+ * so that it can be changed later if necessary.
+ */
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+
+ switch (zp->z_type) {
+
+ case Z_CACHE:
+ doachkpt();
+ break;
+
+ case Z_SECONDARY:
+ if ((zp->z_state & Z_NEED_RELOAD) == 0) {
+ if (zp->z_state & Z_XFER_RUNNING)
+ abortxfer(zp);
+ else if (xfers_running < MAX_XFERS_RUNNING)
+ startxfer(zp);
+ else {
+ zp->z_state |= Z_NEED_XFER;
+ ++xfers_deferred;
+#ifdef DEBUG
+ if (debug > 1)
+ fprintf(ddt,
+ "xfer deferred for %s\n",
+ zp->z_origin);
+#endif
+ }
+ }
+ break;
+#ifdef ALLOW_UPDATES
+ case Z_PRIMARY:
+ /*
+ * Checkpoint the zone if it has changed
+ * since we last checkpointed
+ */
+ if (zp->hasChanged)
+ zonedump(zp);
+ break;
+#endif ALLOW_UPDATES
+ }
+ gettime(&tt);
+ }
+ }
+ sched_maint();
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"exit ns_maint()\n");
+#endif
+}
+
+/*
+ * Find when the next refresh needs to be and set
+ * interrupt time accordingly.
+ */
+sched_maint()
+{
+ register struct zoneinfo *zp;
+ struct itimerval ival;
+ time_t next_refresh = 0;
+ static time_t next_alarm;
+
+ for (zp = zones; zp < &zones[nzones]; zp++)
+ if (zp->z_time != 0 &&
+ (next_refresh == 0 || next_refresh > zp->z_time))
+ next_refresh = zp->z_time;
+ /*
+ * Schedule the next call to ns_maint.
+ * Don't visit any sooner than maint_interval.
+ */
+ bzero((char *)&ival, sizeof (ival));
+ if (next_refresh != 0) {
+ if (next_refresh == next_alarm && alarm_pending) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sched_maint: no schedule change\n");
+#endif
+ return;
+ }
+ ival.it_value.tv_sec = next_refresh - tt.tv_sec;
+ if (ival.it_value.tv_sec < maint_interval)
+ ival.it_value.tv_sec = maint_interval;
+ next_alarm = next_refresh;
+ alarm_pending = 1;
+ }
+ (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sched_maint: Next interrupt in %d sec\n",
+ ival.it_value.tv_sec);
+#endif
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone.
+ * Depends on current time being in tt.
+ * The caller must call sched_maint after startxfer.
+ */
+startxfer(zp)
+ struct zoneinfo *zp;
+{
+ static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
+ int cnt, argc = 0, argc_ns = 0, pid, omask;
+ char debug_str[10];
+ char serial_str[10];
+ char port_str[10];
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"startxfer() %s\n", zp->z_origin);
+#endif
+
+ argv[argc++] = "named-xfer";
+ argv[argc++] = "-z";
+ argv[argc++] = zp->z_origin;
+ argv[argc++] = "-f";
+ argv[argc++] = zp->z_source;
+ argv[argc++] = "-s";
+ sprintf(serial_str, "%d", zp->z_serial);
+ argv[argc++] = serial_str;
+ if (zp->z_state & Z_SYSLOGGED)
+ argv[argc++] = "-q";
+ argv[argc++] = "-P";
+ sprintf(port_str, "%d", ns_port);
+ argv[argc++] = port_str;
+#ifdef DEBUG
+ if (debug) {
+ argv[argc++] = "-d";
+ sprintf(debug_str, "%d", debug);
+ argv[argc++] = debug_str;
+ argv[argc++] = "-l";
+ argv[argc++] = "/usr/tmp/xfer.ddt";
+ if (debug > 5) {
+ argv[argc++] = "-t";
+ argv[argc++] = "/usr/tmp/xfer.trace";
+ }
+ }
+#endif
+
+ /*
+ * Copy the server ip addresses into argv, after converting
+ * to ascii and saving the static inet_ntoa result
+ */
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++)
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(zp->z_addr[cnt]));
+
+ argv[argc] = 0;
+
+#ifdef DEBUG
+#ifdef ECHOARGS
+ if (debug) {
+ int i;
+ for (i = 0; i < argc; i++)
+ fprintf(ddt, "Arg %d=%s\n", i, argv[i]);
+ }
+#endif /* ECHOARGS */
+#endif /* DEBUG */
+
+#ifdef SYSV
+#define vfork fork
+#else
+ gettime(&tt);
+ omask = sigblock(sigmask(SIGCHLD));
+#endif
+ if ((pid = vfork()) == -1) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "xfer [v]fork: %d\n", errno);
+#endif
+ syslog(LOG_ERR, "xfer [v]fork: %m");
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+ zp->z_time = tt.tv_sec + 10;
+ return;
+ }
+
+ if (pid) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "started xfer child %d\n", pid);
+#endif
+ zp->z_state &= ~Z_NEED_XFER;
+ zp->z_state |= Z_XFER_RUNNING;
+ zp->z_xferpid = pid;
+ xfers_running++;
+ zp->z_time = tt.tv_sec + MAX_XFER_TIME;
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+ } else {
+ execve(_PATH_XFER, argv, NULL);
+ syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
+ _exit(XFER_FAIL); /* avoid duplicate buffer flushes */
+ }
+}
+
+#ifdef DEBUG
+printzoneinfo(zonenum)
+int zonenum;
+{
+ struct timeval tt;
+ struct zoneinfo *zp = &zones[zonenum];
+ char *ZoneType;
+
+ if (!debug)
+ return; /* Else fprintf to ddt will bomb */
+ fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
+
+ gettime(&tt);
+ switch (zp->z_type) {
+ case Z_PRIMARY: ZoneType = "Primary"; break;
+ case Z_SECONDARY: ZoneType = "Secondary"; break;
+ case Z_CACHE: ZoneType = "Cache"; break;
+ default: ZoneType = "Unknown";
+ }
+ if (zp->z_origin[0] == '\0')
+ fprintf(ddt,"origin ='.'");
+ else
+ fprintf(ddt,"origin ='%s'", zp->z_origin);
+ fprintf(ddt,", type = %s", ZoneType);
+ fprintf(ddt,", source = %s\n", zp->z_source);
+ fprintf(ddt,"z_refresh = %ld", zp->z_refresh);
+ fprintf(ddt,", retry = %ld", zp->z_retry);
+ fprintf(ddt,", expire = %ld", zp->z_expire);
+ fprintf(ddt,", minimum = %ld", zp->z_minimum);
+ fprintf(ddt,", serial = %ld\n", zp->z_serial);
+ fprintf(ddt,"z_time = %d", zp->z_time);
+ if (zp->z_time) {
+ fprintf(ddt,", now time : %d sec", tt.tv_sec);
+ fprintf(ddt,", time left: %d sec", zp->z_time - tt.tv_sec);
+ }
+ fprintf(ddt,"; state %x\n", zp->z_state);
+}
+#endif DEBUG
+
+/*
+ * remove_zone (htp, zone) --
+ * Delete all RR's in the zone "zone" under specified hash table.
+ */
+remove_zone(htp, zone)
+ register struct hashbuf *htp;
+ register int zone;
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np;
+ struct namebuf **npp, **nppend;
+
+ nppend = htp->h_tab + htp->h_size;
+ for (npp = htp->h_tab; npp < nppend; npp++)
+ for (np = *npp; np != NULL; np = np->n_next) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+ if (dp->d_zone == zone)
+ dp = rm_datum(dp, np, pdp);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+ /* Call recursively to remove subdomains. */
+ if (np->n_hash)
+ remove_zone(np->n_hash, zone);
+ }
+}
+
+/*
+ * Abort an xfer that has taken too long.
+ */
+abortxfer(zp)
+ register struct zoneinfo *zp;
+{
+
+ kill(zp->z_xferpid, SIGKILL); /* don't trust it at all */
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "Killed child %d (zone %s) due to timeout\n",
+ zp->z_xferpid, zp->z_origin);
+#endif /* DEBUG */
+ zp->z_time = tt.tv_sec + zp->z_retry;
+}
+
+#ifdef SYSV
+union wait {
+ unsigned short w_termsig:7; /* termination signal */
+ unsigned short w_coredump:1; /* core dump indicator */
+ unsigned short w_retcode:8; /* exit code if w_termsig==0 */
+};
+#endif
+
+/*
+ * SIGCHLD signal handler: process exit of xfer's.
+ * (Note: also called when outgoing transfer completes.)
+ */
+SIG_FN
+endxfer()
+{
+ register struct zoneinfo *zp;
+ int pid, xfers = 0;
+ union wait status;
+
+ gettime(&tt);
+#if defined(SYSV)
+ { int stat;
+ pid = wait(&stat);
+ status.w_termsig = stat & 0x7f;
+ status.w_retcode = stat >> 8;
+ }
+#else /* SYSV */
+ while ((pid =
+ wait3((int *)&status, WNOHANG, (struct rusage *)NULL)) > 0) {
+#endif /* SYSV */
+ for (zp = zones; zp < &zones[nzones]; zp++)
+ if (zp->z_xferpid == pid) {
+ xfers++;
+ xfers_running--;
+ zp->z_xferpid = 0;
+ zp->z_state &= ~Z_XFER_RUNNING;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "\nendxfer: child %d zone %s returned status=%d termsig=%d\n",
+ pid, zp->z_origin, status.w_retcode,
+ status.w_termsig);
+#endif
+ if (status.w_termsig != 0) {
+ if (status.w_termsig != SIGKILL) {
+ syslog(LOG_ERR,
+ "named-xfer exited with signal %d\n",
+ status.w_termsig);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "\tchild termination with signal %d\n",
+ status.w_termsig);
+#endif
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ } else switch (status.w_retcode) {
+ case XFER_UPTODATE:
+ zp->z_state &= ~Z_SYSLOGGED;
+ zp->z_lastupdate = tt.tv_sec;
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ /*
+ * Restore z_auth in case expired,
+ * but only if there were no errors
+ * in the zone file.
+ */
+ if ((zp->z_state & Z_DB_BAD) == 0)
+ zp->z_auth = 1;
+ if (zp->z_source) {
+#if defined(SYSV)
+ struct utimbuf t;
+
+ t.actime = tt.tv_sec;
+ t.modtime = tt.tv_sec;
+ (void) utime(zp->z_source, &t);
+#else
+ struct timeval t[2];
+
+ t[0] = tt;
+ t[1] = tt;
+ (void) utimes(zp->z_source, t);
+#endif /* SYSV */
+ }
+ break;
+
+ case XFER_SUCCESS:
+ zp->z_state |= Z_NEED_RELOAD;
+ zp->z_state &= ~Z_SYSLOGGED;
+ needzoneload++;
+ break;
+
+ case XFER_TIMEOUT:
+#ifdef DEBUG
+ if (debug) fprintf(ddt,
+ "zoneref: Masters for secondary zone %s unreachable\n",
+ zp->z_origin);
+#endif
+ if ((zp->z_state & Z_SYSLOGGED) == 0) {
+ zp->z_state |= Z_SYSLOGGED;
+ syslog(LOG_WARNING,
+ "zoneref: Masters for secondary zone %s unreachable",
+ zp->z_origin);
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+
+ default:
+ if ((zp->z_state & Z_SYSLOGGED) == 0) {
+ zp->z_state |= Z_SYSLOGGED;
+ syslog(LOG_ERR,
+ "named-xfer exit code %d",
+ status.w_retcode);
+ }
+ /* FALLTHROUGH */
+ case XFER_FAIL:
+ zp->z_state |= Z_SYSLOGGED;
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+ }
+ break;
+ }
+#ifndef SYSV
+ }
+#endif /* SYSV */
+ if (xfers) {
+ for (zp = zones;
+ xfers_deferred != 0 && xfers_running < MAX_XFERS_RUNNING &&
+ zp < &zones[nzones]; zp++)
+ if (zp->z_state & Z_NEED_XFER) {
+ xfers_deferred--;
+ startxfer(zp);
+ }
+ sched_maint();
+ }
+#if defined(SYSV)
+ (void)signal(SIGCLD, endxfer);
+#endif
+}
+
+/*
+ * Reload zones whose transfers have completed.
+ */
+loadxfer()
+{
+ register struct zoneinfo *zp;
+
+ gettime(&tt);
+ for (zp = zones; zp < &zones[nzones]; zp++)
+ if (zp->z_state & Z_NEED_RELOAD) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "loadxfer() '%s'\n",
+ zp->z_origin[0] ? zp->z_origin : ".");
+#endif
+ zp->z_state &= ~Z_NEED_RELOAD;
+ zp->z_auth = 0;
+ remove_zone(hashtab, zp - zones);
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_auth = 1;
+ if (zp->z_state & Z_TMP_FILE)
+ (void) unlink(zp->z_source);
+ }
+ sched_maint();
+}
diff --git a/usr.sbin/named/ns_req.c b/usr.sbin/named/ns_req.c
new file mode 100644
index 00000000000..738d51c60e3
--- /dev/null
+++ b/usr.sbin/named/ns_req.c
@@ -0,0 +1,1353 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 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[] = "from: @(#)ns_req.c 4.47 (Berkeley) 7/1/91";*/
+static char rcsid[] = "$Id: ns_req.c,v 1.1.1.1 1995/10/18 08:47:50 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "ns.h"
+#include "db.h"
+
+#define NADDRECS 20
+
+extern int debug;
+extern FILE *ddt;
+
+struct addinfo {
+ char *a_dname; /* domain name */
+ u_short a_class; /* class for address */
+};
+
+struct addinfo addinfo[NADDRECS]; /* additional info records */
+int addcount; /* number of names in addinfo */
+int xfr_disabled = 0; /* set to disable zone xfrs */
+int needs_prime_cache = 0; /* set if we need a priming */
+
+u_char *dnptrs[20]; /* ptrs to dnames in message for dn_comp */
+
+extern time_t retrytime();
+extern struct qinfo *sysquery();
+extern char *localdomain; /* XXX */
+extern int errno;
+/*
+ * Process request using database; assemble and send response.
+ */
+ns_req(msg, msglen, buflen, qsp, from, dfd)
+ u_char *msg;
+ int msglen, buflen;
+ struct qstream *qsp;
+ struct sockaddr_in *from;
+ int dfd;
+{
+ register HEADER *hp;
+ register u_char *cp;
+ struct namebuf *np;
+ register struct databuf *dp;
+ struct hashbuf *htp;
+ struct netinfo *lp;
+ char *fname, *answers;
+ u_char *eom, *omsg;
+ char dnbuf[MAXDNAME], *dname;
+ u_char **dpp;
+ int n, class, type, count, foundname, founddata, omsglen, cname = 0;
+ u_short id;
+ struct databuf *nsp[NSMAX];
+ struct qinfo *qp;
+ extern struct qinfo *qhead;
+ extern struct netinfo *local();
+ extern int nsid;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt,"ns_req()\n");
+ fp_query((char *)msg, ddt);
+ }
+#endif
+
+ hp = (HEADER *) msg;
+ if (hp->qr) {
+ ns_resp(msg, msglen);
+
+ /* Now is a safe time for housekeeping */
+ if (needs_prime_cache)
+ prime_cache();
+ return;
+ }
+
+ hp->rcode = NOERROR;
+ cp = msg + sizeof(HEADER);
+ eom = msg + msglen;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ addcount = 0;
+
+ switch (hp->opcode) {
+ case QUERY:
+#ifdef STATS
+ stats[S_QUERIES].cnt++;
+#endif
+ if (ntohs(hp->qdcount) != 1 ||
+ hp->ancount || hp->nscount || hp->arcount) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR Query header counts wrong\n");
+#endif
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+ /*
+ * Get domain name, class, and type.
+ */
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp; /* remember name for compression */
+ *dpp = NULL;
+ if ((n = dn_expand(msg, eom, cp, (u_char *)dnbuf,
+ sizeof(dnbuf))) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR Query expand name failed\n");
+#endif
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp > eom) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR Query message length short\n");
+#endif
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+#ifdef DEBUG
+ if (cp < eom)
+ if (debug > 5)
+ fprintf(ddt,"message length > received message\n");
+#endif
+
+#ifdef STATS
+ if ((type > T_ANY) || (type < 0))
+ typestats[0]++; /* Bad type */
+ else
+ typestats[type]++;
+#endif
+ /*
+ * Process query.
+ */
+ if (type == T_AXFR) {
+ /* refuse request if not a TCP connection */
+ if (qsp == QSTREAM_NULL || xfr_disabled) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"T_AXFR via UDP refused\n");
+#endif
+ hp->rcode = REFUSED;
+ goto finish;
+ }
+ dnptrs[0] = NULL; /* don't compress names */
+ hp->rd = 0; /* recursion not possible */
+ }
+ buflen -= msglen;
+ count = 0;
+ foundname = 0;
+ founddata = 0;
+ dname = dnbuf;
+try_again:
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",
+ dname, hp->id, type);
+#endif
+ htp = hashtab; /* lookup relative to root */
+ if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
+ fname = "";
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found",
+ dname, fname, cname);
+#endif
+ /* START XXX */
+ /*
+ * if nlookup failed to find address then
+ * see if there are any '.''s in the name
+ * if not then add local domain name to the
+ * name and try again.
+ */
+ if (np == NULL && localdomain && index(dname, '.') == NULL) {
+ (void) strcat(dname,".");
+ (void) strcat(dname, localdomain);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"req: nlookup(%s) type=%d\n",
+ dname, type);
+#endif
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ }
+ /* END XXX */
+ if (np == NULL || fname != dname)
+ goto fetchns;
+
+ foundname++;
+ answers = (char *)cp;
+ count = cp - msg;
+ n = finddata(np, class, type, hp, &dname, &buflen, &count);
+ if (n == 0)
+ goto fetchns; /* NO data available */
+ cp += n;
+ buflen -= n;
+ msglen += n;
+ hp->ancount += count;
+ if (fname != dname && type != T_CNAME && type != T_ANY) {
+ if (cname++ >= MAXCNAMES) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,
+ "resp: leaving, MAXCNAMES exceeded\n");
+#endif
+ hp->rcode = SERVFAIL;
+ goto finish;
+ }
+ goto try_again;
+ }
+ founddata = 1;
+#ifdef DEBUG
+ if (debug >= 3) {
+ fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);
+ fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);
+ }
+#endif
+ if ((lp = local(from)) != NULL)
+ sort_response(answers, count, lp, cp);
+ if (type == T_AXFR) {
+ if (founddata) {
+ hp->ancount = htons(hp->ancount);
+ startxfr(qsp, np, msg, cp - msg);
+ return;
+ }
+ hp->rcode = REFUSED; /* No go if unauthoritative */
+ goto finish;
+ }
+#ifdef notdef
+ /*
+ * If we found an authoritative answer,
+ * we're done.
+ */
+ if (hp->aa)
+ goto finish;
+#endif
+
+fetchns:
+ /*
+ * Look for name servers to refer to and fill in the authority
+ * section or record the address for forwarding the query
+ * (recursion desired).
+ */
+ nsp[0] = NULL;
+ switch (findns(&np, class, nsp, &count)) {
+ case NXDOMAIN:
+ if (!foundname)
+ hp->rcode = NXDOMAIN;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode);
+#endif
+ if (class != C_ANY) {
+ hp->aa = 1;
+ /* XXX
+ * should return SOA if founddata == 0,
+ * but old named's are confused by an SOA
+ * in the auth. section if there's no error.
+ */
+ if (foundname == 0 && np) {
+ n = doaddauth(hp, cp, buflen, np, nsp[0]);
+ cp += n;
+ buflen -= n;
+ }
+ }
+ goto finish;
+
+ case SERVFAIL:
+ if (!founddata) {
+ hp->rcode = SERVFAIL;
+ goto finish;
+ }
+ }
+
+ /*
+ * If we successfully found the answer in the cache
+ * or this is not a recursive query, then add the
+ * nameserver references here and return.
+ */
+ if (founddata || (!hp->rd)) {
+ n = add_data(np, nsp, cp, buflen);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ cp += n;
+ buflen -= n;
+ hp->nscount = htons((u_short)count);
+ goto finish;
+ }
+
+ /*
+ * At this point, we don't have the answer, but we do
+ * have some NS's to try. If the user would like us
+ * to recurse, create the initial query. If a cname
+ * is involved, we need to build a new query and save
+ * the old one in cmsg/cmsglen.
+ */
+ if (cname) {
+ omsg = (u_char *)malloc((unsigned)msglen);
+ if (omsg == (u_char *)NULL) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"ns_req: malloc fail\n");
+#endif
+ syslog(LOG_ERR, "ns_req: Out Of Memory");
+ hp->rcode = SERVFAIL;
+ break;
+ }
+ id = hp->id;
+ hp->ancount = htons(hp->ancount);
+ bcopy(msg, omsg, omsglen = msglen);
+ msglen = res_mkquery(QUERY, dname, class, type,
+ (char *)NULL, 0, NULL, (char *)msg,
+ msglen+buflen);
+ }
+ n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp);
+ if (n != FW_OK && cname)
+ free(omsg);
+ switch (n) {
+ case FW_OK:
+ if (cname) {
+ qp->q_cname = cname;
+ qp->q_cmsg = (char *)omsg;
+ qp->q_cmsglen = omsglen;
+ qp->q_id = id;
+ }
+ break;
+ case FW_DUP:
+ break; /* Duplicate request dropped */
+ case FW_NOSERVER:
+ if(np)
+ np = np->n_parent;
+ goto fetchns; /* Try again. */
+ case FW_SERVFAIL:
+ hp->rcode = SERVFAIL;
+ goto finish;
+ }
+ /* Now is a safe time for housekeeping */
+ if (needs_prime_cache)
+ prime_cache();
+ return;
+
+ case IQUERY: {
+ register struct invbuf *ip;
+ register int i;
+ int dlen, alen;
+ char anbuf[PACKETSZ], *data;
+
+#ifdef STATS
+ stats[S_IQUERIES].cnt++;
+#endif
+ hp->ancount = htons(hp->ancount);
+ if (hp->ancount != 1 ||
+ hp->qdcount || hp->nscount || hp->arcount) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR IQuery header counts wrong\n");
+#endif
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+ /*
+ * Skip domain name, get class, and type.
+ */
+ if ((n = dn_skipname(cp, eom)) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR IQuery packet name problem\n");
+#endif
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ cp += sizeof(u_long);
+ GETSHORT(dlen, cp);
+ cp += dlen;
+ if (cp != eom) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR IQuery message length off\n");
+#endif
+ hp->rcode = FORMERR;
+ goto finish;
+ }
+ /* not all inverse queries are handled. */
+ switch (type) {
+ case T_A:
+ case T_UID:
+ case T_GID:
+ break;
+
+ default:
+ hp->rcode = REFUSED;
+ goto finish;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"req: IQuery class %d type %d\n",
+ class, type);
+#endif
+ fname = (char *)msg + sizeof(HEADER);
+ bcopy(fname, anbuf, alen = (char *)cp - fname);
+ data = anbuf + alen - dlen;
+ cp = (u_char *)fname;
+ buflen -= sizeof(HEADER);
+ count = 0;
+ for (ip = invtab[dhash(data, dlen)]; ip != NULL;
+ ip = ip->i_next) {
+ for (i = 0; i < INVBLKSZ; i++) {
+ if ((np = ip->i_dname[i]) == NULL)
+ break;
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"dname = %d\n", np->n_dname);
+#endif
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+ if (dp->d_size != dlen ||
+ bcmp(dp->d_data, data, dlen))
+ continue;
+ getname(np, dnbuf, sizeof(dnbuf));
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"req: IQuery found %s\n",
+ dnbuf);
+#endif
+ buflen -= QFIXEDSZ;
+ if ((n = dn_comp((u_char *)dnbuf, cp, buflen,
+ (u_char **)NULL, (u_char **)NULL)) < 0)
+ {
+ hp->tc = 1;
+ goto finish;
+ }
+ cp += n;
+ PUTSHORT((u_short)dp->d_type, cp);
+ PUTSHORT((u_short)dp->d_class, cp);
+ buflen -= n;
+ count++;
+ }
+ }
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"req: IQuery %d records\n", count);
+#endif
+ hp->qdcount = htons((u_short)count);
+ if (alen > buflen) {
+ hp->tc = 1;
+ break;
+ }
+ bcopy(anbuf, cp, alen);
+ cp += alen;
+ break;
+ }
+
+#ifdef ALLOW_UPDATES
+/*
+ * In a sense the following constant should be defined in <arpa/nameser.h>,
+ * since it is returned here in place of a response code if the update was
+ * forwarded, and the response codes are defined in nameser.h. On the other
+ * hand, though, this constant is only seen in this file. The assumption
+ * here is that none of the other return codes equals this one (a good
+ * assumption, since they only occupy 4 bits over-the-wire)
+ */
+#define FORWARDED 1000
+ /* Call InitDynUpdate for all dynamic update requests */
+ case UPDATEM:
+ case UPDATEMA:
+ case UPDATED:
+ case UPDATEDA:
+ case UPDATEA:
+ n = InitDynUpdate(hp, nsp, msg, msglen, cp, from, qsp, dfd);
+ if (n == FORWARDED)
+ return; /* Return directly because InitDynUpdate
+ * forwarded the query to the primary, so we
+ * will send response later
+ */
+ else
+ break; /* Either sucessful primary update or failure;
+ * return response code to client
+ */
+#endif ALLOW_UPDATES
+
+ case ZONEREF:
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"Refresh Zone\n");
+#endif
+
+ default:
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"Opcode %d not implemented\n", hp->opcode);
+#endif
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = NOTIMP;
+ }
+finish:
+#ifdef STATS
+ switch(hp->rcode) {
+ case NOERROR:
+ stats[S_RESPOK].cnt++;
+ break;
+ case FORMERR:
+ stats[S_RESPFORMERR].cnt++;
+ break;
+ default:
+ stats[S_RESPFAIL].cnt++;
+ break;
+ }
+#endif
+ hp->qr = 1; /* set Response flag */
+ hp->ra = 1; /* Recursion is Available */
+ hp->ancount = htons(hp->ancount);
+ if (addcount) {
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n",
+ inet_ntoa(from->sin_addr),
+ qsp == QSTREAM_NULL ? dfd : qsp->s_rfd,
+ ntohs(from->sin_port),
+ ntohs(hp->id), local(from) == NULL ? "Remote" : "Local");
+ }
+ if (debug >= 10)
+ fp_query((char *)msg, ddt);
+#endif DEBUG
+ if (qsp == QSTREAM_NULL) {
+ if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from,
+ sizeof(*from))< 0){
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"error returning msg errno=%d\n",errno);
+#endif DEBUG
+ }
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+ } else {
+ (void) writemsg(qsp->s_rfd, msg, cp - msg);
+ sq_done(qsp);
+ }
+ if (needs_prime_cache)
+ prime_cache(); /* Now is a safe time */
+}
+
+fwritemsg(rfp, msg, msglen)
+ FILE *rfp;
+ char *msg;
+ int msglen;
+{
+ u_short len = htons((u_short)msglen);
+
+ if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 ||
+ fwrite(msg, msglen, 1, rfp) != 1) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"fwrite failed %d\n", errno);
+#endif
+ }
+ return;
+}
+
+writemsg(rfd, msg, msglen)
+ int rfd;
+ char *msg;
+ int msglen;
+{
+ struct iovec iov[2];
+ u_short len = htons((u_short)msglen);
+
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = sizeof(len);
+ iov[1].iov_base = msg;
+ iov[1].iov_len = msglen;
+ if (writev(rfd, iov, 2) != sizeof(len) + msglen) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"write failed %d\n", errno);
+#endif
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Test a datum for validity and return non-zero if it is out of date.
+ */
+stale(dp)
+register struct databuf *dp;
+{
+ register struct zoneinfo *zp = &zones[dp->d_zone];
+
+ switch (zp->z_type) {
+
+ case Z_PRIMARY:
+ return (0);
+
+ case Z_SECONDARY:
+ /*
+ * Check to see whether a secondary zone
+ * has expired; if so clear authority flag
+ * for zone and return true. If lastupdate
+ * is in the future, assume zone is up-to-date.
+ */
+ if ((long)(tt.tv_sec - zp->z_lastupdate) > (long)zp->z_expire) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "stale: secondary zone %s expired\n",
+ zp->z_origin);
+#endif
+ syslog(LOG_ERR, "secondary zone \"%s\" expired\n",
+ zp->z_origin);
+ zp->z_auth = 0;
+ return (1);
+ }
+ return (0);
+
+ case Z_CACHE:
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"stale: ttl %d %d (x%x)\n",
+ dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags);
+#endif
+ if (dp->d_flags & DB_F_HINT)
+ return(0);
+ return(dp->d_ttl < tt.tv_sec);
+
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Copy databuf into a resource record for replies.
+ * Return size of RR if OK, -1 if buffer is full.
+ */
+make_rr(name, dp, buf, buflen, doadd)
+ char *name;
+ register struct databuf *dp;
+ char *buf;
+ int buflen, doadd;
+{
+ register char *cp;
+ char *cp1, *sp;
+ struct zoneinfo *zp;
+ register long n;
+ register long ttl;
+ u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n",
+ name, dp, buf,
+ buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl);
+#endif
+
+ zp = &zones[dp->d_zone];
+ /* check for outdated RR before updating dnptrs by dn_comp() (???) */
+ if (zp->z_type == Z_CACHE) {
+ ttl = dp->d_ttl - (u_long) tt.tv_sec;
+ if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
+#ifdef DEBUG
+/*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %d=>0, x%x\n", ttl, dp->d_flags);
+#endif
+ ttl = 0;
+ }
+ } else {
+ if (dp->d_ttl)
+ ttl = dp->d_ttl;
+ else
+ ttl = zp->z_minimum; /* really default */
+#ifdef notdef /* don't decrease ttl based on time since verification */
+ if (zp->z_type == Z_SECONDARY) {
+ /*
+ * Set ttl to value received from primary,
+ * less time since we verified it (but never
+ * less than a small positive value).
+ */
+ ttl -= tt.tv_sec - zp->z_lastupdate;
+ if (ttl <= 0)
+ ttl = 120;
+ }
+#endif
+ }
+
+ buflen -= RRFIXEDSZ;
+ if ((n = dn_comp((u_char *)name, (u_char *)buf, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return (-1);
+ cp = buf + n;
+ buflen -= n;
+ PUTSHORT((u_short)dp->d_type, cp);
+ PUTSHORT((u_short)dp->d_class, cp);
+ PUTLONG(ttl, cp);
+ sp = cp;
+ cp += sizeof(u_short);
+ switch (dp->d_type) {
+ case T_CNAME:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return (-1);
+ PUTSHORT((u_short)n, sp);
+ cp += n;
+ break;
+
+ case T_MB:
+ case T_NS:
+ /* Store domain name in answer */
+ if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return (-1);
+ PUTSHORT((u_short)n, sp);
+ cp += n;
+ if (doadd)
+ addname(dp->d_data, dp->d_class);
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ cp1 = dp->d_data;
+ if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long);
+ cp1 += strlen(cp1) + 1;
+ if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return (-1);
+ cp += n;
+ if (dp->d_type == T_SOA) {
+ cp1 += strlen(cp1) + 1;
+ bcopy(cp1, cp,
+ (int)(n = dp->d_size - (cp1 - dp->d_data)));
+ cp += n;
+ }
+ n = (u_short)(cp - sp) - sizeof(u_short);
+ PUTSHORT((u_short)n, sp);
+ break;
+
+ case T_MX:
+ /* cp1 == our data/ cp == data of RR */
+ cp1 = dp->d_data;
+
+ /* copy preference */
+ bcopy(cp1,cp,sizeof(u_short));
+ cp += sizeof(u_short);
+ cp1 += sizeof(u_short);
+ buflen -= sizeof(u_short);
+
+ if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)edp)) < 0)
+ return(-1);
+ cp += n;
+
+ /* save data length */
+ n = (u_short)(cp - sp) - sizeof(u_short);
+ PUTSHORT((u_short)n, sp);
+ if (doadd)
+ addname(cp1, dp->d_class);
+ break;
+
+ default:
+ if (dp->d_size > buflen)
+ return (-1);
+ bcopy(dp->d_data, cp, dp->d_size);
+ PUTSHORT((u_short)dp->d_size, sp);
+ cp += dp->d_size;
+ }
+ return (cp - buf);
+}
+
+addname(name, class)
+register char *name;
+short class;
+{
+ register struct addinfo *ap;
+ register int n;
+
+ for (ap = addinfo, n = addcount; --n >= 0; ap++)
+ if (strcasecmp(ap->a_dname, name) == 0)
+ return;
+ /* add domain name to additional section */
+ if (addcount < NADDRECS) {
+ addcount++;
+ ap->a_dname = name;
+ ap->a_class = class;
+ }
+}
+
+/*
+ * Lookup addresses for names in addinfo and put into the message's
+ * additional section.
+ */
+doaddinfo(hp, msg, msglen)
+ HEADER *hp;
+ char *msg;
+ int msglen;
+{
+ register struct namebuf *np;
+ register struct databuf *dp;
+ register struct addinfo *ap;
+ register char *cp;
+ struct hashbuf *htp;
+ char *fname;
+ int n, count, foundstale;
+
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"doaddinfo() addcount = %d\n", addcount);
+#endif
+
+ count = 0;
+ cp = msg;
+ for (ap = addinfo; --addcount >= 0; ap++) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"do additional '%s'\n", ap->a_dname);
+#endif
+ htp = hashtab; /* because "nlookup" stomps on arg. */
+ np = nlookup(ap->a_dname, &htp, &fname, 0);
+ if (np == NULL || fname != ap->a_dname)
+ continue;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"found it\n");
+#endif
+ foundstale = 0;
+ /* look for the data */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, (int)ap->a_class, T_A))
+ continue;
+ if (stale(dp)) {
+ foundstale++;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"doaddinfo: stale entry '%s'%s\n",
+ np->n_dname,
+ (dp->d_flags&DB_F_HINT) ? " hint":"" );
+#endif
+ continue;
+ }
+ /*
+ * Should be smart and eliminate duplicate
+ * data here. XXX
+ */
+ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0)
+ break;
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"addinfo: adding address data n = %d\n",
+ n);
+#endif
+ cp += n;
+ msglen -= n;
+ count++;
+ }
+ if (foundstale) {
+ /* Cache invalidate the address RR's */
+ delete_all(np, (int)ap->a_class, T_A);
+ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A);
+ }
+ }
+ hp->arcount = htons((u_short)count);
+ return (cp - msg);
+}
+
+doaddauth(hp, cp, buflen, np, dp)
+ register HEADER *hp;
+ char *cp;
+ int buflen;
+ struct namebuf *np;
+ struct databuf *dp;
+{
+ char dnbuf[MAXDNAME];
+ int n;
+
+ getname(np, dnbuf, sizeof(dnbuf));
+ if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"doaddauth: can't add '%s' (%d)\n",
+ dnbuf, buflen);
+#endif
+ return(0);
+ } else {
+ hp->nscount = htons(1);
+ return(n);
+ }
+}
+
+
+/*
+ * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
+ */
+getname(np, buf, buflen)
+ struct namebuf *np;
+ char *buf;
+ int buflen;
+{
+ register char *cp;
+ register int i;
+
+ cp = buf;
+ while (np != NULL) {
+ if ((i = strlen(np->n_dname))+1 >= buflen) {
+ *cp = '\0';
+ syslog(LOG_ERR, "domain name too long: %s...\n", buf);
+ strcpy(buf, "Name_Too_Long");
+ return;
+ }
+ if (cp != buf)
+ *cp++ = '.';
+ (void) strcpy(cp, np->n_dname);
+ cp += i;
+ buflen -= (i+1);
+ np = np->n_parent;
+ }
+ *cp = '\0';
+}
+
+/*
+ * Do a zone transfer. SOA record already sent.
+ */
+doaxfr(np, rfp, isroot)
+ register struct namebuf *np;
+ FILE *rfp;
+ int isroot;
+{
+ register struct databuf *dp;
+ register int n;
+ struct hashbuf *htp;
+ struct databuf *gdp; /* glue databuf */
+ struct namebuf *gnp; /* glue namebuf */
+ struct namebuf **npp, **nppend;
+ char msg[PACKETSZ];
+ char *cp;
+ char *fname;
+ char dname[MAXDNAME];
+ HEADER *hp = (HEADER *) msg;
+ int fndns;
+
+#ifdef DEBUG
+ if (debug && isroot)
+ fprintf(ddt,"doaxfr()\n");
+#endif
+ fndns = 0;
+ hp->id = 0;
+ hp->opcode = QUERY;
+ hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
+ hp->qr = 1;
+ hp->rcode = NOERROR;
+ hp->qdcount = 0;
+ hp->ancount = htons(1);
+ hp->nscount = 0;
+ hp->arcount = 0;
+ cp = msg + sizeof(HEADER);
+ getname(np, dname, sizeof(dname));
+
+ /* first do data records */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ /*
+ * Skip the root SOA record (marks end of data);
+ * don't send SOA for subdomains, as we're not sending them.
+ */
+ if (dp->d_type == T_SOA)
+ continue;
+ if (dp->d_type == T_NS)
+ fndns = 1;
+ if (dp->d_zone == 0 || stale(dp))
+ continue;
+ if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
+ continue;
+ fwritemsg(rfp, msg, n + sizeof(HEADER));
+
+ if (dp->d_type == T_NS) {
+ /* Glue the sub domains together by sending
+ * the address records for the sub domain
+ * name servers along.
+ */
+ htp = hashtab;
+ cp = msg + sizeof(HEADER);
+ gnp = nlookup(dp->d_data, &htp, &fname, 0);
+ if (gnp == NULL || fname != dp->d_data)
+ continue;
+ for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
+ if (gdp->d_type != T_A || stale(gdp))
+ continue;
+ if ((n = make_rr(fname, gdp, cp,
+ sizeof(msg)-sizeof(HEADER), 0)) < 0)
+ continue;
+ fwritemsg(rfp, msg, n + sizeof(HEADER));
+ }
+ }
+ }
+
+ /* next do subdomains, unless delegated */
+ if ((isroot == 0 && fndns) || np->n_hash == NULL)
+ return;
+ npp = np->n_hash->h_tab;
+ nppend = npp + np->n_hash->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ doaxfr(np, rfp, 0);
+ }
+ }
+#ifdef DEBUG
+ if (debug && isroot)
+ fprintf(ddt,"exit doaxfr()\n");
+#endif
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the
+ * primary server for the zone being updated, we update the zone's serial
+ * number and then call doupdate directly. If this is a secondary, we just
+ * forward the update; this way, if the primary update fails (e.g., if the
+ * primary is unavailable), we don't update the secondary; if the primary
+ * update suceeds, ns_resp will get called with the response (when it comes
+ * in), and then update the secondary's copy.
+ */
+InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd)
+ register HEADER *hp;
+ struct databuf *nsp[];
+ char *msg;
+ int msglen;
+ u_char *startcp;
+ struct sockaddr_in *from;
+ struct qstream *qsp;
+ int dfd;
+{
+ struct zoneinfo *zp;
+ char dnbuf[MAXDNAME];
+ struct hashbuf *htp = hashtab; /* lookup relative to root */
+ struct namebuf *np;
+ struct databuf *olddp, *newdp, *dp;
+ struct databuf **nspp;
+ char *fname;
+ register u_char *cp = startcp;
+ short class, type;
+ int n, size, zonenum;
+ char ZoneName[MAXDNAME], *znp;
+
+ if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR InitDynUpdate expand name failed\n");
+#endif
+ hp->rcode = FORMERR;
+ return(FORMERR);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ if (type == T_SOA) { /* T_SOA updates not allowed */
+ hp->rcode = REFUSED;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "InitDynUpdate: REFUSED - SOA update\n");
+#endif
+ return(REFUSED);
+ }
+ GETSHORT(class, cp);
+ cp += sizeof(u_long);
+ GETSHORT(size, cp);
+/****XXX - need bounds checking here ****/
+ cp += size;
+
+ if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */
+ hp->rcode = NXDOMAIN;
+ return(NXDOMAIN);
+ }
+ zp = &zones[zonenum];
+
+ /* Disallow updates for which we aren't authoratative. Note: the
+ following test doesn't work right: If it's for a non-local zone,
+ we will think it's a primary but be unable to lookup the namebuf,
+ thus returning 'NXDOMAIN' */
+ if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) {
+ hp->rcode = REFUSED;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "InitDynUpdate: REFUSED - non-primary, non-sedondary update\n");
+#endif
+ return(REFUSED);
+ }
+ if (!(zp->z_state & Z_DYNAMIC)) {
+ hp->rcode = REFUSED;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "InitDynUpdate: REFUSED - dynamic flag not set for zone\n");
+#endif
+ return(REFUSED);
+ }
+
+ /*
+ * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since
+ * otherwise the lookup fails, because '.' may have a nil n_hash
+ * associated with it.
+ */
+ strcpy(ZoneName, zp->z_origin);
+ znp = &ZoneName[strlen(ZoneName) - 1];
+ if (*znp == '.')
+ *znp = NULL;
+ np = nlookup(ZoneName, &htp, &fname, 0);
+ if ((np == NULL) || (fname != ZoneName)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
+ ZoneName);
+#endif DEBUG
+ syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n",
+ ZoneName);
+ hp->rcode = NXDOMAIN;
+ return(NXDOMAIN);
+ }
+
+ /*
+ * If this is the primary copy increment the serial number. Don't
+ * increment the serial number if this is a secondary; this way, if 2
+ * different secondaries both update the primary, they will both have
+ * lower serial numbers than the primary has, and hence eventually
+ * refresh and get all updates and become consistent.
+ *
+ * Note that the serial number must be incremented in both the zone
+ * data structure and the zone's namebuf.
+ */
+ switch (zp->z_type) {
+ case Z_SECONDARY: /* forward update to primary */
+ nspp = nsp;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (match(dp, class, T_NS)) {
+ if (nspp < &nsp[NSMAX-1])
+ *nspp++ = dp;
+ else
+ break;
+ }
+ dp = dp->d_next;
+ }
+ *nspp = NULL; /* Delimiter */
+ if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL) < 0) {
+ hp->rcode = SERVFAIL;
+ return(SERVFAIL);
+ }
+ return(FORWARDED);
+
+ case Z_PRIMARY:
+ zp->z_serial++;
+ olddp = np->n_data; /* old databuf */
+ /* Find the SOA record */
+ for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next)
+ if (match(olddp, class, T_SOA))
+ break;
+ if (olddp == NULL) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"InitDynUpdate: Couldn't find SOA record for '%s'\n",
+ ZoneName);
+#endif DEBUG
+ syslog(LOG_ERR,
+ "InitDynUpdate: Couldn't find SOA record for '%s'\n"
+,
+ ZoneName);
+ hp->rcode = NXDOMAIN;
+ return(NXDOMAIN);
+ }
+ newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl,
+ olddp->d_data, olddp->d_size);
+ newdp->d_zone = olddp->d_zone;
+ cp = (u_char *)newdp->d_data;
+ cp += strlen(cp) + 1; /* skip origin string */
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ putlong((u_long)(zp->z_serial), cp);
+#ifdef DEBUG
+ if (debug >= 4) {
+ fprintf(ddt, "after stuffing data into newdp:\n");
+ printSOAdata(newdp);
+ }
+#endif DEBUG
+
+ if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
+ hashtab)) != NOERROR) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"InitDynUpdate: SOA update failed\n");
+#endif DEBUG
+ hp->rcode = NOCHANGE;
+ return(NOCHANGE);
+ }
+
+ /* Now update the RR itself */
+ if (doupdate(msg, msglen, msg + sizeof(HEADER),
+ zonenum, (struct databuf *)0, DB_NODATA) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"InitDynUpdate: doupdate failed\n");
+#endif DEBUG
+ /* doupdate fills in rcode */
+ return(hp->rcode);
+ }
+ zp->hasChanged++;
+ return(NOERROR);
+ }
+}
+
+#ifdef DEBUG
+/*
+ * Print the contents of the data in databuf pointed to by dp for an SOA record
+ */
+printSOAdata(dp)
+ struct databuf *dp;
+{
+ register u_char *cp;
+
+ if (!debug)
+ return; /* Otherwise fprintf to ddt will bomb */
+ cp = (u_char *)dp->d_data;
+ fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp);
+ cp += strlen(cp) + 1; /* skip origin string */
+ fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));
+}
+#endif DEBUG
+#endif ALLOW_UPDATES
+
+struct databuf *
+rm_datum(dp, np, pdp)
+register struct databuf *pdp, *dp;
+register struct namebuf *np;
+{
+ register struct databuf *ndp = dp->d_next;
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt, "rm_datum(%x, %x, %x) -> %x\n",
+ dp, np->n_data, pdp, ndp);
+#endif DEBUG
+ if (pdp == NULL)
+ np->n_data = ndp;
+ else
+ pdp->d_next = ndp;
+ rminv(dp);
+ (void) free((char *)dp);
+ return(ndp);
+}
+
+startxfr(qsp, np, msg, msglen)
+ struct qstream *qsp;
+ struct namebuf *np;
+ char *msg;
+ int msglen;
+{
+ register FILE *rfp;
+ int fdstat;
+
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"startxfr()\n");
+#endif
+ /*
+ * child does the work while
+ * the parent continues
+ */
+ if (fork() == 0) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt,"startxfr: child pid %d\n", getpid());
+#endif
+ rfp = fdopen(qsp->s_rfd, "w");
+ setproctitle("zone XFR to", qsp->s_rfd);
+ fdstat = fcntl(qsp->s_rfd, F_GETFL, 0);
+ if (fdstat != -1)
+ (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~O_NONBLOCK);
+ fwritemsg(rfp, msg, msglen);
+ doaxfr(np, rfp, 1);
+ fwritemsg(rfp, msg, msglen);
+ (void) fflush(rfp);
+ exit(0);
+ }
+ sqrm(qsp);
+}
diff --git a/usr.sbin/named/ns_resp.c b/usr.sbin/named/ns_resp.c
new file mode 100644
index 00000000000..3e0c2fef80a
--- /dev/null
+++ b/usr.sbin/named/ns_resp.c
@@ -0,0 +1,1704 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 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[] = "from: @(#)ns_resp.c 4.65 (Berkeley) 3/3/91";*/
+static char rcsid[] = "$Id: ns_resp.c,v 1.1.1.1 1995/10/18 08:47:51 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "ns.h"
+#include "db.h"
+
+extern int debug;
+extern FILE *ddt;
+extern int errno;
+extern u_char *dnptrs[];
+extern time_t retrytime();
+extern struct fwdinfo *fwdtab;
+extern struct sockaddr_in from_addr; /* Source addr of last packet */
+extern int needs_prime_cache;
+extern int priming;
+
+struct qinfo *sysquery();
+
+ns_resp(msg, msglen)
+ u_char *msg;
+ int msglen;
+{
+ register struct qinfo *qp;
+ register HEADER *hp;
+ register struct qserv *qs;
+ register struct databuf *ns, *ns2;
+ register u_char *cp;
+ struct databuf *nsp[NSMAX], **nspp;
+ int i, c, n, ancount, aucount, nscount, arcount;
+ int type, class, dbflags;
+ int cname = 0; /* flag for processing cname response */
+ int count, founddata, foundname;
+ int buflen;
+ int newmsglen;
+ char name[MAXDNAME], *dname;
+ char *fname;
+ u_char newmsg[BUFSIZ];
+ u_char **dpp, *tp;
+ time_t rtrip;
+
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct netinfo *lp;
+ extern struct netinfo *local();
+ extern int nsid;
+ extern int addcount;
+ struct fwdinfo *fwd;
+
+#ifdef STATS
+ stats[S_RESPONSES].cnt++;
+#endif
+ hp = (HEADER *) msg;
+ if ((qp = qfindid(hp->id)) == NULL ) {
+#ifdef DEBUG
+ if (debug > 1)
+ fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id));
+#endif
+#ifdef STATS
+ stats[S_DUPRESP].cnt++;
+#endif
+ return;
+ }
+
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"%s response nsid=%d id=%d\n",
+ qp->q_system ? "SYSTEM" : "USER",
+ ntohs(qp->q_nsid), ntohs(qp->q_id));
+#endif
+
+ /*
+ * Here we handle bad responses from servers.
+ * Several possibilities come to mind:
+ * The server is sick and returns SERVFAIL
+ * The server returns some garbage opcode (its sick)
+ * The server can't understand our query and return FORMERR
+ * In all these cases, we simply drop the packet and force
+ * a retry. This will make him look bad due to unresponsiveness.
+ * Be sure not to include authoritative NXDOMAIN
+ */
+ if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
+ || (hp->rcode == NXDOMAIN && !hp->aa)
+ || hp->opcode != QUERY) {
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"resp: error (ret %d, op %d), dropped\n",
+ hp->rcode, hp->opcode);
+#endif
+#ifdef STATS
+ stats[S_BADRESPONSES].cnt++;
+#endif
+ return;
+ }
+
+#ifdef ALLOW_UPDATES
+ if ( (hp->rcode == NOERROR) &&
+ (hp->opcode == UPDATEA || hp->opcode == UPDATED ||
+ hp->opcode == UPDATEDA || hp->opcode == UPDATEM ||
+ hp->opcode == UPDATEMA) ) {
+ /*
+ * Update the secondary's copy, now that the primary
+ * successfully completed the update. Zone doesn't matter
+ * for dyn. update -- doupdate calls findzone to find it
+ */
+ doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER),
+ 0, (struct databuf *)0, 0);
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: leaving, UPDATE*\n");
+#endif
+ /* return code filled in by doupdate */
+ goto return_msg;
+ }
+#endif ALLOW_UPDATES
+
+ /*
+ * Determine if the response came from a forwarder. Packets from
+ * anyplace not listed as a forwarder or as a server to whom we
+ * might have forwarded the query will be dropped.
+ */
+ for (fwd = fwdtab; fwd != (struct fwdinfo *)NULL; fwd = fwd->next)
+ if (bcmp((char *)&fwd->fwdaddr.sin_addr, &from_addr.sin_addr,
+ sizeof(struct in_addr)) == 0)
+ break;
+ /*
+ * If we were using nameservers, find the qinfo pointer and update
+ * the rtt and fact that we have called on this server before.
+ */
+ if (fwd == (struct fwdinfo *)NULL) {
+ struct timeval *stp;
+
+ for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++)
+ if (bcmp((char *)&qs->ns_addr.sin_addr,
+ &from_addr.sin_addr, sizeof(struct in_addr)) == 0)
+ break;
+ if (n >= qp->q_naddr) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "Response from unexpected source %s\n",
+ inet_ntoa(from_addr.sin_addr));
+#endif DEBUG
+#ifdef STATS
+ stats[S_MARTIANS].cnt++;
+#endif
+ /*
+ * We don't know who this response came from so it
+ * gets dropped on the floor.
+ */
+ return;
+ }
+ stp = &qs->stime;
+
+ /* Handle response from different (untried) interface */
+ if (stp->tv_sec == 0) {
+ ns = qs->ns;
+ while (qs > qp->q_addr &&
+ (qs->stime.tv_sec == 0 || qs->ns != ns))
+ qs--;
+ *stp = qs->stime;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "Response from unused address %s, assuming %s\n",
+ inet_ntoa(from_addr.sin_addr),
+ inet_ntoa(qs->ns_addr.sin_addr));
+#endif DEBUG
+ }
+
+ /* compute query round trip time */
+ rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
+ (tt.tv_usec - stp->tv_usec) / 1000);
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"stime %d/%d now %d/%d rtt %d\n",
+ stp->tv_sec, stp->tv_usec,
+ tt.tv_sec, tt.tv_usec, rtrip);
+#endif
+ /* prevent floating point overflow, limit to 1000 sec */
+ if (rtrip > 1000000)
+ rtrip = 1000000;
+ ns = qs->nsdata;
+ /*
+ * Don't update nstime if this doesn't look
+ * like an address databuf now. XXX
+ */
+ if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) {
+ if (ns->d_nstime == 0)
+ ns->d_nstime = (u_long)rtrip;
+ else
+ ns->d_nstime = ns->d_nstime * ALPHA +
+ (1-ALPHA) * (u_long)rtrip;
+ /* prevent floating point overflow, limit to 1000 sec */
+ if (ns->d_nstime > 1000000)
+ ns->d_nstime = 1000000;
+ }
+
+ /*
+ * Record the source so that we do not use this NS again.
+ */
+ if(qp->q_nusedns < NSMAX) {
+ qp->q_usedns[qp->q_nusedns++] = qs->ns;
+#ifdef DEBUG
+ if(debug > 1)
+ fprintf(ddt, "NS #%d addr %s used, rtt %d\n",
+ n, inet_ntoa(qs->ns_addr.sin_addr),
+ ns->d_nstime);
+#endif DEBUG
+ }
+
+ /*
+ * Penalize those who had earlier chances but failed
+ * by multiplying round-trip times by BETA (>1).
+ * Improve nstime for unused addresses by applying GAMMA.
+ * The GAMMA factor makes unused entries slowly
+ * improve, so they eventually get tried again.
+ * GAMMA should be slightly less than 1.
+ * Watch out for records that may have timed out
+ * and are no longer the correct type. XXX
+ */
+
+ for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) {
+ ns2 = qs->nsdata;
+ if (ns2 == ns)
+ continue;
+ if (ns2->d_type != T_A ||
+ ns2->d_class != qs->ns->d_class) /* XXX */
+ continue;
+ if (qs->stime.tv_sec) {
+ if (ns2->d_nstime == 0)
+ ns2->d_nstime = rtrip * BETA;
+ else
+ ns2->d_nstime =
+ ns2->d_nstime * BETA + (1-ALPHA) * rtrip;
+ if (ns2->d_nstime > 1000000)
+ ns2->d_nstime = 1000000;
+ } else
+ ns2->d_nstime = ns2->d_nstime * GAMMA;
+#ifdef DEBUG
+ if(debug > 1)
+ fprintf(ddt, "NS #%d %s rtt now %d\n", n,
+ inet_ntoa(qs->ns_addr.sin_addr),
+ ns2->d_nstime);
+#endif DEBUG
+ }
+ }
+
+ /*
+ * Skip query section
+ */
+ addcount = 0;
+ cp = msg + sizeof(HEADER);
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ if (hp->qdcount) {
+ n = dn_skipname(cp, msg + msglen);
+ if (n <= 0)
+ goto formerr;
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp - msg > msglen)
+ goto formerr;
+ }
+
+ /*
+ * Save answers, authority, and additional records for future use.
+ */
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount);
+ arcount = ntohs(hp->arcount);
+ nscount = 0;
+ tp = cp;
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n",
+ ancount, aucount, arcount);
+#endif
+
+ /*
+ * If there's an answer, check if it's a CNAME response;
+ * if no answer but aucount > 0, see if there is an NS
+ * or just an SOA. (NOTE: ancount might be 1 with a CNAME,
+ * and NS records may still be in the authority section;
+ * we don't bother counting them, as we only use nscount
+ * if ancount == 0.)
+ */
+ if (ancount == 1 || (ancount == 0 && aucount > 0)) {
+ c = aucount;
+ do {
+ if (tp - msg >= msglen)
+ goto formerr;
+ n = dn_skipname(tp, msg + msglen);
+ if (n <= 0)
+ goto formerr;
+ tp += n; /* name */
+ GETSHORT(i, tp); /* type */
+ tp += sizeof(u_short); /* class */
+ tp += sizeof(u_long); /* ttl */
+ GETSHORT(count, tp); /* dlen */
+ if (tp - msg > msglen - count)
+ goto formerr;
+ tp += count;
+ if (ancount && i == T_CNAME) {
+ cname++;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"CNAME - needs more processing\n");
+#endif
+ if (!qp->q_cmsglen) {
+ qp->q_cmsg = qp->q_msg;
+ qp->q_cmsglen = qp->q_msglen;
+ qp->q_msg = NULL;
+ qp->q_msglen = 0;
+ }
+ }
+ /*
+ * See if authority record is a nameserver.
+ */
+ if (ancount == 0 && i == T_NS)
+ nscount++;
+ } while (--c > 0);
+ tp = cp;
+ }
+
+ /*
+ * Add the info received in the response to the Data Base
+ */
+ c = ancount + aucount + arcount;
+#ifdef notdef
+ /*
+ * If the request was for a CNAME that doesn't exist,
+ * but the name is valid, fetch any other data for the name.
+ * DON'T do this now, as it will requery if data are already
+ * in the cache (maybe later with negative caching).
+ */
+ if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR &&
+ !qp->q_system) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: leaving, no CNAME\n");
+#endif
+ /* Cause us to put it in the cache later */
+ prime(class, T_ANY, qp);
+
+ /* Nothing to store, just give user the answer */
+ goto return_msg;
+ }
+#endif /* notdef */
+
+ nspp = nsp;
+ if (qp->q_system)
+ dbflags = DB_NOTAUTH | DB_NODATA;
+ else
+ dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
+ for (i = 0; i < c; i++) {
+ struct databuf *ns3;
+
+ if (cp >= msg + msglen)
+ goto formerr;
+ ns3 = 0;
+ if ((n = doupdate(msg, msglen, cp, 0, &ns3, dbflags)) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: leaving, doupdate failed\n");
+#endif
+ /* return code filled in by doupdate */
+ goto return_msg;
+ }
+ /*
+ * Remember nameservers from the authority section
+ * for referrals.
+ * (This is usually overwritten by findns below(?). XXX
+ */
+ if (ns3 && i >= ancount && i < ancount + aucount &&
+ nspp < &nsp[NSMAX-1])
+ *nspp++ = ns3;
+ cp += n;
+ }
+
+ if (qp->q_system && ancount) {
+ if (qp->q_system == PRIMING_CACHE)
+ check_root();
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"resp: leaving, SYSQUERY ancount %d\n", ancount);
+#endif
+ qremove(qp);
+ return;
+ }
+
+ if (cp > msg + msglen)
+ goto formerr;
+
+ /*
+ * If there are addresses and this is a local query,
+ * sort them appropriately for the local context.
+ */
+ if (ancount > 1 && (lp = local(&qp->q_from)) != NULL)
+ sort_response(tp, ancount, lp, msg + msglen);
+
+ /*
+ * An answer to a T_ANY query or a successful answer to a
+ * regular query with no indirection, then just return answer.
+ */
+ if ((hp->qdcount && type == T_ANY && ancount) ||
+ (!cname && !qp->q_cmsglen && ancount)) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: got as much answer as there is\n");
+#endif
+ goto return_msg;
+ }
+
+ /*
+ * Eventually we will want to cache this negative answer.
+ */
+ if (ancount == 0 && nscount == 0 &&
+ (hp->aa || fwd || class == C_ANY)) {
+ /* We have an authoritative NO */
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: leaving auth NO\n");
+#endif
+ if (qp->q_cmsglen) {
+ msg = (u_char *)qp->q_cmsg;
+ msglen = qp->q_cmsglen;
+ hp = (HEADER *)msg;
+ }
+ goto return_msg;
+ }
+
+ /*
+ * All messages in here need further processing. i.e. they
+ * are either CNAMEs or we got referred again.
+ */
+ count = 0;
+ founddata = 0;
+ foundname = 0;
+ dname = name;
+ if (!cname && qp->q_cmsglen && ancount) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"Cname second pass\n");
+#endif
+ newmsglen = qp->q_cmsglen;
+ bcopy(qp->q_cmsg, newmsg, newmsglen);
+ } else {
+ newmsglen = msglen;
+ bcopy(msg, newmsg, newmsglen);
+ }
+ hp = (HEADER *) newmsg;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ dnptrs[0] = newmsg;
+ dnptrs[1] = NULL;
+ cp = newmsg + sizeof(HEADER);
+ if (cname)
+ cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ;
+ if ((n = dn_expand(newmsg, newmsg + newmsglen,
+ cp, (u_char *)dname, sizeof(name))) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"dn_expand failed\n" );
+#endif
+ goto servfail;
+ }
+ if (!cname)
+ cp += n + QFIXEDSZ;
+ buflen = sizeof(newmsg) - (cp - newmsg);
+
+try_again:
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: nlookup(%s) type=%d\n",dname, type);
+#endif
+ fname = "";
+ htp = hashtab; /* lookup relative to root */
+ np = nlookup(dname, &htp, &fname, 0);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found", dname, fname, cname);
+#endif
+ if (np == NULL || fname != dname)
+ goto fetch_ns;
+
+ foundname++;
+ count = cp - newmsg;
+ n = finddata(np, class, type, hp, &dname, &buflen, &count);
+ if (n == 0)
+ goto fetch_ns; /* NO data available */
+ cp += n;
+ buflen -= n;
+ hp->ancount += count;
+ if (fname != dname && type != T_CNAME && type != T_ANY) {
+ cname++;
+ goto try_again;
+ }
+ founddata = 1;
+
+#ifdef DEBUG
+ if (debug >= 3) {
+ fprintf(ddt,"resp: foundname = %d count = %d ", foundname, count);
+ fprintf(ddt,"founddata = %d cname = %d\n", founddata, cname);
+ }
+#endif
+
+fetch_ns:
+ hp->ancount = htons(hp->ancount);
+ /*
+ * Look for name servers to refer to and fill in the authority
+ * section or record the address for forwarding the query
+ * (recursion desired).
+ */
+ switch (findns(&np, class, nsp, &count)) {
+ case NXDOMAIN: /* shouldn't happen */
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode);
+#endif
+ if (!foundname)
+ hp->rcode = NXDOMAIN;
+ if (class != C_ANY) {
+ hp->aa = 1;
+ /*
+ * should return SOA if founddata == 0,
+ * but old named's are confused by an SOA
+ * in the auth. section if there's no error.
+ */
+ if (foundname == 0 && np) {
+ n = doaddauth(hp, cp, buflen, np, nsp[0]);
+ cp += n;
+ buflen -= n;
+ }
+ }
+ goto return_newmsg;
+
+ case SERVFAIL:
+ goto servfail;
+ }
+
+ if (founddata) {
+ hp = (HEADER *)newmsg;
+ n = add_data(np, nsp, cp, buflen);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ cp += n;
+ buflen -= n;
+ hp->nscount = htons((u_short)count);
+ goto return_newmsg;
+ }
+
+ /*
+ * If we get here, we don't have the answer yet and are about
+ * to iterate to try and get it. First, infinite loop avoidance.
+ */
+ if (qp->q_nqueries++ > MAXQUERIES) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: MAXQUERIES exceeded (%s, class %d, type %d)\n",
+ dname, class, type);
+#endif
+ syslog(LOG_NOTICE,
+ "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+ dname);
+ goto servfail;
+ }
+
+ /* Reset the query control structure */
+ qp->q_naddr = 0;
+ qp->q_curaddr = 0;
+ qp->q_fwd = fwdtab;
+ if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: no addrs found for NS's\n");
+#endif
+ goto servfail;
+ }
+ for (n = 0; n < qp->q_naddr; n++)
+ qp->q_addr[n].stime.tv_sec = 0;
+ if (!qp->q_fwd)
+ qp->q_addr[0].stime = tt;
+ if (cname) {
+ if (qp->q_cname++ == MAXCNAMES) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: leaving, MAXCNAMES exceeded\n");
+#endif
+ goto servfail;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"q_cname = %d\n",qp->q_cname);
+ if (debug >= 3)
+ fprintf(ddt,"resp: building recursive query; nslookup\n");
+#endif
+ if (qp->q_msg)
+ (void) free(qp->q_msg);
+ if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: malloc error\n");
+#endif
+ goto servfail;
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
+ hp = (HEADER *) qp->q_msg;
+ hp->rd = 0;
+ } else
+ hp = (HEADER *)qp->q_msg;
+ hp->id = qp->q_nsid = htons((u_short)++nsid);
+ if (qp->q_fwd)
+ hp->rd = 1;
+ unsched(qp);
+ schedretry(qp, retrytime(qp));
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: forw -> %s %d (%d) nsid=%d id=%d %dms\n",
+ inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+ ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_addr[0].nsdata->d_nstime);
+ if ( debug >= 10)
+ fp_query((char *)msg, ddt);
+#endif
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)Q_NEXTADDR(qp,0),
+ sizeof(struct sockaddr_in)) < 0) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt, "sendto error = %d\n", errno);
+#endif
+ }
+ hp->rd = 0; /* leave set to 0 for dup detection */
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"resp: Query sent.\n");
+#endif
+ return;
+
+formerr:
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR resp() from %s size err %d, msglen %d\n",
+ inet_ntoa(from_addr.sin_addr),
+ cp-msg, msglen);
+#endif
+ syslog(LOG_INFO, "Malformed response from %s\n",
+ inet_ntoa(from_addr.sin_addr));
+#ifdef STATS
+ stats[S_RESPFORMERR].cnt++;
+#endif
+ return;
+
+return_msg:
+#ifdef STATS
+ stats[S_RESPOK].cnt++;
+#endif
+ /* The "standard" return code */
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = 1;
+ (void) send_msg(msg, msglen, qp);
+ qremove(qp);
+ return;
+
+return_newmsg:
+#ifdef STATS
+ stats[S_RESPOK].cnt++;
+#endif
+ if (addcount) {
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = 1;
+ hp->qr = 1;
+ (void) send_msg(newmsg, cp - newmsg, qp);
+ qremove(qp);
+ return;
+
+servfail:
+#ifdef STATS
+ stats[S_RESPFAIL].cnt++;
+#endif
+ hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg);
+ hp->rcode = SERVFAIL;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = 1;
+ hp->qr = 1;
+ (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp);
+ qremove(qp);
+ return;
+}
+
+/*
+ * Decode the resource record 'rrp' and update the database.
+ * If savens is true, record pointer for forwarding queries a second time.
+ */
+doupdate(msg, msglen, rrp, zone, savens, flags)
+ char *msg;
+ u_char *rrp;
+ struct databuf **savens;
+ int msglen, zone, flags;
+{
+ register u_char *cp;
+ register int n;
+ int class, type, dlen, n1;
+ u_long ttl;
+ struct databuf *dp;
+ char dname[MAXDNAME];
+ u_char *cp1;
+ u_char data[BUFSIZ];
+ register HEADER *hp = (HEADER *) msg;
+#ifdef ALLOW_UPDATES
+ int zonenum;
+#endif
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"doupdate(zone %d, savens %x, flags %x)\n",
+ zone, savens, flags);
+#endif
+
+ cp = rrp;
+ if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp,
+ (u_char *)dname, sizeof(dname))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"doupdate: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl);
+#endif
+ /*
+ * Convert the resource record data into the internal
+ * database format.
+ */
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif ALLOW_T_UNSPEC
+ cp1 = cp;
+ n = dlen;
+ cp += n;
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+ cp, data, sizeof(data))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+ cp, data, sizeof(data))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data + (n = strlen((char *)data) + 1);
+ n1 = sizeof(data) - n;
+ if (type == T_SOA)
+ n1 -= 5 * sizeof(u_long);
+ if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+ cp, cp1, n1)) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ bcopy(cp, cp1, n = 5 * sizeof(u_long));
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ /* grab preference */
+ bcopy(cp,data,sizeof(u_short));
+ cp1 = data + sizeof(u_short);
+ cp += sizeof(u_short);
+
+ /* get name */
+ if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+ cp, cp1, sizeof(data) - sizeof(u_short))) < 0)
+ return(-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"unknown type %d\n", type);
+#endif
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n);
+#endif
+ hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */
+ return(-1);
+ }
+
+#ifdef ALLOW_UPDATES
+ /*
+ * If this is a dynamic update request, process it specially; else,
+ * execute normal update code.
+ */
+ switch(hp->opcode) {
+
+ /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */
+ case UPDATEM:
+ case UPDATEMA:
+
+ /*
+ * The named code for UPDATED and UPDATEDA is the same except that for
+ * UPDATEDA we we ignore any data that was passed: we just delete all
+ * RRs whose name, type, and class matches
+ */
+ case UPDATED:
+ case UPDATEDA:
+ if (type == T_SOA) { /* Not allowed */
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "UDPATE: REFUSED - SOA delete\n");
+#endif
+ hp->rcode = REFUSED;
+ return(-1);
+ }
+ /*
+ * Don't check message length if doing UPDATEM/UPDATEMA,
+ * since the whole message wont have been demarshalled until
+ * we reach the code for UPDATEA
+ */
+ if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) {
+ if (cp != (u_char *)(msg + msglen)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR UPDATE message length off\n");
+#endif
+ hp->rcode = FORMERR;
+ return(-1);
+ }
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return(-1);
+ }
+ if (zones[zonenum].z_state & Z_DYNADDONLY) {
+ hp->rcode = NXDOMAIN;
+ return(-1);
+ }
+ if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) {
+ /* Make a dp for use in db_update, as old dp */
+ dp = savedata(class, type, 0, cp1, n);
+ dp->d_zone = zonenum;
+ n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
+ hashtab);
+ if (n != OK) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"UPDATE: db_update failed\n");
+#endif DEBUG
+ free( (struct databuf *) dp);
+ hp->rcode = NOCHANGE;
+ return(-1);
+ }
+ } else { /* UPDATEDA or UPDATEMA */
+ int DeletedOne = 0;
+ /* Make a dp for use in db_update, as old dp */
+ dp = savedata(class, type, 0, NULL, 0);
+ dp->d_zone = zonenum;
+ do { /* Loop and delete all matching RR(s) */
+ n = db_update(dname, dp, NULL, DB_DELETE,
+ hashtab);
+ if (n != OK)
+ break;
+ DeletedOne++;
+ } while (1);
+ free( (struct databuf *) dp);
+ /* Ok for UPDATEMA not to have deleted any RRs */
+ if (!DeletedOne && hp->opcode == UPDATEDA) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"UPDATE: db_update failed\n");
+#endif DEBUG
+ hp->rcode = NOCHANGE;
+ return(-1);
+ }
+ }
+ if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) )
+ return (cp - rrp);;
+ /*
+ * Else unmarshal the RR to be added and continue on to
+ * UPDATEA code for UPDATEM/UPDATEMA
+ */
+ if ((n =
+ dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR UPDATE expand name failed\n");
+#endif
+ hp->rcode = FORMERR;
+ return(-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(n, cp);
+ cp1 = cp;
+/**** XXX - need bounds checking here ****/
+ cp += n;
+
+ case UPDATEA:
+ if (n > MAXDATA) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"UPDATE: too much data\n");
+#endif
+ hp->rcode = NOCHANGE;
+ return(-1);
+ }
+ if (cp != (u_char *)(msg + msglen)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"FORMERR UPDATE message length off\n");
+#endif
+ hp->rcode = FORMERR;
+ return(-1);
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return(-1);
+ }
+ if (zones[zonenum].z_state & Z_DYNADDONLY) {
+ struct hashbuf *htp = hashtab;
+ char *fname;
+ if (nlookup(dname, &htp, &fname, 0) &&
+ !strcmp(dname, fname)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"refusing add of existing name\n");
+#endif
+ hp->rcode = REFUSED;
+ return(-1);
+ }
+ }
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zonenum;
+ if ((n = db_update(dname, NULL, dp, DB_NODATA,
+ hashtab)) != OK) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"UPDATE: db_update failed\n");
+#endif
+ hp->rcode = NOCHANGE;
+ return (-1);
+ }
+ else
+ return (cp - rrp);
+ }
+#endif ALLOW_UPDATES
+
+ if (zone == 0)
+ ttl += tt.tv_sec;
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zone;
+ if ((n = db_update(dname, dp, dp, flags, hashtab)) < 0) {
+#ifdef DEBUG
+ if (debug && (n != DATAEXISTS))
+ fprintf(ddt,"update failed (%d)\n", n);
+ else if (debug >= 3)
+ fprintf(ddt,"update failed (DATAEXISTS)\n");
+#endif
+ (void) free((char *)dp);
+ } else if (type == T_NS && savens != NULL)
+ *savens = dp;
+ return (cp - rrp);
+}
+
+send_msg(msg, msglen, qp)
+ char *msg;
+ int msglen;
+ struct qinfo *qp;
+{
+ extern struct qinfo *qhead;
+#ifdef DEBUG
+ struct qinfo *tqp;
+#endif DEBUG
+
+ if (qp->q_system)
+ return(1);
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt,"send_msg -> %s (%s %d %d) id=%d\n",
+ inet_ntoa(qp->q_from.sin_addr),
+ qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP",
+ qp->q_stream == QSTREAM_NULL ? qp->q_dfd
+ : qp->q_stream->s_rfd,
+ ntohs(qp->q_from.sin_port),
+ ntohs(qp->q_id));
+ }
+ if (debug>4)
+ for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) {
+ fprintf(ddt, "qp %x q_id: %d q_nsid: %d q_msglen: %d ",
+ tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen);
+ fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr,
+ tqp->q_curaddr);
+ fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next,
+ qp->q_link);
+ }
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif DEBUG
+ if (qp->q_stream == QSTREAM_NULL) {
+ if (sendto(qp->q_dfd, msg, msglen, 0,
+ (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "sendto error errno= %d\n",errno);
+#endif
+ return(1);
+ }
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+ } else {
+ (void) writemsg(qp->q_stream->s_rfd, msg, msglen);
+ sq_done(qp->q_stream);
+ }
+ return(0);
+}
+
+prime(class, type, oqp)
+ int class, type;
+ register struct qinfo *oqp;
+{
+ char dname[BUFSIZ];
+
+ if (oqp->q_msg == NULL)
+ return;
+ if (dn_expand((u_char *)oqp->q_msg,
+ (u_char *)oqp->q_msg + oqp->q_msglen,
+ (u_char *)oqp->q_msg + sizeof(HEADER), (u_char *)dname,
+ sizeof(dname)) < 0)
+ return;
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"prime: %s\n", dname);
+#endif
+ (void) sysquery(dname, class, type);
+}
+
+
+prime_cache()
+{
+ register struct qinfo *qp;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"prime_cache: priming = %d\n", priming);
+#endif
+#ifdef STATS
+ stats[S_PRIMECACHE].cnt++;
+#endif
+ if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
+ priming++;
+ if ((qp = sysquery("", C_IN, T_NS)) == NULL)
+ priming = 0;
+ else
+ qp->q_system = PRIMING_CACHE;
+ }
+ needs_prime_cache = 0;
+ return;
+}
+
+struct qinfo *
+sysquery(dname, class, type)
+ char *dname;
+ int class, type;
+{
+ extern struct qinfo *qhead;
+ extern int nsid;
+ register struct qinfo *qp, *oqp;
+ register HEADER *hp;
+ struct namebuf *np;
+ struct databuf *nsp[NSMAX];
+ struct hashbuf *htp;
+ char *fname;
+ int count;
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"sysquery(%s, %d, %d)\n", dname, class, type);
+#endif
+#ifdef STATS
+ stats[S_SYSQUERIES].cnt++;
+#endif
+ htp = hashtab;
+ if (priming && dname[0] == '\0')
+ np = NULL;
+ else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sysquery: nlookup error on %s?\n", dname);
+#endif
+ return(0);
+ }
+
+ switch (findns(&np, class, nsp, &count)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sysquery: findns error on %s?\n", dname);
+#endif
+ return(0);
+ }
+
+ /* build new qinfo struct */
+ qp = qnew();
+ qp->q_cmsg = qp->q_msg = NULL;
+ qp->q_dfd = ds;
+ qp->q_fwd = fwdtab;
+ qp->q_system++;
+
+ if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
+ qfree(qp);
+ return(0);
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
+ hp = (HEADER *) qp->q_msg;
+ hp->id = qp->q_nsid = htons((u_short)++nsid);
+ hp->rd = (qp->q_fwd ? 1 : 0);
+
+ /* First check for an already pending query for this data */
+ for (oqp = qhead; oqp!=QINFO_NULL; oqp = oqp->q_link) {
+ if (oqp != qp && oqp->q_msglen == qp->q_msglen &&
+ bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt, "sysquery: duplicate\n");
+#endif
+ qfree(qp);
+ return(0);
+ }
+ }
+
+ if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"resp: no addrs found for NS's\n");
+#endif
+ qfree(qp);
+ return(0);
+ }
+
+ schedretry(qp, retrytime(qp));
+ if (qp->q_fwd == 0)
+ qp->q_addr[0].stime = tt;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"sysquery: send -> %s %d (%d), nsid=%d id=%d %dms\n",
+ inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+ qp->q_dfd, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_addr[0].nsdata->d_nstime);
+ if ( debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)Q_NEXTADDR(qp,0),
+ sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "sendto error errno= %d\n",errno);
+#endif
+ }
+#ifdef STATS
+ stats[S_OUTPKTS].cnt++;
+#endif
+ return(qp);
+}
+
+/*
+ * Check the list of root servers after receiving a response
+ * to a query for the root servers.
+ */
+check_root()
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np;
+ int count = 0;
+
+ priming = 0;
+ for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next)
+ if (np->n_dname[0] == '\0')
+ break;
+ if (np == NULL) {
+ syslog(LOG_ERR, "check_root: Can't find root!\n");
+ return;
+ }
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next)
+ if (dp->d_type == T_NS)
+ count++;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"%d root servers\n", count);
+#endif
+ if (count < MINROOTS) {
+ syslog(LOG_WARNING,
+ "check_root: %d root servers after query to root server < min",
+ count);
+ return;
+ }
+ pdp = NULL;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (dp->d_type == T_NS && dp->d_zone == 0 &&
+ dp->d_ttl < tt.tv_sec) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"deleting old root server '%s'\n",
+ dp->d_data);
+#endif
+ dp = rm_datum(dp, np, pdp);
+ /* SHOULD DELETE FROM HINTS ALSO */
+ continue;
+ }
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ check_ns();
+}
+
+/*
+ * Check the root to make sure that for each NS record we have a A RR
+ */
+check_ns()
+{
+ register struct databuf *dp, *tdp;
+ register struct namebuf *np, *tnp;
+ struct hashbuf *htp;
+ char *dname;
+ int found_arr;
+ char *fname;
+ time_t curtime;
+
+#ifdef DEBUG
+ if (debug >= 2)
+ fprintf(ddt,"check_ns()\n");
+#endif
+#ifdef STATS
+ stats[S_CHECKNS].cnt++;
+#endif
+
+ curtime = (u_long) tt.tv_sec;
+ for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] != 0)
+ continue;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_type != T_NS)
+ continue;
+
+ /* look for A records */
+ dname = dp->d_data;
+ htp = hashtab;
+ tnp = nlookup(dname, &htp, &fname, 0);
+ if (tnp == NULL || fname != dname) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"check_ns: %s: not found %s %x\n",
+ dname, fname, tnp);
+#endif
+ (void) sysquery(dname, dp->d_class, T_A);
+ continue;
+ }
+ /* look for name server addresses */
+ found_arr = 0;
+ for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) {
+ if (tdp->d_type != T_A ||
+ tdp->d_class != dp->d_class)
+ continue;
+ if ((tdp->d_zone == 0) &&
+ (tdp->d_ttl < curtime)) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"check_ns: stale entry '%s'\n",
+ tnp->n_dname);
+#endif
+ /* Cache invalidate the address RR's */
+ delete_all(tnp, dp->d_class, T_A);
+ found_arr = 0;
+ break;
+ }
+ found_arr++;
+ }
+ if (!found_arr)
+ (void) sysquery(dname, dp->d_class, T_A);
+ }
+ }
+}
+
+#define MAXCLASS 255 /* belongs elsewhere */
+int norootlogged[MAXCLASS];
+
+/*
+ * Find NS's or an SOA for the given dname (np) and fill in the
+ * nsp array. Returns OK on success, and SERVFAIL on error.
+ * We return NXDOMAIN to indicate we are authoritative.
+ */
+findns(npp, class, nsp, countp)
+ register struct namebuf **npp;
+ struct databuf **nsp;
+ int *countp;
+{
+ register struct namebuf *np = *npp;
+ register struct databuf *dp;
+ register struct databuf **nspp;
+ struct hashbuf *htp = hashtab;
+
+ if (priming && (np == NULL || np->n_dname[0] == '\0'))
+ htp = fcachetab;
+try_again:
+ if (htp == fcachetab)
+ needs_prime_cache = 1;
+ while (np == NULL && htp != NULL) {
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt, "findns: using %s\n", htp == hashtab ?
+ "cache" : "hints");
+#endif
+ for (np = htp->h_tab[0]; np != NULL; np = np->n_next)
+ if (np->n_dname[0] == '\0')
+ break;
+ htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */
+ }
+ while(np != NULL) {
+#ifdef DEBUG
+ if (debug >= 5)
+ fprintf(ddt, "findns: np 0x%x\n", np);
+#endif
+ /* Look first for SOA records. */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone != 0 && match(dp, class, T_SOA)) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"findns: SOA found\n");
+#endif
+ if (zones[dp->d_zone].z_auth) {
+ *npp = np;
+ nsp[0] = dp;
+ return(NXDOMAIN);
+ } else
+ return (SERVFAIL);
+ }
+ }
+
+ /* If no SOA records, look for NS records. */
+ nspp = &nsp[0];
+ *nspp = NULL;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_type != T_NS ||
+ (dp->d_class != class && class != C_ANY))
+ continue;
+ /*
+ * Don't use records that may become invalid to
+ * reference later when we do the rtt computation.
+ * Never delete our safety-belt information!
+ */
+ if ((dp->d_zone == 0) &&
+ (dp->d_ttl < (tt.tv_sec+900)) &&
+ !(dp->d_flags & DB_F_HINT)) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"findns: stale entry '%s'\n",
+ np->n_dname);
+#endif
+ /* Cache invalidate the NS RR's */
+ if (dp->d_ttl < tt.tv_sec)
+ delete_all(np, class, T_NS);
+ goto try_parent;
+ }
+ if (nspp < &nsp[NSMAX-1])
+ *nspp++ = dp;
+ }
+
+ *countp = nspp - nsp;
+ if (*countp > 0) {
+#ifdef DEBUG
+ if (debug >= 3)
+ fprintf(ddt,"findns: %d NS's added for '%s'\n",
+ *countp, np->n_dname);
+#endif
+ *nspp = NULL;
+ *npp = np;
+ return(OK); /* Success, got some NS's */
+ }
+try_parent:
+ np = np->n_parent;
+ }
+ if (htp)
+ goto try_again;
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt, "findns: No root nameservers for class %d?\n",
+ class);
+#endif
+ if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
+ norootlogged[class] = 1;
+ syslog(LOG_ERR, "No root nameservers for class %d\n", class);
+ }
+ return(SERVFAIL);
+}
+
+/*
+ * Extract RR's from the given node that match class and type.
+ * Return number of bytes added to response.
+ * If no matching data is found, then 0 is returned.
+ */
+finddata(np, class, type, hp, dnamep, lenp, countp)
+ struct namebuf *np;
+ int class, type;
+ register HEADER *hp;
+ char **dnamep;
+ int *lenp, *countp;
+{
+ register struct databuf *dp;
+ register char *cp;
+ int buflen, n, count = 0, foundstale = 0;
+
+ buflen = *lenp;
+ cp = ((char *)hp) + *countp;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+ if (type == T_CNAME && class == dp->d_class) {
+ /* any data means no CNAME exists */
+ *countp = 0;
+ return(0);
+ }
+ continue;
+ }
+ if (stale(dp)) {
+ /*
+ * Don't use stale data.
+ * Would like to call delete_all here
+ * and continue, but the data chain would get
+ * munged; can't restart, as make_rr has side
+ * effects (leaving pointers in dnptr).
+ * Just skip this entry for now
+ * and call delete_all at the end.
+ */
+#ifdef DEBUG
+ if (debug >=3)
+ fprintf(ddt,"finddata: stale entry '%s'\n",np->n_dname);
+#endif
+ if (dp->d_zone == 0)
+ foundstale++;
+ continue;
+ }
+ if ((n = make_rr(*dnamep, dp, cp, buflen, 1)) < 0) {
+ hp->tc = 1;
+ *countp = count;
+ return(*lenp - buflen);
+ }
+
+ cp += n;
+ buflen -= n;
+ count++;
+#ifdef notdef
+ /* this isn't right for glue records, aa is set in ns_req */
+ if (dp->d_zone && zones[dp->d_zone].z_auth && class != C_ANY)
+ hp->aa = 1; /* XXX */
+#endif
+ if (dp->d_type == T_CNAME) {
+ if (type != T_ANY) { /* or T_NS? */
+ *dnamep = dp->d_data;
+ if (dp->d_zone && zones[dp->d_zone].z_auth &&
+ class != C_ANY) /* XXX */
+ hp->aa = 1; /* XXX */
+ }
+ break;
+ }
+ }
+ /*
+ * Cache invalidate the other RR's of same type
+ * if some have timed out
+ */
+ if (foundstale)
+ delete_all(np, class, type);
+#ifdef DEBUG
+ if (debug >=3)
+ fprintf(ddt,"finddata: added %d class %d type %d RRs\n",
+ count, class, type);
+#endif
+ *countp = count;
+ return(*lenp - buflen);
+}
+
+/*
+ * Do we want this data record based on the class and type?
+ */
+wanted(dp, class, type)
+ struct databuf *dp;
+ int class, type;
+{
+
+#ifdef DEBUG
+ if (debug > 3)
+ fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type,
+ dp->d_class, dp->d_type);
+#endif
+
+ if (dp->d_class != class && class != C_ANY)
+ return (0);
+ if (type == dp->d_type)
+ return (1);
+ switch (dp->d_type) {
+ case T_ANY:
+ case T_CNAME:
+ return (1);
+ }
+ switch (type) {
+ case T_ANY:
+ return (1);
+
+ case T_MAILB:
+ switch (dp->d_type) {
+ case T_MR:
+ case T_MB:
+ case T_MG:
+ case T_MINFO:
+ return (1);
+ }
+ break;
+
+ case T_AXFR:
+ if (dp->d_type == T_SOA)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Add RR entries from dpp array to a query/response.
+ * Return the number of bytes added or negative the amount
+ * added if truncation was required. Typically you are
+ * adding NS records to a response.
+ */
+add_data(np, dpp, cp, buflen)
+ struct namebuf *np;
+ struct databuf **dpp;
+ register char *cp;
+ int buflen;
+{
+ register struct databuf *dp;
+ char dname[MAXDNAME];
+ register int n, count = 0;
+
+ getname(np, dname, sizeof(dname));
+ for(dp = *dpp++; dp != NULL; dp = *dpp++) {
+ if (stale(dp))
+ continue; /* ignore old cache entry */
+ if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0)
+ return(-count); /* Truncation */
+ cp += n;
+ buflen -= n;
+ count += n;
+ }
+ return(count);
+}
+
+/*
+ * This is best thought of as a "cache invalidate" function.
+ * It is called whenever a piece of data is determined to have
+ * timed out. It is better to have no information, than to
+ * have partial information you pass off as complete.
+ */
+delete_all(np, class, type)
+register struct namebuf *np;
+int class, type;
+{
+ register struct databuf *dp, *pdp;
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"delete_all: '%s' 0x%x class %d type %d\n",
+ np->n_dname, np, class, type);
+#endif
+ pdp = NULL;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT)
+ && match(dp, class, type)) {
+ dp = rm_datum(dp, np, pdp);
+ continue;
+ }
+ pdp = dp;
+ dp = dp->d_next;
+ }
+}
diff --git a/usr.sbin/named/ns_sort.c b/usr.sbin/named/ns_sort.c
new file mode 100644
index 00000000000..4d507660b06
--- /dev/null
+++ b/usr.sbin/named/ns_sort.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1986, 1990 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[] = "from: @(#)ns_sort.c 4.10 (Berkeley) 3/3/91";*/
+static char rcsid[] = "$Id: ns_sort.c,v 1.1.1.1 1995/10/18 08:47:51 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ns.h"
+#include "db.h"
+
+extern int debug;
+extern FILE *ddt;
+
+struct netinfo*
+local(from)
+ struct sockaddr_in *from;
+{
+ extern struct netinfo *nettab, netloop, **enettab;
+ struct netinfo *ntp;
+
+ if (from->sin_addr.s_addr == netloop.my_addr.s_addr)
+ return( &netloop);
+ for (ntp = nettab; ntp != *enettab; ntp = ntp->next) {
+ if (ntp->net == (from->sin_addr.s_addr & ntp->mask))
+ return(ntp);
+ }
+ return(NULL);
+}
+
+
+sort_response(cp, ancount, lp, eom)
+ register char *cp;
+ register int ancount;
+ struct netinfo *lp;
+ u_char *eom;
+{
+ register struct netinfo *ntp;
+ extern struct netinfo *nettab;
+
+#ifdef DEBUG
+ if (debug > 2)
+ fprintf(ddt,"sort_response(%d)\n", ancount);
+#endif DEBUG
+ if (ancount > 1) {
+ if (sort_rr(cp, ancount, lp, eom))
+ return;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if ((ntp->net == lp->net) && (ntp->mask == lp->mask))
+ continue;
+ if (sort_rr(cp, ancount, ntp, eom))
+ break;
+ }
+ }
+}
+
+int
+sort_rr(cp, count, ntp, eom)
+ register u_char *cp;
+ int count;
+ register struct netinfo *ntp;
+ u_char *eom;
+{
+ int type, class, dlen, n, c;
+ struct in_addr inaddr;
+ u_char *rr1;
+
+#ifdef DEBUG
+ if (debug > 2) {
+ inaddr.s_addr = ntp->net;
+ fprintf(ddt,"sort_rr( x%x, %d, %s)\n",cp, count,
+ inet_ntoa(inaddr));
+ }
+#endif DEBUG
+ rr1 = NULL;
+ for (c = count; c > 0; --c) {
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (1); /* bogus, stop processing */
+ cp += n;
+ if (cp + QFIXEDSZ > eom)
+ return (1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ cp += sizeof(u_long);
+ GETSHORT(dlen, cp);
+ if (dlen > eom - cp)
+ return (1); /* bogus, stop processing */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (rr1 == NULL)
+ rr1 = cp;
+ if ((ntp->mask & inaddr.s_addr) == ntp->net) {
+#ifdef DEBUG
+ if (debug > 1) {
+ fprintf(ddt,"net %s best choice\n",
+ inet_ntoa(inaddr));
+ }
+#endif DEBUG
+ if (rr1 != cp) {
+ bcopy(rr1, cp, sizeof(inaddr));
+ bcopy((char *)&inaddr, rr1, sizeof(inaddr));
+ }
+ return(1);
+ }
+ break;
+ }
+ break;
+ }
+ cp += dlen;
+ }
+ return(0);
+}
diff --git a/usr.sbin/named/ns_stats.c b/usr.sbin/named/ns_stats.c
new file mode 100644
index 00000000000..4f9f345386e
--- /dev/null
+++ b/usr.sbin/named/ns_stats.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 1986 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[] = "from: @(#)ns_stats.c 4.10 (Berkeley) 6/27/90";*/
+static char rcsid[] = "$Id: ns_stats.c,v 1.1.1.1 1995/10/18 08:47:51 deraadt Exp $";
+#endif /* not lint */
+
+/**************************************************************************/
+/* simple monitoring of named behavior */
+/* dumps a bunch of values into a well-know file */
+/* */
+/**************************************************************************/
+
+#ifdef STATS
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "pathnames.h"
+
+#ifdef STATSFILE
+char *statsfile = STATSFILE;
+#else
+char *statsfile = _PATH_STATS;
+#endif /* STATSFILE */
+
+extern time_t boottime, resettime;
+extern int needStatsDump;
+
+/*
+ * General statistics gathered
+ */
+/* The position in this table must agree with the defines in ns.h */
+struct stats stats[S_NSTATS] = {
+ { 0, "input packets" },
+ { 0, "output packets" },
+ { 0, "queries" },
+ { 0, "iqueries" },
+ { 0, "duplicate queries" },
+ { 0, "responses" },
+ { 0, "duplicate responses" },
+ { 0, "OK answers" },
+ { 0, "FAIL answers" },
+ { 0, "FORMERR answers" },
+ { 0, "system queries" },
+ { 0, "prime cache calls" },
+ { 0, "check_ns calls" },
+ { 0, "bad responses dropped" },
+ { 0, "martian responses" },
+};
+
+/*
+ * Statistics for queries (by type)
+ */
+unsigned long typestats[T_ANY+1];
+char *typenames[T_ANY+1] = {
+ /* 5 types per line */
+ "Unknown", "A", "NS", "invalid(MD)", "invalid(MF)",
+ "CNAME", "SOA", "MB", "MG", "MR",
+ "NULL", "WKS", "PTR", "HINFO", "MINFO",
+ "MX", "TXT", 0, 0, 0,
+ /* 20 per line */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 100 */
+ "UINFO", "UID", "GID", "UNSPEC", 0, 0, 0, 0, 0, 0,
+ /* 110 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 120 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 200 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 240 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 250 */
+ 0, 0, "AXFR", "MAILB", "MAILA", "ANY"
+};
+
+ns_stats()
+{
+ time_t timenow;
+ register FILE *f;
+ register int i;
+
+ if ((f = fopen(statsfile,"a")) == 0)
+ {
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,"can't open stat file, \"%s\"\n",statsfile);
+#endif
+ syslog(LOG_ERR, "cannot open stat file, \"%s\"\n",statsfile);
+ return;
+ }
+
+ time(&timenow);
+ fprintf(f, "### %s", ctime(&timenow));
+ fprintf(f, "%d\ttime since boot (secs)\n", timenow - boottime);
+ fprintf(f, "%d\ttime since reset (secs)\n", timenow - resettime);
+
+ /* general statistics */
+ for (i = 0; i < S_NSTATS; i++)
+ fprintf(f,"%lu\t%s\n", stats[i].cnt, stats[i].description);
+
+ /* query type statistics */
+ fprintf(f, "%d\tUnknown query types\n", typestats[0]);
+ for(i=1; i < T_ANY+1; i++)
+ if (typestats[i])
+ if (typenames[i])
+ fprintf(f, "%lu\t%s queries\n", typestats[i],
+ typenames[i]);
+ else
+ fprintf(f, "%lu\ttype %d queries\n",
+ typestats[i], i);
+ (void) fclose(f);
+}
+#endif STATS
diff --git a/usr.sbin/named/pathnames.h b/usr.sbin/named/pathnames.h
new file mode 100644
index 00000000000..fa4b6831c8f
--- /dev/null
+++ b/usr.sbin/named/pathnames.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1989 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.
+ *
+ * from: @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:51 deraadt Exp $
+ */
+
+
+#define _PATH_BOOT "/etc/named.boot"
+
+#if defined(BSD) && BSD >= 198810
+#include <paths.h>
+#define _PATH_XFER "/usr/libexec/named-xfer"
+#define _PATH_DEBUG "/var/tmp/named.run"
+#define _PATH_DUMPFILE "/var/tmp/named_dump.db"
+#define _PATH_PIDFILE "/var/run/named.pid"
+#define _PATH_STATS "/var/tmp/named.stats"
+#define _PATH_TMPXFER "/var/tmp/xfer.ddt.XXXXXX"
+#define _PATH_TMPDIR "/var/tmp"
+
+#else /* BSD */
+#define _PATH_DEVNULL "/dev/null"
+#define _PATH_TTY "/dev/tty"
+#define _PATH_XFER "/etc/named-xfer"
+#define _PATH_DEBUG "/usr/tmp/named.run"
+#define _PATH_DUMPFILE "/usr/tmp/named_dump.db"
+#define _PATH_PIDFILE "/etc/named.pid"
+#define _PATH_STATS "/usr/tmp/named.stats"
+#define _PATH_TMPXFER "/usr/tmp/xfer.ddt.XXXXXX"
+#define _PATH_TMPDIR "/usr/tmp"
+#endif /* BSD */
diff --git a/usr.sbin/named/storage.c b/usr.sbin/named/storage.c
new file mode 100644
index 00000000000..4f849e60e03
--- /dev/null
+++ b/usr.sbin/named/storage.c
@@ -0,0 +1,167 @@
+/*
+ * S T O R A G E . C
+ *
+ * Ray Tracing program, storage manager.
+ *
+ * Functions -
+ * rt_malloc Allocate storage, with visibility & checking
+ * rt_free Similarly, free storage
+ * rt_prmem When debugging, print memory map
+ * calloc, cfree Which call rt_malloc, rt_free
+ *
+ * Author -
+ * Michael John Muuss
+ *
+ * Source -
+ * SECAD/VLD Computing Consortium, Bldg 394
+ * The U. S. Army Ballistic Research Laboratory
+ * Aberdeen Proving Ground, Maryland 21005-5066
+ *
+ * Copyright Notice -
+ * This software is Copyright (C) 1987 by the United States Army.
+ * All rights reserved.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: storage.c,v 1.1.1.1 1995/10/18 08:47:51 deraadt Exp $";
+#endif
+
+#include <sys/param.h>
+#if BSD >= 43
+#include <sys/syslog.h>
+#else
+#include <stdio.h>
+#define LOG_ERR 0
+#endif BSD
+
+#undef malloc
+#undef free
+
+#define MDB_SIZE 20000
+#define MDB_MAGIC 0x12348969
+struct memdebug {
+ char *mdb_addr;
+ char *mdb_str;
+ int mdb_len;
+} rt_mdb[MDB_SIZE];
+
+/*
+ * R T _ M A L L O C
+ */
+char *
+rt_malloc(cnt)
+unsigned int cnt;
+{
+ register char *ptr;
+ extern char *malloc();
+
+ cnt = (cnt+2*sizeof(int)-1)&(~(sizeof(int)-1));
+ ptr = malloc(cnt);
+
+ if( ptr==(char *)0 ) {
+ syslog(LOG_ERR, "rt_malloc: malloc failure");
+ abort();
+ } else {
+ register struct memdebug *mp = rt_mdb;
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len > 0 ) continue;
+ mp->mdb_addr = ptr;
+ mp->mdb_len = cnt;
+ mp->mdb_str = "???";
+ goto ok;
+ }
+ syslog(LOG_ERR, "rt_malloc: memdebug overflow\n");
+ }
+ok: ;
+ {
+ register int *ip = (int *)(ptr+cnt-sizeof(int));
+ *ip = MDB_MAGIC;
+ }
+ return(ptr);
+}
+
+/*
+ * R T _ F R E E
+ */
+void
+rt_free(ptr)
+char *ptr;
+{
+ register struct memdebug *mp = rt_mdb;
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len <= 0 ) continue;
+ if( mp->mdb_addr != ptr ) continue;
+ {
+ register int *ip = (int *)(ptr+mp->mdb_len-sizeof(int));
+ if( *ip != MDB_MAGIC ) {
+ syslog(LOG_ERR, "ERROR rt_free(x%x, %s) corrupted! x%x!=x%x\n", ptr, "???", *ip, MDB_MAGIC);
+ abort();
+ }
+ }
+ mp->mdb_len = 0; /* successful free */
+ goto ok;
+ }
+ syslog(LOG_ERR, "ERROR rt_free(x%x, %s) bad pointer!\n", ptr, "???");
+ abort();
+ok: ;
+
+ *((int *)ptr) = -1; /* zappo! */
+ free(ptr);
+}
+
+/*
+ * R T _ P R M E M
+ *
+ * Print map of memory currently in use.
+ */
+void
+rt_prmem(str)
+char *str;
+{
+ register struct memdebug *mp = rt_mdb;
+ register int *ip;
+
+ printf("\nRT memory use\t\t%s\n", str);
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len <= 0 ) continue;
+ ip = (int *)(mp->mdb_addr+mp->mdb_len-sizeof(int));
+ printf("%7x %5x %s %s\n",
+ mp->mdb_addr, mp->mdb_len, mp->mdb_str,
+ *ip!=MDB_MAGIC ? "-BAD-" : "" );
+ if( *ip != MDB_MAGIC )
+ printf("\t%x\t%x\n", *ip, MDB_MAGIC);
+ }
+}
+
+char *
+calloc(num, size)
+ register unsigned num, size;
+{
+ extern char *malloc();
+ register char *p;
+
+ size *= num;
+ if (p = rt_malloc(size))
+ bzero(p, size);
+ return (p);
+}
+
+cfree(p, num, size)
+ char *p;
+ unsigned num;
+ unsigned size;
+{
+ rt_free(p);
+}
+
+#if BSD < 43
+openlog() {}
+
+syslog(x, str, a, b, c, d, e, f)
+int x;
+char *str;
+int a, b, c, d, e, f;
+{
+ fprintf(stderr, str, a, b, c, d, e, f);
+}
+#endif BSD
diff --git a/usr.sbin/named/test/:pwedit b/usr.sbin/named/test/:pwedit
new file mode 100644
index 00000000000..1ccd95b9c51
--- /dev/null
+++ b/usr.sbin/named/test/:pwedit
@@ -0,0 +1,4 @@
+ g/^./s/^\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\).*/\U\1\E ANY UID \3\
+ ANY GID \4\
+ ANY UINFO "\5"/
+wq pw
diff --git a/usr.sbin/named/test/atod.y b/usr.sbin/named/test/atod.y
new file mode 100644
index 00000000000..386d9dd5859
--- /dev/null
+++ b/usr.sbin/named/test/atod.y
@@ -0,0 +1,118 @@
+/*
+ * Convert mail alias file to nameserver DB format.
+ */
+
+%{
+#include <stdio.h>
+#include <ctype.h>
+
+char yytext[BUFSIZ];
+int lineno = 1;
+%}
+
+%token NAME
+
+%start list
+
+%%
+
+list: /* empty */
+ | list alias ':' a_list
+ ;
+
+alias: NAME {
+ printf("%s IN MB UCB-VAX.ARPA\n", yytext);
+ }
+ ;
+
+a_list: aname
+ | a_list ',' aname
+ ;
+
+aname: NAME {
+ printf(" IN MG %s\n", yytext);
+ }
+ ;
+%%
+
+yylex()
+{
+ register char *cp;
+ register int c;
+ char op[32];
+
+ for (;;) {
+ c = getchar();
+ top:
+ switch (c) {
+ case '#':
+ while ((c = getchar()) != EOF && c != '\n')
+ ;
+ goto top;
+
+ case '\\':
+ if ((c = getchar()) == EOF) {
+ c = '\\';
+ break;
+ }
+ if (c != '\n') {
+ ungetc(c, stdin);
+ c = '\\';
+ break;
+ }
+ case '\n':
+ lineno++;
+ case ' ':
+ case '\t':
+ continue;
+
+ case EOF:
+ case ':':
+ case ',':
+ return (c);
+ }
+ cp = yytext;
+ do {
+ if (c == '"') {
+ do {
+ if (cp >= &yytext[BUFSIZ-1]) {
+ yyerror("buffer overflow");
+ break;
+ }
+ *cp++ = c;
+ } while ((c = getchar()) != EOF && c != '"');
+ }
+ if (cp >= &yytext[BUFSIZ-1]) {
+ yyerror("buffer overflow");
+ break;
+ }
+ if (islower(c))
+ c = toupper(c);
+ *cp++ = c;
+ } while ((c = getchar()) != EOF && !any(c, ",: \t\n"));
+ ungetc(c, stdin);
+ *cp = '\0';
+ return (NAME);
+ }
+}
+
+any(c, s)
+ int c;
+ register char *s;
+{
+ while (*s)
+ if (c == *s++)
+ return (1);
+ return (0);
+}
+
+main()
+{
+ yyparse();
+}
+
+yyerror(s)
+ char *s;
+{
+ fprintf(stderr, "line %d: %s\n", lineno, s);
+}
diff --git a/usr.sbin/named/test/hosts.mff b/usr.sbin/named/test/hosts.mff
new file mode 100644
index 00000000000..a3a877c717e
--- /dev/null
+++ b/usr.sbin/named/test/hosts.mff
@@ -0,0 +1,3072 @@
+@ IN SOA UCB-ARPA.ARPA RALPH.UCB-ARPA.ARPA
+ 1 3600 300 3600000 3600
+ IN NS UCB-ARPA.ARPA
+SATNET IN A 4.0.0.0
+ETAM-EXPAK IN A 4.0.0.1
+ IN HINFO H-316,SIMP
+GOONHILLY-EXPAK IN A 4.0.0.2
+ IN HINFO H-316,SIMP
+TANUM-EXPAK IN A 4.0.0.3
+ IN HINFO H-316,SIMP
+SATNET-SINK IN A 4.0.0.37
+SATNET-ECHO IN A 4.0.0.40
+ETAM-MONITOR IN A 4.0.0.41
+ IN HINFO H-316,SIMP
+GOONHILLY-MONITOR IN A 4.0.0.42
+ IN HINFO H-316,SIMP
+TANUM-MONITOR IN A 4.0.0.43
+ IN HINFO H-316,SIMP
+ETAM-ECHO IN A 4.0.0.62
+ IN HINFO H-316,SIMP
+GOONHILLY-ECHO IN A 4.0.0.63
+ IN HINFO H-316,SIMP
+TANUM-ECHO IN A 4.0.0.64
+ IN HINFO H-316,SIMP
+RAISTING-ECHO IN A 4.0.0.77
+ IN HINFO H-316,SIMP
+RAISTING-MONITOR IN A 4.0.0.78
+ IN HINFO H-316,SIMP
+RAISTING-EXPAK IN A 4.0.0.79
+ IN HINFO H-316,SIMP
+FUCINO IN A 4.0.0.88
+FUCINO-ECHO IN A 4.0.0.93
+ IN HINFO H-316,SIMP
+FUCINO-MONITOR IN A 4.0.0.94
+ IN HINFO H-316,SIMP
+FUCINO-EXPAK IN A 4.0.0.95
+ IN HINFO H-316,SIMP
+YUMA IN A 6.1.0.1
+ IN HINFO C/70,UNIX
+EDN-VAX IN A 7.0.0.3
+ IN HINFO VAX-11/780,UNIX
+BBNCCA IN A 8.0.0.2
+ IN HINFO C/70,UNIX
+BBNCCB IN A 8.1.0.2
+ IN HINFO C/70,UNIX
+BBNCCD IN A 8.3.0.2
+ IN HINFO C/70,UNIX
+BBN-LABS-ADMIN IN A 8.4.0.2
+ IN HINFO C/70,UNIX
+BBN-LABS IN CNAME BBN-LABS-ADMIN.ARPA
+BBNL IN CNAME BBN-LABS-ADMIN.ARPA
+BBNCCK IN A 8.5.0.2
+ IN HINFO C/70,UNIX
+BBN-LABS-B IN A 8.7.0.2
+ IN A 128.11.1.2
+ IN HINFO VAX-11/750,UNIX
+BBNLB IN CNAME BBN-LABS-B.ARPA
+LABS-B IN CNAME BBN-LABS-B.ARPA
+BBNCCG IN A 8.0.0.3
+ IN HINFO C/70,UNIX
+BBNCC2-TAC IN A 8.2.0.3
+ IN HINFO C/30,TAC
+BBNCC2 IN CNAME BBNCC2-TAC.ARPA
+BBNCCR IN A 8.3.0.3
+ IN HINFO VAX-11/780,VMS
+BBNCCF IN A 8.0.0.4
+ IN HINFO C/70,UNIX
+BBNCCI IN A 8.3.0.4
+ IN HINFO C/70,UNIX
+BBNH IN A 8.4.0.4
+ IN A 128.11.0.4
+ IN HINFO C/70,UNIX
+BBN-CDNOC IN A 8.0.0.5
+ IN HINFO C/70,UNIX
+CDNOC IN CNAME BBN-CDNOC.ARPA
+BBN-CD IN A 8.1.0.5
+ IN HINFO C/70,UNIX
+BBNCD IN CNAME BBN-CD.ARPA
+BBNCC1-TAC IN A 8.2.0.5
+ IN HINFO C/30,TAC
+BBNCC1 IN CNAME BBNCC1-TAC.ARPA
+BBNCCE IN A 8.4.0.5
+ IN HINFO C/70,UNIX
+BBN-ADMIN IN A 8.1.0.6
+ IN HINFO C/70,UNIX
+ADMIN IN CNAME BBN-ADMIN.ARPA
+BBN-INOC IN A 8.2.0.6
+ IN HINFO C/70,UNIX
+INOC IN CNAME BBN-INOC.ARPA
+BBNCCW IN A 8.3.0.6
+ IN HINFO C/70,UNIX
+BBNCCS IN A 8.0.0.7
+ IN HINFO C/70,UNIX
+BBNZ IN A 8.1.0.7
+ IN HINFO C/70,UNIX
+BBNCCQ IN A 8.2.0.7
+ IN HINFO C/70,UNIX
+BBNCCT IN A 8.3.0.7
+ IN HINFO C/70,UNIX
+BBNCCH IN A 8.4.0.8
+ IN HINFO C/70,UNIX
+BBN-UCC IN A 8.7.0.8
+ IN HINFO C/70,UNIX
+UCC IN CNAME BBN-UCC.ARPA
+BBNCC3-TAC IN A 8.2.0.9
+ IN HINFO C/30,TAC
+BBNCC3 IN CNAME BBNCC3-TAC.ARPA
+DIV-5-TAC IN CNAME BBNCC3-TAC.ARPA
+DIV5-TAC IN CNAME BBNCC3-TAC.ARPA
+D5TAC IN CNAME BBNCC3-TAC.ARPA
+BBNCC4-TAC IN A 8.0.0.10
+ IN HINFO C/30,TAC
+BBNCC4 IN CNAME BBNCC4-TAC.ARPA
+DIV-5-TAC2 IN CNAME BBNCC4-TAC.ARPA
+D5TAC-TAC2 IN CNAME BBNCC4-TAC.ARPA
+D5TAC2 IN CNAME BBNCC4-TAC.ARPA
+BBNCC-WASHINGTON IN A 8.0.0.11
+ IN HINFO C/70,UNIX
+BBNCC-WASH IN CNAME BBNCC-WASHINGTON.ARPA
+BBN-WASH IN CNAME BBNCC-WASHINGTON.ARPA
+BBNCC5-TAC IN A 8.2.0.11
+ IN HINFO C/30,TAC
+BBNCC5TAC IN CNAME BBNCC5-TAC.ARPA
+BBNCC5 IN CNAME BBNCC5-TAC.ARPA
+WASH-TAC IN CNAME BBNCC5-TAC.ARPA
+BBN-NOC3 IN A 8.0.0.12
+ IN A 8.1.0.12
+ IN HINFO C/70,UNIX
+NOC3 IN CNAME BBN-NOC3.ARPA
+BBNCCN IN A 8.3.0.12
+ IN HINFO C/70,UNIX
+BBNCCY IN A 8.1.0.13
+ IN HINFO C/70,UNIX
+BBNJ IN A 8.0.0.14
+ IN HINFO VAX-11/750,UNIX
+CSNET4 IN CNAME BBNJ.ARPA
+BBN-NOC IN A 8.1.0.14
+ IN HINFO C/70,UNIX
+BBN-NU IN CNAME BBN-NOC.ARPA
+NOC IN CNAME BBN-NOC.ARPA
+DIV6-TAC IN A 8.2.0.14
+ IN HINFO C/30,TAC
+D6TAC IN CNAME DIV6-TAC.ARPA
+DIV6TAC IN CNAME DIV6-TAC.ARPA
+BBN-NOC2 IN A 8.4.0.14
+ IN HINFO C/70,UNIX
+NOC2 IN CNAME BBN-NOC2.ARPA
+CSNET-DEV IN A 8.5.0.14
+ IN HINFO VAX-11/750,UNIX
+CSNET3 IN CNAME CSNET-DEV.ARPA
+DIV1-TAC IN A 8.6.0.14
+ IN HINFO C/30,TAC
+DIV-1-TAC IN CNAME DIV1-TAC.ARPA
+BBNCCM IN A 8.7.0.14
+ IN HINFO C/70,UNIX
+BBN-RVAX IN A 8.1.0.16
+ IN HINFO VAX-11/750,VMS
+RVAX IN CNAME BBN-RVAX.ARPA
+BBN-SPCA IN A 8.2.0.16
+ IN HINFO VAX-11/750,UNIX
+SPCA IN CNAME BBN-SPCA.ARPA
+BBN-XVAX IN A 8.3.0.16
+ IN HINFO VAX-11/750,VMS
+XVAX IN CNAME BBN-XVAX.ARPA
+BBNCCC IN A 8.0.0.17
+ IN HINFO C/70,UNIX
+BBNCCX IN A 8.1.0.17
+ IN HINFO C/70,UNIX
+BBNCCJ IN A 8.2.0.17
+ IN HINFO C/70,UNIX
+UCLA-TEST IN A 10.0.0.1
+ IN HINFO VAX-11/750,LOCUS
+UCLA-CCN IN A 10.1.0.1
+ IN HINFO IBM-370/3033,MVS
+CCN IN CNAME UCLA-CCN.ARPA
+UCLA-LOCUS IN A 10.2.0.1
+ IN HINFO VAX-11/750,LOCUS
+UCLA-SECURITY IN CNAME UCLA-LOCUS.ARPA
+LOCUS IN CNAME UCLA-LOCUS.ARPA
+UCLA-CS IN CNAME UCLA-LOCUS.ARPA
+UCLA-CECS IN CNAME UCLA-LOCUS.ARPA
+UCLA-ATS IN A 10.3.0.1
+ IN HINFO VAX-11/750,LOCUS
+ATS IN CNAME UCLA-ATS.ARPA
+SRI-SPRM IN A 10.0.0.2
+ IN HINFO PLURIBUS,PLI
+SRI-SNV IN CNAME SRI-SPRM.ARPA
+SNV IN CNAME SRI-SPRM.ARPA
+SRI-KL IN A 10.1.0.2
+ IN HINFO DEC-1090T,TOPS20
+SRI IN CNAME SRI-KL.ARPA
+KL IN CNAME SRI-KL.ARPA
+SRI-CSL IN A 10.2.0.2
+ IN HINFO FOONLY-F4,TENEX
+CSL IN CNAME SRI-CSL.ARPA
+SRI-CSLA IN CNAME SRI-CSL.ARPA
+SRI-TSC IN A 10.3.0.2
+ IN A 128.18.0.200
+ IN HINFO PDP-11/44,UNIX
+SRI-TSCB IN CNAME SRI-TSC.ARPA
+TSCB IN CNAME SRI-TSC.ARPA
+SRI-TSCA IN CNAME SRI-TSC.ARPA
+TSCA IN CNAME SRI-TSC.ARPA
+SRI-AI IN A 10.4.0.2
+ IN HINFO DEC-2060,TOPS20
+AIC IN CNAME SRI-AI.ARPA
+SRI-IU IN A 10.5.0.2
+ IN HINFO VAX-11/780,VMS
+IUV IN CNAME SRI-IU.ARPA
+UTAH-CS IN A 10.0.0.4
+ IN A 192.5.12.21
+ IN HINFO VAX-11/750,UNIX
+UTAH-TAC IN A 10.2.0.4
+ IN HINFO C/30,TAC
+UTAH-20 IN A 10.3.0.4
+ IN A 192.5.12.20
+ IN HINFO DEC-2060T,TOPS20
+BBN-CLXX IN A 10.0.0.5
+ IN HINFO C/70,UNIX
+CLXX IN CNAME BBN-CLXX.ARPA
+BBNG IN A 10.1.0.5
+ IN A 192.1.2.67
+ IN HINFO DEC-2060T,TOPS20
+BBN-TENEXG IN CNAME BBNG.ARPA
+BBNA IN A 10.3.0.5
+ IN A 192.1.2.68
+ IN A 8.5.0.4
+ IN HINFO DEC-2050T,TOPS20
+BBN IN CNAME BBNA.ARPA
+BBNB IN CNAME BBNA.ARPA
+CSNET-RELAY IN A 10.4.0.5
+ IN A 192.5.58.1
+ IN HINFO VAX-11/750,UNIX
+RAND-RELAY IN CNAME CSNET-RELAY.ARPA
+CSNET1 IN CNAME CSNET-RELAY.ARPA
+MMCC IN CNAME CSNET-RELAY.ARPA
+BBN-PR-STATION-1 IN A 10.7.0.5
+ IN HINFO LSI-11,ELF
+MIT-MULTICS IN A 10.0.0.6
+ IN HINFO HONEYWELL-DPS-8/70M,MULTICS
+MULTICS IN CNAME MIT-MULTICS.ARPA
+MIT-AI IN A 10.2.0.6
+ IN HINFO DEC-KS10,ITS
+AI IN CNAME MIT-AI.ARPA
+MITAI IN CNAME MIT-AI.ARPA
+MIT-ML IN A 10.3.0.6
+ IN HINFO DEC-10,ITS
+ML IN CNAME MIT-ML.ARPA
+RAND-ARPA-TAC IN A 10.2.0.7
+ IN HINFO C/30,TAC
+RAND-UNIX IN A 10.3.0.7
+ IN A 192.5.14.33
+ IN HINFO VAX-11/780,UNIX
+RANDVAX IN CNAME RAND-UNIX.ARPA
+HARVARD IN A 10.0.0.9
+ IN A 192.5.66.1
+ IN A 192.5.90.1
+ IN HINFO VAX-11/780,UNIX
+HARV-10 IN CNAME HARVARD.ARPA
+ACL IN CNAME HARVARD.ARPA
+YALE IN A 10.2.0.9
+ IN A 128.36.0.1
+ IN HINFO VAX-11/750,UNIX
+LL IN A 10.0.0.10
+ IN HINFO PDP-11/44,UNIX
+LL-VLSI IN A 10.1.0.10
+ IN HINFO VAX-11/780,UNIX
+LL-XN IN A 10.2.0.10
+ IN HINFO VAX-11/780,UNIX
+LL-EN IN A 10.4.0.10
+ IN HINFO PDP-11/44,UNIX
+LL-SST IN A 10.6.0.10
+ IN HINFO VAX-11/780,UNIX
+SST IN CNAME LL-SST.ARPA
+SU-AI IN A 10.0.0.11
+ IN A 36.36.0.194
+ IN HINFO DEC-1080,WAITS
+SAIL IN CNAME SU-AI.ARPA
+SUAI IN CNAME SU-AI.ARPA
+SU-TAC IN A 10.2.0.11
+ IN HINFO C/30,TAC
+SU-SCORE IN A 10.3.0.11
+ IN A 36.36.0.195
+ IN HINFO DEC-2060,TOPS20
+SCORE IN CNAME SU-SCORE.ARPA
+STANFORD IN A 10.3.1.11
+ IN A 36.36.1.195
+CMU-CS-A IN A 10.1.0.14
+ IN HINFO DEC-1080,TOPS10
+CMU-10A IN CNAME CMU-CS-A.ARPA
+CMUA IN CNAME CMU-CS-A.ARPA
+CMU-CS-C IN A 10.3.0.14
+ IN HINFO DEC-2060,TOPS20
+CMU-20C IN CNAME CMU-CS-C.ARPA
+CMUC IN CNAME CMU-CS-C.ARPA
+ROCHESTER IN A 10.0.0.15
+ IN HINFO VAX-11/750,UNIX
+UR-GATEWAY IN CNAME ROCHESTER.ARPA
+DCEC-ARPA-TAC IN A 10.2.0.20
+ IN HINFO C/30,TAC
+EDN-UNIX IN A 10.3.0.20
+ IN HINFO PDP-11/70,UNIX
+DCEC-PSAT IN A 10.5.0.20
+ IN HINFO PLURIBUS,
+ISI-SPEECH11 IN A 10.0.0.22
+ IN A 10.0.22.22
+ IN A 10.1.22.27
+ IN HINFO PDP-11/45,EPOS
+USC-TAC IN A 10.2.0.23
+ IN HINFO C/30,TAC
+SEISMO IN A 10.0.0.25
+ IN A 192.5.11.5
+ IN A 192.12.25.5
+ IN HINFO VAX-11/780,UNIX
+CSS-SEISMO IN CNAME SEISMO.ARPA
+DDN1 IN A 10.1.0.25
+ IN HINFO C/70,UNIX
+DDN-1 IN CNAME DDN1.ARPA
+USC-ISID IN A 10.0.0.27
+ IN HINFO DEC-2060T,TOPS20
+ISID IN CNAME USC-ISID.ARPA
+ISI-PNG11 IN A 10.1.0.27
+ IN A 10.1.156.27
+ IN HINFO PDP-11/40,EPOS
+ISI-XGP11 IN CNAME ISI-PNG11.ARPA
+ISI-MCON IN A 10.1.21.27
+ IN A 10.0.21.22
+ IN HINFO PDP-11/44,EPOS
+ISI-WBC11 IN A 10.1.23.27
+ IN A 10.0.23.22
+ IN HINFO PDP-11/45,EPOS
+WBC11 IN CNAME ISI-WBC11.ARPA
+ISI-MAINT11 IN A 10.1.25.27
+ IN HINFO PDP-11/40,EPOS
+ISI-SETTING IN A 10.1.89.27
+ IN HINFO CADLINC,V
+SETTING IN CNAME ISI-SETTING.ARPA
+ISI-SUN2 IN CNAME ISI-SETTING.ARPA
+ISI-LORETTA IN A 10.1.90.27
+ IN HINFO CADLINC,V
+LORETTA IN CNAME ISI-LORETTA.ARPA
+ISI-SUN1 IN CNAME ISI-LORETTA.ARPA
+ISI-PALLAS-ATHENE IN A 10.1.91.27
+ IN HINFO CADLINC,V
+PALLAS-ATHENE IN CNAME ISI-PALLAS-ATHENE.ARPA
+ISI-SUN3 IN CNAME ISI-PALLAS-ATHENE.ARPA
+ISI-AIKANE IN A 10.1.97.27
+ IN HINFO PERQ,PERQ-OS
+AIKANE IN CNAME ISI-AIKANE.ARPA
+ISI-PERQ1 IN CNAME ISI-AIKANE.ARPA
+ISI-CZAR IN A 10.1.98.27
+ IN HINFO PERQ,PERQ-OS
+CZAR IN CNAME ISI-CZAR.ARPA
+ISI-PERQ2 IN CNAME ISI-CZAR.ARPA
+ISI-MYCROFTXXX IN A 10.1.99.27
+ IN HINFO PERQ,PERQ-OS
+MYCROFTXXX IN CNAME ISI-MYCROFTXXX.ARPA
+ISI-PERQ3 IN CNAME ISI-MYCROFTXXX.ARPA
+ISI-CMR IN A 10.1.124.27
+ IN HINFO H89,HDOS
+ISI-IHM IN A 10.1.125.27
+ IN HINFO IMSAI,ZMOS
+SPHINX IN CNAME ISI-IHM.ARPA
+ISI-ECHO IN A 10.1.254.27
+ISI-VAXA IN A 10.2.0.27
+ IN A 10.1.33.27
+ IN HINFO VAX-11/780,UNIX
+VAXA IN CNAME ISI-VAXA.ARPA
+ARPA3-TAC IN A 10.0.0.28
+ IN HINFO H-316,TAC
+CCA-UNIX IN A 10.0.0.31
+ IN HINFO VAX-11/780,UNIX
+CCA IN CNAME CCA-UNIX.ARPA
+CCA-TENEX IN CNAME CCA-UNIX.ARPA
+CCA-VMS IN CNAME CCA-UNIX.ARPA
+CCA-PLI IN A 10.2.0.31
+ IN HINFO PLI,PLI
+CISL-SERVICE-MULTICS IN A 10.3.0.31
+ IN A 192.5.1.1
+ IN HINFO H-68/80,MULTICS
+MIT-DEVMULTICS IN CNAME CISL-SERVICE-MULTICS.ARPA
+DEVMULTICS IN CNAME CISL-SERVICE-MULTICS.ARPA
+CISL IN CNAME CISL-SERVICE-MULTICS.ARPA
+CISL-MULTICS IN CNAME CISL-SERVICE-MULTICS.ARPA
+CISL-SERVICE IN CNAME CISL-SERVICE-MULTICS.ARPA
+PARC-MAXC IN A 10.0.0.32
+ IN HINFO MAXC,TENEX
+PARC-VAXC IN A 10.1.0.32
+ IN HINFO VAX-11/785,UNIX
+PARCVAX IN CNAME PARC-VAXC.ARPA
+XEROX IN A 10.2.0.32
+ IN HINFO DORADO,CEDAR
+PARC-GW IN CNAME XEROX.ARPA
+PARC IN CNAME XEROX.ARPA
+KESTREL IN A 10.3.0.32
+ IN HINFO FOONLY-F3,TENEX
+SCI-ICS IN CNAME KESTREL.ARPA
+SCI IN CNAME KESTREL.ARPA
+KES IN CNAME KESTREL.ARPA
+SCT IN CNAME KESTREL.ARPA
+BRAGG-STA1 IN A 10.1.0.38
+ IN HINFO PDP-11/34,ELF
+BRAGG-ARPA-TAC IN A 10.2.0.38
+ IN HINFO H-316,TAC
+MIT-XX IN A 10.0.0.44
+ IN HINFO DEC-2060T,TOPS20
+XX IN CNAME MIT-XX.ARPA
+MIT-TSTGW IN A 10.2.0.44
+ IN A 18.10.0.41
+ IN HINFO PDP-11,MOS
+MIT-MC IN A 10.3.0.44
+ IN HINFO DEC-1080,ITS
+MC IN CNAME MIT-MC.ARPA
+COLLINS-PR IN A 10.0.0.46
+ IN HINFO PDP-11/34,ELF
+COLLINS-GW IN A 10.1.0.46
+ IN HINFO PDP-11/3,MOS
+COLLINS-TAC IN A 10.2.0.46
+ IN HINFO C/30,TAC
+A-LHI-COL-02 IN A 10.4.0.46
+ IN HINFO M68000,CMOS
+ALS02 IN CNAME A-LHI-COL-02.ARPA
+SRI-NIC IN A 10.0.0.51
+ IN A 26.0.0.73
+ IN HINFO DEC-2060,TOPS20
+NIC IN CNAME SRI-NIC.ARPA
+SRI-STA6 IN A 10.1.1.51
+PRMH IN A 10.2.0.51
+ IN A 192.12.16.101
+ IN HINFO PDP-11/44,UNIX
+SRI-PRMH IN CNAME PRMH.ARPA
+SRI-STA2 IN A 10.3.1.51
+A-LHI-SRI-03 IN A 10.7.0.51
+ IN HINFO M68000,CMOS
+ALS03 IN CNAME A-LHI-SRI-03.ARPA
+USC-ISIC IN A 10.0.0.52
+ IN HINFO DEC-2060,TOPS20
+ISIC IN CNAME USC-ISIC.ARPA
+ISI-HOBGOBLIN IN A 10.1.0.52
+ IN A 128.9.0.42
+ IN HINFO VAX-11/750,UNIX
+HOBGOBLIN IN CNAME ISI-HOBGOBLIN.ARPA
+USC-ISIF IN A 10.2.0.52
+ IN HINFO DEC-1090T,TOPS20
+ISIF IN CNAME USC-ISIF.ARPA
+USC-ISIB IN A 10.3.0.52
+ IN HINFO DEC-1090T,TOPS20
+ISIB IN CNAME USC-ISIB.ARPA
+CIT-20 IN A 10.0.0.54
+ IN HINFO DEC-2060,TOPS20
+CALTECH IN CNAME CIT-20.ARPA
+CIT-VAX IN A 10.1.0.54
+ IN A 192.5.7.2
+ IN A 192.12.18.1
+ IN A 192.12.19.1
+ IN HINFO VAX-11/780,UNIX
+ZAPHOD IN CNAME CIT-VAX.ARPA
+JPL-VLSI IN A 10.3.0.54
+ IN HINFO VAX-11/780,VMS
+JPL-VAX IN CNAME JPL-VLSI.ARPA
+JPL-ROBOTICS IN A 10.3.1.54
+ IN HINFO VAX-11/750,VMS
+SUMEX-AIM IN A 10.0.0.56
+ IN A 36.45.0.87
+ IN HINFO DEC-2060,TOPS20
+AIM IN CNAME SUMEX-AIM.ARPA
+SUMEX IN CNAME SUMEX-AIM.ARPA
+AIDS-UNIX IN A 10.2.0.56
+ IN HINFO VAX-11/780,UNIX
+AIDS-VAX IN CNAME AIDS-UNIX.ARPA
+AIDS IN CNAME AIDS-UNIX.ARPA
+UT-NGP IN A 10.0.0.62
+ IN A 192.5.89.24
+ IN HINFO VAX-11/780,UNIX
+UTEXAS-NGP IN CNAME UT-NGP.ARPA
+UTEXAS-20 IN A 10.1.0.62
+ IN A 192.5.89.30
+ IN HINFO DEC-2060,TOPS20
+UT-R20 IN CNAME UTEXAS-20.ARPA
+UTEXAS IN CNAME UTEXAS-20.ARPA
+UT-SALLY IN A 10.2.0.62
+ IN A 192.5.89.11
+ IN A 192.12.23.91
+ IN HINFO VAX-11/780,UNIX
+SALLY IN CNAME UT-SALLY.ARPA
+MCC IN A 10.3.0.62
+ IN HINFO DEC-2065,TOPS20
+MCC-AI IN CNAME MCC.ARPA
+BBN-TEST0-GW IN A 10.0.0.63
+BBN-ARPA-TAC IN A 10.1.0.63
+ IN HINFO C/30,TAC
+BBN-PSAT-IG IN A 10.4.0.63
+A-LHI-BBN-01 IN A 10.6.0.63
+ IN HINFO M68000,CMOS
+ALB01 IN CNAME A-LHI-BBN-01.ARPA
+MIT-TAC IN A 10.2.0.77
+ IN HINFO C/30,TAC
+UCB-ARPA IN A 10.0.0.78
+ IN A 128.32.0.4
+ IN HINFO VAX-11/780,UNIX
+UCBARPA IN CNAME UCB-ARPA.ARPA
+UCB-VAX IN A 10.2.0.78
+ IN A 128.32.0.10
+ IN HINFO VAX-11/750,UNIX
+BERKELEY IN CNAME UCB-VAX.ARPA
+UCBVAX IN CNAME UCB-VAX.ARPA
+DEC-TOPS20 IN A 10.0.0.79
+ IN A 192.5.6.1
+ IN HINFO DEC-2060T,TOPS20
+DEC-2136 IN CNAME DEC-TOPS20.ARPA
+DEC-CHIP IN CNAME DEC-TOPS20.ARPA
+DEC-MARLBORO IN A 10.1.0.79
+ IN HINFO DEC-2060T,TOPS20
+DEC IN CNAME DEC-MARLBORO.ARPA
+MARKET IN CNAME DEC-MARLBORO.ARPA
+DEC-HUDSON IN A 10.2.0.79
+ IN HINFO VAX-11/750,VMS
+SAC-ARPA-TAC IN A 10.1.0.80
+ IN HINFO C/30,TAC
+SAC-STATION IN A 10.6.0.80
+ IN HINFO LSI-11/23,MOS
+BBN-UNIX IN A 10.0.0.82
+ IN A 8.1.0.4
+ IN HINFO C/70,UNIX
+BBNCC IN CNAME BBN-UNIX.ARPA
+BBNU IN CNAME BBN-UNIX.ARPA
+BBN-VAX IN A 10.1.0.82
+ IN A 8.1.0.8
+ IN HINFO VAX-11/780,UNIX
+BBNV IN CNAME BBN-VAX.ARPA
+BBNCCP IN A 10.3.0.82
+ IN HINFO C/70,UNIX
+ARPANET-MC IN A 10.5.0.82
+ IN HINFO C/70,UNIX
+ANOC IN CNAME ARPANET-MC.ARPA
+CSNET-SH IN A 10.7.0.82
+ IN HINFO VAX-11/750,UNIX
+CSNET-CIC IN CNAME CSNET-SH.ARPA
+CSNET2 IN CNAME CSNET-SH.ARPA
+OCC IN CNAME CSNET-SH.ARPA
+COLUMBIA-20 IN A 10.0.0.89
+ IN A 192.5.43.20
+ IN HINFO DEC-2060,TOPS20
+CUCS20 IN CNAME COLUMBIA-20.ARPA
+RUTGERS IN A 10.1.0.89
+ IN A 128.6.0.2
+ IN HINFO DEC-2060T,TOPS20
+RU-RED IN CNAME RUTGERS.ARPA
+COLUMBIA IN A 10.3.0.89
+ IN HINFO VAX-11/750,UNIX
+CU IN CNAME COLUMBIA.ARPA
+WASHINGTON IN A 10.0.0.91
+ IN HINFO DEC-2060,TOPS20
+UDUB IN CNAME WASHINGTON.ARPA
+UW-WARD IN CNAME WASHINGTON.ARPA
+WARD IN CNAME WASHINGTON.ARPA
+WASHINGTON-TAC IN A 10.2.0.91
+ IN HINFO C/30,TAC
+UW-VLSI IN A 10.3.0.91
+ IN A 192.5.8.5
+ IN HINFO VAX-11/780,UNIX
+UDUB-VLSI IN CNAME UW-VLSI.ARPA
+HI-MULTICS IN A 10.1.0.94
+ IN HINFO DPS8/70M,MULTICS
+HONEY IN CNAME HI-MULTICS.ARPA
+CNO-MULTICS IN CNAME HI-MULTICS.ARPA
+UDEL-RELAY IN A 10.0.0.96
+ IN A 192.5.39.3
+ IN HINFO VAX-11/750,UNIX
+UD-RELAY IN CNAME UDEL-RELAY.ARPA
+UDEL IN CNAME UDEL-RELAY.ARPA
+WHARTON-10 IN A 10.1.0.96
+ IN HINFO DEC-10,TOPS10
+WHARTON IN CNAME WHARTON-10.ARPA
+UDEL-EE IN A 10.2.0.96
+ IN A 192.5.39.1
+ IN HINFO VAX-11/780,UNIX
+UDEL-HUEY IN CNAME UDEL-EE.ARPA
+HUEY IN CNAME UDEL-EE.ARPA
+CORNELL IN A 10.3.0.96
+ IN A 192.5.36.3
+ IN A 192.5.51.3
+ IN A 192.12.10.3
+ IN HINFO VAX-11/750,UNIX
+CORNELL-ARPA IN CNAME CORNELL.ARPA
+CU-ARPA IN CNAME CORNELL.ARPA
+PURDUE-X25 IN A 10.2.0.98
+ IN HINFO VAX-11/780,UNIX
+VAX-X25 IN A 10.2.0.99
+BBN-X25-TEST3 IN A 10.3.0.99
+BBN-X25-TEST4 IN A 10.4.0.99
+TEST-HOST5-X25 IN A 10.5.0.99
+SRI-SPAM-TEST IN A 10.2.0.107
+ IN HINFO VAX-11/780,UNIX
+MITRE-GATEWAY IN A 10.1.0.111
+ IN HINFO C/70,UNIX
+MITRE-GW IN CNAME MITRE-GATEWAY.ARPA
+MITRE-LAN IN A 10.2.0.111
+ IN HINFO PDP-11/70,UNIX
+RADC-ARPA-TAC IN A 10.0.0.119
+ IN HINFO C/30,TAC
+RADC-TOPS20 IN A 10.2.0.119
+ IN HINFO DEC-2040T,TOPS20
+RADC-20 IN CNAME RADC-TOPS20.ARPA
+USC-ECLC IN A 10.1.0.121
+ IN HINFO DEC-1090B,TOPS20
+ECLC IN CNAME USC-ECLC.ARPA
+UDEL-TN IN A 14.0.0.3
+ IN HINFO VAX-11/750,UNIX
+UCL-VTEST IN A 14.0.0.4
+UK-SATNET IN A 14.0.0.6
+DFVLR IN A 14.0.0.16
+MIT-CHARMIN IN A 18.26.0.1
+ IN HINFO IMAGEN,IMAGEN
+CHARMIN IN CNAME MIT-CHARMIN.ARPA
+MIT-ATHENA IN A 18.58.0.1
+ IN HINFO VAX-11/750,UNIX
+ATHENA IN CNAME MIT-ATHENA.ARPA
+MIT-CEZANNE IN A 18.27.0.2
+ IN HINFO VAX-11/750,UNIX
+CEZANNE IN CNAME MIT-CEZANNE.ARPA
+MIT-ZEUS IN A 18.58.0.2
+ IN HINFO VAX-11/750,UNIX
+ZEUS IN CNAME MIT-ZEUS.ARPA
+MIT-DEGAS IN A 18.27.0.3
+ IN HINFO VAX-11/750,UNIX
+DEGAS IN CNAME MIT-DEGAS.ARPA
+MIT-HERA IN A 18.58.0.3
+ IN HINFO VAX-11/750,UNIX
+HERA IN CNAME MIT-HERA.ARPA
+MIT-DEMETER IN A 18.58.0.4
+ IN HINFO VAX-11/750,UNIX
+DEMETER IN CNAME MIT-DEMETER.ARPA
+MIT-ARES IN A 18.58.0.5
+ IN HINFO VAX-11/750,UNIX
+ARES IN CNAME MIT-ARES.ARPA
+MIT-SLUDGE IN A 18.10.0.6
+ IN A 18.26.0.134
+ IN HINFO PDP-11,MOS
+MIT-SL IN CNAME MIT-SLUDGE.ARPA
+SLUDGE IN CNAME MIT-SLUDGE.ARPA
+MIT-POSEIDON IN A 18.58.0.6
+ IN HINFO VAX-11/750,UNIX
+POSEIDON IN CNAME MIT-POSEIDON.ARPA
+MIT-BRIDGE IN A 18.2.0.7
+ IN A 18.10.0.5
+ IN HINFO PDP-11,MOS
+MIT-BR IN CNAME MIT-BRIDGE.ARPA
+BRIDGE IN CNAME MIT-BRIDGE.ARPA
+MIT-GOOFY IN A 18.9.0.8
+ IN HINFO IBM-PC,MSDOS
+GOOFY IN CNAME MIT-GOOFY.ARPA
+MIT-CSR IN A 18.10.0.8
+ IN HINFO PDP-11/45,UNIX
+CSR IN CNAME MIT-CSR.ARPA
+CSR2 IN CNAME MIT-CSR.ARPA
+PRINTER IN CNAME MIT-CSR.ARPA
+MIT-LN IN CNAME MIT-CSR.ARPA
+LN IN CNAME MIT-CSR.ARPA
+MIT-MELKOR IN A 18.26.0.8
+ IN HINFO IBM-PC,MSDOS
+MELKOR IN CNAME MIT-MELKOR.ARPA
+MEL IN CNAME MIT-MELKOR.ARPA
+MIT-PERSEPHONE IN A 18.58.0.8
+ IN HINFO VAX-11/750,UNIX
+PERSEPHONE IN CNAME MIT-PERSEPHONE.ARPA
+PHONE IN CNAME MIT-PERSEPHONE.ARPA
+MIT-AI-LCS IN A 18.10.0.9
+ IN A 128.52.22.9
+ IN HINFO LSI-11/23,MOS
+AI-LCS IN CNAME MIT-AI-LCS.ARPA
+MIT-GROSS IN CNAME MIT-AI-LCS.ARPA
+GROSS IN CNAME MIT-AI-LCS.ARPA
+MIT-APOLLO IN A 18.58.0.10
+ IN HINFO VAX-11/750,UNIX
+APOLLO IN CNAME MIT-APOLLO.ARPA
+MIT-ARTEMIS IN A 18.58.0.11
+ IN HINFO VAX-11/750,UNIX
+ARTEMIS IN CNAME MIT-ARTEMIS.ARPA
+ARTY IN CNAME MIT-ARTEMIS.ARPA
+MIT-APHRODITE IN A 18.58.0.12
+ IN HINFO VAX-11/750,UNIX
+APHRODITE IN CNAME MIT-APHRODITE.ARPA
+MIT-CHARON IN A 18.58.0.13
+ IN HINFO VAX-11/750,UNIX
+CHARON IN CNAME MIT-CHARON.ARPA
+SIPBVAX IN CNAME MIT-CHARON.ARPA
+MIT-PROMETHEUS IN A 18.58.0.14
+ IN HINFO VAX-11/750,UNIX
+PROMETHEUS IN CNAME MIT-PROMETHEUS.ARPA
+PROM IN CNAME MIT-PROMETHEUS.ARPA
+MIT-ATLAS IN A 18.58.0.15
+ IN HINFO VAX-11/750,UNIX
+ATLAS IN CNAME MIT-ATLAS.ARPA
+MIT-TWEETY-PIE IN A 18.27.0.16
+ IN HINFO SYMBOLICS-3600,LISPM
+TWEETY-PIE IN CNAME MIT-TWEETY-PIE.ARPA
+TWEETY IN CNAME MIT-TWEETY-PIE.ARPA
+MIT-BUGS-BUNNY IN A 18.20.27.17
+ IN A 18.27.0.17
+ IN HINFO VAX-11/750,UNIX
+BUGS-BUNNY IN CNAME MIT-BUGS-BUNNY.ARPA
+BUNNY IN CNAME MIT-BUGS-BUNNY.ARPA
+MIT-ALTO-509 IN A 18.2.0.18
+ALTO-509 IN CNAME MIT-ALTO-509.ARPA
+MIT-ALTO-510 IN A 18.2.0.20
+ALTO-510 IN CNAME MIT-ALTO-510.ARPA
+MIT-PORKY-PIG IN A 18.27.0.20
+ IN HINFO VAX-11/750,UNIX
+PORKY IN CNAME MIT-PORKY-PIG.ARPA
+PORKY-PIG IN CNAME MIT-PORKY-PIG.ARPA
+MIT-YOSEMITE-SAM IN A 18.20.27.21
+ IN A 18.27.0.21
+ IN HINFO VAX-11/750,UNIX
+SAM IN CNAME MIT-YOSEMITE-SAM.ARPA
+YOSEMITE-SAM IN CNAME MIT-YOSEMITE-SAM.ARPA
+SCRC-RIVERSIDE IN A 18.20.41.21
+ IN A 192.10.41.21
+ IN HINFO SYMBOLICS-3600,LISPM
+MIT-DAFFY-DUCK IN A 18.27.0.23
+ IN HINFO SYMBOLICS-3600,LISPM
+DAFFY-DUCK IN CNAME MIT-DAFFY-DUCK.ARPA
+DAFFY IN CNAME MIT-DAFFY-DUCK.ARPA
+MIT-NMS IN A 18.10.0.24
+ IN HINFO PDP-11,NMS
+NMS IN CNAME MIT-NMS.ARPA
+MIT-BABY-BLUE IN A 18.26.0.24
+BABY-BLUE IN CNAME MIT-BABY-BLUE.ARPA
+BABY IN CNAME MIT-BABY-BLUE.ARPA
+MIT-BLUE-THUNDER IN A 18.26.0.25
+BLUE-THUNDER IN CNAME MIT-BLUE-THUNDER.ARPA
+THUNDER IN CNAME MIT-BLUE-THUNDER.ARPA
+MIT-BLUE-BAYOU IN A 18.26.0.26
+BLUE-BAYOU IN CNAME MIT-BLUE-BAYOU.ARPA
+BAYOU IN CNAME MIT-BLUE-BAYOU.ARPA
+MIT-BLUE-SUEDE-SHOES IN A 18.26.0.27
+BLUE-SUEDE-SHOES IN CNAME MIT-BLUE-SUEDE-SHOES.ARPA
+BLUE-SUEDE IN CNAME MIT-BLUE-SUEDE-SHOES.ARPA
+MIT-MISTY-BLUE IN A 18.26.0.28
+MISTY-BLUE IN CNAME MIT-MISTY-BLUE.ARPA
+MISTY IN CNAME MIT-MISTY-BLUE.ARPA
+MIT-CAR-WASH-BLUES IN A 18.26.0.29
+CAR-WASH-BLUES IN CNAME MIT-CAR-WASH-BLUES.ARPA
+CAR-WASH IN CNAME MIT-CAR-WASH-BLUES.ARPA
+MIT-BLUE-JEANS IN A 18.26.0.30
+BLUE-JEANS IN CNAME MIT-BLUE-JEANS.ARPA
+JEANS IN CNAME MIT-BLUE-JEANS.ARPA
+MIT-BLUE-BLOOD IN A 18.26.0.31
+BLUE-BLOOD IN CNAME MIT-BLUE-BLOOD.ARPA
+BLOOD IN CNAME MIT-BLUE-BLOOD.ARPA
+MIT-ALTO-524 IN A 18.2.0.32
+ALTO-524 IN CNAME MIT-ALTO-524.ARPA
+GUTTAG IN CNAME MIT-ALTO-524.ARPA
+MIT-PLUTO IN A 18.26.0.35
+ IN HINFO IBM-PC,MSDOS
+PLUTO IN CNAME MIT-PLUTO.ARPA
+MIT-ZUD IN A 18.26.0.38
+ IN HINFO IBM-PC,MSDOS
+ZUD IN CNAME MIT-ZUD.ARPA
+MIT-COKE IN A 18.26.0.39
+ IN HINFO NOW,SWIFT
+COKE IN CNAME MIT-COKE.ARPA
+MIT-DR-PEPPER IN A 18.26.0.40
+ IN HINFO NOW,SWIFT
+MIT-DP IN CNAME MIT-DR-PEPPER.ARPA
+DR-PEPPER IN CNAME MIT-DR-PEPPER.ARPA
+DP IN CNAME MIT-DR-PEPPER.ARPA
+MIT-PEPSI IN A 18.26.0.41
+ IN HINFO NOW,SWIFT
+PEPSI IN CNAME MIT-PEPSI.ARPA
+MIT-SELTZER IN A 18.26.0.42
+ IN HINFO NOW,SWIFT
+SELTZER IN CNAME MIT-SELTZER.ARPA
+MIT-GUANO IN A 18.26.0.44
+ IN HINFO IBM-PC,MSDOS
+GUANO IN CNAME MIT-GUANO.ARPA
+MIT-CJT IN A 18.26.0.45
+ IN HINFO IBM-PC,MSDOS
+CJT IN CNAME MIT-CJT.ARPA
+MIT-ALTO-214B IN A 18.2.0.56
+ALTO-214B IN CNAME MIT-ALTO-214B.ARPA
+OA-ALTO IN CNAME MIT-ALTO-214B.ARPA
+MIT-AJAX IN A 18.10.0.64
+ IN HINFO VAX-11/750,UNIX
+AJAX IN CNAME MIT-AJAX.ARPA
+MIT-VAXLET IN A 18.26.0.64
+ IN A 18.20.26.64
+ IN HINFO VAX-11/750,UNIX
+VAXLET IN CNAME MIT-VAXLET.ARPA
+MIT-BORAX IN A 18.10.0.65
+ IN HINFO VAX-11/750,UNIX
+BORAX IN CNAME MIT-BORAX.ARPA
+MIT-COMET IN A 18.10.0.66
+ IN HINFO VAX-11/750,UNIX
+MIT-DUTCH IN A 18.10.0.67
+ IN HINFO VAX-11/750,UNIX
+DUTCH IN CNAME MIT-DUTCH.ARPA
+MIT-MRCLEAN IN A 18.10.0.68
+ IN HINFO VAX-11/750,UNIX
+MRCLEAN IN CNAME MIT-MRCLEAN.ARPA
+MIT-BOLD IN A 18.10.0.69
+ IN HINFO VAX-11/750,UNIX
+BOLD IN CNAME MIT-BOLD.ARPA
+MIT-FAB IN A 18.10.0.70
+ IN HINFO VAX-11/750,UNIX
+FAB IN CNAME MIT-FAB.ARPA
+MIT-PRJ IN A 18.10.0.71
+ IN HINFO VAX-11/750,UNIX
+PRJ IN CNAME MIT-PRJ.ARPA
+MIT-ALTO-511 IN A 18.2.0.72
+ALTO-511 IN CNAME MIT-ALTO-511.ARPA
+MIT-DUZ IN A 18.10.0.72
+ IN HINFO VAX-11/750,UNIX
+DUZ IN CNAME MIT-DUZ.ARPA
+MIT-DASH IN A 18.10.0.73
+ IN HINFO VAX-11/750,UNIX
+DASH IN CNAME MIT-DASH.ARPA
+MIT-TIDE IN A 18.10.0.74
+ IN HINFO VAX-11/750,UNIX
+TIDE IN CNAME MIT-TIDE.ARPA
+MIT-NEWTOWNE-VARIETY IN A 18.10.0.75
+ IN HINFO VAX-11/750,UNIX
+MIT-FLA IN CNAME MIT-NEWTOWNE-VARIETY.ARPA
+NEWT IN CNAME MIT-NEWTOWNE-VARIETY.ARPA
+MIT-WILD-BLUE-YONDER IN A 18.26.0.75
+ IN HINFO VAX-11/750,UNIX
+WILD-BLUE IN CNAME MIT-WILD-BLUE-YONDER.ARPA
+MIT-WBY IN CNAME MIT-WILD-BLUE-YONDER.ARPA
+WBY IN CNAME MIT-WILD-BLUE-YONDER.ARPA
+MIT-CLS IN A 18.10.0.76
+ IN HINFO VAX-11/750,UNIX
+CLS IN CNAME MIT-CLS.ARPA
+MIT-GRAPE-NEHI IN A 18.10.0.77
+ IN HINFO VAX-11/780,UNIX
+GRAPE-NEHI IN CNAME MIT-GRAPE-NEHI.ARPA
+C6 IN CNAME MIT-GRAPE-NEHI.ARPA
+MIT-HEINEKEN IN A 18.10.0.78
+ IN HINFO VAX-11/750,UNIX
+HEINEKEN IN CNAME MIT-HEINEKEN.ARPA
+MIT-OA IN A 18.10.0.79
+ IN HINFO VAX-11/750,UNIX
+OA IN CNAME MIT-OA.ARPA
+MIT-MURIEL IN A 18.2.0.80
+MURIEL IN CNAME MIT-MURIEL.ARPA
+MIT-MACEWAN IN A 18.10.0.80
+ IN HINFO VAX-11/750,UNIX
+MACEWAN IN CNAME MIT-MACEWAN.ARPA
+MIT-KIRIN IN A 18.10.0.81
+ IN HINFO VAX-11/750,UNIX
+KIRIN IN CNAME MIT-KIRIN.ARPA
+MIT-MOLSON IN A 18.10.0.82
+ IN HINFO VAX-11/750,UNIX
+MOLSON IN CNAME MIT-MOLSON.ARPA
+MIT-MILO IN A 18.10.0.86
+ IN HINFO VAX-11/750,UNIX
+MILO IN CNAME MIT-MILO.ARPA
+MIT-OPUS IN A 18.10.0.87
+ IN HINFO VAX-11/750,UNIX
+OPUS IN CNAME MIT-OPUS.ARPA
+MIT-RINSO IN A 18.10.0.88
+ IN HINFO VAX-11/750,UNIX
+RINSO IN CNAME MIT-RINSO.ARPA
+MIT-VAX IN A 18.26.0.95
+ IN HINFO VAX-11/780,UNIX
+MIT-ALTO-508 IN A 18.2.0.96
+ALTO-508 IN CNAME MIT-ALTO-508.ARPA
+MIT-ALTO-503 IN A 18.2.0.100
+ALTO-503 IN CNAME MIT-ALTO-503.ARPA
+MIT-SPOOLER IN A 18.2.0.128
+ IN HINFO ALTO,TFTPSP
+SPOOLER IN CNAME MIT-SPOOLER.ARPA
+SPOOL IN CNAME MIT-SPOOLER.ARPA
+MIT-PCGW IN A 18.9.0.128
+ IN A 18.10.0.40
+ IN HINFO PDP-11,MOS
+PCGW IN CNAME MIT-PCGW.ARPA
+MIT-LCS-HQ IN A 18.10.0.128
+ IN HINFO VAX-11/780,UNIX
+LCS-HQ IN CNAME MIT-LCS-HQ.ARPA
+MIT-NP-ALTO IN A 18.2.0.129
+NP-ALTO IN CNAME MIT-NP-ALTO.ARPA
+MIT-DM IN A 18.10.0.129
+ IN HINFO VAX-11/780,UNIX
+DM IN CNAME MIT-DM.ARPA
+MIT-ALTO-502 IN A 18.2.0.130
+ALTO-502 IN CNAME MIT-ALTO-502.ARPA
+MIT-ALTO-828 IN A 18.2.0.134
+ALTO-828 IN CNAME MIT-ALTO-828.ARPA
+MEDG IN CNAME MIT-ALTO-828.ARPA
+MIT-BLUE-APOLLO IN A 18.26.0.136
+ IN A 18.105.0.9
+ IN HINFO APOLLO,APOLLO
+BLUE-APOLLO IN CNAME MIT-BLUE-APOLLO.ARPA
+MIT-ALTO-520 IN A 18.2.0.170
+ALTO-520 IN CNAME MIT-ALTO-520.ARPA
+MIT-BLUE-LIGHT IN A 18.10.0.192
+ IN HINFO IBM-PC,MSDOS
+BLUE-LIGHT IN CNAME MIT-BLUE-LIGHT.ARPA
+MIT-BLUE-DANUBE IN A 18.10.0.193
+ IN HINFO IBM-PC,MSDOS
+BLUE-DANUBE IN CNAME MIT-BLUE-DANUBE.ARPA
+DANUBE IN CNAME MIT-BLUE-DANUBE.ARPA
+MIT-MOTHER IN A 18.10.0.194
+ IN HINFO IBMPCXT,MSDOS
+MOTHER IN CNAME MIT-MOTHER.ARPA
+MIT-BIG-BLUE IN A 18.10.0.195
+ IN HINFO IBM-4341,VM/SP
+MIT-BIGBLUE IN CNAME MIT-BIG-BLUE.ARPA
+BIG-BLUE IN CNAME MIT-BIG-BLUE.ARPA
+BIGBLUE IN CNAME MIT-BIG-BLUE.ARPA
+MINET-OBL-EM IN A 24.0.0.1
+ IN HINFO C/70,UNIX
+OBLEM IN CNAME MINET-OBL-EM.ARPA
+MINET-OBL IN CNAME MINET-OBL-EM.ARPA
+OBL IN CNAME MINET-OBL-EM.ARPA
+MINET-OBL-TAC IN A 24.1.0.1
+ IN HINFO C/30,TAC
+OBLTC IN CNAME MINET-OBL-TAC.ARPA
+MINET-VHN-TAC IN A 24.1.0.2
+ IN HINFO C/30,TAC
+VHNTC IN CNAME MINET-VHN-TAC.ARPA
+MINET-VHN-EM IN A 24.2.0.2
+ IN HINFO C/70,UNIX
+MINET-VHN-NOC IN CNAME MINET-VHN-EM.ARPA
+VHN IN CNAME MINET-VHN-EM.ARPA
+VHNEM IN CNAME MINET-VHN-EM.ARPA
+VHNNC IN CNAME MINET-VHN-EM.ARPA
+MINET-VHN IN CNAME MINET-VHN-EM.ARPA
+DCA-EUR IN A 24.3.0.2
+ IN HINFO C/70,UNIX
+PATCH IN A 24.6.0.2
+ IN HINFO LSI-11/23,FUZZ
+PATCHNET IN CNAME PATCH.ARPA
+MINET-RAM-TAC IN A 24.1.0.3
+ IN HINFO C/30,TAC
+RAMTC IN CNAME MINET-RAM-TAC.ARPA
+MINET-HDL-TAC IN A 24.1.0.4
+ IN HINFO C/30,TAC
+HDLTC IN CNAME MINET-HDL-TAC.ARPA
+MINET-BRM-TAC IN A 24.1.0.5
+ IN HINFO C/30,TAC
+BRMTC IN CNAME MINET-BRM-TAC.ARPA
+MINET-RDM-TAC IN A 24.1.0.6
+ IN HINFO C/30,TAC
+RMDTC IN CNAME MINET-RDM-TAC.ARPA
+MINET-LON-EM IN A 24.0.0.7
+ IN HINFO C/70,UNIX
+LONEM IN CNAME MINET-LON-EM.ARPA
+MINET-LON IN CNAME MINET-LON-EM.ARPA
+LON IN CNAME MINET-LON-EM.ARPA
+MINET-LON-TAC IN A 24.1.0.7
+ IN HINFO C/30,TAC
+LONTC IN CNAME MINET-LON-TAC.ARPA
+CPO IN A 24.0.0.8
+ IN HINFO C/70,UNIX
+MINET-CPO-EM IN CNAME CPO.ARPA
+MINET-CPO-TAC IN A 24.1.0.8
+ IN HINFO C/30,TAC
+CPOTC IN CNAME MINET-CPO-TAC.ARPA
+MINET-SIG-TAC IN A 24.1.0.9
+ IN HINFO C/30,TAC
+SIGTC IN CNAME MINET-SIG-TAC.ARPA
+MINET-TC2-EM IN A 24.0.0.11
+ IN A 26.6.0.49
+ IN HINFO C/70,
+TC2 IN CNAME MINET-TC2-EM.ARPA
+MINET-HLH-TAC IN A 24.1.0.13
+ IN HINFO C/30,TAC
+HLHTC IN CNAME MINET-HLH-TAC.ARPA
+NOSC IN A 26.0.0.3
+ IN A 128.49.0.2
+ IN A 128.54.0.2
+ IN HINFO VAX-11/750,UNIX
+NOSC-BASS IN CNAME NOSC.ARPA
+BASS IN CNAME NOSC.ARPA
+NOSC-CC IN CNAME NOSC.ARPA
+NTECTSD IN A 26.1.0.3
+ IN HINFO VAX-11/780,VMS
+LOGICON IN A 26.2.0.3
+ IN HINFO PDP-11/70,UNIX
+NPRDC IN A 26.3.0.3
+ IN A 192.5.65.1
+ IN HINFO VAX-11/780,UNIX
+NPRDC-AEGEAN IN CNAME NPRDC.ARPA
+NRL IN A 26.0.0.8
+ IN HINFO VAX-11/750,UNIX
+NRL-AIC IN A 26.1.0.8
+ IN HINFO VAX-11/780,UNIX
+ASPUR-CSC IN A 26.2.0.8
+ IN HINFO VAX-11/750,VMS
+NRL-TOPS10 IN A 26.3.0.8
+ IN HINFO DEC-10,TOPS10
+NARDACWASH-001 IN A 26.5.0.8
+ IN HINFO UNIVAC-1100/62,OS-1100
+NRL-ARCTAN IN A 26.6.0.8
+ IN HINFO PDP-11/40,RSX11M
+NRL-CSS IN A 26.7.0.8
+ IN A 192.5.17.112
+ IN HINFO VAX-11/780,UNIX
+RAND2-MIL-TAC IN A 26.0.0.12
+ IN HINFO C/30,TAC
+GUNTER-ADAM IN A 26.1.0.13
+ IN HINFO DEC-2060,TOPS20
+GUNTER-TAC IN A 26.2.0.13
+ IN HINFO C/30,TAC
+GUNT IN CNAME GUNTER-TAC.ARPA
+AMES-TAC IN A 26.1.0.16
+ IN HINFO C/30,TAC
+AMES-VMSB IN A 26.3.0.16
+ IN HINFO VAX-11/780,VMS
+AMES-11 IN CNAME AMES-VMSB.ARPA
+AMES-NAS IN A 26.4.0.16
+ IN A 192.5.64.1
+ IN HINFO VAX-11/780,UNIX
+AMELIA IN CNAME AMES-NAS.ARPA
+AMELIA-EC IN CNAME AMES-NAS.ARPA
+RIACS-ICARUS IN A 26.6.0.16
+ IN A 192.5.35.1
+ IN HINFO VAX-11/730,UNIX
+ICARUS IN CNAME RIACS-ICARUS.ARPA
+MITRE IN A 26.0.0.17
+ IN HINFO C/70,UNIX
+MITRE-TAC IN A 26.2.0.17
+ IN HINFO C/30,TAC
+DDN-PMO-MIL-TAC IN A 26.5.0.17
+ IN HINFO C/30,TAC
+RADC-MULTICS IN A 26.0.0.18
+ IN HINFO HONEYWELL-DPS-8/70M,MULTICS
+RADC IN CNAME RADC-MULTICS.ARPA
+RADC-TAC IN A 26.2.0.18
+ IN HINFO C/30,TAC
+RADT IN CNAME RADC-TAC.ARPA
+RADC-LONEX IN A 26.5.0.18
+ IN HINFO VAX-11/750,UNIX
+LNX IN CNAME RADC-LONEX.ARPA
+GE-CRD IN A 26.6.0.18
+ IN HINFO VAX-11/780,VMS
+GE IN CNAME GE-CRD.ARPA
+NBS-VMS IN A 26.0.0.19
+ IN HINFO VAX-11/780,VMS
+NBS-10 IN CNAME NBS-VMS.ARPA
+NBS IN CNAME NBS-VMS.ARPA
+NBS-SDC IN A 26.1.0.19
+ IN HINFO VAX-11/780,VMS
+NBS-UNIX IN A 26.2.0.19
+ IN HINFO VAX-11/750,UNIX
+NBS-PL IN A 26.3.0.19
+ IN HINFO PDP-11/70,UNIX
+NBS-AMRF IN A 26.6.0.19
+ IN HINFO VAX-11/780,VMS
+AMRF IN CNAME NBS-AMRF.ARPA
+NBS-SSI IN A 26.7.0.19
+ IN HINFO VAX-11/750,UNIX
+DCEC-TAC IN A 26.2.0.20
+ IN HINFO C/30,TAC
+LLL-TIS IN A 26.0.0.21
+ IN HINFO PDP-11/70,UNIX
+LLL-UNIX IN CNAME LLL-TIS.ARPA
+LLL-MFE IN A 26.1.0.21
+ IN HINFO DEC-1090,TOPS10
+MFE IN CNAME LLL-MFE.ARPA
+LLL-ZDIVISION IN A 26.2.0.21
+ IN HINFO PDP-11/70,UNIX
+LLL-CRG IN A 26.3.0.21
+ IN HINFO VAX-11/780,UNIX
+GLUTEUS IN CNAME LLL-CRG.ARPA
+NADC IN A 26.0.0.24
+ IN HINFO VAX-11/780,UNIX
+PENTAGON-TAC IN A 26.0.0.26
+ IN HINFO C/30,TAC
+IGMIRS-DAIG IN A 26.1.0.26
+ IN HINFO CTIWS-117,CTOS
+TCACCIS-CSC IN A 26.3.0.26
+ IN HINFO VAX-11/750,VMS
+BRL IN A 26.0.0.29
+ IN HINFO VAX-11/780,UNIX
+APG-1 IN A 26.1.0.29
+ IN HINFO C/70,UNIX
+BRL-TAC IN A 26.2.0.29
+ IN HINFO C/30,TAC
+APG-3 IN A 26.4.0.29
+ IN HINFO C/70,UNIX
+APG-2 IN A 26.6.0.29
+ IN HINFO IBM-SERIES/1,EDX
+BROOKS-AFB-TAC IN A 26.0.0.30
+ IN HINFO C/30,TAC
+AFSC-HRL-TAC IN CNAME BROOKS-AFB-TAC.ARPA
+AFMPC-2 IN A 26.1.0.30
+ IN HINFO HONEYWELL-DPS6,GCOS
+NPS IN A 26.0.0.33
+ IN HINFO PLURIBUS,PLI
+NPS-TAC IN A 26.2.0.33
+ IN HINFO C/30,TAC
+FNOC-SECURE IN A 26.3.0.33
+ IN HINFO PDP-11/34,PLI
+FNWC-SECURE IN CNAME FNOC-SECURE.ARPA
+LBL IN A 26.0.0.34
+ IN HINFO VAX-11/750,VMS
+LBL-WS IN CNAME LBL.ARPA
+LBL-CSAM IN A 26.1.0.34
+ IN HINFO VAX-11/780,UNIX
+MCCLELLAN IN A 26.2.0.34
+ IN HINFO PDP-11/70,UNIX
+SACRAMENTO-UNIX IN CNAME MCCLELLAN.ARPA
+NOSC-SECURE2 IN A 26.0.0.35
+ IN HINFO PLURIBUS,PLI
+USC-ISIR1 IN CNAME NOSC-SECURE2.ARPA
+ISIR1 IN CNAME NOSC-SECURE2.ARPA
+NOSC-TECR IN A 26.1.0.35
+ IN HINFO VAX-11/780,VMS/EUNICE
+TECR IN CNAME NOSC-TECR.ARPA
+ACCAT-TAC IN A 26.2.0.35
+ IN HINFO C/30,TAC
+NELC-TIP IN CNAME ACCAT-TAC.ARPA
+NOSC-SECURE3 IN A 26.3.0.35
+ IN HINFO PDP-11/70,PLI
+NOSC-F4 IN A 26.4.0.35
+ IN HINFO FOONLY-F4,FOONEX
+HAWAII-EMH IN A 26.1.0.36
+ IN HINFO C/70,UNIX
+CINCPAC-TAC IN A 26.2.0.36
+ IN HINFO C/30,TAC
+EDWARDS-VAX IN A 26.0.0.39
+ IN HINFO VAX-11/782,VMS
+EVAX IN CNAME EDWARDS-VAX.ARPA
+EDWARDS-2060 IN A 26.1.0.39
+ IN HINFO DEC-2060T,TOPS20
+BBN-MIL-TAC IN A 26.0.0.40
+ IN HINFO C/30,TAC
+MICOM-TEST IN A 26.1.0.41
+ IN HINFO PDP-11/70,UNIX
+MICOM-TAC IN A 26.2.0.41
+ IN HINFO C/30,TAC
+ORNL-MSR IN A 26.3.0.41
+ IN HINFO VAX-11/780,UNIX
+OFFICE-1 IN A 26.0.0.43
+ IN HINFO FOONLY-F4,TENEX
+OF1 IN CNAME OFFICE-1.ARPA
+OFFICE-15 IN A 26.1.0.43
+ IN HINFO FOONLY-F4,TENEX
+OF15 IN CNAME OFFICE-15.ARPA
+OFFICE-3 IN A 26.2.0.43
+ IN HINFO FOONLY-F3,TENEX
+OF3 IN CNAME OFFICE-3.ARPA
+OFFICE-7 IN A 26.3.0.43
+ IN HINFO FOONLY-F3,TENEX
+OF7 IN CNAME OFFICE-7.ARPA
+ARDC-TAC IN A 26.0.0.45
+ IN HINFO C/30,TAC
+ARDC IN A 26.1.0.45
+ IN HINFO VAX-11/780,UNIX
+ARDC-MS IN CNAME ARDC.ARPA
+PICA IN CNAME ARDC.ARPA
+ARRADCOM IN CNAME ARDC.ARPA
+WPAFB-AFWAL IN A 26.1.0.47
+ IN HINFO DEC-1077,TOPS10
+AVSAIL IN CNAME WPAFB-AFWAL.ARPA
+WPAFB-AFAL IN CNAME WPAFB-AFWAL.ARPA
+WPAFB-TAC IN A 26.2.0.47
+ IN HINFO C/30,TAC
+WPAFB-INFO1 IN A 26.3.0.47
+ IN HINFO VAX-11/780,VMS
+WPAFB-JALCF IN A 26.4.0.47
+ IN HINFO VAX-11/780,VMS
+WPAFB-AFITA IN A 26.5.0.47
+ IN HINFO VAX-11/780,UNIX
+AFIT IN CNAME WPAFB-AFITA.ARPA
+WPAFB-FDL IN A 26.6.0.47
+ IN HINFO VAX-11/780,VMS
+CMU-CS-B IN A 26.7.0.47
+ IN HINFO DEC-1050,TOPS10
+CMUB IN CNAME CMU-CS-B.ARPA
+LOGNET2 IN A 26.8.0.47
+ IN HINFO VAX-11/780,UNIX
+AFWL IN A 26.1.0.48
+ IN HINFO PDP-11/50,RSX11M
+AFWL-TAC IN A 26.2.0.48
+ IN HINFO C/30,TAC
+DARCOM-HQ IN A 26.0.0.50
+ IN HINFO VAX-11/750,UNIX
+ARI-HQ1 IN A 26.1.0.50
+ IN HINFO VAX-11/780,VMS
+DARCOM-TAC IN A 26.2.0.50
+ IN HINFO C/30,TAC
+LSSA-DB1 IN A 26.3.0.50
+ IN HINFO NAS3-5,MVS
+USADHQ2 IN A 26.6.0.50
+ IN HINFO PYRAMID-90X,UNIX
+ETL-AI IN A 26.7.0.50
+ IN HINFO VAX-11/780,VMS
+USAETL IN CNAME ETL-AI.ARPA
+ETL IN CNAME ETL-AI.ARPA
+AFSC-AD IN A 26.0.0.53
+ IN HINFO PDP-11/45,RSX11M
+EGLIN IN CNAME AFSC-AD.ARPA
+AFSC-AD-TAC IN A 26.3.0.53
+ IN HINFO C/30,TAC
+EGLIN-TAC IN CNAME AFSC-AD-TAC.ARPA
+NCSC IN A 26.4.0.53
+ IN HINFO VAX-11/750,UNIX
+NCSL IN CNAME NCSC.ARPA
+MARTIN IN A 26.5.0.53
+ IN HINFO PDP-11/45,RSX11M
+MMC IN CNAME MARTIN.ARPA
+EGLIN-VAX IN A 26.6.0.53
+ IN HINFO VAX-11/780,VMS
+ANL-MCS IN A 26.1.0.55
+ IN HINFO VAX-11/780,UNIX
+GSWD-VMS IN A 26.2.0.55
+ IN HINFO VAX-11/750,VMS
+CC-VMS IN CNAME GSWD-VMS.ARPA
+DTI IN CNAME GSWD-VMS.ARPA
+COMPION-VMS IN CNAME GSWD-VMS.ARPA
+TYCHO IN A 26.0.0.57
+ IN HINFO PDP-11/70,UNIX
+NSA IN CNAME TYCHO.ARPA
+COINS-GATEWAY IN A 26.1.0.57
+ IN HINFO PLURIBUS,PLI
+COINS IN CNAME COINS-GATEWAY.ARPA
+MARYLAND IN A 26.2.0.57
+ IN A 128.8.0.8
+ IN HINFO VAX-11/780,UNIX
+MIMSY IN CNAME MARYLAND.ARPA
+UMD-CSD IN CNAME MARYLAND.ARPA
+UMD8 IN CNAME MARYLAND.ARPA
+UMCP-CS IN CNAME MARYLAND.ARPA
+NYU IN A 26.0.0.58
+ IN A 192.5.15.129
+ IN HINFO VAX-11/780,UNIX
+NYU-CMCL2 IN CNAME NYU.ARPA
+CMCL2 IN CNAME NYU.ARPA
+BNL IN A 26.1.0.58
+ IN HINFO PDP-11/44,UNIX
+BROOKHAVEN IN CNAME BNL.ARPA
+SCOTT-TAC IN A 26.1.0.59
+ IN HINFO C/30,TAC
+CECOM-2 IN A 26.0.0.60
+ IN HINFO VAX-11/780,UNIX
+CORADCOM-TAC IN A 26.1.0.60
+ IN HINFO C/30,TAC
+CORADCOM2-TAC IN A 26.2.0.60
+ IN HINFO C/30,TAC
+CECOM-1 IN A 26.3.0.60
+ IN HINFO FOONLY-F4,TENEX
+CE IN CNAME CECOM-1.ARPA
+CECOM IN CNAME CECOM-1.ARPA
+MONMOUTH-EISN IN A 26.4.0.60
+ IN HINFO PLURIBUS,SATOPS
+STL-HOST1 IN A 26.0.0.61
+ IN HINFO DEC-2040,TOPS20
+STL1 IN CNAME STL-HOST1.ARPA
+ALMSA-1 IN A 26.1.0.61
+ IN HINFO VAX-11/750,UNIX
+ALMSA IN CNAME ALMSA-1.ARPA
+STLA-TAC IN A 26.2.0.61
+ IN HINFO C/30,TAC
+STL-TIP IN CNAME STLA-TAC.ARPA
+IGMIRS-FTGILLM IN A 26.0.0.64
+ IN HINFO CTIWS-117,CTOS
+FTGILLEM-CSC IN CNAME IGMIRS-FTGILLM.ARPA
+IGMIRS-FTGILLEM-CSC IN CNAME IGMIRS-FTGILLM.ARPA
+MARTIN-B IN A 26.1.0.64
+ IN HINFO VAX-11/750,VMS
+MMC-B IN CNAME MARTIN-B.ARPA
+ROBINS-TAC IN A 26.2.0.64
+ IN HINFO C/30,TAC
+WRALC-TAC IN CNAME ROBINS-TAC.ARPA
+ROBINS-UNIX IN A 26.3.0.64
+ IN HINFO PDP-11/45,UNIX
+IGMIRS-FORSCOM IN A 26.4.0.64
+ IN HINFO CTIWS-117,CTOS
+FORSCOM-IG IN CNAME IGMIRS-FORSCOM.ARPA
+AFSC-SD IN A 26.0.0.65
+ IN HINFO DEC-2020T,TOPS20
+AFSD IN CNAME AFSC-SD.ARPA
+AFSC-SD-TAC IN A 26.1.0.65
+ IN HINFO C/30,TAC
+SD-TIP IN CNAME AFSC-SD-TAC.ARPA
+AEROSPACE IN A 26.2.0.65
+ IN HINFO VAX-11/780,UNIX
+AERO IN CNAME AEROSPACE.ARPA
+MARTIN-ED IN A 26.3.0.65
+ IN HINFO PDP-11/45,RSX11M
+MMC-ED IN CNAME MARTIN-ED.ARPA
+USC-ECL IN A 26.5.0.65
+ IN HINFO DEC-1090B,TOPS20
+ECL IN CNAME USC-ECL.ARPA
+USC-ECLA IN CNAME USC-ECL.ARPA
+ECLA IN CNAME USC-ECL.ARPA
+ACC IN A 26.6.0.65
+ IN HINFO PDP-11/70,UNIX
+USC-ECLB IN A 26.7.0.65
+ IN HINFO DEC-1090B,TOPS20
+ECLB IN CNAME USC-ECLB.ARPA
+AFGL IN A 26.1.0.66
+ IN HINFO PDP-11/50,RSX11M
+AFGL-TAC IN A 26.2.0.66
+ IN HINFO C/30,TAC
+MITRE-BEDFORD IN A 26.3.0.66
+ IN HINFO VAX-11/780,UNIX
+MITRE-B IN CNAME MITRE-BEDFORD.ARPA
+BEDFORD IN CNAME MITRE-BEDFORD.ARPA
+AFSC-HQ IN A 26.0.0.67
+ IN HINFO DEC-2040T,TOPS20
+HQAFSC IN CNAME AFSC-HQ.ARPA
+AFSC-HQ-TAC IN A 26.1.0.67
+ IN HINFO C/30,TAC
+HQAFSC-TAC IN CNAME AFSC-HQ-TAC.ARPA
+IGMIRS-CIDC IN A 26.2.0.67
+ IN HINFO CTIWS-117,CTOS
+IGMIRS-DARCOM IN A 26.3.0.67
+ IN HINFO CTIWS-117,CTOS
+DARCOM-IG IN CNAME IGMIRS-DARCOM.ARPA
+IGMIRS-DARCOM-IG IN CNAME IGMIRS-DARCOM.ARPA
+USGS2-MULTICS IN A 26.0.0.69
+ IN HINFO H-60/68,MULTICS
+DENVER IN CNAME USGS2-MULTICS.ARPA
+USGS2-TAC IN A 26.1.0.69
+ IN HINFO C/30,TAC
+USGS3-VMS IN A 26.0.0.70
+ IN HINFO VAX-11/780,VMS
+MENLO IN CNAME USGS3-VMS.ARPA
+USGS3-TAC IN A 26.1.0.70
+ IN HINFO C/30,TAC
+OKC-UNIX IN A 26.0.0.71
+ IN HINFO PDP-11/70,UNIX
+IGMIRS-SILL-IG IN A 26.1.0.71
+ IN HINFO CTIWS-117,CTOS
+FTSILL-IG IN CNAME IGMIRS-SILL-IG.ARPA
+TINKER-MIL-TAC IN A 26.2.0.71
+ IN HINFO C/30,TAC
+DDN2 IN A 26.2.0.72
+ IN HINFO C/70,UNIX
+DDN-2 IN CNAME DDN2.ARPA
+DDN IN CNAME DDN2.ARPA
+BBN-RSM IN A 26.3.0.72
+ IN HINFO PDP-11/70,PLI
+BBNR IN CNAME BBN-RSM.ARPA
+SRI-WARF IN A 26.1.0.73
+ IN HINFO PDP-11/44,PLI
+WARF IN CNAME SRI-WARF.ARPA
+TSCF IN CNAME SRI-WARF.ARPA
+SRI-MIL-TAC IN A 26.3.0.73
+ IN HINFO C/30,TAC
+SRI-F4 IN A 26.4.0.73
+ IN HINFO FOONLY-F4,TENEX
+SIMTEL20 IN A 26.0.0.74
+ IN HINFO DEC-2040T,TOPS20
+SANDS-20 IN CNAME SIMTEL20.ARPA
+SIMTEL-20 IN CNAME SIMTEL20.ARPA
+WSMR01 IN A 26.1.0.74
+ IN HINFO C/70,UNIX
+WSMR-01 IN CNAME WSMR01.ARPA
+WSMRA IN CNAME WSMR01.ARPA
+WSMR70A IN CNAME WSMR01.ARPA
+USAREC-5 IN CNAME WSMR01.ARPA
+WSMR-TAC IN A 26.2.0.74
+ IN HINFO C/30,TAC
+IGMIRS-FTBLISS IN A 26.4.0.74
+ IN HINFO CTIWS-117,CTOS
+FTBLISS-IG IN CNAME IGMIRS-FTBLISS.ARPA
+YUMA-TAC IN A 26.2.0.75
+ IN HINFO C/30,TAC
+NEMS IN A 26.0.0.81
+ IN HINFO VAX-11/750,UNIX
+NALCON IN A 26.1.0.81
+ IN HINFO VAX-11/750,UNIX
+DAVID-TAC IN A 26.2.0.81
+ IN HINFO C/30,TAC
+DTRC IN A 26.3.0.81
+ IN HINFO VAX-11/780,UNIX
+NSRDCOA IN CNAME DTRC.ARPA
+NSWC-DL IN A 26.0.0.84
+ IN HINFO PDP-11/40,RSX11M
+NSWC-G IN A 26.1.0.84
+ IN HINFO VAX-11/750,UNIX
+NSWC-TAC IN A 26.2.0.84
+ IN HINFO C/30,TAC
+NSWC-OAS IN A 26.3.0.84
+ IN HINFO VAX-11/780,UNIX
+IGMIRS-TRADOC IN A 26.4.0.84
+ IN HINFO CTIWS-117,CTOS
+TRADOC-IG IN CNAME IGMIRS-TRADOC.ARPA
+NWC-387A IN A 26.0.0.85
+ IN HINFO VAX-11/750,VMS
+NWC-3603 IN A 26.1.0.85
+ IN HINFO VAX-11/750,VMS
+CAEP IN CNAME NWC-3603.ARPA
+NWC-TAC IN A 26.2.0.85
+ IN HINFO C/30,TAC
+NWC-387B IN A 26.3.0.85
+ IN HINFO VAX-11/780,VMS
+SANDIA IN A 26.0.0.87
+ IN HINFO DEC-2060T,TOPS20
+SNL IN CNAME SANDIA.ARPA
+NLM-MCS IN A 26.0.0.88
+ IN A 192.5.52.1
+ IN HINFO VAX-11/780,UNIX
+NLM IN CNAME NLM-MCS.ARPA
+MCS IN CNAME NLM-MCS.ARPA
+LANL IN A 26.0.0.90
+ IN HINFO VAX-11/750,UNIX
+NTECFREY IN A 26.0.0.92
+ IN HINFO VAX-11/750,VMS
+TACDEW IN CNAME NTECFREY.ARPA
+NUSC-ADA IN A 26.1.0.92
+ IN HINFO VAX-11/780,VMS
+NUSC-NPT IN A 26.2.0.92
+ IN HINFO VAX-11/780,VMS
+NUSC IN A 26.3.0.92
+ IN HINFO VAX-11/780,VMS
+NAVDAF-NEWPORT IN A 26.4.0.92
+ IN HINFO UNIVAC-1100,CMS
+OFFICE-8 IN A 26.0.0.93
+ IN HINFO FOONLY-F4,TENEX
+OF8 IN CNAME OFFICE-8.ARPA
+OFFICE-10 IN A 26.1.0.93
+ IN HINFO FOONLY-F3,TENEX
+OF10 IN CNAME OFFICE-10.ARPA
+OFFICE-2 IN A 26.2.0.93
+ IN HINFO FOONLY-F4,TENEX
+OF2 IN CNAME OFFICE-2.ARPA
+OFFICE IN CNAME OFFICE-2.ARPA
+OFF IN CNAME OFFICE-2.ARPA
+S1-A IN A 26.1.0.95
+ IN HINFO FOONLY-F2,WAITS
+S1 IN CNAME S1-A.ARPA
+S1A IN CNAME S1-A.ARPA
+S-1 IN CNAME S1-A.ARPA
+S1-COPROLITE IN CNAME S1-A.ARPA
+S1-B IN A 26.2.0.95
+ IN A 128.15.0.2
+ IN HINFO VAX-11/750,UNIX
+S1-ANGBAND IN CNAME S1-B.ARPA
+ANGBAND IN CNAME S1-B.ARPA
+S1-C IN A 26.3.0.95
+ IN A 128.15.0.3
+ IN HINFO VAX-11/750,UNIX
+S1-MORDOR IN CNAME S1-C.ARPA
+MORDOR IN CNAME S1-C.ARPA
+PAXRV-NES IN A 26.2.0.97
+ IN HINFO VAX-11/730,VMS
+PAX IN CNAME PAXRV-NES.ARPA
+PAX-RV-TAC IN A 26.3.0.97
+ IN HINFO C/30,TAC
+AFMPC-1 IN A 26.0.0.101
+ IN HINFO HONEYWELL-DPS8/70,GCOS
+NSWC-WO IN A 26.0.0.102
+ IN HINFO VAX-11/750,UNIX
+USC-ISIE IN A 26.1.0.103
+ IN HINFO DEC-1090T,TOPS20
+ISIE IN CNAME USC-ISIE.ARPA
+ADA-VAX IN A 26.2.0.103
+ IN HINFO VAX-11/780,VMS
+ISI-VAXB IN CNAME ADA-VAX.ARPA
+AJPO IN CNAME ADA-VAX.ARPA
+VAXB IN CNAME ADA-VAX.ARPA
+USC-ISI IN A 26.3.0.103
+ IN HINFO DEC-1090T,TOPS20
+USC-ISIA IN CNAME USC-ISI.ARPA
+ISIA IN CNAME USC-ISI.ARPA
+ISI IN CNAME USC-ISI.ARPA
+DCEC-LSUS2 IN A 26.1.0.104
+ IN HINFO IBM-4341,MVS/SP
+DCEC2 IN CNAME DCEC-LSUS2.ARPA
+DCEC-MIL-TAC IN A 26.2.0.104
+ IN HINFO C/30,TAC
+CSC-OA IN A 26.3.0.104
+ IN HINFO IBM-4331,VM
+DCEC-LSUS IN A 26.4.0.104
+ IN HINFO IBM-4341,MVS/SP
+DCEC1 IN CNAME DCEC-LSUS.ARPA
+DCA-EMS IN A 26.5.0.104
+ IN HINFO C/70,UNIX
+DCEMS IN CNAME DCA-EMS.ARPA
+SAC1-MIL-TAC IN A 26.1.0.105
+ IN HINFO C/30,TAC
+SAC2-MIL-TAC IN A 26.7.0.105
+ IN HINFO C/30,TAC
+ARPA1-MIL-TAC IN A 26.1.0.106
+ IN HINFO C/30,TAC
+ARPA2-MIL-TAC IN A 26.2.0.106
+ IN HINFO C/30,TAC
+ARPA-PNG11 IN A 26.3.0.106
+ IN HINFO PDP-11/34,EPOS
+ARPA-XGP11 IN CNAME ARPA-PNG11.ARPA
+NORFOLK-MILTAC IN A 26.4.0.108
+ IN HINFO C/30,TAC
+UNIC IN A 26.6.0.108
+ IN HINFO UNIVAC-1160,OS-1160
+NRDCNRVA IN CNAME UNIC.ARPA
+NORL-MIL-TAC IN A 26.2.0.109
+ IN HINFO C/30,TAC
+NRDCNOLA-U1100 IN A 26.3.0.109
+ IN HINFO UNIVAC-1100/62,OS-1100
+NRDCNOLA IN CNAME NRDCNOLA-U1100.ARPA
+JAX1-MIL-TAC IN A 26.4.0.110
+ IN HINFO C/30,TAC
+STL-HOST2 IN A 26.0.0.112
+ IN HINFO BBN-C/60,UNIX
+IGMIRS-CAMP-IG IN A 26.1.0.112
+ IN HINFO CTIWS-117,CTOS
+ANNIS-MIL-TAC IN A 26.2.0.113
+ IN HINFO C/30,TAC
+CDA-PDP01 IN A 26.1.0.114
+ IN HINFO PDP-11/70,UNIX
+CDA IN CNAME CDA-PDP01.ARPA
+NCAD-MIL-TAC IN A 26.2.0.114
+ IN HINFO C/30,TAC
+NCAD2-MIL-TAC IN A 26.5.0.114
+ IN HINFO C/30,TAC
+TACOM-TAC IN A 26.2.0.115
+ IN HINFO C/30,TAC
+FRANKFURT-MIL-TAC IN A 26.0.0.116
+ IN HINFO C/30,TAC
+SECKENHEIM-EMH IN A 26.4.0.116
+ IN HINFO C/70,UNIX
+KOREA-EMH IN A 26.0.0.117
+ IN HINFO C/70,UNIX
+KOREA-TAC IN A 26.2.0.117
+ IN HINFO C/30,TAC
+SCOTT2-MIL-TAC IN A 26.0.0.118
+ IN HINFO C/30,TAC
+SC2TC IN CNAME SCOTT2-MIL-TAC.ARPA
+AFCC-1 IN A 26.4.0.118
+ IN HINFO FOONLY-F4,TENEX
+AFCC-2 IN A 26.5.0.118
+ IN HINFO FOONLY-F4,TENEX
+AFCC-3 IN A 26.6.0.118
+ IN HINFO FOONLY-F4,TENEX
+AFCC-4 IN A 26.7.0.118
+ IN HINFO FOONLY-F4,TENEX
+DUGWAY-MIL-TAC IN A 26.0.0.120
+ IN HINFO C/30,TAC
+DPG-1 IN A 26.1.0.120
+ IN HINFO C/70,UNIX
+DPG IN CNAME DPG-1.ARPA
+FTH-1 IN A 26.2.0.122
+ IN HINFO VAX-11/750,VMS
+UCL-TAC IN A 32.2.0.42
+ IN HINFO H-316,TAC
+LONDON-TAC IN CNAME UCL-TAC.ARPA
+SU-SAFE IN A 36.44.0.1
+ IN HINFO VAX-11/750,UNIX
+SAFE IN CNAME SU-SAFE.ARPA
+SU-ARDVAX IN A 36.47.0.1
+ IN HINFO VAX-11/750,UNIX
+ARDVAX IN CNAME SU-ARDVAX.ARPA
+SU-STAR IN A 36.10.0.5
+ IN HINFO VAX-11/780,VMS
+STAR IN CNAME SU-STAR.ARPA
+SU-PESCADERO IN A 36.8.0.8
+ IN A 36.36.0.101
+ IN HINFO VAX-11/750,UNIX
+PESCADERO IN CNAME SU-PESCADERO.ARPA
+SU-RUSSELL IN A 36.9.0.9
+ IN HINFO VAX-11/750,UNIX
+RUSSELL IN CNAME SU-RUSSELL.ARPA
+SU-HPP-3600-1 IN A 36.47.0.9
+ IN HINFO SYMBOLICS-3600,LISPM
+HPP-3600-1 IN CNAME SU-HPP-3600-1.ARPA
+SU-HPP-3600-2 IN A 36.47.0.10
+ IN HINFO SYMBOLICS-3600,LISPM
+HPP-3600-2 IN CNAME SU-HPP-3600-2.ARPA
+SU-GREGORIO IN A 36.8.0.11
+ IN A 36.36.0.102
+ IN HINFO VAX-11/750,UNIX
+GREGORIO IN CNAME SU-GREGORIO.ARPA
+SU-LINDY IN A 36.9.0.11
+ IN HINFO VAX-11/780,UNIX
+LINDY IN CNAME SU-LINDY.ARPA
+SU-HPP-3670-3 IN A 36.47.0.11
+ IN HINFO SYMBOLICS-3670,LISPM
+HPP-3670-3 IN CNAME SU-HPP-3670-3.ARPA
+SU-FORSYTHE IN A 36.9.0.12
+ IN HINFO IBM-3081,MVS
+FORSYTHE IN CNAME SU-FORSYTHE.ARPA
+SU-HPP-3670-4 IN A 36.47.0.12
+ IN HINFO SYMBOLICS-3670,LISPM
+HPP-3670-4 IN CNAME SU-HPP-3670-4.ARPA
+SU-CSLI IN A 36.18.0.93
+ IN HINFO DEC-2060,TOPS20
+CSLI IN CNAME SU-CSLI.ARPA
+TURING IN CNAME SU-CSLI.ARPA
+SU-TURING IN CNAME SU-CSLI.ARPA
+SU-SHASTA IN A 36.40.0.192
+ IN HINFO VAX-11/780,UNIX
+SHASTA IN CNAME SU-SHASTA.ARPA
+SU-AIMVAX IN A 36.45.0.193
+ IN HINFO VAX-11/780,UNIX
+AIMVAX IN CNAME SU-AIMVAX.ARPA
+SU-DIABLO IN CNAME SU-AIMVAX.ARPA
+DIABLO IN CNAME SU-AIMVAX.ARPA
+SU-HNV IN CNAME SU-AIMVAX.ARPA
+SU-HELENS IN A 36.40.0.199
+ IN A 36.2.0.5
+ IN HINFO VAX-11/780,UNIX
+HELENS IN CNAME SU-HELENS.ARPA
+SU-DSN IN A 36.40.0.200
+ IN HINFO VAX-11/780,UNIX
+DSN IN CNAME SU-DSN.ARPA
+SU-ISL IN A 36.40.0.201
+ IN HINFO VAX-11/780,UNIX
+ISL IN CNAME SU-ISL.ARPA
+SU-NAVAJO IN A 36.36.0.203
+ IN HINFO VAX-11/780,UNIX
+NAVAJO IN CNAME SU-NAVAJO.ARPA
+SU-NA-VAX IN CNAME SU-NAVAJO.ARPA
+SU-WHITNEY IN A 36.18.0.204
+ IN HINFO VAX-11/780,UNIX
+WHITNEY IN CNAME SU-WHITNEY.ARPA
+SU-ROBOTICS IN CNAME SU-WHITNEY.ARPA
+SU-GLACIER IN A 36.40.0.205
+ IN HINFO VAX-11/750,UNIX
+GLACIER IN CNAME SU-GLACIER.ARPA
+SU-ICL IN CNAME SU-GLACIER.ARPA
+SU-FUJI IN A 36.40.0.206
+ IN HINFO VAX-11/780,UNIX
+FUJI IN CNAME SU-FUJI.ARPA
+SU-GSB-WHY IN A 36.19.0.209
+ IN HINFO DEC-2060,TOPS20
+WHY IN CNAME SU-GSB-WHY.ARPA
+SU-GSB-HOW IN A 36.19.0.210
+ IN HINFO DEC-2060,TOPS20
+HOW IN CNAME SU-GSB-HOW.ARPA
+SU-SIERRA IN A 36.40.0.213
+ IN A 36.10.0.13
+ IN HINFO DEC-2060,TOPS20
+SIERRA IN CNAME SU-SIERRA.ARPA
+SU-COYOTE IN A 36.18.0.215
+ IN HINFO VAX-11/750,UNIX
+COYOTE IN CNAME SU-COYOTE.ARPA
+SU-CASCADE IN A 36.40.0.216
+ IN HINFO VAX-11/750,UNIX
+CASCADE IN CNAME SU-CASCADE.ARPA
+UCL-SAM IN A 128.16.9.0
+ IN HINFO LSI-11/23,MOS
+DCN1 IN A 128.4.0.1
+ IN A 10.0.0.111
+ IN HINFO LSI-11/23,FUZZ
+POGO IN CNAME DCN1.ARPA
+FORD1 IN A 128.5.0.1
+ IN HINFO LS1-11/23,FUZZ
+FORD IN CNAME FORD1.ARPA
+FORD-WDL1 IN A 128.5.32.1
+ IN HINFO VAX-11/780,UNIX
+FACC IN CNAME FORD-WDL1.ARPA
+FORD-SCF1 IN A 128.5.33.1
+ IN HINFO VAX-11/780,UNIX
+FORD-COS1 IN A 128.5.34.1
+ IN HINFO VAX-11/780,UNIX
+FORD-HOU1 IN A 128.5.35.1
+ IN HINFO VAX-11/780,UNIX
+FORD-MAC1 IN A 128.5.37.1
+ IN HINFO MC500,UNIX
+DFVLR1 IN A 128.7.0.1
+ IN HINFO LSI-11/23,FUZZ
+OBERPFAFFENHOFEN IN CNAME DFVLR1.ARPA
+UMD1 IN A 128.8.0.1
+ IN HINFO LSI-11/23,FUZZ
+UMD IN CNAME UMD1.ARPA
+PURDUE IN A 128.10.0.1
+ IN A 10.0.0.37
+ IN A 192.5.48.1
+ IN HINFO VAX-11/780,UNIX
+PURDUE-CS IN CNAME PURDUE.ARPA
+PURDUE-ARTHUR IN CNAME PURDUE.ARPA
+ARTHUR IN CNAME PURDUE.ARPA
+UCL-PROBE IN A 128.16.9.1
+ IN HINFO ,LOGICAL-HOST
+SRI-MED IN A 128.18.0.1
+ IN HINFO SUN-150,UNIX
+MED IN CNAME SRI-MED.ARPA
+SRI-VAX IN A 128.18.10.1
+ IN HINFO VAX-11/782,VMS
+SRI-CRVAX IN CNAME SRI-VAX.ARPA
+CRVAX IN CNAME SRI-VAX.ARPA
+EDN-HOST1 IN A 128.19.1.1
+ IN HINFO PDP-11/45,UNIX
+BRL-TAC1 IN A 128.20.2.1
+ IN HINFO C/30,TAC
+AMSAA IN A 128.20.3.1
+ IN HINFO VAX-11/780,UNIX
+AMSAA-VMS IN A 128.20.4.1
+ IN HINFO VAX-11/780,VMS
+RICE-GOLIATH IN A 128.42.2.1
+ IN HINFO IBM-4341,VM/CMS
+GOLIATH IN CNAME RICE-GOLIATH.ARPA
+RICE-MIMAS IN A 128.42.3.1
+ IN HINFO VAX-11/750,UNIX
+MIMAS IN CNAME RICE-MIMAS.ARPA
+RICE-ZETA IN A 128.42.4.1
+ IN HINFO VAX-11/750,UNIX
+ZETA IN CNAME RICE-ZETA.ARPA
+WSMR03 IN A 128.44.0.1
+ IN HINFO C/70,UNIX
+WSMR-03 IN CNAME WSMR03.ARPA
+WSMR04 IN A 128.44.1.1
+ IN HINFO C/70,UNIX
+WSMR-04 IN CNAME WSMR04.ARPA
+WSMR05 IN A 128.44.2.1
+ IN HINFO C/70,UNIX
+WSMR-05 IN CNAME WSMR05.ARPA
+NOSC-BUGS IN A 128.49.0.1
+ IN HINFO VAX-11/750,UNIX
+BUGS IN CNAME NOSC-BUGS.ARPA
+NOSC-SHARK IN A 128.49.1.1
+ IN HINFO UNIVAC-1100,OS-1100
+SHARK IN CNAME NOSC-SHARK.ARPA
+NOSC-FROG IN A 128.49.129.1
+ IN HINFO VAX-11/780,UNIX
+FROG IN CNAME NOSC-FROG.ARPA
+SDCSVAX IN A 128.54.0.1
+ IN HINFO VAX-11/780,UNIX
+UCSD IN CNAME SDCSVAX.ARPA
+CMU-EE-FARADAY IN A 128.2.251.2
+ IN HINFO VAX-11/780,UNIX
+DCN2 IN A 128.4.0.2
+ IN HINFO LSI-11/2,FUZZ
+BOOMBAH IN CNAME DCN2.ARPA
+FORD2 IN A 128.5.0.2
+ IN HINFO LSI-11/23,FUZZ
+FORD-WDL2 IN A 128.5.32.2
+ IN HINFO PDP-11/70,UNIX
+FORD-COS2 IN A 128.5.34.2
+ IN HINFO PDP-11/70,UNIX
+FORD-MAC2 IN A 128.5.37.2
+ IN HINFO IMAGEN-8/300,UNIX
+DFVLR2 IN A 128.7.0.2
+ IN HINFO LSI-11/23,FUZZ
+UMD2 IN A 128.8.0.2
+ IN HINFO UNIVAC-1100,OS-1100
+UMD-UNIVAC IN CNAME UMD2.ARPA
+UNIVAC IN CNAME UMD2.ARPA
+PURDUE-MORDRED IN A 128.10.0.2
+ IN A 192.5.48.2
+ IN HINFO VAX-11/780,UNIX
+MORDRED IN CNAME PURDUE-MORDRED.ARPA
+BBN-CVAX IN A 128.11.0.2
+ IN HINFO VAX-11/750,VMS
+CVAX IN CNAME BBN-CVAX.ARPA
+UCL-TERMINAL-GATEWAY IN A 128.16.3.2
+UCL-TG IN A 128.16.9.2
+ IN A 14.0.0.5
+ IN HINFO ,LOGICAL-HOST
+SRI-OVAX IN A 128.18.10.2
+ IN HINFO VAX-11/780,VMS
+OVAX IN CNAME SRI-OVAX.ARPA
+BRL-HEP IN A 128.20.1.2
+ IN HINFO PDP-11/44,UNIX
+BRL-TAC2 IN A 128.20.2.2
+ IN HINFO C/30,TAC
+BRL-VOC IN A 128.20.3.2
+ IN A 192.5.22.18
+ IN HINFO VAX-11/750,UNIX
+VOC IN CNAME BRL-VOC.ARPA
+BRL-VAT IN A 128.20.4.2
+ IN HINFO VAX-11/750,UNIX
+VAT IN CNAME BRL-VAT.ARPA
+SRI-SPAM IN A 128.21.32.2
+ IN A 192.5.38.3
+ IN HINFO VAX-11/780,UNIX
+SPAM IN CNAME SRI-SPAM.ARPA
+YALE-RING IN A 128.36.0.2
+ IN HINFO APOLLO,DOMAIN
+RICE-RHEA IN A 128.42.1.2
+ IN HINFO VAX-11/750,UNIX
+RHEA IN CNAME RICE-RHEA.ARPA
+RICE-TETHYS IN A 128.42.3.2
+ IN HINFO VAX-11/750,UNIX
+TETHYS IN CNAME RICE-TETHYS.ARPA
+WSMR06 IN A 128.44.1.2
+ IN HINFO C/70,UNIX
+WSMR-06 IN CNAME WSMR06.ARPA
+WSMR IN CNAME WSMR06.ARPA
+WSMR07 IN A 128.44.2.2
+ IN HINFO C/70,UNIX
+WSMR-07 IN CNAME WSMR07.ARPA
+WSMR09 IN A 128.44.3.2
+ IN HINFO C/70,UNIX
+WSMR-09 IN CNAME WSMR09.ARPA
+WSMR10 IN A 128.44.4.2
+ IN HINFO C/70,UNIX
+WSMR-10 IN CNAME WSMR10.ARPA
+CMU-EE-MAXWELL IN A 128.2.251.3
+ IN HINFO VAX-11/750,UNIX
+DCN3 IN A 128.4.0.3
+ IN HINFO LSI-11/23,FUZZ
+ALBERT IN CNAME DCN3.ARPA
+FORD3 IN A 128.5.0.3
+ IN HINFO LSI-11/23,FUZZ
+FORD-WDL3 IN A 128.5.32.3
+ IN HINFO PDP-11/34,DCN
+FORD-COS3 IN A 128.5.34.3
+ IN HINFO ONYX-Z8000,UNIX
+FORD-MAC3 IN A 128.5.37.3
+ IN HINFO SUN-2/120,UNIX
+RU-GREEN IN A 128.6.0.3
+ IN HINFO DEC-2060,TOPS20
+DFVLR3 IN A 128.7.0.3
+UMD3 IN A 128.8.0.3
+ IN HINFO LSI-11/23,FUZZ
+UCL-CS IN A 128.16.9.3
+ IN HINFO ,LOGICAL-HOST
+UCL IN CNAME UCL-CS.ARPA
+SRI-UNIX IN A 128.18.10.3
+ IN HINFO PYRAMID-90X,UNIX
+SRI-PRISM IN CNAME SRI-UNIX.ARPA
+PRISM IN CNAME SRI-UNIX.ARPA
+BRL-TBD IN A 128.20.0.3
+ IN HINFO VAX-11/780,UNIX
+TBD IN CNAME BRL-TBD.ARPA
+BRL-TAC3 IN A 128.20.2.3
+ IN HINFO C/30,TAC
+SAC-VAX IN A 128.26.32.3
+ IN A 10.0.0.80
+ IN HINFO VAX-11/780,UNIX
+SRI-SPUD IN CNAME SAC-VAX.ARPA
+SPUD IN CNAME SAC-VAX.ARPA
+YALE-PENGUIN IN A 128.36.0.3
+ IN HINFO VAX-11/750,UNIX
+PENGUIN IN CNAME YALE-PENGUIN.ARPA
+NTARE1 IN A 128.39.0.3
+ IN HINFO LSI-11/23,FUZZ
+NTARE IN CNAME NTARE1.ARPA
+RICE-JANUS IN A 128.42.1.3
+ IN HINFO VAX-11/780,VMS
+RICE-VMS IN CNAME RICE-JANUS.ARPA
+RICE-780 IN CNAME RICE-JANUS.ARPA
+RICE-HYPERION IN A 128.42.3.3
+ IN HINFO VAX-11/750,UNIX
+HYPERION IN CNAME RICE-HYPERION.ARPA
+HYP IN CNAME RICE-HYPERION.ARPA
+WSMR08 IN A 128.44.0.3
+ IN HINFO C/70,UNIX
+WSMR-08 IN CNAME WSMR08.ARPA
+WSMR02 IN A 128.44.1.3
+ IN HINFO C/70,UNIX
+WSMR-02 IN CNAME WSMR02.ARPA
+WSMRB IN CNAME WSMR02.ARPA
+WSMR70B IN CNAME WSMR02.ARPA
+NOSC-GUPPY IN A 128.49.0.3
+ IN HINFO VAX-11/750,UNIX
+GUPPY IN CNAME NOSC-GUPPY.ARPA
+CMU-EE-GAUSS IN A 128.2.251.4
+ IN HINFO VAX-11/780,UNIX
+DCN4 IN A 128.4.0.4
+ IN HINFO LSI-11/23,FUZZ
+HOWLAND IN CNAME DCN4.ARPA
+FORD4 IN A 128.5.0.4
+ IN HINFO LSI-11/23,FUZZ
+FORD-WDL4 IN A 128.5.32.4
+ IN HINFO ONYX-Z8000,UNIX
+FORD-MAC4 IN A 128.5.37.4
+ IN HINFO SUN-2/120,UNIX
+RU-BLUE IN A 128.6.0.4
+ IN HINFO DEC-2060,TOPS20
+CVL IN A 128.8.0.4
+ IN HINFO VAX-11/780,UNIX
+UMD4 IN CNAME CVL.ARPA
+UCL-NIFTP IN A 128.16.9.4
+ IN HINFO ,LOGICAL-HOST
+BRL-LFD IN A 128.20.0.4
+ IN HINFO VAX-11/780,VMS
+LFD IN CNAME BRL-LFD.ARPA
+BRL-TAC4 IN A 128.20.2.4
+ IN HINFO C/30,TAC
+SRI-ROLM IN A 128.21.48.4
+ IN HINFO ROLM-1666,RMX/RDOS
+YALE-CHEOPS IN A 128.36.0.4
+ IN HINFO PYRAMID-90X,UNIX
+CHEOPS IN CNAME YALE-CHEOPS.ARPA
+RICE-IAPETUS IN A 128.42.1.4
+ IN HINFO VAX-11/750,UNIX
+IAPETUS IN CNAME RICE-IAPETUS.ARPA
+IAP IN CNAME RICE-IAPETUS.ARPA
+RICE-PHOBOS IN A 128.42.3.4
+ IN HINFO PDP-11/44,UNIX
+PHOBOS IN CNAME RICE-PHOBOS.ARPA
+NOSC-MARLIN IN A 128.49.0.4
+ IN HINFO VAX-11/780,UNIX
+MARLIN IN CNAME NOSC-MARLIN.ARPA
+DCN5 IN A 128.4.0.5
+ IN HINFO LSI-11/23,FUZZ
+HEPZIBAH IN CNAME DCN5.ARPA
+FORD-WDL5 IN A 128.5.32.5
+ IN HINFO ONYX-Z8000,UNIX
+FORD-MAC5 IN A 128.5.37.5
+ IN HINFO SUN-2/120,UNIX
+UMD5 IN A 128.8.0.5
+ IN HINFO PDP-11/44,UNIX
+HEL-ACE IN A 128.20.0.5
+ IN HINFO VAX-11/750,UNIX
+ACE IN CNAME HEL-ACE.ARPA
+HEL-CPX IN A 128.20.1.5
+ IN HINFO VAX-11/750,UNIX
+CPX IN CNAME HEL-CPX.ARPA
+UCBCAD IN A 128.32.0.5
+ IN HINFO VAX-11/780,UNIX
+OSLO-VAX IN A 128.39.0.5
+ IN HINFO VAX-11/780,UNIX
+OSLO IN CNAME OSLO-VAX.ARPA
+RICE-CERES IN A 128.42.1.5
+ IN HINFO SUN-100,UNIX
+CERES IN CNAME RICE-CERES.ARPA
+NOSC-COD IN A 128.49.0.5
+ IN HINFO VAX-11/780,UNIX
+COD IN CNAME NOSC-COD.ARPA
+MIT-TINMAN IN A 128.52.22.5
+ IN HINFO VAX-11/750,UNIX
+TINMAN IN CNAME MIT-TINMAN.ARPA
+MIT-HTJR IN CNAME MIT-TINMAN.ARPA
+HTJR IN CNAME MIT-TINMAN.ARPA
+CMU-EE-HENRY IN A 128.2.251.6
+ IN HINFO VAX-11/780,UNIX
+DCN6 IN A 128.4.0.6
+ IN HINFO LSI-11/23,FUZZ
+BACKROOM IN CNAME DCN6.ARPA
+FORD-WDL6 IN A 128.5.32.6
+ IN HINFO PDP-11/34,DCN
+UMD6 IN A 128.8.0.6
+PURDUE-MERLIN IN A 128.10.0.6
+ IN A 192.5.48.3
+ IN HINFO VAX-11/780,UNIX
+MERLIN IN CNAME PURDUE-MERLIN.ARPA
+CRDC IN A 128.20.0.6
+ IN HINFO VAX-11/780,UNIX
+CRDC-VAX2 IN A 128.20.1.6
+ IN HINFO VAX-11/780,UNIX
+CRDC-TAC IN A 128.20.2.6
+ IN HINFO C/30,TAC
+CRDC-PADEA IN A 128.20.3.6
+ IN HINFO VAX-11/750,UNIX
+PADEA IN CNAME CRDC-PADEA.ARPA
+UCBERNIE IN A 128.32.0.6
+ IN HINFO VAX-11/780,UNIX
+RICE-PALLAS IN A 128.42.1.6
+ IN HINFO SUN-100U,UNIX
+PALLAS IN CNAME RICE-PALLAS.ARPA
+NOSC-PERCH IN A 128.49.0.6
+ IN HINFO PDP-11/70,UNIX
+PERCH IN CNAME NOSC-PERCH.ARPA
+DCN7 IN A 128.4.0.7
+ IN HINFO LSI-11/23,FUZZ
+SNAVELY IN CNAME DCN7.ARPA
+UMD7 IN A 128.8.0.7
+ IN HINFO UNIVAC-1100,OS-1100
+UCBMONET IN A 128.32.0.7
+ IN HINFO VAX-11/750,UNIX
+YALE-APVAX IN A 128.36.0.7
+ IN HINFO VAX-11/785,VMS
+RICE-VESTA IN A 128.42.1.7
+ IN HINFO SUN-100,UNIX
+VESTA IN CNAME RICE-VESTA.ARPA
+NOSC-TROUT IN A 128.49.0.7
+ IN HINFO VAX-11/750,UNIX
+TROUT IN CNAME NOSC-TROUT.ARPA
+DCN8 IN A 128.4.0.8
+ IN HINFO LSI-11/23,FUZZ
+PORKYPINE IN CNAME DCN8.ARPA
+FORD-LAB IN A 128.5.0.8
+ IN HINFO LSI-11/23,FUZZ
+FORD8 IN CNAME FORD-LAB.ARPA
+FORD-WDL8 IN A 128.5.32.8
+ IN HINFO M-6800,CMOS
+YALE-NAVAX IN A 128.36.0.8
+ IN HINFO VAX-11/750,VMS
+RICE-NEXUS IN A 128.42.1.8
+ IN HINFO SUN-150U,UNIX
+NEXUS IN CNAME RICE-NEXUS.ARPA
+NOSC-EEL IN A 128.49.0.8
+ IN HINFO VAX-11/750,UNIX
+EEL IN CNAME NOSC-EEL.ARPA
+DCN9 IN A 128.4.0.9
+ IN HINFO SUN-170,UNIX
+CHURCHY IN CNAME DCN9.ARPA
+FORD-VAX IN A 128.5.0.9
+ IN HINFO VAX-11/780,VMS
+FORD9 IN CNAME FORD-VAX.ARPA
+FORD-WDL9 IN A 128.5.32.9
+ IN HINFO M-6800,CMOS
+UMD9 IN A 128.8.0.9
+ IN HINFO LSI-11/23,FUZZ
+BBN-META IN A 128.11.0.9
+ IN HINFO C/70,UNIX
+META IN CNAME BBN-META.ARPA
+STC IN A 128.16.9.9
+ IN HINFO LSI-11/23,FUZZ
+YALE-LM1 IN A 128.36.0.9
+ IN HINFO SYMBOLICS-3670,LISPM
+RICE-EESUN IN A 128.42.1.9
+ IN HINFO SUN-150,UNIX
+EESUN IN CNAME RICE-EESUN.ARPA
+FORD-RES IN A 128.5.0.10
+ IN HINFO DEC-2060,TOPS20
+FORDA IN CNAME FORD-RES.ARPA
+FORD-20 IN CNAME FORD-RES.ARPA
+FORD-WDL10 IN A 128.5.32.10
+ IN HINFO M-6800,CMOS
+UMDA IN A 128.8.0.10
+ IN HINFO IBM-4341,VM
+UMDVMA IN CNAME UMDA.ARPA
+YALE-LM2 IN A 128.36.0.10
+ IN HINFO SYMBOLICS-3670,LISPM
+RICE-INVADER IN A 128.42.1.10
+ IN HINFO SUN-100,UNIX
+INVADER IN CNAME RICE-INVADER.ARPA
+MKDSUN IN CNAME RICE-INVADER.ARPA
+FORD-ECC IN A 128.5.0.11
+ IN HINFO H-68,MULTICS
+FORDB IN CNAME FORD-ECC.ARPA
+UMDB IN A 128.8.0.11
+ IN HINFO IBM-4341,VM
+UMDVMB IN CNAME UMDB.ARPA
+UCBKIM IN A 128.32.0.11
+ IN HINFO VAX-11/780,UNIX
+YALE-LM3 IN A 128.36.0.11
+ IN HINFO SYMBOLICS-3670,LISPM
+RICE-ENCELADUS IN A 128.42.1.11
+ IN HINFO SUN-100U,UNIX
+ENCELADUS IN CNAME RICE-ENCELADUS.ARPA
+ENC IN CNAME RICE-ENCELADUS.ARPA
+FORD-SRL IN A 128.5.0.12
+ IN HINFO LSI-11/23,FUZZ
+FORDC IN CNAME FORD-SRL.ARPA
+UMDC IN A 128.8.0.12
+ IN HINFO IBM-4341,VM
+UCBCALDER IN A 128.32.0.12
+ IN HINFO VAX-11/750,UNIX
+YALE-LM4 IN A 128.36.0.12
+ IN HINFO SYMBOLICS-3670,LISPM
+RICE-JUNO IN A 128.42.1.12
+ IN HINFO SUN-100U,UNIX
+JUNO IN CNAME RICE-JUNO.ARPA
+FORD-ERS IN A 128.5.0.13
+ IN HINFO LSI-11/23,
+FORDD IN CNAME FORD-ERS.ARPA
+DEARBORN IN CNAME FORD-ERS.ARPA
+UMDD IN A 128.8.0.13
+UCBDALI IN A 128.32.0.13
+ IN HINFO VAX-11/750,UNIX
+YALE-MTRANS IN A 128.36.0.13
+ IN HINFO VAX-11/750,UNIX
+RICE-POLARIS IN A 128.42.1.13
+ IN HINFO SUN-100,UNIX
+POLARIS IN CNAME RICE-POLARIS.ARPA
+LBL-UX4 IN A 128.3.254.14
+ IN HINFO VAX-11/780,UNIX
+FORD-EED IN A 128.5.0.14
+ IN HINFO LSI-11/23,FUZZ
+FORDE IN CNAME FORD-EED.ARPA
+DPTC IN CNAME FORD-EED.ARPA
+UMDE IN A 128.8.0.14
+ IN HINFO LSI-11/23,FUZZ
+UCBMATISSE IN A 128.32.0.14
+ IN HINFO VAX-11/750,UNIX
+YALE-PTRANS IN A 128.36.0.14
+ IN HINFO VAX-11/750,UNIX
+RICE-THEMIS IN A 128.42.1.14
+ IN HINFO SUN-120,UNIX
+THEMIS IN CNAME RICE-THEMIS.ARPA
+MIT-PREP IN A 128.52.22.14
+ IN HINFO VAX-11/750,UNIX
+PREP IN CNAME MIT-PREP.ARPA
+PREP-VAX IN CNAME MIT-PREP.ARPA
+LBL-UX5 IN A 128.3.254.15
+ IN HINFO VAX-11/750,UNIX
+DCN-ECHO IN A 128.4.0.15
+FORD-FOE IN A 128.5.0.15
+ IN HINFO LSI-11/23,FUZZ
+FORDF IN CNAME FORD-FOE.ARPA
+DUNTON IN CNAME FORD-FOE.ARPA
+UMDF IN A 128.8.0.15
+ IN HINFO UNIVAC-1100,OS-1100
+UMD-UNIVAC-TEST IN CNAME UMDF.ARPA
+YALE-ELI IN A 128.36.0.15
+ IN HINFO VAX-11/750,VMS
+RICE-RN01 IN A 128.42.1.15
+ IN HINFO LSI-11/2,FUZZ
+RN01 IN CNAME RICE-RN01.ARPA
+LBL-UX6 IN A 128.3.254.16
+ IN HINFO VAX-11/750,UNIX
+GYMBLE IN A 128.8.128.16
+ IN HINFO PYRAMID-90X,UNIX
+UMD-GYMBLE IN CNAME GYMBLE.ARPA
+S1-ATLANTIS IN A 128.15.0.16
+ IN HINFO SUN-150,UNIX
+ATLANTIS IN CNAME S1-ATLANTIS.ARPA
+YALE-MBUILD IN A 128.36.0.16
+ IN HINFO VAX-11/750,UNIX
+RICE-EOS IN A 128.42.1.16
+ IN HINFO SUN-120,UNIX
+EOS IN CNAME RICE-EOS.ARPA
+FORD-WDL17 IN A 128.5.32.17
+ IN HINFO MC500,UNIX
+AMANDA IN A 128.8.128.17
+ IN HINFO PDP-11/45,UNIX
+UMD-AMANDA IN CNAME AMANDA.ARPA
+YALE-COMIX IN A 128.36.0.17
+ IN HINFO VAX-11/750,UNIX
+RICE-CHIRON IN A 128.42.1.17
+ IN HINFO SUN-120,UNIX
+CHIRON IN CNAME RICE-CHIRON.ARPA
+FORD-WDL18 IN A 128.5.32.18
+ IN HINFO IMAGEN-8/300,UNIX
+YALE-VLSIVAX IN A 128.36.0.18
+ IN HINFO VAX-11/750,UNIX
+RICE-THULE IN A 128.42.1.18
+ IN HINFO SUN-120,UNIX
+THULE IN CNAME RICE-THULE.ARPA
+FORD-WDL19 IN A 128.5.32.19
+UCBINGRES IN A 128.32.0.19
+ IN HINFO VAX-11/780,UNIX
+YALE-ZOO IN A 128.36.0.19
+ IN HINFO APOLLO,AEGIS
+RICE-ATEN IN A 128.42.1.19
+ IN HINFO SUN-120,UNIX
+ATEN IN CNAME RICE-ATEN.ARPA
+FORD-WDL20 IN A 128.5.32.20
+ IN HINFO SUN-2/170,UNIX
+RICE-ENDYMION IN A 128.42.1.20
+ IN HINFO SUN-120,UNIX
+ENDYMION IN CNAME RICE-ENDYMION.ARPA
+LBL-G IN A 128.3.0.21
+ IN HINFO VAX-11/780,VMS
+FORD-WDL21 IN A 128.5.32.21
+ IN HINFO SUN-2/120,UNIX
+RICE-HEKTOR IN A 128.42.1.21
+ IN HINFO SUN-120,UNIX
+HEKTOR IN CNAME RICE-HEKTOR.ARPA
+CMU-CS-SC IN A 128.2.250.22
+ IN HINFO VAX-11/750,VMS
+LBL-H IN A 128.3.0.22
+ IN HINFO VAX-11/780,VMS
+FORD-WDL22 IN A 128.5.32.22
+ IN HINFO SUN-2/120,UNIX
+UCBDEGAS IN A 128.32.0.22
+ IN HINFO VAX-11/750,UNIX
+RICE-CERBERUS IN A 128.42.1.22
+ IN HINFO SUN-120,UNIX
+CERBERUS IN CNAME RICE-CERBERUS.ARPA
+MIT-HTVAX IN A 128.52.22.22
+ IN HINFO VAX-11/780,UNIX
+HTVAX IN CNAME MIT-HTVAX.ARPA
+MIT-HT IN CNAME MIT-HTVAX.ARPA
+HT IN CNAME MIT-HTVAX.ARPA
+CMU-CS-FT IN A 128.2.250.23
+ IN HINFO VAX-11/750,VMS
+FORD-WDL23 IN A 128.5.32.23
+ IN HINFO SUN-2/120,UNIX
+RICE-PROSERPINA IN A 128.42.1.23
+ IN HINFO SUN-120,UNIX
+PROSERPINA IN CNAME RICE-PROSERPINA.ARPA
+FORD-WDL24 IN A 128.5.32.24
+ IN HINFO SUN-2/120,UNIX
+CHESSIE IN A 128.8.128.24
+ IN HINFO PDP-11/24,UNIX
+UMD-CHESSIE IN CNAME CHESSIE.ARPA
+ISI-ACCUTEST IN A 128.9.0.24
+ IN HINFO LSI-11/23,RSX11M
+RICE-ASTRAEA IN A 128.42.1.24
+ IN HINFO SUN-120,UNIX
+ASTRAEA IN CNAME RICE-ASTRAEA.ARPA
+LBL-K IN A 128.3.255.25
+ IN HINFO VAX-11/750,VMS
+FORD-WDL25 IN A 128.5.32.25
+ IN HINFO SUN-2/120,UNIX
+RICE-ARIADNE IN A 128.42.1.25
+ IN HINFO SUN-120,UNIX
+ARIADNE IN CNAME RICE-ARIADNE.ARPA
+FORD-WDL26 IN A 128.5.32.26
+ IN HINFO SUN-2/120,UNIX
+RICE-HYPATIA IN A 128.42.1.26
+ IN HINFO SUN-120,UNIX
+HYPATIA IN CNAME RICE-HYPATIA.ARPA
+FORD-WDL27 IN A 128.5.32.27
+ IN HINFO SUN-2/120,UNIX
+RICE-DIOMEDES IN A 128.42.1.27
+ IN HINFO SUN-120,UNIX
+DIOMEDES IN CNAME RICE-DIOMEDES.ARPA
+FORD-WDL28 IN A 128.5.32.28
+ IN HINFO SUN-2/120,UNIX
+RICE-EUPHROSENE IN A 128.42.1.28
+ IN HINFO SUN-120,UNIX
+EUPHROSENE IN CNAME RICE-EUPHROSENE.ARPA
+FORD-WDL29 IN A 128.5.32.29
+ IN HINFO SUN-2/120,UNIX
+RICE-URANIA IN A 128.42.1.29
+ IN HINFO SUN-100,UNIX
+URANIA IN CNAME RICE-URANIA.ARPA
+RICE-TITAN IN A 128.42.1.30
+ IN HINFO VAX-11/790,UNIX
+TITAN IN CNAME RICE-TITAN.ARPA
+UCBRENOIR IN A 128.32.0.31
+ IN HINFO VAX-11/750,UNIX
+RICE-PHOEBE IN A 128.42.1.31
+ IN HINFO VAX-11/750,VMS
+PHOEBE IN CNAME RICE-PHOEBE.ARPA
+RICE-RA IN A 128.42.1.32
+ IN HINFO PYRAMID-90,UNIX
+RA IN CNAME RICE-RA.ARPA
+UCBMIKE IN A 128.32.131.33
+ IN HINFO SUN-120,UNIX
+ISI-VAXC IN A 128.9.0.35
+ IN HINFO VAX-11/780,VMS
+VAXC IN CNAME ISI-VAXC.ARPA
+MIT-HERMES IN A 128.52.22.37
+ IN HINFO VAX-11/750,UNIX
+HERMES IN CNAME MIT-HERMES.ARPA
+MIT-YAK IN CNAME MIT-HERMES.ARPA
+YAK IN CNAME MIT-HERMES.ARPA
+ISI-ELVIRA IN A 128.9.0.41
+ IN HINFO VAX-11/750,UNIX
+ELVIRA IN CNAME ISI-ELVIRA.ARPA
+TOVE IN A 128.8.128.42
+ IN HINFO VAX-11/750,UNIX
+UMD-TOVE IN CNAME TOVE.ARPA
+SRI-THX1138 IN A 128.18.8.42
+ IN HINFO PDP-11/70,UNIX
+THX1138 IN CNAME SRI-THX1138.ARPA
+THX IN CNAME SRI-THX1138.ARPA
+LBL-NMC IN A 128.3.254.43
+ IN HINFO VAX-11/780,VMS
+LBL-NMM IN CNAME LBL-NMC.ARPA
+ISI-VLSIE IN A 128.9.0.43
+ IN HINFO VAX-11/750,VMS
+VLSIE IN CNAME ISI-VLSIE.ARPA
+LBL-PDM IN A 128.3.254.44
+ IN HINFO VAX-11/780,VMS
+ISI-TROLL IN A 128.9.0.44
+ IN HINFO VAX-11/750,UNIX
+TROLL IN CNAME ISI-TROLL.ARPA
+LBL-IGM IN A 128.3.254.45
+ IN HINFO VAX-11/780,VMS
+ISI-VLSIF IN A 128.9.0.45
+ IN HINFO VAX-11/750,UNIX
+VLSIF IN CNAME ISI-VLSIF.ARPA
+ISI-CURLY IN CNAME ISI-VLSIF.ARPA
+CURLY IN CNAME ISI-VLSIF.ARPA
+ISI-SHEMP IN A 128.9.0.46
+ IN HINFO VAX-11/750,VMS
+SHEMP IN CNAME ISI-SHEMP.ARPA
+ISI-VLSID IN A 128.9.0.47
+ IN HINFO VAX-11/750,VMS
+VLSID IN CNAME ISI-VLSID.ARPA
+ISI-VLSIC IN A 128.9.0.48
+ IN HINFO VAX-11/750,VMS
+VLSIC IN CNAME ISI-VLSIC.ARPA
+ISI-VLSIA IN A 128.9.0.49
+ IN HINFO VAX-11/750,VMS
+VLSIA IN CNAME ISI-VLSIA.ARPA
+ISI-VLSIB IN A 128.9.0.50
+ IN HINFO VAX-11/750,VMS
+VLSIB IN CNAME ISI-VLSIB.ARPA
+NCNA IN A 128.18.0.50
+ IN HINFO VAX-11/730,UNIX
+SRI-NCNA IN CNAME NCNA.ARPA
+LBL-HISS IN A 128.3.255.51
+ IN HINFO VAX-11/780,VMS
+NCNB IN A 128.18.0.51
+ IN HINFO VAX-11/730,UNIX
+SRI-NCNB IN CNAME NCNB.ARPA
+SRI-STATION1 IN A 128.21.0.59
+ IN HINFO LSI-11/23,ELF
+UCL-LSIH IN A 128.16.1.67
+ IN HINFO LSI-11/23,MOS
+SRI-STATION2 IN A 128.21.0.67
+ IN HINFO LSI-11/23,ELF
+LBL-RTSG IN A 128.3.255.68
+ IN HINFO VAX-11/780,UNIX
+SRI-STATION3 IN A 128.21.0.75
+ IN HINFO LSI-11/23,ELF
+GYRE IN A 128.8.128.77
+ IN HINFO VAX-11/750,UNIX
+UMD-GYRE IN CNAME GYRE.ARPA
+ISI-DAWN IN A 128.9.0.92
+ IN HINFO SUN-150U,UNIX
+DAWN IN CNAME ISI-DAWN.ARPA
+ISI-SUN5 IN CNAME ISI-DAWN.ARPA
+ISI-RISING IN A 128.9.0.93
+ IN HINFO SUN-120,UNIX
+RISING IN CNAME ISI-RISING.ARPA
+ISI-SUN4 IN CNAME ISI-RISING.ARPA
+ISI-HELIOS IN A 128.9.0.94
+ IN HINFO SUN-100U,UNIX
+HELIOS IN CNAME ISI-HELIOS.ARPA
+ISI-SUN6 IN CNAME ISI-HELIOS.ARPA
+ISI-BABETTE IN A 128.9.0.95
+ IN HINFO SUN-120,UNIX
+BABETTE IN CNAME ISI-BABETTE.ARPA
+ISI-SUN7 IN CNAME ISI-BABETTE.ARPA
+LBL-ADV2 IN A 128.3.254.99
+ IN HINFO IS-1,UNIX
+LOKI IN A 128.11.0.100
+ IN HINFO SUN-100,UNIX
+BBN-LOKI IN CNAME LOKI.ARPA
+LBL-ACAL2 IN A 128.3.254.102
+ IN HINFO VAX-11/780,VMS
+LBL-ACAL3 IN A 128.3.255.103
+ IN HINFO VAX-11/780,VMS
+LBL-ACAL4 IN A 128.3.255.104
+ IN HINFO VAX-11/780,VMS
+SRI-MARS IN A 128.18.0.104
+ IN HINFO SUN-100,UNIX
+MARS IN CNAME SRI-MARS.ARPA
+LBL-ACAL5 IN A 128.3.255.105
+ IN HINFO VAX-11/780,VMS
+UCL-LSIL IN A 128.16.1.106
+ IN HINFO LSI-11/23,MOS
+SRI-NEPTUNE IN A 128.18.0.107
+ IN HINFO SUN-120,UNIX
+SAC-STATION-2 IN A 128.26.0.107
+ IN HINFO LSI-11/23,ELF
+UCL-LSIM IN A 128.16.1.110
+ IN A 128.16.2.241
+ IN HINFO LSI-11/23,MOS
+LBL-GEN IN A 128.3.254.112
+ IN HINFO VAX-11/780,VMS
+ISI-SPANKY IN A 128.9.0.112
+ IN HINFO IBM-PC,MSDOS
+SPANKY IN CNAME ISI-SPANKY.ARPA
+UCL-LSII IN A 128.16.1.112
+ IN HINFO LSI-11/23,MOS
+ISI-ALFALFA IN A 128.9.0.113
+ IN HINFO IBM-PC,MSDOS
+ALFALFA IN CNAME ISI-ALFALFA.ARPA
+UCL-LSIJ IN A 128.16.1.113
+ IN A 128.16.2.174
+ IN HINFO LSI-11/23,MOS
+ISI-DARLA IN A 128.9.0.114
+ IN HINFO IBM-PC,MSDOS
+DARLA IN CNAME ISI-DARLA.ARPA
+ISI-BUCKWHEAT IN A 128.9.0.115
+ IN HINFO IBM-PC,MSDOS
+BUCKWHEAT IN CNAME ISI-BUCKWHEAT.ARPA
+UCL-LSIK IN A 128.16.1.115
+ IN HINFO LSI-11/23,MOS
+SAC-STATION-3 IN A 128.26.0.115
+ IN HINFO LSI-11/23,ELF
+ISI-STYMIE IN A 128.9.0.116
+ IN HINFO IBM-PC,MSDOS
+STYMIE IN CNAME ISI-STYMIE.ARPA
+ISI-FARINA IN A 128.9.0.117
+ IN HINFO IBM-PC,MSDOS
+FARINA IN CNAME ISI-FARINA.ARPA
+ISI-PETE IN A 128.9.0.118
+ IN HINFO IBM-PC,MSDOS
+PETE IN CNAME ISI-PETE.ARPA
+PETE-THE-PUP IN CNAME ISI-PETE.ARPA
+ISI-FROGGIE IN A 128.9.0.119
+ IN HINFO IBM-PC,MSDOS
+FROGGIE IN CNAME ISI-FROGGIE.ARPA
+ISI-WAB2 IN A 128.9.0.121
+ IN HINFO IBM-PC,MSDOS
+ISI-RANDY IN A 128.9.0.122
+ IN HINFO IBM-PC,MSDOS
+ISI-RAG2 IN A 128.9.0.123
+ IN HINFO IBM-PC,MSDOS
+CMU-CS-IUS IN A 128.2.254.128
+ IN HINFO VAX-11/780,UNIX
+CMU-CS-IUS1 IN CNAME CMU-CS-IUS.ARPA
+ISI-ANNETTE IN A 128.9.0.128
+ IN HINFO XEROX-8010,XDE
+ANNETTE IN CNAME ISI-ANNETTE.ARPA
+CMU-CS-VLSI IN A 128.2.254.129
+ IN HINFO VAX-11/780,UNIX
+ISI-GG IN A 128.9.0.129
+ IN HINFO XEROX-8010,INTERLISP
+GG IN CNAME ISI-GG.ARPA
+CMU-CS-PS1 IN A 128.2.254.130
+ IN HINFO VAX-11/780,VMS
+CMU-CS-ZOG IN A 128.2.254.131
+ IN HINFO VAX-11/750,UNIX
+ISI-TARAXACUM IN A 128.9.0.131
+ IN HINFO XEROX-8010,XDE
+ISI-BOOM IN CNAME ISI-TARAXACUM.ARPA
+BOOM IN CNAME ISI-TARAXACUM.ARPA
+CMU-CS-G IN A 128.2.254.132
+ IN HINFO VAX-11/780,UNIX
+CMU-CS-CAD IN A 128.2.254.133
+ IN HINFO VAX-11/780,UNIX
+CMU-PSY-A IN A 128.2.254.134
+ IN HINFO VAX-11/780,VMS
+CMU-CS-K IN A 128.2.254.137
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-FAS IN A 128.2.254.138
+ IN HINFO VAX-11/780,UNIX
+CMU-CS-SPICE IN A 128.2.254.139
+ IN HINFO VAX-11/780,UNIX
+CMU-CS-GANDALF IN A 128.2.254.140
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-LEG IN A 128.2.254.141
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-ISL1 IN A 128.2.254.143
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-ISL IN CNAME CMU-RI-ISL1.ARPA
+CMU-CS-J IN A 128.2.254.144
+ IN HINFO VAX-11/750,VMS
+CMU-CS-SPEECH IN A 128.2.254.145
+ IN HINFO VAX-11/780,UNIX
+CMU-CS-SPEECH1 IN CNAME CMU-CS-SPEECH.ARPA
+CMU-CS-PS2 IN A 128.2.254.146
+ IN HINFO VAX-11/780,VMS
+CMU-RI-SENSOR IN A 128.2.254.147
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-UNH IN A 128.2.254.150
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-ARM IN A 128.2.254.151
+ IN HINFO VAX-11/750,UNIX
+CMU-RI-ISL2 IN A 128.2.254.152
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-CFS IN A 128.2.254.153
+ IN HINFO VAX-11/750,UNIX
+CMU-RI-ISL3 IN A 128.2.254.154
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-PT IN A 128.2.254.155
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-H IN A 128.2.254.156
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-ROVER IN A 128.2.254.157
+ IN HINFO VAX-11/750,UNIX
+CMU-RI-VI IN A 128.2.254.158
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-PS3 IN A 128.2.254.159
+ IN HINFO VAX-11/780,VMS
+CMU-CS-IUS2 IN A 128.2.254.176
+ IN HINFO VAX-11/780,UNIX
+CMU-RI-CIVE IN A 128.2.254.177
+ IN HINFO VAX-11/750,UNIX
+CMU-RI-ML IN A 128.2.254.178
+ IN HINFO VAX-11/750,UNIX
+CMU-CS-SPEECH2 IN A 128.2.254.179
+ IN HINFO VAX-11/750,UNIX
+TOPAZ IN A 128.6.0.194
+ IN HINFO PYRAMID-90X,UNIX
+RU-TOPAZ IN CNAME TOPAZ.ARPA
+OPAL IN A 128.6.0.195
+ IN HINFO SUN-150,UNIX
+RU-OPAL IN CNAME OPAL.ARPA
+SRIJOYCE IN A 128.18.0.202
+ IN HINFO VAX-11/750,UNIX
+JOYCE IN CNAME SRIJOYCE.ARPA
+CISL-DEVELOPMENT-MULTICS IN A 192.5.1.0
+ IN HINFO H-68/80,MULTICS
+WISC-RSCH IN A 192.5.2.1
+ IN HINFO VAX-11/780,UNIX
+RSCH IN CNAME WISC-RSCH.ARPA
+UWVAX IN CNAME WISC-RSCH.ARPA
+UW-BEAVER IN A 192.5.8.1
+ IN HINFO VAX-11/750,UNIX
+BEAVER IN CNAME UW-BEAVER.ARPA
+THEODORE IN CNAME UW-BEAVER.ARPA
+CSS-SUN IN A 192.5.11.1
+ IN HINFO SUN-2/150,UNIX
+WHEAT IN CNAME CSS-SUN.ARPA
+UCI-750A IN A 192.5.19.1
+ IN HINFO VAX-11/750,UNIX
+UCI IN CNAME UCI-750A.ARPA
+BRL-BMD IN A 192.5.21.1
+ IN HINFO PDP-11/70,UNIX
+BMD70 IN CNAME BRL-BMD.ARPA
+DTNSRDC3 IN A 192.5.26.1
+ IN HINFO VAX-11/750,UNIX
+DTNSRDC1 IN A 192.5.27.1
+ IN HINFO VAX-11/750,UNIX
+SRI-DIMSUN IN A 192.5.38.1
+ IN HINFO SUN-150,UNIX
+DIMSUN IN CNAME SRI-DIMSUN.ARPA
+DIM IN CNAME SRI-DIMSUN.ARPA
+PUCC-C IN A 192.5.40.1
+ IN HINFO PDP-11/70,UNIX
+PUCCC IN CNAME PUCC-C.ARPA
+CU-GARFIELD IN A 192.5.43.1
+ IN HINFO VAX-11/750,UNIX
+GARFIELD IN CNAME CU-GARFIELD.ARPA
+GAR IN CNAME CU-GARFIELD.ARPA
+LASSPVAX IN A 192.5.51.1
+ IN HINFO VAX-11/750,UNIX
+TL-20B IN A 192.5.56.1
+ IN HINFO DEC-2060,TOPS20
+TARTAN IN CNAME TL-20B.ARPA
+YALE-EE-CESUN1 IN A 192.5.88.1
+ IN A 128.36.0.5
+ IN HINFO SUN-100,UNIX
+CESUN1 IN CNAME YALE-EE-CESUN1.ARPA
+CADRE IN A 192.12.9.1
+ IN HINFO VAX-11/780,UNIX
+CADRE-VAX IN CNAME CADRE.ARPA
+WISC-DB IN A 192.5.2.2
+ IN HINFO VAX-11/750,UNIX
+DBVAX IN CNAME WISC-DB.ARPA
+DEC-ETHER IN A 192.5.6.2
+ IN HINFO ,TOPS20
+UW-LUMPY IN A 192.5.8.2
+ IN HINFO VAX-11/730,UNIX
+LUMPY IN CNAME UW-LUMPY.ARPA
+CLARENCE IN CNAME UW-LUMPY.ARPA
+PAERO1 IN A 192.5.9.2
+ IN HINFO VAX-11/780,UNIX
+HUGO IN A 192.5.11.2
+ IN HINFO VAX-11/780,UNIX
+CSS-HUGO IN CNAME HUGO.ARPA
+HOPS IN CNAME HUGO.ARPA
+IPTO IN A 192.5.18.2
+ IN HINFO SUN-150U,UNIX
+IPTO2 IN CNAME IPTO.ARPA
+UCI-ICSB IN A 192.5.19.2
+ IN HINFO VAX-11/750,UNIX
+UCI-750B IN CNAME UCI-ICSB.ARPA
+UCIB IN CNAME UCI-ICSB.ARPA
+BRL-VLD IN A 192.5.21.2
+ IN HINFO PDP-11/70,UNIX
+VLD70 IN CNAME BRL-VLD.ARPA
+DTNSRDC2 IN A 192.5.27.2
+ IN HINFO VAX-11/750,UNIX
+RSRE IN A 192.5.29.2
+ IN HINFO PDP-11/23,EMMOS
+RIACS IN A 192.5.35.2
+ IN HINFO VAX-11/780,UNIX
+RIACS-DAEDALUS IN CNAME RIACS.ARPA
+DAEDALUS IN CNAME RIACS.ARPA
+SRI-WONTON IN A 192.5.38.2
+ IN HINFO SUN-150,UNIX
+WONTON IN CNAME SRI-WONTON.ARPA
+WON IN CNAME SRI-WONTON.ARPA
+UDEL-DEWEY IN A 192.5.39.2
+ IN HINFO VAX-11/780,UNIX
+DEWEY IN CNAME UDEL-DEWEY.ARPA
+PUCC-D IN A 192.5.40.2
+ IN HINFO PDP-11/70,UNIX
+PUCCD IN CNAME PUCC-D.ARPA
+CU-HEATHCLIFF IN A 192.5.43.2
+ IN HINFO VAX-11/750,UNIX
+HEATHCLIFF IN CNAME CU-HEATHCLIFF.ARPA
+HEA IN CNAME CU-HEATHCLIFF.ARPA
+DEVVAX IN A 192.5.51.2
+ IN HINFO VAX-11/750,UNIX
+NLM-VAX IN A 192.5.52.2
+ IN HINFO VAX-11/780,UNIX
+TL-20A IN A 192.5.56.2
+ IN HINFO DEC-2060,TOPS20
+PURDUE-TN IN A 192.5.58.2
+ IN HINFO VAX-11/780,UNIX
+ORVILLE-EC IN A 192.5.64.2
+ IN HINFO VAX-11/780,UNIX
+ORVILLE IN CNAME ORVILLE-EC.ARPA
+NPRDC-PACIFIC IN A 192.5.65.2
+ IN HINFO VAX-11/780,UNIX
+HU-TALCOTT IN A 192.5.66.2
+ IN HINFO VAX-11/750,UNIX
+YALE-EE-CESUN2 IN A 192.5.88.2
+ IN HINFO SUN-100,UNIX
+CESUN2 IN CNAME YALE-EE-CESUN2.ARPA
+HU-CHIMERA IN A 192.5.90.2
+ IN HINFO RIDGE,UNIX
+CHIMERA IN CNAME HU-CHIMERA.ARPA
+CADRE-SOL IN A 192.12.9.2
+ IN HINFO SUN-150U,UNIX
+PRODIGAL IN CNAME CADRE-SOL.ARPA
+CIT-SYS IN A 192.12.19.2
+ IN HINFO VAX-11/780,UNIX
+DEC-RONCO IN A 192.5.6.3
+ IN HINFO ,TOPS20
+CIT-750 IN A 192.5.7.3
+ IN A 192.12.18.2
+ IN HINFO VAX-11/750,UNIX
+PEEWEE IN CNAME CIT-750.ARPA
+UW-WALLY IN A 192.5.8.3
+ IN HINFO VAX-11/750,UNIX
+WALLY IN CNAME UW-WALLY.ARPA
+AERO2 IN A 192.5.9.3
+ IN HINFO VAX-11/780,UNIX
+EL-SEGUNDO IN CNAME AERO2.ARPA
+SDCCIS IN A 192.5.11.3
+ IN HINFO PDP-11/44,UNIX
+CSS-SDCCIS IN CNAME SDCCIS.ARPA
+IPTO3 IN A 192.5.18.3
+ IN HINFO SUN-100U,UNIX
+UCI-ICSC IN A 192.5.19.3
+ IN HINFO VAX-11/750,UNIX
+UCI-750C IN CNAME UCI-ICSC.ARPA
+UCIC IN CNAME UCI-ICSC.ARPA
+BRL-MIS IN A 192.5.21.3
+ IN HINFO PDP-11/70,UNIX
+AMES-HJULIAN IN A 192.5.35.3
+ IN HINFO VAX-11/780,VMS
+HJULIAN IN CNAME AMES-HJULIAN.ARPA
+PUCC-E IN A 192.5.40.3
+ IN HINFO PDP-11/70,UNIX
+PUCCE IN CNAME PUCC-E.ARPA
+CU-TOM IN A 192.5.43.3
+ IN HINFO VAX-11/750,UNIX
+TOM IN CNAME CU-TOM.ARPA
+TL-VAXA IN A 192.5.56.3
+ IN HINFO VAX-11/750,VMS
+DECWRL IN A 192.5.58.3
+ IN HINFO VAX-11/750,UNIX
+DEC-WRL IN CNAME DECWRL.ARPA
+DECSRC IN CNAME DECWRL.ARPA
+DEC-SRC IN CNAME DECWRL.ARPA
+DECWSL IN CNAME DECWRL.ARPA
+DEC-WSL IN CNAME DECWRL.ARPA
+NPRDC-SUNA IN A 192.5.65.3
+ IN HINFO SUN-68000,UNIX
+HU-WJH12 IN A 192.5.66.3
+ IN HINFO PDP-11/44,UNIX
+WJH12 IN CNAME HU-WJH12.ARPA
+YALE-EE-CESUN3 IN A 192.5.88.3
+ IN HINFO SUN-100,UNIX
+CESUN3 IN CNAME YALE-EE-CESUN3.ARPA
+HU-DASY IN A 192.5.90.3
+ IN HINFO C/70,UNIX
+NYU-SETL1 IN A 192.12.7.3
+ IN HINFO SUN-150U,UNIX
+SETL1 IN CNAME NYU-SETL1.ARPA
+WISC-GOSSET IN A 192.12.12.3
+ IN HINFO PYRAMID-90X,UNIX
+GOSSET IN CNAME WISC-GOSSET.ARPA
+DEC-LATOUR IN A 192.5.6.4
+ IN HINFO ,UNIX
+UW-JUNE IN A 192.5.8.4
+ IN HINFO VAX-11/780,UNIX
+JUNE IN CNAME UW-JUNE.ARPA
+CISCLON IN A 192.5.11.4
+ IN HINFO PDP-11/44,UNIX
+CSS-CISCLON IN CNAME CISCLON.ARPA
+IPTO4 IN A 192.5.18.4
+ IN HINFO SUN-120,UNIX
+UCI-ICSD IN A 192.5.19.4
+ IN HINFO VAX-11/750,UNIX
+UCI-750D IN CNAME UCI-ICSD.ARPA
+UCID IN CNAME UCI-ICSD.ARPA
+BRL-TGR IN A 192.5.21.4
+ IN HINFO VAX-11/780,UNIX
+TGR IN CNAME BRL-TGR.ARPA
+CORNELL-PVAX IN A 192.5.36.4
+ IN HINFO VAX-11/780,UNIX
+SRI-IMAGEN IN A 192.5.38.4
+AITAD-IMAGEN IN CNAME SRI-IMAGEN.ARPA
+PUCC-H IN A 192.5.40.4
+ IN HINFO VAX-11/780,UNIX
+PUCCH IN CNAME PUCC-H.ARPA
+CU-SYLVESTER IN A 192.5.43.4
+ IN HINFO VAX-11/750,UNIX
+SYLVESTER IN CNAME CU-SYLVESTER.ARPA
+SYL IN CNAME CU-SYLVESTER.ARPA
+AMVAX IN A 192.5.51.4
+ IN HINFO VAX-11/750,UNIX
+NPRDC-SUNB IN A 192.5.65.4
+ IN HINFO SUN-68000,UNIX
+YALE-EE-CESUN4 IN A 192.5.88.4
+ IN HINFO SUN-100,UNIX
+CESUN4 IN CNAME YALE-EE-CESUN4.ARPA
+IMAPVM IN A 192.12.10.4
+ IN HINFO IBM-4341,VM/CMS
+AERO3 IN A 192.5.9.5
+ IN HINFO VAX-11/750,UNIX
+NYU-CMCL1 IN A 192.5.15.5
+ IN HINFO VAX-11/780,VMS
+CMCL1 IN CNAME NYU-CMCL1.ARPA
+IPTO5 IN A 192.5.18.5
+ IN HINFO SUN-120,UNIX
+UCI-ICSE IN A 192.5.19.5
+ IN HINFO VAX-11/750,UNIX
+UCI-750E IN CNAME UCI-ICSE.ARPA
+UCIE IN CNAME UCI-ICSE.ARPA
+CORNELL-GVAX IN A 192.5.36.5
+ IN HINFO VAX-11/780,UNIX
+GVAX IN CNAME CORNELL-GVAX.ARPA
+PUCC-I IN A 192.5.40.5
+ IN A 128.10.0.4
+ IN HINFO VAX-11/780,UNIX
+PUCCI IN CNAME PUCC-I.ARPA
+CU-CHESHIRE IN A 192.5.43.5
+ IN HINFO VAX-11/750,UNIX
+CHESHIRE IN CNAME CU-CHESHIRE.ARPA
+CHE IN CNAME CU-CHESHIRE.ARPA
+LNSVAX IN A 192.5.51.5
+ IN HINFO VAX-11/750,UNIX
+NPRDC-SUNC IN A 192.5.65.5
+ IN HINFO SUN-68000,UNIX
+YALE-EE-CESUN5 IN A 192.5.88.5
+ IN HINFO SUN-100,UNIX
+CESUN5 IN CNAME YALE-EE-CESUN5.ARPA
+MAEVAX IN A 192.12.10.5
+ IN HINFO VAX-11/750,UNIX
+WISC-MADSUN IN A 192.12.12.5
+ IN HINFO SUN-2,UNIX
+MADSUN IN CNAME WISC-MADSUN.ARPA
+UW-EDDIE IN A 192.5.8.6
+ IN HINFO VAX-11/730,UNIX
+EDDIE IN CNAME UW-EDDIE.ARPA
+CSS-TIU1 IN A 192.5.11.6
+ IN HINFO DEC-FALCON,MOS
+NYU-ACF1 IN A 192.5.15.6
+ IN HINFO VAX-11/780,VMS
+ACF1 IN CNAME NYU-ACF1.ARPA
+IPTO6 IN A 192.5.18.6
+ IN HINFO SUN-120,UNIX
+BRL-VGR IN A 192.5.21.6
+ IN A 128.20.1.1
+ IN HINFO VAX-11/780,UNIX
+VGR IN CNAME BRL-VGR.ARPA
+CORNELL-GIDNEY IN A 192.5.36.6
+ IN HINFO SUN-100U,UNIX
+GIDNEY IN CNAME CORNELL-GIDNEY.ARPA
+PUCC-J IN A 192.5.40.6
+ IN HINFO VAX-11/780,UNIX
+PUCCJ IN CNAME PUCC-J.ARPA
+CU-FELIX IN A 192.5.43.6
+ IN HINFO VAX-11/750,UNIX
+FELIX IN CNAME CU-FELIX.ARPA
+FEL IN CNAME CU-FELIX.ARPA
+RICE IN A 192.5.58.6
+ IN A 128.42.1.1
+ IN HINFO VAX-11/750,UNIX
+RICE-DIONE IN CNAME RICE.ARPA
+DIONE IN CNAME RICE.ARPA
+NPRDC-SUND IN A 192.5.65.6
+ IN HINFO SUN-68000,UNIX
+WISC-CRYS IN A 192.5.2.7
+ IN HINFO VAX-11/780,UNIX
+CRYSTAL IN CNAME WISC-CRYS.ARPA
+WISCONSIN IN CNAME WISC-CRYS.ARPA
+UWISC IN CNAME WISC-CRYS.ARPA
+UW-BLUECHIP IN A 192.5.8.7
+ IN HINFO VAX-11/780,UNIX
+BLUECHIP IN CNAME UW-BLUECHIP.ARPA
+UW-LARRY IN CNAME UW-BLUECHIP.ARPA
+LARRY IN CNAME UW-BLUECHIP.ARPA
+CSS-TIU2 IN A 192.5.11.7
+ IN HINFO DEC-FALCON,MOS
+IPTO7 IN A 192.5.18.7
+ IN HINFO SUN-120,UNIX
+CU-ROBOTICS IN A 192.5.36.7
+ IN HINFO VAX-11/750,UNIX
+ROCKY IN CNAME CU-ROBOTICS.ARPA
+PUCC-K IN A 192.5.40.7
+ IN HINFO VAX-11/780,UNIX
+PUCCK IN CNAME PUCC-K.ARPA
+HU-ODIN IN A 192.5.66.7
+ IN HINFO VAX-11/780,UNIX
+WISC-STAT IN A 192.5.2.8
+ IN HINFO VAX-11/750,UNIX
+STATISTICS IN CNAME WISC-STAT.ARPA
+STAT IN CNAME WISC-STAT.ARPA
+UW-TAHITI IN A 192.5.8.8
+ IN HINFO SUN-150U,UNIX
+TAHITI IN CNAME UW-TAHITI.ARPA
+JANUS IN A 192.5.11.8
+ IN HINFO VAX-11/780,UNIX
+CSS-JANUS IN CNAME JANUS.ARPA
+NYU-ACF3 IN A 192.5.15.8
+ IN HINFO VAX-11/780,VMS
+ACF3 IN CNAME NYU-ACF3.ARPA
+IPTO8 IN A 192.5.18.8
+ IN HINFO SUN-120,UNIX
+NTA-VAX IN A 192.5.46.8
+ IN HINFO VAX-11/70,UNIX
+UW-FIJI IN A 192.5.8.9
+ IN HINFO SUN-100U,UNIX
+FIJI IN CNAME UW-FIJI.ARPA
+NYU-ACF2 IN A 192.5.15.9
+ IN HINFO VAX-11/780,VMS
+NYU-ADA IN CNAME NYU-ACF2.ARPA
+ACF2 IN CNAME NYU-ACF2.ARPA
+IPTO9 IN A 192.5.18.9
+ IN HINFO SUN-120,UNIX
+HU-LOKI IN A 192.5.66.9
+ IN HINFO VAX-11/750,UNIX
+CSS-S3SUN IN A 192.12.25.9
+ IN HINFO SUN-2/150,UNIX
+S3SUN IN CNAME CSS-S3SUN.ARPA
+CORN IN CNAME CSS-S3SUN.ARPA
+BBNV1 IN A 192.1.7.10
+ IN HINFO VAX-11/780,VMS
+UW-BALI IN A 192.5.8.10
+ IN HINFO SUN-100U,UNIX
+BALI IN CNAME UW-BALI.ARPA
+NYU-CIMS1 IN A 192.5.15.10
+ IN HINFO VAX-11/750,VMS
+CIMS1 IN CNAME NYU-CIMS1.ARPA
+IPTO10 IN A 192.5.18.10
+ IN HINFO SUN-120,UNIX
+CU-BETELGEUZE IN A 192.5.43.10
+ IN HINFO SUN-150,UNIX
+BETELGEUZE IN CNAME CU-BETELGEUZE.ARPA
+BETALGEUZE IN CNAME CU-BETELGEUZE.ARPA
+BETA IN CNAME CU-BETELGEUZE.ARPA
+HU-THOR IN A 192.5.66.10
+ IN HINFO VAX-11/750,UNIX
+CIT-SOL IN A 192.12.18.10
+ IN HINFO SUN-2/170,UNIX
+SOL IN CNAME CIT-SOL.ARPA
+CSS-RAISUN IN A 192.12.25.10
+ IN HINFO SUN-2/150,UNIX
+RAISUN IN CNAME CSS-RAISUN.ARPA
+BARLEY IN CNAME CSS-RAISUN.ARPA
+SRN-VAX IN A 192.1.7.11
+ IN HINFO VAX-11/750,UNIX
+SURAN-VAX IN CNAME SRN-VAX.ARPA
+UW-SUMATRA IN A 192.5.8.11
+ IN HINFO SUN-150U,UNIX
+SUMATRA IN CNAME UW-SUMATRA.ARPA
+NYU-LSP1 IN A 192.5.15.11
+ IN HINFO VAX-11/750,VMS
+LSP1 IN CNAME NYU-LSP1.ARPA
+IPTO11 IN A 192.5.18.11
+ IN HINFO SUN-120,UNIX
+CIT-SATURN IN A 192.12.18.11
+ IN HINFO SUN-2/120,UNIX
+SATURN IN CNAME CIT-SATURN.ARPA
+BBNV8 IN A 192.1.5.12
+ IN HINFO VAX-11/750,VMS
+UW-MAUI IN A 192.5.8.12
+ IN HINFO SUN-100U,UNIX
+MAUI IN CNAME UW-MAUI.ARPA
+CU-RIGEL IN A 192.5.43.12
+ IN HINFO SUN-100,UNIX
+RIGEL IN CNAME CU-RIGEL.ARPA
+HU-TARDIS IN A 192.5.66.12
+ IN HINFO PDP-11/44,UNIX
+TARDIS IN CNAME HU-TARDIS.ARPA
+UT-RATLIFF IN A 192.5.89.12
+ IN HINFO VAX-11/750,UNIX
+RATLIFF IN CNAME UT-RATLIFF.ARPA
+CIT-NEPTUNE IN A 192.12.18.12
+ IN HINFO SUN-2/120,UNIX
+NEPTUNE IN CNAME CIT-NEPTUNE.ARPA
+UW-CEYLON IN A 192.5.8.13
+ IN HINFO SUN-170,UNIX
+CEYLON IN CNAME UW-CEYLON.ARPA
+NYU-ACF5 IN A 192.5.15.13
+ IN HINFO VAX-11/780,VMS
+ACF5 IN CNAME NYU-ACF5.ARPA
+CIT-MERCURY IN A 192.12.18.13
+ IN HINFO SUN-2/120,UNIX
+MERCURY IN CNAME CIT-MERCURY.ARPA
+UT-EYEBEAM IN A 192.12.22.13
+ IN A 192.12.23.93
+ IN HINFO VAX-11/750,UNIX
+EYEBEAM IN CNAME UT-EYEBEAM.ARPA
+UW-JAVA IN A 192.5.8.14
+ IN HINFO SUN-120,UNIX
+JAVA IN CNAME UW-JAVA.ARPA
+CIT-VENUS IN A 192.12.18.14
+ IN HINFO SUN-2/120,UNIX
+VENUS IN CNAME CIT-VENUS.ARPA
+UT-LAWNURD IN A 192.12.22.14
+ IN HINFO VAX-11/750,UNIX
+LAWNURD IN CNAME UT-LAWNURD.ARPA
+UW-KAUAI IN A 192.5.8.15
+ IN HINFO SUN-120,UNIX
+KAUAI IN CNAME UW-KAUAI.ARPA
+CIT-IO IN A 192.12.18.15
+ IN HINFO SUN-2/150,UNIX
+IO IN CNAME CIT-IO.ARPA
+UT-VERNON IN A 192.12.22.15
+ IN HINFO VAX-11/750,UNIX
+VERNON IN CNAME UT-VERNON.ARPA
+UW-TIMOR IN A 192.5.8.16
+ IN HINFO SUN-120,UNIX
+TIMOR IN CNAME UW-TIMOR.ARPA
+BRL-ZAP IN A 192.5.23.16
+ IN HINFO MC68000,IOS
+CIT-CALLISTO IN A 192.12.18.16
+ IN HINFO SUN-2/150,UNIX
+CALLISTO IN CNAME CIT-CALLISTO.ARPA
+UT-SHORTBREAD IN A 192.12.22.16
+ IN HINFO VAX-11/750,UNIX
+SHORTBREAD IN CNAME UT-SHORTBREAD.ARPA
+UW-TULAGI IN A 192.5.8.17
+ IN HINFO SUN-120,UNIX
+TULAGI IN CNAME UW-TULAGI.ARPA
+CIT-EUROPA IN A 192.12.18.17
+ IN HINFO SUN-2/150,UNIX
+EUROPA IN CNAME CIT-EUROPA.ARPA
+UT-SNUFF IN A 192.12.22.17
+ IN HINFO VAX-11/750,UNIX
+SNUFF IN CNAME UT-SNUFF.ARPA
+UW-BORNEO IN A 192.5.8.18
+ IN HINFO SUN-170,UNIX
+BORNEO IN CNAME UW-BORNEO.ARPA
+UT-HANK IN A 192.5.89.18
+ IN HINFO VAX-11/780,UNIX
+HANK IN CNAME UT-HANK.ARPA
+UW-KORO IN A 192.5.8.19
+ IN HINFO SUN-120,UNIX
+KORO IN CNAME UW-KORO.ARPA
+BRL-CYBER IN A 192.5.22.19
+ IN HINFO CDC-170/750,NOS-2
+MFA IN CNAME BRL-CYBER.ARPA
+UT-DUFFY IN A 192.5.89.19
+ IN HINFO VAX-11/780,UNIX
+DUFFY IN CNAME UT-DUFFY.ARPA
+UW-TASMAN IN A 192.5.8.20
+ IN HINFO SUN-120,UNIX
+TASMAN IN CNAME UW-TASMAN.ARPA
+UW-TANGA IN A 192.5.8.21
+ IN HINFO SUN-120,UNIX
+TANGA IN CNAME UW-TANGA.ARPA
+UT-ICV1 IN A 192.5.89.21
+ IN HINFO VAX-11/780,UNIX
+UW-MOALA IN A 192.5.8.22
+ IN HINFO SUN-120,UNIX
+MOALA IN CNAME UW-MOALA.ARPA
+UTAH-GR IN A 192.5.12.22
+ IN HINFO VAX-11/750,UNIX
+UT-ICV2 IN A 192.5.89.22
+ IN HINFO VAX-11/780,VMS
+UW-OAHU IN A 192.5.8.23
+ IN HINFO SUN-120,UNIX
+OAHU IN CNAME UW-OAHU.ARPA
+UTAH-SP IN A 192.5.12.23
+ IN HINFO VAX-11/750,UNIX
+UT-ICV3 IN A 192.5.89.23
+ IN HINFO VAX-11/780,VMS
+WISCVM IN A 192.5.2.24
+ IN A 192.5.58.8
+ IN HINFO IBM-4341,VM/CMS
+WISC-IBM IN CNAME WISCVM.ARPA
+UTAH-UG IN A 192.5.12.24
+ IN HINFO VAX-11/750,UNIX
+UTAH-ORION IN A 192.5.12.25
+ IN HINFO VAX-11/750,UNIX
+SCRC-CUPID IN A 192.10.41.27
+ IN HINFO VAX-11/750,UNIX
+SCRC-PERN IN A 192.10.41.30
+ IN HINFO SUN-120,UNIX
+PERN IN CNAME SCRC-PERN.ARPA
+UT-A20 IN A 192.5.89.31
+ IN HINFO DEC-2060,TOPS20
+RANDGR IN A 192.5.14.34
+ IN HINFO VAX-11/750,UNIX
+RAND-GR IN CNAME RANDGR.ARPA
+UT-A3081 IN A 192.5.89.39
+ IN HINFO IBM-3081,VM/CMS
+UT-IBM IN CNAME UT-A3081.ARPA
+CAPELLA IN A 192.5.89.41
+ IN HINFO SUN-2/120,UNIX
+GAUSS IN A 192.5.89.42
+ IN HINFO SUN-2/120,UNIX
+KENTARUS IN A 192.5.89.50
+ IN HINFO SUN-2/120,UNIX
+TAUCETI IN A 192.5.89.51
+ IN HINFO SUN-2/120,UNIX
+WISC-SPOOL IN A 192.5.2.55
+ IN A 192.12.12.1
+ IN HINFO VAX-11/750,UNIX
+LOOPS IN CNAME WISC-SPOOL.ARPA
+NEEDLE IN CNAME WISC-SPOOL.ARPA
+ZOTZ IN A 192.5.89.61
+ IN HINFO SUN-2/120,UNIX
+SOATS IN CNAME ZOTZ.ARPA
+TZEC IN A 192.5.89.62
+ IN HINFO SUN-2/120,UNIX
+ZAKE IN CNAME TZEC.ARPA
+XUL IN A 192.5.89.63
+ IN HINFO SUN-2/120,UNIX
+SHOOL IN CNAME XUL.ARPA
+YAXKIN IN A 192.5.89.64
+ IN HINFO SUN-2/120,UNIX
+YOSHKEEN IN CNAME YAXKIN.ARPA
+MOL IN A 192.5.89.65
+ IN HINFO SUN-2/120,UNIX
+MOLE IN CNAME MOL.ARPA
+BBNF IN A 192.1.2.66
+ IN A 8.4.0.12
+ IN HINFO DEC-2040T,TOPS20
+BBN-TENEXF IN CNAME BBNF.ARPA
+KANKIN IN A 192.5.89.66
+ IN HINFO SUN-2/120,UNIX
+CONKEEN IN CNAME KANKIN.ARPA
+ZIP IN A 192.5.89.67
+ IN HINFO SUN-2/120,UNIX
+SEEP IN CNAME ZIP.ARPA
+SCRC-TRICERATOPS IN A 192.10.41.67
+ IN HINFO K102,KOS
+POP IN A 192.5.89.68
+ IN HINFO SUN-2/120,UNIX
+POPE IN CNAME POP.ARPA
+MUAN IN A 192.5.89.69
+ IN HINFO SUN-2/120,UNIX
+MWAHN IN CNAME MUAN.ARPA
+UO IN A 192.5.89.70
+ IN HINFO SUN-2/120,UNIX
+WOE IN CNAME UO.ARPA
+CHEN IN A 192.5.89.71
+ IN HINFO SUN-2/120,UNIX
+CHAIN IN CNAME CHEN.ARPA
+ZAC IN A 192.5.89.72
+ IN HINFO SUN-2/120,UNIX
+SOCK IN CNAME ZAC.ARPA
+CEH IN A 192.5.89.73
+ IN HINFO SUN-2/120,UNIX
+SAY IN CNAME CEH.ARPA
+MAC IN A 192.5.89.74
+ IN HINFO SUN-2/120,UNIX
+MOCK IN CNAME MAC.ARPA
+KEYNES IN A 192.5.89.81
+ IN HINFO SUN-2/120,UNIX
+BRL-AOS IN A 192.5.22.82
+ IN HINFO VAX-11/780,UNIX
+AOS IN CNAME BRL-AOS.ARPA
+RUCKER-VAX IN CNAME BRL-AOS.ARPA
+ZOO IN A 192.5.89.82
+ IN HINFO SUN-2/120,UNIX
+UR-SENECA IN A 192.5.37.83
+ IN HINFO VAX-11/780,UNIX
+UR-FILTER-QUEEN IN CNAME UR-SENECA.ARPA
+UTASTRO IN A 192.12.23.98
+ IN A 192.5.89.40
+ IN HINFO VAX-11/780,UNIX
+UTAH-VMS IN A 192.5.12.99
+ IN HINFO VAX-11/750,VMS
+MCC-DBVAX IN A 192.12.23.99
+ IN HINFO VAX-11/750,UNIX
+UTAH-ARCHES IN A 192.5.12.100
+ IN HINFO SUN-2/120,UNIX
+UTAH-YAMPA IN A 192.5.12.101
+ IN HINFO SUN-2/120,UNIX
+CHALMERS-SUNET IN A 192.5.58.101
+ IN HINFO VAX-11/750,UNIX
+NRL-MMS IN A 192.5.17.103
+ IN HINFO SMI,UNIX
+NRL-SPEECH IN A 192.5.17.104
+ IN HINFO VAX-11/750,VMS
+NRL-GRAPHICS IN A 192.5.17.105
+ IN HINFO PDP-11/45,UNIX
+UTAH-APOLLO IN A 192.5.12.127
+ IN HINFO APOLLO,UNIX
+UTAH-AP IN CNAME UTAH-APOLLO.ARPA
+CU20B IN A 192.5.43.128
+ IN HINFO DEC-2060,TOPS20
+NYU-CSD1 IN A 192.5.15.131
+ IN A 192.12.7.1
+ IN HINFO VAX-11/750,UNIX
+CSD1 IN CNAME NYU-CSD1.ARPA
+NYU-CSD2 IN A 192.5.15.132
+ IN A 192.12.7.2
+ IN HINFO VAX-11/750,UNIX
+CSD2 IN CNAME NYU-CSD2.ARPA
+NYU-ACF4 IN A 192.5.15.133
+ IN HINFO VAX-11/780,UNIX
+ACF4 IN CNAME NYU-ACF4.ARPA
+NYU-TUT IN A 192.5.15.134
+ IN HINFO PYRAMID-90,UNIX
+TUT IN CNAME NYU-TUT.ARPA
+NYU-BAY-RIDGE IN A 192.5.15.135
+ IN HINFO RIDGE-32,ROS
+BAY-RIDGE IN CNAME NYU-BAY-RIDGE.ARPA
+BAY IN CNAME NYU-BAY-RIDGE.ARPA
+SCRC-QUABBIN IN A 192.10.41.136
+ IN HINFO SYMBOLICS-3600,LISPM
+SCRC-STONY-BROOK IN A 192.10.41.144
+ IN HINFO SYMBOLICS-3600,LISPM
+SCRC IN CNAME SCRC-STONY-BROOK.ARPA
+SYMBOLICS IN CNAME SCRC-STONY-BROOK.ARPA
+NRL-OSTC IN A 192.5.17.153
+ IN HINFO PDP-11/45,UNIX
+UR-CAYUGA IN A 192.5.37.209
+ IN HINFO VAX-11/750,UNIX
+UR-ELECTROLUX IN CNAME UR-CAYUGA.ARPA
+UR-KEUKA IN A 192.5.37.210
+ IN HINFO VAX-11/750,UNIX
+UR-KIRBY IN CNAME UR-KEUKA.ARPA
+UR-CANANDAIGUA IN A 192.5.37.211
+ IN HINFO VAX-11/750,UNIX
+UR-HOOVER IN CNAME UR-CANANDAIGUA.ARPA
+UR-SKANEATELES IN A 192.5.37.212
+ IN HINFO VAX-11/750,UNIX
+UR-EUREKA IN CNAME UR-SKANEATELES.ARPA
diff --git a/usr.sbin/named/test/ns.al2 b/usr.sbin/named/test/ns.al2
new file mode 100644
index 00000000000..b656e865574
--- /dev/null
+++ b/usr.sbin/named/test/ns.al2
@@ -0,0 +1,3414 @@
+~MAILER~DAEMON~ IN MB UCB-VAX.ARPA
+ IN MG POSTMASTER
+~MAILER~DAEMON~ IN MB UCB-VAX.ARPA
+ IN MG POSTMASTER
+MAILER-DAEMON IN MB UCB-VAX.ARPA
+ IN MG POSTMASTER
+MAILER-DAEMON IN MB UCB-VAX.ARPA
+ IN MG POSTMASTER
+POSTMASTER IN MB UCB-VAX.ARPA
+ IN MG RWH
+OWNER-OWNER IN MB UCB-VAX.ARPA
+ IN MG POSTMASTER
+STATALLNET IN MB UCB-VAX.ARPA
+ IN MG /USR/SPOOL/BERKNET/NETSTATS
+MSGS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/ucb/msgs -s"
+ IN MG "|/usr/spool/news/lib/recnews msgs"
+ALLMSGS IN MB UCB-VAX.ARPA
+ IN MG CSMSGS
+ IN MG CFOMSGS@JADE
+ IN MG MSMSGS@BACH
+ IN MG MSGS@EAR
+ IN MG MSGS@IC
+CSMSGS IN MB UCB-VAX.ARPA
+ IN MG MSGS
+ IN MG MSGS@INGRES
+ IN MG MSGS@KIM
+ IN MG MSGS@MEDEA
+ IN MG MSGS@ESVAX
+ IN MG MSGS@ARPA
+ IN MG MSGS@ERNIE
+ IN MG MSGS@ONYX
+ IN MG MSGS@CAD
+ IN MG MSGS@DALI
+ IN MG UCBMSGS@CORY
+ IN MG MSGS@DEGAS
+ IN MG MSGS@MIRO
+ IN MG MSGS@MONET
+ IN MG MSGS@OZ
+ IN MG MSGS@CALDER
+ IN MG MSGS@RENOIR
+ IN MG MSGS@SHADOW
+ IN MG ETCHMSGS@NEWTON
+ IN MG MSGS@UCBCOGSCI
+CCMSGS IN MB UCB-VAX.ARPA
+ IN MG MSGS@A.CC
+ IN MG MSGS@B.CC
+ IN MG MSGS@C.CC
+ IN MG MSGS@D.CC
+ IN MG MSGS@E.CC
+ IN MG MSGS@F.CC
+ IN MG MSGS@POPULI.CC
+ IN MG MSGS@JADE.CC
+ IN MG MSGS@RUBY.CC
+ IN MG MSGS@TOPAZ.CC
+ IN MG MSGS@CORAL.CC
+ IN MG MSGS@AMBER.CC
+ IN MG MSGS@S.CC
+ IN MG MSGS@UCBOPAL
+TROUBLE IN MB UCB-VAX.ARPA
+ IN MG TROUBLE@CORY
+ IN MG TROUBLE@ERNIE
+BBOARD IN MB UCB-VAX.ARPA
+ IN MG CSMSGS
+ALLMANAGERS IN MB UCB-VAX.ARPA
+ IN MG MANAGER@ERNIE
+ IN MG MANAGER@ARPA
+ IN MG MANAGER@KIM
+ IN MG MANAGER@INGRES
+ IN MG MANAGER@ESVAX
+ IN MG MANAGER@CORY
+ IN MG MANAGER@TOPAZ
+ IN MG MANAGER@EAR
+ IN MG MANAGER@CAD
+ IN MG MANAGER@SHADOW
+ IN MG MANAGER@BACH
+ IN MG MANAGER@NEWTON
+ IN MG MANAGERS@UCBMIRO
+ IN MG MANAGER@LBL-CSAM
+ IN MG MANAGER@DALI
+ IN MG MANAGER@COGSCI
+TERMCAP IN MB UCB-VAX.ARPA
+ IN MG RALPH@ARPA
+CSLI-FRIENDS IN MB UCB-VAX.ARPA
+ IN MG CSLI-FRIENDS@UCBKIM
+LEPREAU IN MB UCB-VAX.ARPA
+ IN MG LEPREAU@UTAH-CS.ARPA
+USENET-ADMIN IN MB UCB-VAX.ARPA
+ IN MG EEF
+USENET IN MB UCB-VAX.ARPA
+ IN MG FAIR
+ IN MG POSTMASTER
+OWNER-RNEWS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+RNEWS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/uurec"
+NEWS IN MB UCB-VAX.ARPA
+ IN MG GENERAL
+GAMES IN MB UCB-VAX.ARPA
+ IN MG NET-GAMES
+BERKNEWS IN MB UCB-VAX.ARPA
+ IN MG ALLMSGS
+ IN MG UCB-BBOARD
+OWNER-POST-ARMS-D IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-ARMS-D IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.arms-d arms-d"
+ARMS-D IN MB UCB-VAX.ARPA
+ IN MG ARMS-D@MIT-MC.ARPA
+OWNER-POST-ARPA-BBOARD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-ARPA-BBOARD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.arpa-bboard arpa-bboard"
+ARPA-BBOARD IN MB UCB-VAX.ARPA
+ IN MG ARPA-BBOARD@MIT-MC.ARPA
+OWNER-POST-ENERGY IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-ENERGY IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.energy energy"
+ENERGY IN MB UCB-VAX.ARPA
+ IN MG ENERGY@MIT-MC.ARPA
+OWNER-POST-HUMAN-NETS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-HUMAN-NETS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.human-nets human-nets"
+HUMAN-NETS IN MB UCB-VAX.ARPA
+ IN MG HUMAN-NETS@RUTGERS.ARPA
+OWNER-POST-INFO-KERMIT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-KERMIT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.info-kermit info-kermit"
+INFO-KERMIT IN MB UCB-VAX.ARPA
+ IN MG INFO-KERMIT@COLUMBIA-20.ARPA
+OWNER-POST-INFO-MICRO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-MICRO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.info-micro info-micro"
+INFO-MICRO IN MB UCB-VAX.ARPA
+ IN MG INFO-MICRO@BRL-VGR.ARPA
+OWNER-POST-INFO-TERMS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-TERMS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.info-terms info-terms"
+INFO-TERMS IN MB UCB-VAX.ARPA
+ IN MG INFO-TERMS@MIT-MC.ARPA
+OWNER-POST-INFO-VAX IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-VAX IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.info-vax info-vax"
+INFO-VAX IN MB UCB-VAX.ARPA
+ IN MG INFO-VAX@SRI-CSL.ARPA
+OWNER-POST-INFO-VLSI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-VLSI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.info-vlsi info-vlsi"
+INFO-VLSI IN MB UCB-VAX.ARPA
+ IN MG INFO-VLSI@SANDIA.ARPA
+OWNER-POST-POLI-SCI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-POLI-SCI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.poli-sci poli-sci"
+POLI-SCI IN MB UCB-VAX.ARPA
+ IN MG POLI-SCI@MIT-MC.ARPA
+OWNER-POST-RAILROAD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-RAILROAD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.railroad railroad"
+RAILROAD IN MB UCB-VAX.ARPA
+ IN MG RAILROAD@MIT-MC.ARPA
+OWNER-POST-SPACE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-SPACE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.space space"
+SPACE IN MB UCB-VAX.ARPA
+ IN MG SPACE@MIT-MC.ARPA
+OWNER-POST-TELECOM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-TELECOM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.telecom telecom"
+TELECOM IN MB UCB-VAX.ARPA
+ IN MG TELECOM@MIT-MC.ARPA
+OWNER-POST-TELETEXT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-TELETEXT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.teletext teletext"
+TELETEXT IN MB UCB-VAX.ARPA
+ IN MG TELETEXT@MIT-MC.ARPA
+OWNER-POST-UNIX-CPM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-UNIX-CPM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.unix-cpm unix-cpm"
+UNIX-CPM IN MB UCB-VAX.ARPA
+ IN MG UNIX-CPM@UDEL.ARPA
+OWNER-POST-UNIX-WIZARDS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-UNIX-WIZARDS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.unix-wizards unix-wizards"
+UNIX-WIZARDS IN MB UCB-VAX.ARPA
+ IN MG UNIX-WIZARDS@BRL.ARPA
+OWNER-POST-WORKS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-WORKS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.works works"
+WORKS IN MB UCB-VAX.ARPA
+ IN MG WORKS@RUTGERS.ARPA
+OWNER-POST-DIGEST-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-DIGEST-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.digest-p digest-people"
+DIGEST-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG DIGEST-PEOPLE@MIT-MC.ARPA
+OWNER-POST-EDITOR-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-EDITOR-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.editor-p editor-people"
+EDITOR-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG EDITOR-PEOPLE@SU-SCORE.ARPA
+OWNER-POST-INFO-BITGRAPH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-BITGRAPH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.bitgraph info-bitgraph"
+INFO-BITGRAPH IN MB UCB-VAX.ARPA
+ IN MG INFO-BITGRAPH@MIT-MC.ARPA
+OWNER-POST-INFO-PRINTERS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-INFO-PRINTERS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.printers info-printers"
+INFO-PRINTERS IN MB UCB-VAX.ARPA
+ IN MG INFO-PRINTERS@MIT-MC.ARPA
+OWNER-POST-TCP-IP-UNIX IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+POST-TCP-IP-UNIX IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews fa.tcp-ip tcp-ip-unix"
+TCP-IP-UNIX IN MB UCB-VAX.ARPA
+ IN MG TCP-IP-UNIX@NIC.ARPA
+OWNER-BA-GENERAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+BA-GENERAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ba.general"
+OWNER-BA-NEWS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+BA-NEWS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ba.news"
+OWNER-BA-NEWS-CONFIG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+BA-NEWS-CONFIG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ba.news.config"
+OWNER-BA-NEWS-GROUP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+BA-NEWS-GROUP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ba.news.group"
+OWNER-BA-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+BA-TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ba.test"
+OWNER-CA-GENERAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+CA-GENERAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ca.general"
+OWNER-CA-NEWS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+CA-NEWS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ca.news"
+OWNER-CA-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+CA-TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ca.test"
+OWNER-GENERAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+GENERAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews general"
+OWNER-NA-FORSALE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NA-FORSALE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews na.forsale"
+OWNER-NET-ABORTION IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ABORTION IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.abortion"
+OWNER-NET-AI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-AI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.ai"
+OWNER-NET-ANALOG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ANALOG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.analog"
+OWNER-NET-ANNOUNCE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ANNOUNCE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.announce"
+OWNER-NET-ANNOUNCE-NEWUSERS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ANNOUNCE-NEWUSERS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.announce.newusers"
+OWNER-NET-ARCH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ARCH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.arch"
+OWNER-NET-ASTRO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ASTRO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.astro"
+OWNER-NET-ASTRO-EXPERT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ASTRO-EXPERT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.astro.expert"
+OWNER-NET-AUDIO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-AUDIO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.audio"
+OWNER-NET-AUTO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-AUTO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.auto"
+OWNER-NET-AVIATION IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-AVIATION IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.aviation"
+OWNER-NET-BICYCLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BICYCLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bicycle"
+OWNER-NET-BIO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BIO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bio"
+OWNER-NET-BOOKS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BOOKS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.books"
+OWNER-NET-BUGS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs"
+OWNER-NET-BUGS-2BSD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS-2BSD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs.2bsd"
+OWNER-NET-BUGS-4BSD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS-4BSD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs.4bsd"
+OWNER-NET-BUGS-USG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS-USG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs.usg"
+OWNER-NET-BUGS-UUCP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS-UUCP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs.uucp"
+OWNER-NET-BUGS-V7 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-BUGS-V7 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.bugs.v7"
+OWNER-NET-CHESS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-CHESS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.chess"
+OWNER-NET-COG-ENG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-COG-ENG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.cog-eng"
+OWNER-NET-COLLEGE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-COLLEGE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.college"
+OWNER-NET-COLUMBIA IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-COLUMBIA IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.columbia"
+OWNER-NET-COMICS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-COMICS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.comics"
+OWNER-NET-CONSUMERS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-CONSUMERS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.consumers"
+OWNER-NET-COOKS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-COOKS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.cooks"
+OWNER-NET-CRYPT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-CRYPT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.crypt"
+OWNER-NET-CSE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-CSE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.cse"
+OWNER-NET-CYCLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-CYCLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.cycle"
+OWNER-NET-DCOM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-DCOM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.dcom"
+OWNER-NET-DECUS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-DECUS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.decus"
+OWNER-NET-EMACS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-EMACS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.emacs"
+OWNER-NET-EUNICE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-EUNICE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.eunice"
+OWNER-NET-FLAME IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-FLAME IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.flame"
+OWNER-NET-FOLLOWUP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-FOLLOWUP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.followup"
+OWNER-NET-GAMES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games"
+OWNER-NET-GAMES-EMP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-EMP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.emp"
+OWNER-NET-GAMES-FRP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-FRP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.frp"
+OWNER-NET-GAMES-GO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-GO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.go"
+OWNER-NET-GAMES-PBM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-PBM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.pbm"
+OWNER-NET-GAMES-ROGUE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-ROGUE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.rogue"
+OWNER-NET-GAMES-TRIVIA IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-TRIVIA IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.trivia"
+OWNER-NET-GAMES-VIDEO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GAMES-VIDEO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.games.video"
+OWNER-NET-GARDEN IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GARDEN IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.garden"
+OWNER-NET-GENERAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GENERAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.general"
+OWNER-NET-GRAPHICS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-GRAPHICS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.graphics"
+OWNER-NET-HAM-RADIO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-HAM-RADIO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.ham-radio"
+OWNER-NET-INFO-TERMS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-INFO-TERMS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.info-terms"
+OWNER-NET-INVEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-INVEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.invest"
+OWNER-NET-JOBS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-JOBS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.jobs"
+OWNER-NET-JOKES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-JOKES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.jokes"
+OWNER-NET-JOKES-D IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-JOKES-D IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.jokes.d"
+OWNER-NET-KIDS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-KIDS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.kids"
+OWNER-NET-LAN IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LAN IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lan"
+OWNER-NET-LANG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang"
+OWNER-NET-LANG-ADA IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-ADA IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.ada"
+OWNER-NET-LANG-APL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-APL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.apl"
+OWNER-NET-LANG-C IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-C IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.c"
+OWNER-NET-LANG-F77 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-F77 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.f77"
+OWNER-NET-LANG-FORTH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-FORTH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.forth"
+OWNER-NET-LANG-LISP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-LISP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.lisp"
+OWNER-NET-LANG-MOD2 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-MOD2 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.mod2"
+OWNER-NET-LANG-PASCAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-PASCAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.pascal"
+OWNER-NET-LANG-PROLOG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-PROLOG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.prolog"
+OWNER-NET-LANG-ST80 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LANG-ST80 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lang.st80"
+OWNER-NET-LEGAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LEGAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.legal"
+OWNER-NET-LSI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-LSI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.lsi"
+OWNER-NET-MAG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MAG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.mag"
+OWNER-NET-MAIL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MAIL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.mail"
+OWNER-NET-MAIL-HEADERS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MAIL-HEADERS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.mail.headers"
+OWNER-NET-MAIL-MSGGROUP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MAIL-MSGGROUP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.mail.msggroup"
+OWNER-NET-MATH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MATH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.math"
+OWNER-NET-MATH-STAT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MATH-STAT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.math.stat"
+OWNER-NET-MATH-SYMBOLIC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MATH-SYMBOLIC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.math.symbolic"
+OWNER-NET-MED IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MED IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.med"
+OWNER-NET-MICRO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro"
+OWNER-NET-MICRO-16K IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-16K IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.16k"
+OWNER-NET-MICRO-432 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-432 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.432"
+OWNER-NET-MICRO-6809 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-6809 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.6809"
+OWNER-NET-MICRO-68K IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-68K IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.68k"
+OWNER-NET-MICRO-APPLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-APPLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.apple"
+OWNER-NET-MICRO-ATARI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-ATARI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.atari"
+OWNER-NET-MICRO-CBM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-CBM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.cbm"
+OWNER-NET-MICRO-CPM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-CPM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.cpm"
+OWNER-NET-MICRO-HP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-HP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.hp"
+OWNER-NET-MICRO-MAC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-MAC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.mac"
+OWNER-NET-MICRO-PC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-PC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.pc"
+OWNER-NET-MICRO-TI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-TI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.ti"
+OWNER-NET-MICRO-TRS-80 IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-TRS-80 IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.trs-80"
+OWNER-NET-MICRO-ZX IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MICRO-ZX IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.micro.zx"
+OWNER-NET-MISC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MISC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.misc"
+OWNER-NET-MOTSS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MOTSS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.motss"
+OWNER-NET-MOVIES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MOVIES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.movies"
+OWNER-NET-MOVIES-SW IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MOVIES-SW IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.movies.sw"
+OWNER-NET-MUSIC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MUSIC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.music"
+OWNER-NET-MUSIC-CLASSICAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-MUSIC-CLASSICAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.music.classical"
+OWNER-NET-NET-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NET-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.net-people"
+OWNER-NET-NEWS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news"
+OWNER-NET-NEWS-ADM IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-ADM IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.adm"
+OWNER-NET-NEWS-B IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-B IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.b"
+OWNER-NET-NEWS-CONFIG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-CONFIG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.config"
+OWNER-NET-NEWS-GROUP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-GROUP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.group"
+OWNER-NET-NEWS-MAP IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-MAP IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.map"
+OWNER-NET-NEWS-NEWSITE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-NEWSITE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.newsite"
+OWNER-NET-NEWS-SA IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NEWS-SA IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.news.sa"
+OWNER-NET-NLANG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NLANG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.nlang"
+OWNER-NET-NLANG-CELTS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NLANG-CELTS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.nlang.celts"
+OWNER-NET-NLANG-GREEK IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NLANG-GREEK IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.nlang.greek"
+OWNER-NET-NOTES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-NOTES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.notes"
+OWNER-NET-ORIGINS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ORIGINS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.origins"
+OWNER-NET-PERIPHS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-PERIPHS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.periphs"
+OWNER-NET-PETS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-PETS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.pets"
+OWNER-NET-PHILOSOPHY IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-PHILOSOPHY IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.philosophy"
+OWNER-NET-PHYSICS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-PHYSICS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.physics"
+OWNER-NET-POEMS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-POEMS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.poems"
+OWNER-NET-POLITICS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-POLITICS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.politics"
+OWNER-NET-PUZZLE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-PUZZLE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.puzzle"
+OWNER-NET-RAILROAD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RAILROAD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.railroad"
+OWNER-NET-REC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec"
+OWNER-NET-REC-BIRDS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-BIRDS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.birds"
+OWNER-NET-REC-BOAT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-BOAT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.boat"
+OWNER-NET-REC-BRIDGE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-BRIDGE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.bridge"
+OWNER-NET-REC-COINS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-COINS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.coins"
+OWNER-NET-REC-DISC IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-DISC IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.disc"
+OWNER-NET-REC-NUDE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-NUDE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.nude"
+OWNER-NET-REC-PHOTO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-PHOTO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.photo"
+OWNER-NET-REC-SCUBA IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-SCUBA IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.scuba"
+OWNER-NET-REC-SKI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-SKI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.ski"
+OWNER-NET-REC-SKYDIVE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-SKYDIVE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.skydive"
+OWNER-NET-REC-WOOD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-REC-WOOD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rec.wood"
+OWNER-NET-RELIGION IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RELIGION IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.religion"
+OWNER-NET-RELIGION-CHRISTIAN IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RELIGION-CHRISTIAN IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.religion.christian"
+OWNER-NET-RELIGION-JEWISH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RELIGION-JEWISH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.religion.jewish"
+OWNER-NET-RESEARCH IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RESEARCH IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.research"
+OWNER-NET-ROOTS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-ROOTS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.roots"
+OWNER-NET-RUMOR IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-RUMOR IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.rumor"
+OWNER-NET-SCI IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SCI IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sci"
+OWNER-NET-SF-LOVERS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SF-LOVERS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sf-lovers"
+OWNER-NET-SINGLES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SINGLES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.singles"
+OWNER-NET-SOCIAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SOCIAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.social"
+OWNER-NET-SOURCES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SOURCES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sources"
+OWNER-NET-SOURCES-BUGS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SOURCES-BUGS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sources.bugs"
+OWNER-NET-SPACE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPACE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.space"
+OWNER-NET-SPORT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPORT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sport"
+OWNER-NET-SPORT-BASEBALL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPORT-BASEBALL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sport.baseball"
+OWNER-NET-SPORT-FOOTBALL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPORT-FOOTBALL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sport.football"
+OWNER-NET-SPORT-HOCKEY IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPORT-HOCKEY IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sport.hockey"
+OWNER-NET-SPORT-HOOPS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SPORT-HOOPS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.sport.hoops"
+OWNER-NET-STARTREK IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-STARTREK IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.startrek"
+OWNER-NET-STD IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-STD IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.std"
+OWNER-NET-SUICIDE IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-SUICIDE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.suicide"
+OWNER-NET-TAXES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TAXES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.taxes"
+OWNER-NET-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.test"
+OWNER-NET-TEXT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TEXT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.text"
+OWNER-NET-TRAVEL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TRAVEL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.travel"
+OWNER-NET-TV IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TV IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.tv"
+OWNER-NET-TV-DRWHO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TV-DRWHO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.tv.drwho"
+OWNER-NET-TV-SOAPS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-TV-SOAPS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.tv.soaps"
+OWNER-NET-UNIX IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-UNIX IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.unix"
+OWNER-NET-UNIX-WIZARDS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-UNIX-WIZARDS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.unix-wizards"
+OWNER-NET-USENIX IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-USENIX IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.usenix"
+OWNER-NET-USOFT IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-USOFT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.usoft"
+OWNER-NET-VEG IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-VEG IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.veg"
+OWNER-NET-VIDEO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-VIDEO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.video"
+OWNER-NET-WANTED IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WANTED IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.wanted"
+OWNER-NET-WANTED-SOURCES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WANTED-SOURCES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.wanted.sources"
+OWNER-NET-WINES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WINES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.wines"
+OWNER-NET-WOBEGON IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WOBEGON IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.wobegon"
+OWNER-NET-WOMEN IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WOMEN IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.women"
+OWNER-NET-WOMEN-ONLY IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WOMEN-ONLY IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.women.only"
+OWNER-NET-WORKS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WORKS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.works"
+OWNER-NET-WORKS-APOLLO IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+NET-WORKS-APOLLO IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews net.works.apollo"
+OWNER-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews test"
+OWNER-UC-GENERAL IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UC-GENERAL IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews uc.general"
+OWNER-UC-NEWS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UC-NEWS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews uc.news"
+OWNER-UC-SOURCES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UC-SOURCES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews uc.sources"
+OWNER-UC-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UC-TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews uc.test"
+OWNER-UCB-ARTS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-ARTS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.arts"
+OWNER-UCB-EATS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-EATS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.eats"
+OWNER-UCB-HOUSING IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-HOUSING IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.housing"
+OWNER-UCB-JOBS IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-JOBS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.jobs"
+OWNER-UCB-TEST IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-TEST IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.test"
+OWNER-UCB-WINES IN MB UCB-VAX.ARPA
+ IN MG USENET-ADMIN
+UCB-WINES IN MB UCB-VAX.ARPA
+ IN MG "|/usr/spool/news/lib/recnews ucb.wines"
+2BSD-BUGS IN MB UCB-VAX.ARPA
+ IN MG 2BSD-BUGS@UCBARPA
+OWNER-2BSD-BUGS IN MB UCB-VAX.ARPA
+ IN MG CARL@UCBERNIE
+2BSD-HELP IN MB UCB-VAX.ARPA
+ IN MG CARL@UCBERNIE
+OWNER-2BSD-PEOPLE IN MB UCB-VAX.ARPA
+ IN MG CARL@UCBERNIE
+CORYV7BUGS IN MB UCB-VAX.ARPA
+ IN MG 2BSD-BUGS
+ALPHA281 IN MB UCB-VAX.ARPA
+ IN MG UCBERNIE.TO_ALPHA281_ARCHIVE
+ IN MG WILLIAM
+ IN MG DIST2
+ IN MG KARELS
+ IN MG TEKLABS!DAVEC
+ IN MG DECVAX!PUR-EE!PURDUE!JRS
+ IN MG DECVAX!PUR-EE!PUCC.ACG
+ IN MG HARPO!PRESBY!JOEL
+ IN MG BH@SU-AI
+ IN MG UCBCAD.VODERVAX!WJH12!CLP
+ IN MG SJK
+ IN MG TEKLABS!TEKCRD!STERLING
+ IN MG CROFT@SRI-UNIX
+ IN MG RANDVAX!FORTUNE!DAY
+ IN MG DOVE@MIT-DSPG@MIT-MC
+ IN MG MENLO70!BEKINS
+ IN MG SALKIND@NYU
+ IN MG UCBERNIE.TO_UUCP_ARCHIVE
+ IN MG ROMINE@SEISMO
+ IN MG HARPO!SEISMO!SDCCIS!STEWART
+ IN MG DECVAX!IDIS!MI-CEC!DVK
+ IN MG MBM@MIT-CIPG@MIT-MC
+ IN MG JPAYNE@BBN-UNIX
+ IN MG DAN@SRI-TSC
+ IN MG AMD70!ALPHA281
+BETA29 IN MB UCB-VAX.ARPA
+ IN MG WILLIAM
+ IN MG CARL
+ IN MG KARELS
+ IN MG LBL-CSAM!LANL-A!UNM-IVAX!BOB
+ IN MG WHEPS!VRV
+ IN MG TEKLABS!TEKCRD!DAVEC
+ IN MG MENLO70!HERRIOT
+ IN MG MENLO70!SLU70!EJH
+ IN MG FLOYD!PERI!ANDY
+ IN MG SALKIND@NYU
+ IN MG MENLO70!FONG
+ IN MG MENLO70!BEKINS
+ IN MG DAN@SRI-TSC
+ IN MG WSS
+ IN MG SJK
+ IN MG LBL-CSAM!LLL-TIS!WSS
+ IN MG AMD70!BETA29
+BARRY IN MB UCB-VAX.ARPA
+ IN MG TEKLABS!OGCVAX!METHEUS!BARRY
+ IN MG BARRY@KIM
+DECODE IN MB UCB-VAX.ARPA
+ IN MG "|/usr/ucb/uudecode"
+RXCT IN MB UCB-VAX.ARPA
+ IN MG "|/usr/new/rxct"
+BOBHENRY IN MB UCB-VAX.ARPA
+ IN MG RWH
+STAFF IN MB UCB-VAX.ARPA
+ IN MG SKLOWER
+ IN MG RALPH@ARPA
+ IN MG JKF
+ IN MG RWH
+ IN MG KARELS
+ IN MG MOSHER@ARPA
+CSOFFICE IN MB UCB-VAX.ARPA
+ IN MG JONATHAN
+ IN MG SWEET@ERNIE
+OPERATORS IN MB UCB-VAX.ARPA
+ IN MG ADAM@ARPA
+ IN MG TAG@ARPA
+ IN MG ALLYNH@ARPA
+ IN MG RWH
+DUMPER IN MB UCB-VAX.ARPA
+ IN MG ALLYNH@ARPA
+ IN MG RWH
+EATERS IN MB UCB-VAX.ARPA
+ IN MG WILLIAM
+ IN MG ED
+ IN MG LANDMAN
+ IN MG KSH
+ IN MG LARRY
+ IN MG CAMH@CORY
+ IN MG MICHAEL
+ IN MG MARK
+ IN MG PETER
+ IN MG FATEMAN
+ IN MG KARP
+ IN MG YING
+ IN MG UPSTILL
+ IN MG EARL
+ IN MG GEOFF
+ IN MG KRIDLE
+ IN MG HALBERT
+ IN MG DMU
+ IN MG PRESOTTO
+ IN MG WSS
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG WILDBILL
+ IN MG J.KALASH
+ IN MG KELLER@CAD
+ IN MG JTD@CAD
+ IN MG SMITH
+ IN MG ALBERTO@CAD
+NEFF IN MB UCB-VAX.ARPA
+ IN MG NEFF@UCBLAPIS.CC.BERKELEY.ARPA
+BARBM IN MB UCB-VAX.ARPA
+ IN MG BARBM@UCBRUBY.CC.BERKELEY.ARPA
+JBY IN MB UCB-VAX.ARPA
+ IN MG CFOJBY@UCBCMSA.CC.BERKELEY.ARPA
+SSCHWAB IN MB UCB-VAX.ARPA
+ IN MG SSCHWAB@UCBUGS
+APPLELAB IN MB UCB-VAX.ARPA
+ IN MG ALEX@ERNIE
+ IN MG CLANCY@ERNIE
+ IN MG COUCH@CORY
+ IN MG J.LARRY
+RMSGS IN MB UCB-VAX.ARPA
+ IN MG "|/usr/new/rmsgs -s"
+ IN MG KELLER
+ IN MG JTD@CAD
+ IN MG JPEEK
+ IN MG LOCK@CAD
+ IN MG FODERARO@DALI
+ IN MG MHA@KIM
+ IN MG DMU
+ IN MG MAYO
+MAPLE-SYS IN MB UCB-VAX.ARPA
+ IN MG MAPLE@KIM
+FPA IN MB UCB-VAX.ARPA
+ IN MG SKLOWER
+ IN MG PATTRSN
+ IN MG TAYLOR
+ IN MG ISRAEL
+ IN MG PATT
+ IN MG FATEMAN
+ IN MG COONEN
+ IN MG FMSGS
+ IN MG DEMMEL
+ IN MG ASPIN@DALI
+ IN MG LYLE
+ IN MG DAVIS
+ IN MG LEBLANC@DALI
+DOUCETTE IN MB UCB-VAX.ARPA
+ IN MG DOUCETTE@INGVAX
+PETERM IN MB UCB-VAX.ARPA
+ IN MG PETERM@UCBIC
+MKM IN MB UCB-VAX.ARPA
+ IN MG MCKUSICK
+KIRK IN MB UCB-VAX.ARPA
+ IN MG MCKUSICK
+CORTOPAS IN MB UCB-VAX.ARPA
+ IN MG JOE
+MIDI IN MB UCB-VAX.ARPA
+ IN MG MIDI@UCBSHADOW
+YOUNG IN MB UCB-VAX.ARPA
+ IN MG YOUNG@WASHINGTON.ARPA
+SWENSON IN MB UCB-VAX.ARPA
+ IN MG SWENSEN@ERNIE
+DEERING IN MB UCB-VAX.ARPA
+ IN MG DEERING@ERNIE
+SOURCES IN MB UCB-VAX.ARPA
+ IN MG SOURCES@ERNIE
+ALBERTO IN MB UCB-VAX.ARPA
+ IN MG ALBERTO@CAD
+WALL IN MB UCB-VAX.ARPA
+ IN MG WALL@UCBARPA
+CLEMC IN MB UCB-VAX.ARPA
+ IN MG CLEMC@UCBCAD
+FRISH IN MB UCB-VAX.ARPA
+ IN MG FRISH@UCBCORY
+MARION IN MB UCB-VAX.ARPA
+ IN MG MARION@UCBKIM
+NICCOLO IN MB UCB-VAX.ARPA
+ IN MG NICCOLO@CORY
+RICKS IN MB UCB-VAX.ARPA
+ IN MG RICKS@UCBCAD
+MIKE IN MB UCB-VAX.ARPA
+ IN MG MIKE@INGRES
+GILL IN MB UCB-VAX.ARPA
+ IN MG GILL@UCBEAR
+POHL IN MB UCB-VAX.ARPA
+ IN MG UCSCC!POHL
+AVI IN MB UCB-VAX.ARPA
+ IN MG AVI@UCBERNIE
+BH IN MB UCB-VAX.ARPA
+ IN MG BH@UCBDALI
+WILENSKY IN MB UCB-VAX.ARPA
+ IN MG WILENSKY@DALI
+OKSENIUK IN MB UCB-VAX.ARPA
+ IN MG OKSENIUK@DALI
+KORDA IN MB UCB-VAX.ARPA
+ IN MG KORDA@ERNIE
+F77 IN MB UCB-VAX.ARPA
+ IN MG SIF
+ IN MG FATEMAN
+ IN MG BIDDULPH
+ IN MG SKLOWER
+ IN MG ANLAMS!F77
+ IN MG JKF
+ IN MG DOUGLAS
+ IN MG ESVAX.F77
+ IN MG TBL@ERNIE
+ IN MG VAX135!TBL
+ IN MG GRAHAM
+ IN MG KAHAN
+ IN MG RABIN
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG MICHAEL
+ IN MG GST
+ IN MG DEMMEL
+ IN MG WILLIAM
+ IN MG YING
+ IN MG MENLO70!WARD
+ IN MG LEBLANC
+ IN MG UCSFCGL!TEF
+ IN MG RUSTY
+ IN MG CHACKO
+ IN MG HEAD@CORY
+ IN MG ED
+ IN MG AMD70!F77
+ADA IN MB UCB-VAX.ARPA
+ IN MG MARK
+ IN MG EARL
+ IN MG HALBERT
+ IN MG GRAHAM
+ IN MG DOUGLAS
+ IN MG DESPAIN
+ IN MG HILFINGER
+ IN MG DEERING
+ IN MG ELLIS@UCBCAD
+ IN MG JIMBO@UCBCAD
+ IN MG MP
+ IN MG YING
+ IN MG GARRISON
+ IN MG DMU
+ IN MG TEKLABS!STEVEG
+ IN MG SHANNON
+ IN MG DECVAX!APS
+ IN MG DECVAX!BM
+ IN MG KELLER
+ IN MG ANLAMS!ADA
+ IN MG MCCARTY
+ IN MG WASERMAN
+ IN MG KELLER@CAD
+ IN MG JTD@CAD
+EX IN MB UCB-VAX.ARPA
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG MICHAEL
+ IN MG RESEARCH!ARK
+ IN MG MHTSA!STEVE
+ IN MG MHTSA!MJS
+ IN MG HARPO!HOUXT!BRUCE
+ IN MG UWVAX!RAPHAEL
+ IN MG MHTSA!MHUXM!MITCH
+ IN MG HARPO!BER
+ IN MG VAX135!HPK
+ IN MG VAX135!ADB
+ IN MG RUSTY
+ IN MG DMU
+ IN MG WSS
+ IN MG YING
+ IN MG ERIC
+ IN MG DASILVA@C.CC
+ IN MG KIRK@D.CC
+ IN MG ALAN@CORY
+ IN MG LAYER
+ IN MG JIMBO@UCBCAD
+ IN MG ELLIS@UCBCAD
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG JOHNK@E.CC
+ IN MG GST
+ IN MG RON@NOSC-CC
+ IN MG WILLIAM
+ IN MG ALONSO@UCBARPA
+TORES IN MB UCB-VAX.ARPA
+ IN MG KRALEY@BBN-UNIX
+ IN MG JIS@MIT-AI
+ IN MG WILLIAM
+EXUPDATE IN MB UCB-VAX.ARPA
+ IN MG VAX135!HPK
+ IN MG RESEARCH!ARK
+ IN MG ERIC
+ IN MG KIRK
+ IN MG HARPO!BER
+ IN MG LAYER
+ IN MG RUSTY
+ IN MG RON@NOSC-CC
+ IN MG MENLO70!UCB
+MAC-USERS IN MB UCB-VAX.ARPA
+ IN MG MAC-USERS@UCBKIM
+MAC-USERS-REQUEST IN MB UCB-VAX.ARPA
+ IN MG MAC-USERS-REQUEST@UCBKIM
+JDD IN MB UCB-VAX.ARPA
+ IN MG ALLEGRA!JDD
+AGK IN MB UCB-VAX.ARPA
+ IN MG IHUXI!AGK
+SLG IN MB UCB-VAX.ARPA
+ IN MG IHUXI!IWSL1!SLG
+RAPHAEL IN MB UCB-VAX.ARPA
+ IN MG UWVAX!RAPHAEL
+SOLOMON IN MB UCB-VAX.ARPA
+ IN MG UWVAX!SOLOMON
+DEWITT IN MB UCB-VAX.ARPA
+ IN MG UWVAX!DEWITT
+DAVEM IN MB UCB-VAX.ARPA
+ IN MG TEKLABS!DAVEM
+STEVEG IN MB UCB-VAX.ARPA
+ IN MG TEKLABS!STEVEG
+DENNIS IN MB UCB-VAX.ARPA
+ IN MG DECVAX!DUKE!PHS!DENNIS
+SWD IN MB UCB-VAX.ARPA
+ IN MG HARPO!DUKE!SWD
+TRT IN MB UCB-VAX.ARPA
+ IN MG HARPO!DUKE!TRT
+MHTSAJEFF IN MB UCB-VAX.ARPA
+ IN MG MHTSA!JEFF
+IANJ IN MB UCB-VAX.ARPA
+ IN MG MHTSA!IANJ
+ IN MG IANJ
+MJS IN MB UCB-VAX.ARPA
+ IN MG MHTSA!MJS
+SJB IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!SJB
+SBB IN MB UCB-VAX.ARPA
+ IN MG CBOSG!SBB
+EWL IN MB UCB-VAX.ARPA
+ IN MG CBOSG!EWL
+GREG IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!GREG
+DENNING IN MB UCB-VAX.ARPA
+ IN MG PUR-EE!PURDUE!PJD
+DED IN MB UCB-VAX.ARPA
+ IN MG PUR-EE!PURDUE!DED
+DALE IN MB UCB-VAX.ARPA
+ IN MG CBOSG!DALE
+RUSTY IN MB UCB-VAX.ARPA
+ IN MG SDCARL!RUSTY
+DGL IN MB UCB-VAX.ARPA
+ IN MG SDCARL!DGL
+FRM IN MB UCB-VAX.ARPA
+ IN MG SDCARL!FRM
+WALLEN IN MB UCB-VAX.ARPA
+ IN MG SDCSVAX!WALLEN
+DBW IN MB UCB-VAX.ARPA
+ IN MG SDCSVAX!DBW
+TRB IN MB UCB-VAX.ARPA
+ IN MG FLOYD!TRB
+DIAMANDA IN MB UCB-VAX.ARPA
+ IN MG SDCARL!DIAMANDA
+ARPAPEOPLE IN MB UCB-VAX.ARPA
+ IN MG RAPHAEL
+ IN MG SOLOMON
+ IN MG DAVEM
+ IN MG STEVEG
+ IN MG DENNIS
+ IN MG SWD
+ IN MG MHTSAJEFF
+ IN MG IANJ
+ IN MG MJS
+ IN MG GREG
+ IN MG ARDEN
+ IN MG DENNING
+ IN MG DEWITT
+ IN MG DALE
+ IN MG RUSTY
+ IN MG MP
+ IN MG DBW
+ IN MG FRM
+ IN MG DGL
+ IN MG DIAMANDA
+ IN MG DECVAX!APS
+ IN MG SJK
+RAS IN MB UCB-VAX.ARPA
+ IN MG PETER
+ IN MG HALBERT
+ IN MG JKF
+ IN MG SOIFFER
+ IN MG EUKEL@ESVAX
+ IN MG HURST@CAD
+ IN MG RDF@CAD
+ IN MG KURT@INGRES
+ IN MG MCCARTY
+ IN MG MHA@KIM
+CSNET-PLAN-GROUP IN MB UCB-VAX.ARPA
+ IN MG ROWE
+ IN MG HABERMANN@CMU-10A
+ IN MG FELDMAN@SUMEX-AIM
+ IN MG FATEMAN
+ IN MG FARBER@UDEL-EE
+ IN MG CERF@USC-ISI
+ IN MG FARBER@DARCOM-KA
+ IN MG WFRANTA.NSP@HI-MULTICS
+ IN MG HEARN@UTAH-20
+ IN MG NSF-CS@USC-ISI
+ IN MG LANDWEBER
+ IN MG CORBATO@MIT-XX
+ IN MG ARDEN
+ IN MG DENNING
+ IN MG RITCHIE
+ IN MG KAHN@USC-ISI
+ IN MG CSL.LANTZ@SU-SCORE
+ IN MG SPROULL@CMU-10A
+ IN MG BATSON@UTAH-20
+ IN MG PHELLER.EDUCOM@MIT-MULTICS
+ IN MG MARK
+ IN MG ERIC
+ IN MG DECVAX!APS
+ IN MG RASHID@CMU-10A
+ IN MG TEKLABS!RICKL
+ IN MG TEKLABS!TOMM
+ IN MG AMD70!CSNET
+ IN MG LAYER
+CSNET-INF IN MB UCB-VAX.ARPA
+ IN MG CSNET-PLAN-GROUP
+ IN MG POSTEL@ISIE
+ IN MG DCROCKER@UDEL-EE
+ IN MG UNCAPHER@USC-ISIB
+ IN MG DECVAX!APS
+ IN MG HARRISON@UCBRENOIR
+ IN MG TEKLABS!RICKL
+ IN MG TEKLABS!TOMM
+CAROLE IN MB UCB-VAX.ARPA
+ IN MG CAROLE@ERNIE
+MARK IN MB UCB-VAX.ARPA
+ IN MG CBOSGD!MARK
+MRH IN MB UCB-VAX.ARPA
+ IN MG MARK
+HORTON IN MB UCB-VAX.ARPA
+ IN MG MARK
+MARKH IN MB UCB-VAX.ARPA
+ IN MG MARK
+2BSD IN MB UCB-VAX.ARPA
+ IN MG DIST2@ERNIE
+ IN MG GRAHAM@ERNIE
+ IN MG 2BSD@CORY
+GRAHAM IN MB UCB-VAX.ARPA
+ IN MG GRAHAM@UCBERNIE
+EATS IN MB UCB-VAX.ARPA
+ IN MG UPSTILL
+CHUCK IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!CHUCK
+KEN IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!KEN
+DMR IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!DMR
+SIF IN MB UCB-VAX.ARPA
+ IN MG SIF@UCBKIM
+WCWELLS IN MB UCB-VAX.ARPA
+ IN MG WCWELLS@UCBOPAL
+SCJ IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!SCJ
+DAVE IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!DAVE
+DITZEL IN MB UCB-VAX.ARPA
+ IN MG DAVE
+BWK IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!BWK
+RFC IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!ALICE!RFC
+HOWARD IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+HAL IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+PLA IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+ IN MG DESPAIN
+ IN MG JKF
+ IN MG SEQUIN
+ IN MG RFC
+ IN MG JIMBO@CAD
+ IN MG NEWTON@CAD
+MKPLA IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+MKFSM IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+PLACE IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+PLASORT IN MB UCB-VAX.ARPA
+ IN MG JIMBO@CAD
+ IN MG LANDMAN
+SIMIAN IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+SYNMOS IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+SYNMOS IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+XLINK IN MB UCB-VAX.ARPA
+ IN MG LANDMAN
+ IN MG DECUIR
+ IN MG SEQUIN
+XPORT IN MB UCB-VAX.ARPA
+ IN MG XLINK
+JOLITZ IN MB UCB-VAX.ARPA
+ IN MG WILLIAM
+WILLIAM IN MB UCB-VAX.ARPA
+ IN MG WILLIAM@ERNIE
+ IN MG TO_WILLIAM_ARCHIVE@ERNIE
+KEVIN IN MB UCB-VAX.ARPA
+ IN MG KEVIN@CORY
+RWB IN MB UCB-VAX.ARPA
+ IN MG RWB@UCBMEDEA
+PAG IN MB UCB-VAX.ARPA
+ IN MG PAG@ERNIE
+KATSEFF IN MB UCB-VAX.ARPA
+ IN MG KATSEFF@ERNIE
+KAVALER IN MB UCB-VAX.ARPA
+ IN MG KAVALER@KIM
+HPK IN MB UCB-VAX.ARPA
+ IN MG VAX135!HPK
+JFR IN MB UCB-VAX.ARPA
+ IN MG VAX135!JFR
+BER IN MB UCB-VAX.ARPA
+ IN MG HARPO!BER
+TOY IN MB UCB-VAX.ARPA
+ IN MG TOY@ARPA
+FICH IN MB UCB-VAX.ARPA
+ IN MG FAITH
+TANDY IN MB UCB-VAX.ARPA
+ IN MG TANDY@INGRES
+VAXIMA IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG CHAR
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG LAYER
+ IN MG RABIN
+ IN MG BIRMAN
+ IN MG FKUNZE
+ IN MG YING
+ IN MG LEBLANC
+ IN MG HALBERT
+ IN MG DOUGLAS
+ IN MG SOIFFER
+ IN MG DESPAIN
+ IN MG DRB
+ IN MG YING
+ IN MG TANG
+ IN MG KELLER@CAD
+ IN MG JTD@CAD
+VAXIMA-I IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG CHAR
+ IN MG DOUGLAS
+ IN MG LAYER
+ANDANTE IN MB UCB-VAX.ARPA
+ IN MG DRB
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG FATEMAN
+ IN MG CHAR
+ IN MG SOIFFER
+ IN MG DEMMEL
+ IN MG /USR/NEWS/ANDANTE
+PASCADA IN MB UCB-VAX.ARPA
+ IN MG GRAHAM
+ IN MG IP
+ IN MG GARRISON
+ IN MG ALBRECHT
+ IN MG SHIVAJI
+SEMINAR IN MB UCB-VAX.ARPA
+ IN MG JKF@KIM
+FORT IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG SIF
+ IN MG SKLOWER
+FATEMAN IN MB UCB-VAX.ARPA
+ IN MG FATEMAN@UCBDALI
+TAMIR IN MB UCB-VAX.ARPA
+ IN MG TAMIR@UCBKIM
+HALPERN IN MB UCB-VAX.ARPA
+ IN MG JDH@MITRE-BEDFORD
+PECK IN MB UCB-VAX.ARPA
+ IN MG GEOFF
+WASSERMAN IN MB UCB-VAX.ARPA
+ IN MG WASERMAN
+TONYW IN MB UCB-VAX.ARPA
+ IN MG WASERMAN
+GGP IN MB UCB-VAX.ARPA
+ IN MG GEOFF@ERNIE
+GEOFF IN MB UCB-VAX.ARPA
+ IN MG GEOFF@UCBARPA
+JTD IN MB UCB-VAX.ARPA
+ IN MG JTD@CAD
+CSGSA IN MB UCB-VAX.ARPA
+ IN MG PRESOTTO
+ IN MG SOIFFER
+ IN MG GARRISON
+ IN MG BART
+BERKSFS IN MB UCB-VAX.ARPA
+ IN MG RICKI@UCBKIM
+ IN MG BART
+ IN MG SCOTT@UCBKIM
+ IN MG WSS@LLL-COMP
+ IN MG PETER
+ IN MG HAMACHI
+ IN MG PRESOTTO
+ IN MG DMU
+ IN MG ATEMAN
+ IN MG SIF
+ IN MG NORVIG@UCBKIM
+APNYT IN MB UCB-VAX.ARPA
+ IN MG "|cat > /usr/public/apnyt"
+LANAM IN MB UCB-VAX.ARPA
+ IN MG DOUGLAS@ERNIE
+DHL IN MB UCB-VAX.ARPA
+ IN MG DOUGLAS@ERNIE
+DOUGLAS IN MB UCB-VAX.ARPA
+ IN MG DOUGLAS@ERNIE
+RABIN IN MB UCB-VAX.ARPA
+ IN MG RABIN@ERNIE
+KJW IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!MDDM!KJW
+ERICS IN MB UCB-VAX.ARPA
+ IN MG SHIENBRO@BBN-UNIX
+YING IN MB UCB-VAX.ARPA
+ IN MG DECVAX!HARPO!IHPS3!HOUXQ!YING
+CHAR IN MB UCB-VAX.ARPA
+ IN MG ALLEGRA!WATMATH!WATDAISY!BWCHAR
+MICHAEL IN MB UCB-VAX.ARPA
+ IN MG MICHAEL@ERNIE
+PAULW IN MB UCB-VAX.ARPA
+ IN MG KENTVAX!PAULW
+DCH IN MB UCB-VAX.ARPA
+ IN MG HALBERT
+UUCP-MAP IN MB UCB-VAX.ARPA
+ IN MG FAIR
+ IN MG RICKS
+ IN MG DLW@UCBOPAL
+FAIR IN MB UCB-VAX.ARPA
+ IN MG FAIR@UCBARPA
+ERIK IN MB UCB-VAX.ARPA
+ IN MG FAIR
+EEF IN MB UCB-VAX.ARPA
+ IN MG \FAIR
+BRAND IN MB UCB-VAX.ARPA
+ IN MG BRAND@UCBERNIE
+HEAD IN MB UCB-VAX.ARPA
+ IN MG HEAD@UCBARPA
+SMH IN MB UCB-VAX.ARPA
+ IN MG HEAD
+H19S IN MB UCB-VAX.ARPA
+ IN MG ALONSO@UCBARPA
+ IN MG CHACKO
+ IN MG COOPER
+ IN MG FUJIMOTO
+ IN MG GARDNER
+ IN MG GARRISON
+ IN MG GEOFF
+ IN MG HAGMANN@UCBINGRES
+ IN MG HARRISON@UCBRENOIR
+ IN MG HATCHER@UCBCORY
+ IN MG HEAD@UCBARPA
+ IN MG JKF
+ IN MG MCCARTY
+ IN MG MRLLAN@B.CC
+ IN MG PETER
+ IN MG SCHULTZ
+ IN MG TAMIR
+ IN MG TERRY
+ IN MG WALLEN
+ IN MG WSS
+ IN MG AMD!H19S
+ IN MG SDCARL!H19
+ IN MG FELDMAN
+ IN MG GRAHAM
+ IN MG OLDPHIL
+ IN MG DMU
+ IN MG CONDE
+ IN MG WINKLER
+ IN MG HUTTON
+ IN MG ANLAMS!H19S
+ IN MG BLOOM@UCBSHADOW
+ IN MG ABAR
+ IN MG ARENS@UCBKIM
+ IN MG JSC@MIRO
+MIMES IN MB UCB-VAX.ARPA
+ IN MG MARK
+ IN MG HALBERT
+ IN MG SOIFFER
+ IN MG DIPPE
+CONCEPTS IN MB UCB-VAX.ARPA
+ IN MG BADEN
+ IN MG BARSKY
+ IN MG ERIC
+ IN MG GRAHAM
+ IN MG HARRISON@UCBRENOIR
+ IN MG HILFINGER
+ IN MG LARUS
+ IN MG LAYER
+ IN MG WILENSKY
+ IN MG CONCEPTS@LBL-CSAM.ARPA
+ IN MG UCSFCGL!TEF
+BAIB IN MB UCB-VAX.ARPA
+ IN MG BORSKE
+ IN MG BADEN
+ IN MG BARRY
+ IN MG DAVIS
+ IN MG DMU@UCBKIM
+ IN MG MHA@UCBKIM
+NEWTON IN MB UCB-VAX.ARPA
+ IN MG NEWTON@UCBCAD
+ILP IN MB UCB-VAX.ARPA
+ IN MG AMANDA@UCBCAD
+ IN MG NEWTON@UCBCAD
+CHIN IN MB UCB-VAX.ARPA
+ IN MG CHIN@UCBDALI
+FALETTI IN MB UCB-VAX.ARPA
+ IN MG FALETTI@UCBDALI
+PEARL-BUGS IN MB UCB-VAX.ARPA
+ IN MG PEARL-BUGS@UCBKIM
+PROG-D IN MB UCB-VAX.ARPA
+ IN MG PROG-D@UCBDEGAS
+PROG-D-REQUEST IN MB UCB-VAX.ARPA
+ IN MG UPSTILL@UCBDEGAS
+JACOBS IN MB UCB-VAX.ARPA
+ IN MG JACOBS@UCBDALI
+LURIA IN MB UCB-VAX.ARPA
+ IN MG LURIA@UCBDALI
+MARTIN IN MB UCB-VAX.ARPA
+ IN MG MARTIN@UCBDALI
+MAYFIELD IN MB UCB-VAX.ARPA
+ IN MG MAYFIELD@UCBDALI
+NORVIG IN MB UCB-VAX.ARPA
+ IN MG NORVIG@UCBDALI
+LEBLANC IN MB UCB-VAX.ARPA
+ IN MG LEBLANC@UCBDALI
+PTANG IN MB UCB-VAX.ARPA
+ IN MG PTANG@UCBDALI
+RWB IN MB UCB-VAX.ARPA
+ IN MG RWB@MEDEA
+HY IN MB UCB-VAX.ARPA
+ IN MG HY@UCBOZ
+EUKEL IN MB UCB-VAX.ARPA
+ IN MG EUKEL@ESVAX
+RISC IN MB UCB-VAX.ARPA
+ IN MG PATTRSN
+ IN MG SEQUIN
+ IN MG TAMIR
+ IN MG RISCIT
+ IN MG RESEARCH!DAVE
+ IN MG EARL
+ IN MG RFC
+ IN MG HALBERT
+ IN MG JIMBO@CAD
+ IN MG ELLIS@CAD
+ IN MG LOCK
+ IN MG NEWTON
+ IN MG TAYLOR
+ IN MG DMU
+ IN MG JKF
+ IN MG KELLER
+ IN MG LANDMAN
+ IN MG ALONSO@UCBARPA
+ IN MG MCCARTY
+ IN MG JTD@CAD
+RISCE IN MB UCB-VAX.ARPA
+ IN MG BADEN
+ IN MG BECK
+ IN MG DAVIS
+ IN MG HANSEN
+ IN MG PATTRSN
+ IN MG SHILOH
+OSMOSIS IN MB UCB-VAX.ARPA
+ IN MG POWELL
+ IN MG BART
+ IN MG LINTON
+ IN MG PRESOTTO
+ IN MG GARDNER
+ IN MG WILDBILL
+ IN MG BECK
+ IN MG WEIJIN
+TESTER IN MB UCB-VAX.ARPA
+ IN MG BECK
+ IN MG RFC
+ IN MG KORBINV@UCBKIM
+ IN MG PATTRSN
+ IN MG JKF
+ IN MG FITZ
+ IN MG KELLER@CAD
+ IN MG JIMBO@CAD
+PROBER IN MB UCB-VAX.ARPA
+ IN MG BECK
+ IN MG KORBINV@KIM
+ IN MG JKF
+ IN MG PATTRSN
+ IN MG SPP@ESVAX
+ IN MG RWB@ESVAX
+ IN MG RDF@ESVAX
+ IN MG HURST@ESVAX
+ IN MG GLAD@ESVAX
+ IN MG TCC@ESVAX
+ IN MG BJORN@ESVAX
+ IN MG YUNUS@ESVAX
+ IN MG KELLER@CAD
+ IN MG JIMBO@CAD
+CHS IN MB UCB-VAX.ARPA
+ IN MG CSH@ERNIE
+VAXCOM IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG KRIDLE
+ IN MG HALBERT
+ IN MG PATTRSN
+ IN MG BERLEK
+ IN MG SMITH
+JFK IN MB UCB-VAX.ARPA
+ IN MG JKF
+KORBINV IN MB UCB-VAX.ARPA
+ IN MG KORBINV@ERNIE
+MHA IN MB UCB-VAX.ARPA
+ IN MG MHA@UCBKIM
+LYRA IN MB UCB-VAX.ARPA
+ IN MG MHA@UCBKIM
+CADDY IN MB UCB-VAX.ARPA
+ IN MG OUSTER
+ IN MG SEQUIN
+ IN MG DMU
+ IN MG FITZ
+ IN MG WALLACE
+ IN MG MHA
+ IN MG KELLER@CAD
+ IN MG MAYO
+MCLURE IN MB UCB-VAX.ARPA
+ IN MG MENLO70!SRI-UNIX!MCLURE
+EMACSUSERS IN MB UCB-VAX.ARPA
+ IN MG YING
+ IN MG FATEMAN
+ IN MG JKF
+ IN MG WILENSKY
+ IN MG KOHNBD
+ IN MG COOPER
+ IN MG DOUGLAS
+ IN MG ANLAMS!BOYLE
+ IN MG MCCARTY
+ IN MG BADEN
+ IN MG SHILOH
+ IN MG BARSKY
+ IN MG GEOFF
+ IN MG TAMIR
+ IN MG EARL
+ IN MG AMD70!EMACS
+ IN MG LAYER
+ IN MG HARRISON@UCBRENOIR
+ IN MG NORVIG@DALI
+ IN MG ARENS@DALI
+ IN MG CHIN@DALI
+ IN MG LURIA@DALI
+ IN MG PORCARJ
+ IN MG CONDE
+ IN MG KELLER@CAD
+ IN MG JTDI@CAD
+ IN MG ELDRIDGE
+EMACS IN MB UCB-VAX.ARPA
+ IN MG EMACSUSERS
+ IN MG EMACSUSERS@UCBARPA
+ IN MG LBL-CSAM!EMACSUSERS
+ IN MG UNIX.EMACS@CMU-10A
+LOCAL-EMACS IN MB UCB-VAX.ARPA
+ IN MG EMACSUSERS
+ IN MG EMACSUSERS@UCBARPA
+ IN MG LBL-CSAM!EMACSUSERS
+ IN MG MARK
+LISZTBUGS IN MB UCB-VAX.ARPA
+ IN MG JKF@UCBKIM
+ IN MG LAYER
+RJF IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+SRB IN MB UCB-VAX.ARPA
+ IN MG RESEARCH!SRB
+BUZ IN MB UCB-VAX.ARPA
+ IN MG UCLA-S!BUZ
+KEBI IN MB UCB-VAX.ARPA
+ IN MG KEBI@UCBERNIE
+TEF IN MB UCB-VAX.ARPA
+ IN MG TEF@ERNIE
+FERRIN IN MB UCB-VAX.ARPA
+ IN MG TEF
+KELLER IN MB UCB-VAX.ARPA
+ IN MG KELLER@CAD
+ABARBANEL IN MB UCB-VAX.ARPA
+ IN MG ABAR
+RL IN MB UCB-VAX.ARPA
+ IN MG UCSFCGL!RL
+V7BUGS IN MB UCB-VAX.ARPA
+ IN MG UCSFCGL!TEF
+ IN MG MICHAEL
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG ERIC
+ IN MG RUSTY
+ IN MG LAYER
+ IN MG /USR/NEWS/V7BUGS
+ IN MG RESEARCH!DMR
+ IN MG KRIDLE
+ IN MG MHTSA!STEVE
+ IN MG WHIT@LL-ASG
+ IN MG KAS
+ IN MG WINKLER
+ IN MG MHTSA!WHR
+ IN MG JIMBO@CAD
+ IN MG SCHULTZ
+ IN MG ELLIS@CAD
+ IN MG MP@MIT-ML
+ IN MG WILLIAM
+ IN MG MENLO70!BUGS
+ IN MG WSS
+ IN MG DECPEOPLE
+ IN MG SDCSVAX!SDCATTB!MADDEN
+ IN MG MCCARTY
+ IN MG JTD@CAD
+ IN MG AMD70!V7BUGS
+ IN MG LAYER
+VBALL IN MB UCB-VAX.ARPA
+ IN MG GARRISON
+ IN MG DMU
+ IN MG JKF
+ IN MG HAMACHI
+ IN MG MCCARTY
+PROLOG IN MB UCB-VAX.ARPA
+ IN MG PROLOG@UCBERNIE
+KRIDLE IN MB UCB-VAX.ARPA
+ IN MG KRIDLE@CORY
+GST IN MB UCB-VAX.ARPA
+ IN MG TRUJILLO@LBL-CSAM
+ALLCAD IN MB UCB-VAX.ARPA
+ IN MG XTREE
+ IN MG CAD@ESVAX
+ IN MG CAD@CAD
+HPTERMS IN MB UCB-VAX.ARPA
+ IN MG JIMBO@CAD
+ IN MG ELLIS@CAD
+ IN MG MARK
+ IN MG SHARAD@ERNIE
+ IN MG UCSFCGL!TOM
+ IN MG ERIC
+ IN MG VANANDEL@CORY
+ IN MG MARK
+ IN MG HY
+ IN MG SEQUIN
+ IN MG MCBURNET
+ IN MG DMU
+ IN MG QUARLES@CAD
+ IN MG JTD@CAD
+GOODMAN IN MB UCB-VAX.ARPA
+ IN MG GOODMAN@ERNIE
+PROGRES IN MB UCB-VAX.ARPA
+ IN MG PROGRES@ERNIE
+BABAOGLU IN MB UCB-VAX.ARPA
+ IN MG OZALP@CORNELL
+OZALP IN MB UCB-VAX.ARPA
+ IN MG OZALP@CORNELL
+JUAN IN MB UCB-VAX.ARPA
+ IN MG PORCARJ
+PORCAR IN MB UCB-VAX.ARPA
+ IN MG PORCARJ
+HILL IN MB UCB-VAX.ARPA
+ IN MG MARKHILL
+SIPPEL IN MB UCB-VAX.ARPA
+ IN MG SIPPEL@UCBKIM
+BRUCKNER IN MB UCB-VAX.ARPA
+ IN MG CLAUSEN.IABG@MIT-MULTICS
+DECPEOPLE IN MB UCB-VAX.ARPA
+ IN MG DECVAX!FRED
+ IN MG DECVAX!APS
+APS IN MB UCB-VAX.ARPA
+ IN MG APS@UCBARPA
+SHANNON IN MB UCB-VAX.ARPA
+ IN MG SHANNON@UCBARPA
+DUE IN MB UCB-VAX.ARPA
+ IN MG DLW@RUBY
+KURT IN MB UCB-VAX.ARPA
+ IN MG KURT@INGRES
+RATMAN IN MB UCB-VAX.ARPA
+ IN MG MORGAN
+JOE IN MB UCB-VAX.ARPA
+ IN MG JOE@INGRES
+LARRY IN MB UCB-VAX.ARPA
+ IN MG LARRY@INGRES
+ROWE IN MB UCB-VAX.ARPA
+ IN MG LARRY@INGRES
+KAS IN MB UCB-VAX.ARPA
+ IN MG KURT@INGRES
+BOUNCE IN MB UCB-VAX.ARPA
+ IN MG RXCT@INGRES
+68000 IN MB UCB-VAX.ARPA
+ IN MG DEERING
+ IN MG JIMBO@CAD
+ IN MG ELLIS@CAD
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG VAX135!HPK
+ IN MG VAX135!TBL
+ IN MG KELLER@CAD
+ IN MG JTD@CAD
+ IN MG DOUGLAS
+ IN MG BRZ
+ IN MG DESPAIN
+ IN MG GEOFF
+ IN MG MICROCOMPUTER@RUTGERS
+ IN MG RUSTY
+ IN MG DMU
+ IN MG WSS
+ IN MG WILLIAM
+ IN MG ALONSO@UCBARPA
+ IN MG KELLER
+ IN MG HALBERT
+ IN MG MCCARTY
+ IN MG SJK
+ IN MG KALASH
+ IN MG LAYER
+STEVE IN MB UCB-VAX.ARPA
+ IN MG MHTSA!STEVE
+AI-GAMERS IN MB UCB-VAX.ARPA
+ IN MG MARK
+ IN MG DOUGLAS
+ IN MG ROMINE@SDAC-UNIX
+ IN MG GHB
+ IN MG DANIEL@MIT-ML
+ IN MG MIKE@UCLA-SECURITY
+ IN MG SHL@MIT-MC
+ IN MG HICKMAN
+ IN MG MHTSA!MJS
+ IN MG KEVIN@CORY
+ IN MG KALASH@CORY
+ IN MG HATCHER@CORY
+ IN MG DEERING
+ IN MG DRB
+ IN MG DMU
+ IN MG WILLIAM
+ IN MG MHTSA!BSO
+ IN MG MCCARTY
+ IN MG BAIR
+BILL IN MB UCB-VAX.ARPA
+ IN MG WNJ
+ANITA IN MB UCB-VAX.ARPA
+ IN MG JOPLIN@UCBERNIE
+JOPLIN IN MB UCB-VAX.ARPA
+ IN MG JOPLIN@UCBERNIE
+MCBURNET IN MB UCB-VAX.ARPA
+ IN MG MHTSA!DRUXV!NEAL
+VERBINSK IN MB UCB-VAX.ARPA
+ IN MG HO3E2!CAV
+CINDY IN MB UCB-VAX.ARPA
+ IN MG HO3E2!CAV
+EPA IN MB UCB-VAX.ARPA
+ IN MG ERIC
+UCBERIC IN MB UCB-VAX.ARPA
+ IN MG UCBERIC@UCBARPA
+BLIERIC IN MB UCB-VAX.ARPA
+ IN MG UCSFCGL!BLIA!ERIC
+OWNER-BLIERIC IN MB UCB-VAX.ARPA
+ IN MG UCBERIC
+MAIL-BUGS IN MB UCB-VAX.ARPA
+ IN MG MAIL-BUGS@UCBARPA
+JIMBO IN MB UCB-VAX.ARPA
+ IN MG JIMBO@UCBCAD
+KLECKNER IN MB UCB-VAX.ARPA
+ IN MG JIMBO@UCBCAD
+SPLICE IN MB UCB-VAX.ARPA
+ IN MG SPLICE@UCBCAD
+SPICE IN MB UCB-VAX.ARPA
+ IN MG SPICE@UCBCAD
+ARPANEWS IN MB UCB-VAX.ARPA
+ IN MG RWK@MIT-MC
+ IN MG ZELLICH@OFFICE-1
+ IN MG DAVID@UTEXAS
+ IN MG SWG@MIT-DMS
+ IN MG HAINES@LL
+ IN MG COINS@USC-ISI
+ IN MG ZELLICH@OFFICE-1
+ IN MG MEYERS@SRI-KL
+ IN MG OBRIEN@RAND-UNIX
+ IN MG WALKER.9993I6180@RADC-MULTICS
+ IN MG MORGAN@WHARTON
+ IN MG LAUREN@UCLA-SECURITY
+ IN MG WEDEL@UTEXAS
+ IN MG OAF@MIT-MC
+ IN MG VAX135!HPK
+ IN MG RON@NOSC-CC
+ IN MG POSTEL@ISIF
+ IN MG CROFT@SRI-UNIX
+ IN MG WANCHO@DARCOM-KA
+ IN MG HEROT@CCA
+ IN MG HOLMGREN@MITRE
+ IN MG LAYER
+ IN MG DAY@RAND-UNIX
+ IN MG MP@ML
+ IN MG WILLIAM
+ IN MG GHB
+ IN MG SJK
+ IN MG LBL-CSAM!MO
+ IN MG KELLER@CAD
+ IN MG JTD@CAD
+NOBODY IN MB UCB-VAX.ARPA
+ IN MG /DEV/NULL
+PATTERSON IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+PATTERSN IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+PATTRSON IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+PATTERSO IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+PATERSON IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+OUSTERHOUT IN MB UCB-VAX.ARPA
+ IN MG OUSTER
+OUSTER IN MB UCB-VAX.ARPA
+ IN MG OUSTER@KIM
+PATTRSN IN MB UCB-VAX.ARPA
+ IN MG PATTRSN@KIM
+THOMPSON IN MB UCB-VAX.ARPA
+ IN MG THOMPSON@UCBARPA
+ZADEH IN MB UCB-VAX.ARPA
+ IN MG ZADEH@DALI
+FORTUNE IN MB UCB-VAX.ARPA
+ IN MG ARNOLD
+ED IN MB UCB-VAX.ARPA
+ IN MG VODERVAX!ED
+ IN MG UNISOFT!ED
+CSR IN MB UCB-VAX.ARPA
+ IN MG CSRGINFO@UCBARPA
+CSRGINFO IN MB UCB-VAX.ARPA
+ IN MG CSRGINFO@UCBARPA
+CSRGSTAFF IN MB UCB-VAX.ARPA
+ IN MG CSRGSTAFF@UCBARPA
+CSRG IN MB UCB-VAX.ARPA
+ IN MG MOSHER
+ IN MG JANET
+EEFACULTY IN MB UCB-VAX.ARPA
+ IN MG EEFACULTY@UCBEAR
+CSFACULTY IN MB UCB-VAX.ARPA
+ IN MG BARSKY@ERNIE
+ IN MG BERLEK@ERNIE
+ IN MG BLUM@ERNIE
+ IN MG CLANCY@ERNIE
+ IN MG DESPAIN@ERNIE
+ IN MG FABRY@UCBARPA
+ IN MG FATEMAN@DALI
+ IN MG FERRARI@ERNIE
+ IN MG GILL@UCBEAR
+ IN MG GRAHAM@ERNIE
+ IN MG GROSH@ERNIE
+ IN MG HARRISON@UCBRENOIR
+ IN MG HILFINGER
+ IN MG KAHAN@ERNIE
+ IN MG KARP@ERNIE
+ IN MG LOU@UCBARPA
+ IN MG LAWLER@ERNIE
+ IN MG LYLE@ERNIE
+ IN MG MORTON@UCBARPA
+ IN MG OUSTER@KIM
+ IN MG PARLETT@ERNIE
+ IN MG PATT@ERNIE
+ IN MG PATTRSN@ERNIE
+ IN MG RAM@ERNIE
+ IN MG ROWE@INGRES
+ IN MG SEQUIN@ERNIE
+ IN MG SMITH@ERNIE
+ IN MG MIKE@INGRES
+ IN MG THOMPSON@UCBARPA
+ IN MG TUTTLE@ERNIE
+ IN MG WASERMAN@RENOIR
+ IN MG WILENSKY@DALI
+ IN MG ZADEH@DALI
+ IN MG CAROLE@ERNIE
+ IN MG SWEET@ERNIE
+EECSFACULTY IN MB UCB-VAX.ARPA
+ IN MG CSFACULTY
+ IN MG EEFACULTY
+ALLFACULTY IN MB UCB-VAX.ARPA
+ IN MG EECSFACULTY
+FACULTY IN MB UCB-VAX.ARPA
+ IN MG CSFACULTY
+THEORY IN MB UCB-VAX.ARPA
+ IN MG THEORY-F
+ IN MG THEORY-G
+ IN MG THEORY-S
+THEORY-F IN MB UCB-VAX.ARPA
+ IN MG BERLEK
+ IN MG BLUM
+ IN MG GILL@UCBEAR
+ IN MG HARRISON@UCBRENOIR
+ IN MG KAHAN
+ IN MG KARP
+ IN MG LAWLER
+ IN MG PARLETT
+ IN MG THOMPSON@UCBARPA
+THEORY-G IN MB UCB-VAX.ARPA
+ IN MG DEMMEL
+ IN MG HILFINGER
+ IN MG GRAHAM
+THEORY-S IN MB UCB-VAX.ARPA
+ IN MG FAITH
+ IN MG DEMMEL
+ IN MG COOPER
+ IN MG DMU
+ IN MG WINKLER
+ IN MG BACH
+ IN MG SHAFI
+ IN MG SHALLIT
+ IN MG SILVIO
+ IN MG NOTION
+ IN MG PELEGRI
+ IN MG JOAN
+ IN MG KARLOFF
+ IN MG POTONG
+ IN MG HELENA
+ IN MG VAZIRANI
+ IN MG SHMOYS
+ IN MG PERALTA
+GRAPHICS-WORLD IN MB UCB-VAX.ARPA
+ IN MG UPSTILL
+ IN MG DIPPE
+ IN MG BARSKY
+ IN MG SWENSEN
+ IN MG WILHELMS
+ IN MG DEROSE
+ IN MG HARUYAMA
+PS300 IN MB UCB-VAX.ARPA
+ IN MG UCSFCGL!TEF
+ IN MG BARSKY
+ IN MG DIPPE
+ IN MG SWENSEN
+ IN MG UPSTILL
+ IN MG WILHELMS
+ IN MG DEROSE
+ IN MG STRAUSS
+ IN MG HARUYAMA
+PLAIN IN MB UCB-VAX.ARPA
+ IN MG WASERMAN
+ IN MG CITRIN
+ IN MG PIRCHER
+4BSD-BUGS IN MB UCB-VAX.ARPA
+ IN MG 4BSD-BUGS@UCBARPA
+4BSD-IDEAS IN MB UCB-VAX.ARPA
+ IN MG 4BSD-IDEAS@UCBARPA
+4BSD-HELP IN MB UCB-VAX.ARPA
+ IN MG 4BSD-HELP@UCBARPA
+WALES IN MB UCB-VAX.ARPA
+ IN MG UCLA-S!WALES
+ IN MG MARK
+LAUREN IN MB UCB-VAX.ARPA
+ IN MG LAUREN@RAND-UNIX
+KEITH IN MB UCB-VAX.ARPA
+ IN MG SKLOWER@DALI
+POLLEZ IN MB UCB-VAX.ARPA
+ IN MG PTZ@SU-AI
+ROB IN MB UCB-VAX.ARPA
+ IN MG RESEARC!ROB
+UCSD IN MB UCB-VAX.ARPA
+ IN MG UCSD@ERNIE
+ROGUE IN MB UCB-VAX.ARPA
+ IN MG ARNOLD
+BLFP IN MB UCB-VAX.ARPA
+ IN MG ELLIS@CAD
+ IN MG RUSTY
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG LAUREN
+ IN MG DOUGLAS
+CS298-1 IN MB UCB-VAX.ARPA
+ IN MG DESPAIN
+ IN MG FABRY
+ IN MG FERRARI
+ IN MG OUSTER
+ IN MG PATT
+ IN MG PATTRSN
+ IN MG POWELL
+ IN MG SEQUIN
+ IN MG SMITH
+DAY IN MB UCB-VAX.ARPA
+ IN MG DAY@RAND-UNIX
+SUSAN IN MB UCB-VAX.ARPA
+ IN MG SUSAN@CAD
+LOCK IN MB UCB-VAX.ARPA
+ IN MG LOCK@ESVAX
+FRODO IN MB UCB-VAX.ARPA
+ IN MG TED.KOWALSKI@CMU-10A
+CHAZ IN MB UCB-VAX.ARPA
+ IN MG WILLIAM
+FRANZ-TIMING IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG JKF
+ IN MG DOUGLAS
+ IN MG ANLAMS!FRANZ-TIMING
+ IN MG JTD@CAD
+ IN MG LAYER
+FRANZ-TRANSLATORS IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG JKF
+ IN MG SKLOWER
+ IN MG DOUGLAS
+ IN MG ANLAMS!FRANZ-TIMING
+ IN MG LAYER
+FRANZ-SOURCES IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG JKF
+ IN MG DOUGLAS
+ IN MG ANLAMS!FRANZ-TIMING
+ IN MG LAYER
+JEK IN MB UCB-VAX.ARPA
+ IN MG JEKULP@MIT-MC
+CSRGF77 IN MB UCB-VAX.ARPA
+ IN MG VANCE@OPAL.CC
+ IN MG SIF
+ IN MG DLW
+ IN MG FKUNZE
+ IN MG PJW
+ IN MG TEF
+ IN MG FABRY
+ IN MG SKLOWER
+ IN MG WILLIAM
+ IN MG DECVAX!APS
+ IN MG CORBETT
+ IN MG AF77
+ IN MG ED
+LAURA IN MB UCB-VAX.ARPA
+ IN MG JANET@UCBARPA
+DIANA IN MB UCB-VAX.ARPA
+ IN MG DIANA@KIM
+JERI IN MB UCB-VAX.ARPA
+ IN MG PAULINE@UCBARPA
+ECC IN MB UCB-VAX.ARPA
+ IN MG COOPER
+ECOOPER IN MB UCB-VAX.ARPA
+ IN MG COOPER
+COOPER IN MB UCB-VAX.ARPA
+ IN MG COOPER@UCBARPA
+TERRY IN MB UCB-VAX.ARPA
+ IN MG TERRY@UCBARPA
+DCOOPER IN MB UCB-VAX.ARPA
+ IN MG DBCOOPER@UCBARPA
+DBCOOPER IN MB UCB-VAX.ARPA
+ IN MG DBCOOPER@UCBARPA
+COMTAL IN MB UCB-VAX.ARPA
+ IN MG HICKMAN
+ IN MG SWENSEN
+ IN MG UPSTILL
+ IN MG DEERING
+GBC IN MB UCB-VAX.ARPA
+ IN MG CBOSG!GBC
+OOSIK IN MB UCB-VAX.ARPA
+ IN MG DIPPE
+TSO IN MB UCB-VAX.ARPA
+ IN MG TSO@DEGAS
+LINDY IN MB UCB-VAX.ARPA
+ IN MG LINDY@DEGAS
+SYMPHONY IN MB UCB-VAX.ARPA
+ IN MG SYM
+ IN MG GRAHAM
+ IN MG HARRISON@UCBRENOIR
+SYM IN MB UCB-VAX.ARPA
+ IN MG SYM-X
+ IN MG SYM-Y
+ IN MG SYM-Q
+SYM-X IN MB UCB-VAX.ARPA
+ IN MG GEOFF
+ IN MG EARL
+ IN MG EAK@MIT-MC
+ IN MG WINKLER
+SYM-Y IN MB UCB-VAX.ARPA
+ IN MG GEOFF
+ IN MG HAGMANN@INGRES
+ IN MG HALBERT
+SYM-Q IN MB UCB-VAX.ARPA
+ IN MG FAITH
+ IN MG DWS@LLL-MFE
+SYM-GUESTS IN MB UCB-VAX.ARPA
+ IN MG COOPER
+ IN MG OUSTER
+ IN MG YING
+GHG IN MB UCB-VAX.ARPA
+ IN MG PUR-EE!GHG
+MAH IN MB UCB-VAX.ARPA
+ IN MG HARRISON@UCBRENOIR
+PRESTON IN MB UCB-VAX.ARPA
+ IN MG GARDNER
+KRE IN MB UCB-VAX.ARPA
+ IN MG DECVAX!MULGA!KRE
+EDITORS IN MB UCB-VAX.ARPA
+ IN MG DAY@RAND-UNIX
+ IN MG CBOSG!MARK
+ IN MG MHTSA!HAIGHT
+ IN MG GOSLING@CMUA
+ IN MG RMS@MIT-AI
+ IN MG ALLEGRA!JDD
+ IN MG VAX135!JFR
+ IN MG CBOSG!SBB
+ IN MG SDCARL!RUSTY
+ IN MG SJK
+HICKMAN IN MB UCB-VAX.ARPA
+ IN MG HICKMAN@INGRES
+CSH IN MB UCB-VAX.ARPA
+ IN MG ELLEN
+FABRY IN MB UCB-VAX.ARPA
+ IN MG FABRY@UCBARPA
+GHB IN MB UCB-VAX.ARPA
+ IN MG GHB@UCBARPA
+SJK IN MB UCB-VAX.ARPA
+ IN MG SJK@UCBARPA
+CAREY IN MB UCB-VAX.ARPA
+ IN MG CAREY@INGRES
+MOSHER IN MB UCB-VAX.ARPA
+ IN MG MOSHER@UCBARPA
+ARCH IN MB UCB-VAX.ARPA
+ IN MG ARCH@UCBARPA
+SAM IN MB UCB-VAX.ARPA
+ IN MG SAM@UCBARPA
+WNJ IN MB UCB-VAX.ARPA
+ IN MG WNJ@UCBARPA
+MORTON IN MB UCB-VAX.ARPA
+ IN MG MORTON@UCBARPA
+FELDMAN IN MB UCB-VAX.ARPA
+ IN MG FELDMAN@UCBARPA
+MENDLER IN MB UCB-VAX.ARPA
+ IN MG DREW.MENDLER@CMU-10A
+WAYNE IN MB UCB-VAX.ARPA
+ IN MG WAYNE@LBL-CSAM
+DBJ IN MB UCB-VAX.ARPA
+ IN MG ALLEGRA!PSUVAX!JOHNSON
+GEORGE IN MB UCB-VAX.ARPA
+ IN MG GEORGE@E.CC
+HAGMANN IN MB UCB-VAX.ARPA
+ IN MG HAGMANN@INGRES
+FRISH IN MB UCB-VAX.ARPA
+ IN MG FRISH@UCBCORY
+GNF IN MB UCB-VAX.ARPA
+ IN MG \FRISH
+LOU IN MB UCB-VAX.ARPA
+ IN MG LOU@UCBARPA
+SMALLTALK IN MB UCB-VAX.ARPA
+ IN MG DMU
+ IN MG PELEGRI
+ IN MG PATTRSN
+ IN MG RICKI@KIM
+ IN MG BADEN
+ IN MG LEBLANC
+ IN MG HALBERT
+ IN MG HAGMANN@INGRES
+ IN MG JKF
+ IN MG MAYO
+ IN MG CONROY@KIM
+ IN MG PROBST@INGRES
+ IN MG JTD@CAD
+ IN MG CONDE
+432EVAL IN MB UCB-VAX.ARPA
+ IN MG PATTRSN
+ IN MG HANSEN
+ IN MG MARGIE
+ IN MG MAYO
+ IN MG JTD@CAD
+ IN MG DMU
+ IN MG LINTON
+ IN MG KELLER@CAD
+ IN MG TAMIR
+CAREN IN MB UCB-VAX.ARPA
+ IN MG CAREN@ERNIE
+HARTWELL IN MB UCB-VAX.ARPA
+ IN MG SHASTA!HARTWELL
+GOD IN MB UCB-VAX.ARPA
+ IN MG SHASTA!HARTWELL
+ARNOLD IN MB UCB-VAX.ARPA
+ IN MG ARNOLD@INGRES
+KCRCA IN MB UCB-VAX.ARPA
+ IN MG \ARNOLD
+KIMCOM IN MB UCB-VAX.ARPA
+ IN MG FATEMAN
+ IN MG PATTRSN
+ IN MG SKLOWER
+ IN MG WILENSKY
+SKLOWER IN MB UCB-VAX.ARPA
+ IN MG SKLOWER@DALI
+CGGS IN MB UCB-VAX.ARPA
+ IN MG RRH
+ IN MG PETER
+ IN MG MCKUSICK
+ IN MG GRAHAM
+ IN MG PELEGRI
+BADEN IN MB UCB-VAX.ARPA
+ IN MG BADEN@UCBKIM
+ALOEVERA IN MB UCB-VAX.ARPA
+ IN MG ALOEVERA@UCBESVAX
+TROLL IN MB UCB-VAX.ARPA
+ IN MG TROLL@UCBMEDEA
+DIST2 IN MB UCB-VAX.ARPA
+ IN MG CARL@ERNIE
+DMU IN MB UCB-VAX.ARPA
+ IN MG DMU@UCBKIM
+BAIR IN MB UCB-VAX.ARPA
+ IN MG BAIR@DALI
+OKENIUK IN MB UCB-VAX.ARPA
+ IN MG OKENIUK@DALI
+521EVANS IN MB UCB-VAX.ARPA
+ IN MG LARUS
+ IN MG DRB
+ IN MG SOIFFER
+ IN MG DEMMEL
+ IN MG DJAVAHER
+ IN MG ISRAEL
+ IN MG ANDERSON
+ IN MG ASPIN@DALI
+ IN MG MORRISON@DALI
+ IN MG FOSTER
+ IN MG PONDER@KIM
+ IN MG LAYER
+BALLANCE IN MB UCB-VAX.ARPA
+ IN MG BALLANCE@ERNIE
+SCHMIDT IN MB UCB-VAX.ARPA
+ IN MG SCHMIDT.PA@PARC-MAXC
+KSBOOTH IN MB UCB-VAX.ARPA
+ IN MG DECVAX!WATMATH!WATCGL!KSBOOTH
+ IN MG TEKLABS!WATMATH!WATCGL!KSBOOTH
+KESSLER IN MB UCB-VAX.ARPA
+ IN MG PETER
+ALONSO IN MB UCB-VAX.ARPA
+ IN MG ALONSO@UCBARPA
+RAFAEL IN MB UCB-VAX.ARPA
+ IN MG ALONSO@UCBARPA
+KBH IN MB UCB-VAX.ARPA
+ IN MG KBH@ERNIE
+DOLORES IN MB UCB-VAX.ARPA
+ IN MG DOLORES@DALI
+RENEGADE IN MB UCB-VAX.ARPA
+ IN MG ISRAEL
+GILL IN MB UCB-VAX.ARPA
+ IN MG GILL@UCBEAR
+KALASH IN MB UCB-VAX.ARPA
+ IN MG KALASH@INGRES
+PROBST IN MB UCB-VAX.ARPA
+ IN MG PROBST@ERNIE
+STETTNER IN MB UCB-VAX.ARPA
+ IN MG STETTNER@INGRES
+SOIFFER IN MB UCB-VAX.ARPA
+ IN MG SOIFFER@DALI
+DRB IN MB UCB-VAX.ARPA
+ IN MG DRB@DALI
+ANDERSON IN MB UCB-VAX.ARPA
+ IN MG ANDERSON@UCBDALI
+WALLACE IN MB UCB-VAX.ARPA
+ IN MG WALLACE@KIM
+DANDD IN MB UCB-VAX.ARPA
+ IN MG ISRAEL
+ IN MG ANTHONYF@E.CC
+ IN MG BUTLER@DALI
+ IN MG CHRIS@UCBCORY
+LISA IN MB UCB-VAX.ARPA
+ IN MG LISA@DALI
+TURIN IN MB UCB-VAX.ARPA
+ IN MG TURIN@UCBEAR
+ IN MG DORIAN@UCBEAR
+CADDIST IN MB UCB-VAX.ARPA
+ IN MG CADDIST@KIM
+CHACKO IN MB UCB-VAX.ARPA
+ IN MG ZILOG!CHACKO
+BUTLER IN MB UCB-VAX.ARPA
+ IN MG BUTLER@DALI
+CHRIS IN MB UCB-VAX.ARPA
+ IN MG CHRIS@UCBCORY
+LERES IN MB UCB-VAX.ARPA
+ IN MG LERES@UCBARPA
+POSKANZER IN MB UCB-VAX.ARPA
+ IN MG POSKANZER.PA@PARC-MAXC.ARPA
+ABAR IN MB UCB-VAX.ARPA
+ IN MG ABAR@ERNIE
+ IN MG UCSFMIS!ABAR
+AIGRAIN IN MB UCB-VAX.ARPA
+ IN MG AIGRAIN@UCBERNIE
+AL IN MB UCB-VAX.ARPA
+ IN MG AL@ERNIE
+ALEX IN MB UCB-VAX.ARPA
+ IN MG ALEX@ERNIE
+ALICE IN MB UCB-VAX.ARPA
+ IN MG ALICE@ERNIE
+AMNON IN MB UCB-VAX.ARPA
+ IN MG AMNON@ERNIE
+ANN IN MB UCB-VAX.ARPA
+ IN MG ANN@ERNIE
+ASPIN IN MB UCB-VAX.ARPA
+ IN MG ASPIN@ERNIE
+AUNGAR IN MB UCB-VAX.ARPA
+ IN MG AUNGAR@ERNIE
+BACH IN MB UCB-VAX.ARPA
+ IN MG BACH@UCBERNIE
+BAHRAM IN MB UCB-VAX.ARPA
+ IN MG BAHRAM@ERNIE
+BALABAN IN MB UCB-VAX.ARPA
+ IN MG BALABAN@ERNIE
+BARSKY IN MB UCB-VAX.ARPA
+ IN MG BARSKY@DEGAS
+BARSKY2 IN MB UCB-VAX.ARPA
+ IN MG BARSKY2@DEGAS
+BART IN MB UCB-VAX.ARPA
+ IN MG BART@ARPA
+BECK IN MB UCB-VAX.ARPA
+ IN MG BECK@ERNIE
+BERLEK IN MB UCB-VAX.ARPA
+ IN MG BERLEK@ERNIE
+BHATTI IN MB UCB-VAX.ARPA
+ IN MG BHATTI@ERNIE
+BIDDULPH IN MB UCB-VAX.ARPA
+ IN MG BIDDULPH@ERNIE
+BIRMAN IN MB UCB-VAX.ARPA
+ IN MG BIRMAN@ERNIE
+BLUM IN MB UCB-VAX.ARPA
+ IN MG BLUM@ERNIE
+BORSKE IN MB UCB-VAX.ARPA
+ IN MG BORSKE@ERNIE
+CAD IN MB UCB-VAX.ARPA
+ IN MG CAD@ERNIE
+CAM IN MB UCB-VAX.ARPA
+ IN MG CAM@ERNIE
+CARL IN MB UCB-VAX.ARPA
+ IN MG CARL@ERNIE
+CARYL IN MB UCB-VAX.ARPA
+ IN MG CARYL@ERNIE
+CARYN IN MB UCB-VAX.ARPA
+ IN MG CARYN@ERNIE
+CHOW IN MB UCB-VAX.ARPA
+ IN MG CHOW@ERNIE
+CITRIN IN MB UCB-VAX.ARPA
+ IN MG CITRIN@ERNIE
+CLANCY IN MB UCB-VAX.ARPA
+ IN MG CLANCY@ERNIE
+CMA IN MB UCB-VAX.ARPA
+ IN MG CMA@ERNIE
+COLE IN MB UCB-VAX.ARPA
+ IN MG COLE@ERNIE
+COLEMAN IN MB UCB-VAX.ARPA
+ IN MG COLEMAN@UCBARPA
+CONDE IN MB UCB-VAX.ARPA
+ IN MG CONDE@ERNIE
+CONROY IN MB UCB-VAX.ARPA
+ IN MG CONROY@ERNIE
+COONEN IN MB UCB-VAX.ARPA
+ IN MG COONEN@ERNIE
+CORBETT IN MB UCB-VAX.ARPA
+ IN MG CORBETT@ERNIE
+CORY IN MB UCB-VAX.ARPA
+ IN MG CORY@ERNIE
+COX IN MB UCB-VAX.ARPA
+ IN MG COX@DALI
+CRYO IN MB UCB-VAX.ARPA
+ IN MG CRYO@ERNIE
+DAEMON IN MB UCB-VAX.ARPA
+ IN MG ROOT
+ IN MG USENET-ADMIN
+DAMBROSI IN MB UCB-VAX.ARPA
+ IN MG DAMBROSI@ERNIE
+DAVIS IN MB UCB-VAX.ARPA
+ IN MG DAVIS@ERNIE
+DEMMEL IN MB UCB-VAX.ARPA
+ IN MG DEMMEL@ERNIE
+DEROSE IN MB UCB-VAX.ARPA
+ IN MG DEROSE@ERNIE
+DESMEDT IN MB UCB-VAX.ARPA
+ IN MG DESMEDT@ERNIE
+DESPAIN IN MB UCB-VAX.ARPA
+ IN MG DESPAIN@ERNIE
+DETAYL IN MB UCB-VAX.ARPA
+ IN MG DETAYL@ERNIE
+DEVEL IN MB UCB-VAX.ARPA
+ IN MG DEVEL@ERNIE
+DIMITRIS IN MB UCB-VAX.ARPA
+ IN MG DIMITRIS@ERNIE
+DIPPE IN MB UCB-VAX.ARPA
+ IN MG DIPPE@UCBDEGAS
+DJAVAHER IN MB UCB-VAX.ARPA
+ IN MG DJAVAHER@ERNIE
+DJAVAHERI IN MB UCB-VAX.ARPA
+ IN MG DJAVAHER@ERNIE
+DOE IN MB UCB-VAX.ARPA
+ IN MG DOE@ERNIE
+DON IN MB UCB-VAX.ARPA
+ IN MG DON@ERNIE
+DORFMAN IN MB UCB-VAX.ARPA
+ IN MG DORFMAN@ERNIE
+DRAPER IN MB UCB-VAX.ARPA
+ IN MG DRAPER@ERNIE
+EARL IN MB UCB-VAX.ARPA
+ IN MG EARL@ERNIE
+ELAINE IN MB UCB-VAX.ARPA
+ IN MG ELAINE@ERNIE
+ELLEN IN MB UCB-VAX.ARPA
+ IN MG ELLEN@ERNIE
+ELLIS IN MB UCB-VAX.ARPA
+ IN MG ELLIS@ERNIE
+EVEN IN MB UCB-VAX.ARPA
+ IN MG EVEN@ERNIE
+FAITH IN MB UCB-VAX.ARPA
+ IN MG FAITH@ERNIE
+FALLER IN MB UCB-VAX.ARPA
+ IN MG FALLER@ERNIE
+FERRARI IN MB UCB-VAX.ARPA
+ IN MG FERRARI@ERNIE
+FITZ IN MB UCB-VAX.ARPA
+ IN MG FITZ@ERNIE
+FMUELLER IN MB UCB-VAX.ARPA
+ IN MG FMUELLER@ERNIE
+FOLEY IN MB UCB-VAX.ARPA
+ IN MG FOLEY@ERNIE
+FRED IN MB UCB-VAX.ARPA
+ IN MG FRED@ERNIE
+FREED IN MB UCB-VAX.ARPA
+ IN MG FREED@ERNIE
+FUJIMOTO IN MB UCB-VAX.ARPA
+ IN MG FUJIMOTO@ERNIE
+GARDNER IN MB UCB-VAX.ARPA
+ IN MG GARDNER@ERNIE
+GARRISON IN MB UCB-VAX.ARPA
+ IN MG GARRISON@UCBERNIE
+GRAHAM IN MB UCB-VAX.ARPA
+ IN MG GRAHAM@UCBERNIE
+ IN MG GRAHAM@UCBARPA
+GROSH IN MB UCB-VAX.ARPA
+ IN MG GROSH@ERNIE
+GRUNBAUM IN MB UCB-VAX.ARPA
+ IN MG GRUNBAUM@ERNIE
+HALBERT IN MB UCB-VAX.ARPA
+ IN MG HALBERT@ERNIE
+HAMACHI IN MB UCB-VAX.ARPA
+ IN MG HAMACHI@ERNIE
+HANIA IN MB UCB-VAX.ARPA
+ IN MG HANIA@ERNIE
+HARRISON IN MB UCB-VAX.ARPA
+ IN MG HARRISON@UCBRENOIR
+HARUYAMA IN MB UCB-VAX.ARPA
+ IN MG HARUYAMA@ERNIE
+HELENA IN MB UCB-VAX.ARPA
+ IN MG HELENA@ERNIE
+HERTZFE IN MB UCB-VAX.ARPA
+ IN MG HERTZFE@ERNIE
+HILFINGR IN MB UCB-VAX.ARPA
+ IN MG HILFINGR@RENOIR
+HILFINGER IN MB UCB-VAX.ARPA
+ IN MG HILFINGR@RENOIR
+HO IN MB UCB-VAX.ARPA
+ IN MG HO@ERNIE
+HOBEN IN MB UCB-VAX.ARPA
+ IN MG HOBEN@ERNIE
+HODGES IN MB UCB-VAX.ARPA
+ IN MG HODGES@MEDEA
+HOFMANN IN MB UCB-VAX.ARPA
+ IN MG HOFMANN@ERNIE
+IBIOCCA IN MB UCB-VAX.ARPA
+ IN MG IBIOCCA@ERNIE
+INGRES IN MB UCB-VAX.ARPA
+ IN MG INGRES@INGRES
+ISRAEL IN MB UCB-VAX.ARPA
+ IN MG ISRAEL@ERNIE
+JAK IN MB UCB-VAX.ARPA
+ IN MG JAK@ERNIE
+JANET IN MB UCB-VAX.ARPA
+ IN MG JANET@UCBARPA
+JCBEATTY IN MB UCB-VAX.ARPA
+ IN MG JCBEATTY@ERNIE
+JEFF IN MB UCB-VAX.ARPA
+ IN MG JEFF@ERNIE
+JEN IN MB UCB-VAX.ARPA
+ IN MG JEN@ERNIE
+JIM IN MB UCB-VAX.ARPA
+ IN MG JIM@ERNIE
+JLM IN MB UCB-VAX.ARPA
+ IN MG JLM@ERNIE
+JMG IN MB UCB-VAX.ARPA
+ IN MG JMG@ERNIE
+JOAN IN MB UCB-VAX.ARPA
+ IN MG JOAN@ERNIE
+JOHNSON IN MB UCB-VAX.ARPA
+ IN MG JOHNSON@ERNIE
+JONATHAN IN MB UCB-VAX.ARPA
+ IN MG JONATHAN@ERNIE
+JPEEK IN MB UCB-VAX.ARPA
+ IN MG JPEEK@ERNIE
+JSTO IN MB UCB-VAX.ARPA
+ IN MG JSTO@ERNIE
+KAHAN IN MB UCB-VAX.ARPA
+ IN MG KAHAN@ERNIE
+KARLOFF IN MB UCB-VAX.ARPA
+ IN MG KARLOFF@UCBERNIE
+KARMAR IN MB UCB-VAX.ARPA
+ IN MG KARMAR@ERNIE
+KARP IN MB UCB-VAX.ARPA
+ IN MG KARP@ERNIE
+KLEIN IN MB UCB-VAX.ARPA
+ IN MG KLEIN@MEDEA
+DIEKS IN MB UCB-VAX.ARPA
+ IN MG KLEIN@MEDEA
+LAKOFF IN MB UCB-VAX.ARPA
+ IN MG LAKOFF@ERNIE
+LANDIS IN MB UCB-VAX.ARPA
+ IN MG LANDIS@ERNIE
+LAW IN MB UCB-VAX.ARPA
+ IN MG LAW@ERNIE
+LAWLER IN MB UCB-VAX.ARPA
+ IN MG LAWLER@ERNIE
+LEE IN MB UCB-VAX.ARPA
+ IN MG LEE@ERNIE
+LIHR IN MB UCB-VAX.ARPA
+ IN MG LIHR@ERNIE
+LINDNER IN MB UCB-VAX.ARPA
+ IN MG LINDNER@ERNIE
+LONE IN MB UCB-VAX.ARPA
+ IN MG LONE@UCBERNIE
+LUK IN MB UCB-VAX.ARPA
+ IN MG LUK@ERNIE
+LUU IN MB UCB-VAX.ARPA
+ IN MG LUU@ERNIE
+MANOLI IN MB UCB-VAX.ARPA
+ IN MG MANOLI@ERNIE
+MARGIE IN MB UCB-VAX.ARPA
+ IN MG MARGIE@ERNIE
+MARKHILL IN MB UCB-VAX.ARPA
+ IN MG MARKHILL@ERNIE
+MARSH IN MB UCB-VAX.ARPA
+ IN MG CAROLE@ERNIE
+MASAHIDE IN MB UCB-VAX.ARPA
+ IN MG MASAHIDE@ERNIE
+MCCARTY IN MB UCB-VAX.ARPA
+ IN MG MCCARTY@ERNIE
+MCCORMIC IN MB UCB-VAX.ARPA
+ IN MG MCCORMIC@ERNIE
+MCINTOSH IN MB UCB-VAX.ARPA
+ IN MG MCINTOSH@ERNIE
+MCKUSICK IN MB UCB-VAX.ARPA
+ IN MG MCKUSICK@UCBERNIE
+MESSER IN MB UCB-VAX.ARPA
+ IN MG MESSER@ERNIE
+MIROS IN MB UCB-VAX.ARPA
+ IN MG MIROS@UCBERNIE
+MITCH IN MB UCB-VAX.ARPA
+ IN MG MITCH@ERNIE
+MITSU IN MB UCB-VAX.ARPA
+ IN MG MITSU@ERNIE
+MO IN MB UCB-VAX.ARPA
+ IN MG MO@ARPA
+MORGAN IN MB UCB-VAX.ARPA
+ IN MG MORGAN@ERNIE
+MORITZ IN MB UCB-VAX.ARPA
+ IN MG MORITZ@ERNIE
+MURPHY IN MB UCB-VAX.ARPA
+ IN MG MURPHY@ERNIE
+NETWORK IN MB UCB-VAX.ARPA
+ IN MG ROOT
+NICKLIN IN MB UCB-VAX.ARPA
+ IN MG NICKLIN@UCBARPA
+NOTION IN MB UCB-VAX.ARPA
+ IN MG NOTION@ERNIE
+OPERATOR IN MB UCB-VAX.ARPA
+ IN MG OPERATOR@ERNIE
+PAO IN MB UCB-VAX.ARPA
+ IN MG PAO@ERNIE
+PARIS IN MB UCB-VAX.ARPA
+ IN MG PARIS@ERNIE
+PARLETT IN MB UCB-VAX.ARPA
+ IN MG PARLETT@ERNIE
+PATT IN MB UCB-VAX.ARPA
+ IN MG PATT@ERNIE
+PELEGRI IN MB UCB-VAX.ARPA
+ IN MG PELEGRI@ERNIE
+PERALTA IN MB UCB-VAX.ARPA
+ IN MG PERALTA@UCBERNIE
+PETER IN MB UCB-VAX.ARPA
+ IN MG PETER@UCBERNIE
+PINTO IN MB UCB-VAX.ARPA
+ IN MG PINTO@ERNIE
+PJW IN MB UCB-VAX.ARPA
+ IN MG PJW@ERNIE
+PONDER IN MB UCB-VAX.ARPA
+ IN MG PONDER@ERNIE
+PORCARJ IN MB UCB-VAX.ARPA
+ IN MG PORCARJ@ERNIE
+POTONG IN MB UCB-VAX.ARPA
+ IN MG POTONG@ERNIE
+POWELL IN MB UCB-VAX.ARPA
+ IN MG POWELL@ERNIE
+PRESOTTO IN MB UCB-VAX.ARPA
+ IN MG PRESOTTO@ARPA
+RAGHAVAN IN MB UCB-VAX.ARPA
+ IN MG RAGHAVAN@ERNIE
+RAM IN MB UCB-VAX.ARPA
+ IN MG RAM@ERNIE
+RESEARCH IN MB UCB-VAX.ARPA
+ IN MG RESEARCH@ERNIE
+RESNIKOF IN MB UCB-VAX.ARPA
+ IN MG RESNIKOF@ERNIE
+RHM IN MB UCB-VAX.ARPA
+ IN MG RHM@ERNIE
+RICKI IN MB UCB-VAX.ARPA
+ IN MG RICKI@KIM
+RISCIT IN MB UCB-VAX.ARPA
+ IN MG RISCIT@ERNIE
+RLD IN MB UCB-VAX.ARPA
+ IN MG RLD@ERNIE
+ROWLAND IN MB UCB-VAX.ARPA
+ IN MG ROWLAND@ERNIE
+RR IN MB UCB-VAX.ARPA
+ IN MG RR@ERNIE
+RRH IN MB UCB-VAX.ARPA
+ IN MG RRH@UCBERNIE
+RUBIN IN MB UCB-VAX.ARPA
+ IN MG HARRY
+PAULINE IN MB UCB-VAX.ARPA
+ IN MG PAULINE@UCBARPA
+SANTOS IN MB UCB-VAX.ARPA
+ IN MG SANTOS@ERNIE
+SCHMITT IN MB UCB-VAX.ARPA
+ IN MG SCHMITT@ERNIE
+SCHULMAN IN MB UCB-VAX.ARPA
+ IN MG SCHULMAN@ERNIE
+SEARLE IN MB UCB-VAX.ARPA
+ IN MG SEARLE@ERNIE
+SENDEROW IN MB UCB-VAX.ARPA
+ IN MG SENDEROW@ERNIE
+SEQUIN IN MB UCB-VAX.ARPA
+ IN MG SEQUIN@ERNIE
+SHAFI IN MB UCB-VAX.ARPA
+ IN MG SHAFI@ERNIE
+SHALLIT IN MB UCB-VAX.ARPA
+ IN MG SHALLIT@ERNIE
+SHENG IN MB UCB-VAX.ARPA
+ IN MG SHENG@ERNIE
+SHERERTZ IN MB UCB-VAX.ARPA
+ IN MG SHERERTZ@ERNIE
+SHEU IN MB UCB-VAX.ARPA
+ IN MG SHEU@ERNIE
+SHIVAJI IN MB UCB-VAX.ARPA
+ IN MG SHIVAJI@ERNIE
+SHMOYS IN MB UCB-VAX.ARPA
+ IN MG SHMOYS@ERNIE
+SHOEMAKE IN MB UCB-VAX.ARPA
+ IN MG SHOEMAKE@ERNIE
+SILVIO IN MB UCB-VAX.ARPA
+ IN MG SILVIO@ERNIE
+SIMON IN MB UCB-VAX.ARPA
+ IN MG SIMON@ERNIE
+SMITH IN MB UCB-VAX.ARPA
+ IN MG SMITH@ERNIE
+SNAKE IN MB UCB-VAX.ARPA
+ IN MG SNAKE@ERNIE
+STRAUSS IN MB UCB-VAX.ARPA
+ IN MG STRAUSS@ERNIE
+SWENSEN IN MB UCB-VAX.ARPA
+ IN MG SWENSEN@ERNIE
+SYMBER IN MB UCB-VAX.ARPA
+ IN MG SYMBER@ERNIE
+TANG IN MB UCB-VAX.ARPA
+ IN MG TANG@ERNIE
+TATSUMI IN MB UCB-VAX.ARPA
+ IN MG TATSUMI@ERNIE
+TAYLOR IN MB UCB-VAX.ARPA
+ IN MG TAYLOR@ERNIE
+TEDRICK IN MB UCB-VAX.ARPA
+ IN MG TEDRICK@ERNIE
+TOOR IN MB UCB-VAX.ARPA
+ IN MG TOOR@ERNIE
+TPLEE IN MB UCB-VAX.ARPA
+ IN MG TPLEE@ERNIE
+TSAI IN MB UCB-VAX.ARPA
+ IN MG TSAI@ERNIE
+TUCK IN MB UCB-VAX.ARPA
+ IN MG TUCK@ERNIE
+TUTTLE IN MB UCB-VAX.ARPA
+ IN MG TUTTLE@ERNIE
+UPSTILL IN MB UCB-VAX.ARPA
+ IN MG UPSTILL@ERNIE
+USG IN MB UCB-VAX.ARPA
+ IN MG USG@ERNIE
+VANCE IN MB UCB-VAX.ARPA
+ IN MG VANCE@UCBOPAL
+VAZIRANI IN MB UCB-VAX.ARPA
+ IN MG VAZIRANI@ERNIE
+VICKIE IN MB UCB-VAX.ARPA
+ IN MG SWEET@ERNIE
+VIRGINIA IN MB UCB-VAX.ARPA
+ IN MG VIRGINIA@ERNIE
+VIVIAN IN MB UCB-VAX.ARPA
+ IN MG VIVIAN@ERNIE
+WAGONER IN MB UCB-VAX.ARPA
+ IN MG WAGONER@ERNIE
+WASERMAN IN MB UCB-VAX.ARPA
+ IN MG WASERMAN@UCBRENOIR
+WEIJIN IN MB UCB-VAX.ARPA
+ IN MG WEIJIN@ERNIE
+WILDBILL IN MB UCB-VAX.ARPA
+ IN MG WILDBILL@ERNIE
+WILHELMS IN MB UCB-VAX.ARPA
+ IN MG WILHELMS@ERNIE
+WINKLER IN MB UCB-VAX.ARPA
+ IN MG WINKLER@ERNIE
+WOLD IN MB UCB-VAX.ARPA
+ IN MG WOLD@ERNIE
+WOODSON IN MB UCB-VAX.ARPA
+ IN MG WOODSON@ERNIE
+WSS IN MB UCB-VAX.ARPA
+ IN MG WSS@ERNIE
+XTREE IN MB UCB-VAX.ARPA
+ IN MG XTREE@ERNIE
+WINGO IN MB UCB-VAX.ARPA
+ IN MG WINGO@ERNIE
+EVANS IN MB UCB-VAX.ARPA
+ IN MG EVANS@KIM
+KOREN IN MB UCB-VAX.ARPA
+ IN MG KOREN@ERNIE
+PASQUALE IN MB UCB-VAX.ARPA
+ IN MG PASQUALE@ERNIE
+KGLICKMAN IN MB UCB-VAX.ARPA
+ IN MG \GLICKMAN
+SINZ IN MB UCB-VAX.ARPA
+ IN MG SINZ@KIM
+GORDANA IN MB UCB-VAX.ARPA
+ IN MG GORDANA@INGRES
+CHESSON IN MB UCB-VAX.ARPA
+ IN MG GREG@ARPA
+LOFTS IN MB UCB-VAX.ARPA
+ IN MG LOFTS@ERNIE
+BELGIUM IN MB UCB-VAX.ARPA
+ IN MG BELGIUM@ERNIE
+YOUNG IN MB UCB-VAX.ARPA
+ IN MG YOUNG@ERNIE
+SPEER IN MB UCB-VAX.ARPA
+ IN MG SPEER@ERNIE
+EGGERS IN MB UCB-VAX.ARPA
+ IN MG EGGERS@ERNIE
+BK IN MB UCB-VAX.ARPA
+ IN MG BK@KIM
+JEFFC IN MB UCB-VAX.ARPA
+ IN MG JEFFC@DALI
+HERSK IN MB UCB-VAX.ARPA
+ IN MG HERSK@KIM
+MALT IN MB UCB-VAX.ARPA
+ IN MG MALT@KIM
+LEARMONT IN MB UCB-VAX.ARPA
+ IN MG LEARMONT@ERNIE
+MAX IN MB UCB-VAX.ARPA
+ IN MG WARMUTH@ERNIE
+WARMUTH IN MB UCB-VAX.ARPA
+ IN MG WARMUTH@ERNIE
+GREER IN MB UCB-VAX.ARPA
+ IN MG GREER@ERNIE
+JHCHANG IN MB UCB-VAX.ARPA
+ IN MG JHCHANG@ERNIE
+GAO IN MB UCB-VAX.ARPA
+ IN MG GAO@DALI
+SHMOYS IN MB UCB-VAX.ARPA
+ IN MG SHMOYS@ERNIE
+GREER IN MB UCB-VAX.ARPA
+ IN MG GREER@ERNIE
+BK IN MB UCB-VAX.ARPA
+ IN MG BK@ERNIE
+ALTMAN IN MB UCB-VAX.ARPA
+ IN MG ALTMAN@ERNIE
+BIANCO IN MB UCB-VAX.ARPA
+ IN MG BIANCO@ERNIE
+BURNS IN MB UCB-VAX.ARPA
+ IN MG BURNS@ERNIE
+BUSH IN MB UCB-VAX.ARPA
+ IN MG BUSH@ERNIE
+CANNING IN MB UCB-VAX.ARPA
+ IN MG CANNING@ERNIE
+CHANG IN MB UCB-VAX.ARPA
+ IN MG CHANG@ERNIE
+KIMMAN IN MB UCB-VAX.ARPA
+ IN MG KIMMAN@ERNIE
+CHENG IN MB UCB-VAX.ARPA
+ IN MG CHENG@ERNIE
+CHOU IN MB UCB-VAX.ARPA
+ IN MG CHOU@ERNIE
+DANIELS IN MB UCB-VAX.ARPA
+ IN MG DANIELS@ERNIE
+DUFFY IN MB UCB-VAX.ARPA
+ IN MG DUFFY@ERNIE
+FAGIN IN MB UCB-VAX.ARPA
+ IN MG FAGIN@ERNIE
+FENG IN MB UCB-VAX.ARPA
+ IN MG FENG@ERNIE
+FISHKIN IN MB UCB-VAX.ARPA
+ IN MG FISHKIN@ERNIE
+GODDARD IN MB UCB-VAX.ARPA
+ IN MG GODDARD@ERNIE
+GROSS IN MB UCB-VAX.ARPA
+ IN MG GROSS@ERNIE
+HERNANDE IN MB UCB-VAX.ARPA
+ IN MG HERNANDE@ERNIE
+HUANG IN MB UCB-VAX.ARPA
+ IN MG HUANG@ERNIE
+HUGHES IN MB UCB-VAX.ARPA
+ IN MG HUGHES@ERNIE
+JEON IN MB UCB-VAX.ARPA
+ IN MG JEON@ERNIE
+KOO IN MB UCB-VAX.ARPA
+ IN MG KOO@ERNIE
+KUBE IN MB UCB-VAX.ARPA
+ IN MG KUBE@ERNIE
+MENG IN MB UCB-VAX.ARPA
+ IN MG MENG@ERNIE
+LIU IN MB UCB-VAX.ARPA
+ IN MG LIU@ERNIE
+LOCKLEAR IN MB UCB-VAX.ARPA
+ IN MG LOCKLEAR@ERNIE
+LUKAC IN MB UCB-VAX.ARPA
+ IN MG LUKAC@ERNIE
+MELVIN IN MB UCB-VAX.ARPA
+ IN MG MELVIN@ERNIE
+MMURPHY IN MB UCB-VAX.ARPA
+ IN MG MMURPHY@ERNIE
+NG IN MB UCB-VAX.ARPA
+ IN MG NG@ERNIE
+ONG IN MB UCB-VAX.ARPA
+ IN MG ONG@ERNIE
+PAINTER IN MB UCB-VAX.ARPA
+ IN MG PAINTER@ERNIE
+SWEET IN MB UCB-VAX.ARPA
+ IN MG SWEET@ERNIE
+PLATT IN MB UCB-VAX.ARPA
+ IN MG PLATT@ERNIE
+RAGDE IN MB UCB-VAX.ARPA
+ IN MG RAGDE@ERNIE
+RIEWE IN MB UCB-VAX.ARPA
+ IN MG RIEWE@ERNIE
+RIGGLE IN MB UCB-VAX.ARPA
+ IN MG RIGGLE@ERNIE
+ROMO IN MB UCB-VAX.ARPA
+ IN MG ROMO@ERNIE
+SAMPLES IN MB UCB-VAX.ARPA
+ IN MG SAMPLES@ERNIE
+SEGAL IN MB UCB-VAX.ARPA
+ IN MG SEGAL@ERNIE
+SHEM IN MB UCB-VAX.ARPA
+ IN MG SHEM@ERNIE
+SLATTENG IN MB UCB-VAX.ARPA
+ IN MG SLATTENG@ERNIE
+TONI IN MB UCB-VAX.ARPA
+ IN MG TONI@INGRES
+ZORN IN MB UCB-VAX.ARPA
+ IN MG ZORN@ERNIE
+THIEN IN MB UCB-VAX.ARPA
+ IN MG THIEN@ERNIE
+TURNBOW IN MB UCB-VAX.ARPA
+ IN MG TURNBOW@ERNIE
+VOGE IN MB UCB-VAX.ARPA
+ IN MG VOGE@ERNIE
+WENSLEY IN MB UCB-VAX.ARPA
+ IN MG WENSLEY@ERNIE
+ZHOU IN MB UCB-VAX.ARPA
+ IN MG ZHOU@ERNIE
+WRABETZ IN MB UCB-VAX.ARPA
+ IN MG WRABETZ@ERNIE
+YATES IN MB UCB-VAX.ARPA
+ IN MG YATES@ERNIE
+YEN IN MB UCB-VAX.ARPA
+ IN MG YEN@ERNIE
+FUJIMOTO IN MB UCB-VAX.ARPA
+ IN MG FUJIMOTO@ERNIE
+JGROSS IN MB UCB-VAX.ARPA
+ IN MG JGROSS@ERNIE
+TONG IN MB UCB-VAX.ARPA
+ IN MG TONG@ERNIE
+TEP IN MB UCB-VAX.ARPA
+ IN MG TEP@ERNIE
+MOUSE IN MB UCB-VAX.ARPA
+ IN MG MOUSE@ERNIE
+KSUT IN MB UCB-VAX.ARPA
+ IN MG KSUT@ERNIE
+KBH IN MB UCB-VAX.ARPA
+ IN MG KBH@ERNIE
+NISHIZAK IN MB UCB-VAX.ARPA
+ IN MG NISHIZAK@ERNIE
+FRANKLE IN MB UCB-VAX.ARPA
+ IN MG FRANKLE@ERNIE
+SWEET IN MB UCB-VAX.ARPA
+ IN MG SWEET@ERNIE
+OWWING IN MB UCB-VAX.ARPA
+ IN MG OWWING@ERNIE
+THE IN MB UCB-VAX.ARPA
+ IN MG THE@DALI
+SZETO IN MB UCB-VAX.ARPA
+ IN MG SZETO@KIM
+DAAVEN IN MB UCB-VAX.ARPA
+ IN MG DAAVEN@ERNIE
+JOSEPH IN MB UCB-VAX.ARPA
+ IN MG JOSEPH@ERNIE
+KLINE IN MB UCB-VAX.ARPA
+ IN MG KLINE@ARPA
+REEDS IN MB UCB-VAX.ARPA
+ IN MG ALICE!REEDS
+RWG IN MB UCB-VAX.ARPA
+ IN MG ROBERT@UCBBACH
+ICMA IN MB UCB-VAX.ARPA
+ IN MG ROBERT@UCBBACH
+HELGE IN MB UCB-VAX.ARPA
+ IN MG HELGE@UCBARPA
+SCHALLEN IN MB UCB-VAX.ARPA
+ IN MG SCHALLEN@ERNIE
+MATTAUSH IN MB UCB-VAX.ARPA
+ IN MG MATTAUSH@ERNIE
+GOLON IN MB UCB-VAX.ARPA
+ IN MG GOLON@ERNIE
+HYERLE IN MB UCB-VAX.ARPA
+ IN MG HYERLE@ERNIE
+NORMAN IN MB UCB-VAX.ARPA
+ IN MG NORMAN@ERNIE
+MIRANKER IN MB UCB-VAX.ARPA
+ IN MG MIRANKER@ERNIE
+GORDON IN MB UCB-VAX.ARPA
+ IN MG GORDON@ERNIE
+MILLER IN MB UCB-VAX.ARPA
+ IN MG MILLER@ERNIE
+CONN IN MB UCB-VAX.ARPA
+ IN MG CONN@ERNIE
+FAUSTUS IN MB UCB-VAX.ARPA
+ IN MG FAUSTUS@ERNIE
+WAC IN MB UCB-VAX.ARPA
+ IN MG WAC@MIRO
+GUSELLA IN MB UCB-VAX.ARPA
+ IN MG GUSELLA@ERNIE
+STUART IN MB UCB-VAX.ARPA
+ IN MG "ucbcmsa=stuart"@G.CC
+LYNN IN MB UCB-VAX.ARPA
+ IN MG "ucbcmsa=stuart"@G.CC
+GRAY IN MB UCB-VAX.ARPA
+ IN MG GRAY@UCBARPA
+SPP IN MB UCB-VAX.ARPA
+ IN MG SPP@ESVAX
+BLAKKAN IN MB UCB-VAX.ARPA
+ IN MG BLAKKAN@ERNIE
+LOWY IN MB UCB-VAX.ARPA
+ IN MG LOWY@KIM
+MILLS IN MB UCB-VAX.ARPA
+ IN MG TEKTRONIX!TEKECS!CHARLIEM
+PETERSEN IN MB UCB-VAX.ARPA
+ IN MG PETERSEN@ERNIE
+ARPA-NEWS IN MB UCB-VAX.ARPA
+ IN MG ERIC
+ IN MG MSGS@SHADOW
+ IN MG MSGS@ERNIE
+ IN MG MSGS@INGRES
+ IN MG MIKE
+ IN MG MSGS@KIM
+ IN MG MSGS@ARPA
+ETHERNET IN MB UCB-VAX.ARPA
+ IN MG SAM@ARPA
+ IN MG MOSHER@ARPA
+ IN MG LAYER
+ALLMAN IN MB UCB-VAX.ARPA
+ IN MG ERIC
+SCOTTB IN MB UCB-VAX.ARPA
+ IN MG BADEN@KIM
+BJORN IN MB UCB-VAX.ARPA
+ IN MG BJORN@ESVAX
+FODERARO IN MB UCB-VAX.ARPA
+ IN MG JKF
+MARC IN MB UCB-VAX.ARPA
+ IN MG MARC@INGRES
+MUCHNICK IN MB UCB-VAX.ARPA
+ IN MG MUCHNICK@CORY
+MULLER IN MB UCB-VAX.ARPA
+ IN MG MULLER@MEDEA
+MUDGE IN MB UCB-VAX.ARPA
+ IN MG MUDGE@CAD
+OLDHAM IN MB UCB-VAX.ARPA
+ IN MG OLDHAM@ESVAX
+PS IN MB UCB-VAX.ARPA
+ IN MG PS@ERNIE
+SINGER IN MB UCB-VAX.ARPA
+ IN MG SINGER@MEDEA
+STEERING IN MB UCB-VAX.ARPA
+ IN MG STEERING@ARPA
+TKG IN MB UCB-VAX.ARPA
+ IN MG GUSTAFSO@ESVAX
+SOMEONEONUUCP IN MB UCB-VAX.ARPA
+ IN MG ERIC
+41ADMIN IN MB UCB-VAX.ARPA
+ IN MG MOSHER@ARPA
+MAXWELL IN MB UCB-VAX.ARPA
+ IN MG MHTSA!AUSTRALIA!PETERM
+HAGMAN IN MB UCB-VAX.ARPA
+ IN MG HAGMANN@INGRES
+TWG IN MB UCB-VAX.ARPA
+ IN MG TWG@FORD-WDL1
+ IN MG JBS!TWG
+JBS IN MB UCB-VAX.ARPA
+ IN MG JBS!TWG
+CMPLRES IN MB UCB-VAX.ARPA
+ IN MG CMPLRES@ERNIE
+EDWARD IN MB UCB-VAX.ARPA
+ IN MG EDWARD@ARPA
+RDF IN MB UCB-VAX.ARPA
+ IN MG RDF@CAD
+MARSHALL IN MB UCB-VAX.ARPA
+ IN MG MARSHALL@ARPA
+BLOMSETH IN MB UCB-VAX.ARPA
+ IN MG BLOMSETH@UCBKIM
+WONG IN MB UCB-VAX.ARPA
+ IN MG WONG@INGRES
+LAMPORT IN MB UCB-VAX.ARPA
+ IN MG LAMPORT@SRI-CSL
+ANDLER IN MB UCB-VAX.ARPA
+ IN MG ANDLER@ERNIE
+ANDLER IN MB UCB-VAX.ARPA
+ IN MG ANDLER@ERNIE
+FRANZ-FRIENDS IN MB UCB-VAX.ARPA
+ IN MG FRANZ-FRIENDS-BOUNCE@UCBKIM
+FRANZ-FRIENDS-REQUEST IN MB UCB-VAX.ARPA
+ IN MG JKF
+FRANZ-COMPOSERS IN MB UCB-VAX.ARPA
+ IN MG FRANZ-COMPOSERS-UCB
+ IN MG FRANZ-COMPOSERS-ARPA
+ IN MG FRANZ-COMPOSERS-UUCP
+OWNER-FRANZ-COMPOSERS IN MB UCB-VAX.ARPA
+ IN MG JKF
+FRANZ-BUGS IN MB UCB-VAX.ARPA
+ IN MG FRANZ-BUGS@UCBKIM
+OWNER-FRANZ-FRIENDS-UUCP IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-COMPOSERS-UUCP IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-COMPOSERS-UCB IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-COMPOSERS-ARPA IN MB UCB-VAX.ARPA
+ IN MG JKF
+FRANZ-FRIENDS-ARPA IN MB UCB-VAX.ARPA
+ IN MG FRANZ-FRIENDS-1
+ IN MG FRANZ-FRIENDS-2
+ IN MG FRANZ-FRIENDS-3
+ IN MG FRANZ-FRIENDS-CMU
+ IN MG FRANZ-FRIENDS-SCORE
+OWNER-FRANZ-FRIENDS-ARPA IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-FRIENDS-1 IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-FRIENDS-2 IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-FRIENDS-3 IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-FRIENDS-SCORE IN MB UCB-VAX.ARPA
+ IN MG JKF
+OWNER-FRANZ-FRIENDS-CMU IN MB UCB-VAX.ARPA
+ IN MG JKF
+INFO-COBOL-LOCAL IN MB UCB-VAX.ARPA
+ IN MG INFO-COBOL-LOCAL@KIM
+INFO-COBOL-LOCAL-REQUEST IN MB UCB-VAX.ARPA
+ IN MG INFO-COBOL-LOCAL-REQUEST@KIM
+INGRES-LOVERS IN MB UCB-VAX.ARPA
+ IN MG KALASH@BERKELEY
+ IN MG PETER@LBL-CSAM
+ IN MG Z@CCA
+ IN MG DECVAX!DUKE!UCF-CS!CHEN
+ IN MG LBL-CSAM!SSC-VAX!STEVE
+ IN MG LBL-CSAM!FLUKE!NORM
+ IN MG MILTON@SRI-AI
+ IN MG TEKLABS!OGCVAX!ROOT
+ IN MG KENTVAX!CRAIGM
+ IN MG ANZALDI@SUMEX-AIM
+ IN MG DAN@CCA
+ IN MG DECVAX!ITTVAX!ITTAPP!INGRES
+ IN MG CHRISB@CORNELL
+BAM IN MB UCB-VAX.ARPA
+ IN MG SDCSVAX!SDCHEMA!BAM
+INFO-TEX IN MB UCB-VAX.ARPA
+ IN MG PETER
+ IN MG HARRISON@UCBRENOIR
+ IN MG ECC
+ IN MG BALLANCE
+ IN MG DBCOOPER
+ IN MG GRAHAM
+ IN MG BARSKY
+ IN MG DAN
+ IN MG LARUS
+ELDRIDGE IN MB UCB-VAX.ARPA
+ IN MG ELDRIDGE@E.CC
+DAN IN MB UCB-VAX.ARPA
+ IN MG ELDRIDGE
+MAZEWAR IN MB UCB-VAX.ARPA
+ IN MG MAZEWAR@UCBCORY
+DAS-INFO IN MB UCB-VAX.ARPA
+ IN MG MAYO@UCBKIM
+ IN MG BLAKKAN@UCBERNIE
+ IN MG CONROY@UCBERNIE
+ IN MG BLOMSETH@UCBKIM
+ IN MG JTD@UCBIC
+ IN MG MARKHILL@UCBKIM
+ IN MG BECK@UCBERNIE
+ IN MG DIMITRIS@UCBKIM
+ IN MG SHERBURN@UCBKIM
+ IN MG TEKMDP!DADLA-C!GERD@TEKLABS.UUCP
+USENIX IN MB UCB-VAX.ARPA
+ IN MG USENIX@UCBAMBER.CC
+MANUALS IN MB UCB-VAX.ARPA
+ IN MG USENIX@UCBAMBER.CC
+MANUAL IN MB UCB-VAX.ARPA
+ IN MG USENIX@UCBAMBER.CC
diff --git a/usr.sbin/named/test/ns.boot b/usr.sbin/named/test/ns.boot
new file mode 100644
index 00000000000..523e5beb0a5
--- /dev/null
+++ b/usr.sbin/named/test/ns.boot
@@ -0,0 +1,9 @@
+;
+; boot file for name server
+; Note that there should be one primary entry for each SOA record.
+;
+; type domain source file or host
+;
+primary ucb.arpa ns.db
+cache . ns.ca ; initial cache data
+;secondary ucb.arpa 128.32.0.7 ; ucbvax
diff --git a/usr.sbin/named/test/ns.boot1 b/usr.sbin/named/test/ns.boot1
new file mode 100644
index 00000000000..15b570b0cfb
--- /dev/null
+++ b/usr.sbin/named/test/ns.boot1
@@ -0,0 +1,6 @@
+;
+; boot file for name server
+;
+; type domain source file or host
+;
+primary . ns.db1
diff --git a/usr.sbin/named/test/ns.boot2 b/usr.sbin/named/test/ns.boot2
new file mode 100644
index 00000000000..629155d3da6
--- /dev/null
+++ b/usr.sbin/named/test/ns.boot2
@@ -0,0 +1,9 @@
+;
+; boot file for name server
+;
+; type domain source file or host
+;
+primary ARPA hosts.mff
+primary UCB.ARPA ns.pw2
+primary UCB.ARPA ns.al2
+cache . ns.ca2 ; initial cache data
diff --git a/usr.sbin/named/test/ns.boot3 b/usr.sbin/named/test/ns.boot3
new file mode 100644
index 00000000000..ceb8e1bf6ea
--- /dev/null
+++ b/usr.sbin/named/test/ns.boot3
@@ -0,0 +1,8 @@
+;
+; boot file for name server
+; Note that there should be one primary entry for each SOA record.
+;
+; type domain source file or host
+;
+primary ucb.arpa ns.db3
+cache . ns.ca3 ; initial cache data
diff --git a/usr.sbin/named/test/ns.ca b/usr.sbin/named/test/ns.ca
new file mode 100644
index 00000000000..7373239e42d
--- /dev/null
+++ b/usr.sbin/named/test/ns.ca
@@ -0,0 +1,5 @@
+;
+; Initial cache data for root domain servers.
+;
+. 9999 IN NS USC-ISIF.ARPA
+USC-ISIF.ARPA 9999 IN A 10.2.0.52
diff --git a/usr.sbin/named/test/ns.ca2 b/usr.sbin/named/test/ns.ca2
new file mode 100644
index 00000000000..af6b13482dc
--- /dev/null
+++ b/usr.sbin/named/test/ns.ca2
@@ -0,0 +1,5 @@
+;
+; Initial cache data for root domain servers.
+;
+. 9999 IN NS SRI-NIC.ARPA
+ 9999 IN NS USC-ISIB.ARPA
diff --git a/usr.sbin/named/test/ns.ca3 b/usr.sbin/named/test/ns.ca3
new file mode 100644
index 00000000000..5ddf730d506
--- /dev/null
+++ b/usr.sbin/named/test/ns.ca3
@@ -0,0 +1,7 @@
+;
+; Initial cache data for ROOT.
+;
+MIT.ARPA 999999 IN NS MATISSE.MIT.ARPA
+MATISSE.MIT.ARPA 999999 IN A 128.32.14
+ISI.ARPA 999999 IN NS CALDER.ISI.ARPA
+CALDER.ISI.ARPA 999999 IN A 128.32.12
diff --git a/usr.sbin/named/test/ns.db b/usr.sbin/named/test/ns.db
new file mode 100644
index 00000000000..a9282ac0fc0
--- /dev/null
+++ b/usr.sbin/named/test/ns.db
@@ -0,0 +1,17 @@
+;
+; Authoritative data for ucb.arpa
+;
+@ IN SOA UCBMONET.UCB.ARPA RALPH.UCBMONET.UCB.ARPA
+ 1 3600 300 3600000 3600
+ IN NS UCBMONET.UCB.ARPA
+UCB-ARPA IN A 10.0.0.78
+ IN A 128.32.0.4
+ IN HINFO VAX-11/780,UNIX
+ARPA IN CNAME UCB-ARPA.UCB.ARPA
+UCB-VAX 9999 IN A 10.2.0.78
+ IN A 128.32.0.10
+ IN HINFO VAX-11/750
+BERKELEY IN CNAME UCB-VAX.UCB.ARPA
+UCBVAX IN CNAME UCB-VAX.UCB.ARPA
+UCBMONET IN A 128.32.0.7
+ IN HINFO VAX-11/750,UNIX
diff --git a/usr.sbin/named/test/ns.db1 b/usr.sbin/named/test/ns.db1
new file mode 100644
index 00000000000..f9afb4d5996
--- /dev/null
+++ b/usr.sbin/named/test/ns.db1
@@ -0,0 +1,16 @@
+;
+; Authoritative data
+;
+@ IN SOA UCBMONET RALPH.UCBMONET
+ 1 3600 300 3600000 3600
+ IN NS UCBMONET
+UCBMONET IN A 128.32.0.7
+ IN HINFO VAX-11/750,UNIX
+RALPH ANY UID 1027
+ ANY GID 10
+ ANY UINFO "& Campbell,463E,8337"
+ ANY MB UCBARPA.ARPA
+KARELS ANY UID 1030
+ ANY GID 10
+ ANY UINFO "& Karels,463E,8337"
+ ANY MB UCBARPA.ARPA
diff --git a/usr.sbin/named/test/ns.db3 b/usr.sbin/named/test/ns.db3
new file mode 100644
index 00000000000..169e53e03bb
--- /dev/null
+++ b/usr.sbin/named/test/ns.db3
@@ -0,0 +1,19 @@
+;
+; Authoritative data for ucb.arpa
+;
+@ IN SOA MONET.UCB.ARPA RALPH.MONET.UCB.ARPA
+ 1 3600 300 3600000 3600
+ IN NS MONET.UCB.ARPA
+UCB-ARPA IN A 10.0.0.78
+ IN A 128.32.0.4
+ IN HINFO VAX-11/780,UNIX
+ARPA IN CNAME UCB-ARPA.UCB.ARPA
+UCB-VAX 9999 IN A 10.2.0.78
+ IN A 128.32.0.10
+ IN HINFO VAX-11/750
+BERKELEY IN CNAME UCB-VAX.UCB.ARPA
+UCBVAX IN CNAME UCB-VAX.UCB.ARPA
+MONET IN A 128.32.0.7
+ IN HINFO VAX-11/750,UNIX
+CC IN NS CALDER.CC.UCB.ARPA
+CALDER.CC IN A 128.32.4
diff --git a/usr.sbin/named/test/ns.pw2 b/usr.sbin/named/test/ns.pw2
new file mode 100644
index 00000000000..9b7caf8fa11
--- /dev/null
+++ b/usr.sbin/named/test/ns.pw2
@@ -0,0 +1,1965 @@
+ROOT ANY UID 0
+ROOT ANY GID 10
+ROOT ANY UINFO "Ernie Co-vax,508JE,0204"
+TOOR ANY UID 0
+TOOR ANY GID 10
+TOOR ANY UINFO "Ernie Co-vax,508JE,0204"
+DAEMON ANY UID 1
+DAEMON ANY GID 1
+DAEMON ANY UINFO "The devil himself"
+UUCP ANY UID 66
+UUCP ANY GID 31
+UUCP ANY UINFO "UNIX-to-UNIX Copy"
+OPERATOR ANY UID 17
+OPERATOR ANY GID 28
+OPERATOR ANY UINFO "System &"
+SKLOWER ANY UID 2
+SKLOWER ANY GID 10
+SKLOWER ANY UINFO "Keith &,467E,9587,8630990"
+KLS ANY UID 2
+KLS ANY GID 10
+KLS ANY UINFO "Keith &,467E,9587,8630990"
+KRIDLE ANY UID 3
+KRIDLE ANY GID 10
+KRIDLE ANY UINFO "Bob &,,,5485610"
+KAREN ANY UID 4
+KAREN ANY GID 10
+KAREN ANY UINFO "& Smoler"
+MOSHER ANY UID 5
+MOSHER ANY GID 10
+MOSHER ANY UINFO "David &,509E,8882"
+RWH ANY UID 6
+RWH ANY GID 10
+RWH ANY UINFO "Robert W. Henry,463E,8493,"
+KATSEFF ANY UID 9
+KATSEFF ANY GID 10
+KATSEFF ANY UINFO "Howard &,2019495337"
+KARELS ANY UID 10
+KARELS ANY GID 10
+KARELS ANY UINFO "Mike &,455E,4948"
+MARK ANY UID 12
+MARK ANY GID 10
+MARK ANY UINFO "& Horton,6148604276"
+ARCH ANY UID 13
+ARCH ANY GID 10
+ARCH ANY UINFO "& Turner,463E,1319,4796659"
+BLOOM ANY UID 15
+BLOOM ANY GID 10
+BLOOM ANY UINFO "Jim &,175MC,6744"
+BRAD ANY UID 16
+BRAD ANY GID 10
+BRAD ANY UINFO "Brad Krebs,207C,3203,"
+KALASH ANY UID 18
+KALASH ANY GID 10
+KALASH ANY UINFO "Joe &,380C,7520,8483371"
+NOLAN ANY UID 19
+NOLAN ANY GID 10
+NOLAN ANY UINFO "Earl &,8487084"
+NEWS ANY UID 20
+NEWS ANY GID 10
+NEWS ANY UINFO "The MH news program"
+CARL ANY UID 21
+CARL ANY GID 10
+CARL ANY UINFO "& Smith,508-21E,6258"
+DIST2 ANY UID 21
+DIST2 ANY GID 10
+DIST2 ANY UINFO "Carl Smith,508-21E,6258"
+HELGE ANY UID 22
+HELGE ANY GID 90
+HELGE ANY UINFO "& Skrivervik,466E,7780,540-7330"
+RALPH ANY UID 23
+RALPH ANY GID 10
+RALPH ANY UINFO "& Campbell,463E,7780"
+LEARN ANY UID 24
+LEARN ANY GID 90
+LEARN ANY UINFO "John Kunze"
+LAYER ANY UID 30
+LAYER ANY GID 10
+LAYER ANY UINFO "Kevin &,608-5E,3437,6522405"
+ERIC ANY UID 31
+ERIC ANY GID 10
+ERIC ANY UINFO "& Allman,380C,7520,8439535"
+TEF ANY UID 39
+TEF ANY GID 90
+TEF ANY UINFO "Thomas Ferrin,UCSF,6661100"
+RICKI ANY UID 41
+RICKI ANY GID 10
+RICKI ANY UINFO "& Blau,508-2E,5422,8419671"
+JONATHAN ANY UID 44
+JONATHAN ANY GID 30
+JONATHAN ANY UINFO "& Davis-Petty,573E,1024"
+RHM ANY UID 45
+RHM ANY GID 10
+RHM ANY UINFO "Robert H. Morris,% center 127 Math, Bell Labs"
+WAYNE ANY UID 46
+WAYNE ANY GID 90
+WAYNE ANY UINFO "& Graves,LBL7035,7923013"
+PUBS ANY UID 47
+PUBS ANY GID 30
+PUBS ANY UINFO "Administration Publications"
+BRASSARD ANY UID 48
+BRASSARD ANY GID 30
+BRASSARD ANY UINFO "Gilles Brassard,459E,2714,"
+LOU ANY UID 49
+LOU ANY GID 10
+LOU ANY UINFO "& Katz,521E,9503,5301430"
+STEVE ANY UID 54
+STEVE ANY GID 10
+STEVE ANY UINFO "& Eisen,5483591"
+USG ANY UID 55
+USG ANY GID 10
+USG ANY UINFO "UNIX Support Group,Bell Labs @ Murray Hill"
+DEVEL ANY UID 56
+DEVEL ANY GID 26
+DEVEL ANY UINFO "EECS Elect. Shop,6744"
+FRED ANY UID 57
+FRED ANY GID 10
+FRED ANY UINFO "& Archibald,6744"
+GEORGE ANY UID 59
+GEORGE ANY GID 90
+GEORGE ANY UINFO "& Lavender"
+RICK ANY UID 60
+RICK ANY GID 90
+RICK ANY UINFO "Rick Llewellyn, DEC"
+PAO ANY UID 64
+PAO ANY GID 10
+PAO ANY UINFO "Fred Pao"
+XUUCP ANY UID 66
+XUUCP ANY GID 10
+XUUCP ANY UINFO "UNIX-to-UNIX Copy"
+EUUCP ANY UID 66
+EUUCP ANY GID 10
+EUUCP ANY UINFO "UNIX-to-UNIX Copy"
+UUCLERK ANY UID 66
+UUCLERK ANY GID 10
+UUCLERK ANY UINFO "Maintain UUCP without doing infinite chown's"
+APS ANY UID 67
+APS ANY GID 90
+APS ANY UINFO "Armando Stettner,Digital Equipment"
+DLW ANY UID 74
+DLW ANY GID 10
+DLW ANY UINFO "David Wasley,SESM-VAX,3478,"
+MITBB ANY UID 75
+MITBB ANY GID 10
+MITBB ANY UINFO "Bruce Beattie,442E,7780,6744"
+CAM ANY UID 76
+CAM ANY GID 10
+CAM ANY UINFO "Carol Martin,179MC,6744"
+JAK ANY UID 77
+JAK ANY GID 90
+JAK ANY UINFO "John A. Kunze,291E,1530"
+ARNOLD ANY UID 78
+ARNOLD ANY GID 27
+ARNOLD ANY UINFO "Kenneth C R C Arnold,461E,7780,8483371"
+LAMPE ANY UID 79
+LAMPE ANY GID 10
+LAMPE ANY UINFO "John Lampe"
+DEE ANY UID 83
+DEE ANY GID 10
+DEE ANY UINFO "Dee Wunderlich,179MC,6744"
+GOD ANY UID 85
+GOD ANY GID 90
+GOD ANY UINFO "Steve Hartwell,Stanford University,4979369"
+MITCH ANY UID 86
+MITCH ANY GID 10
+MITCH ANY UINFO "& Marcus,__Bell_Labs,2015823948"
+UCSD ANY UID 87
+UCSD ANY GID 90
+UCSD ANY UINFO "UC San Diego"
+GHG ANY UID 93
+GHG ANY GID 10
+GHG ANY UINFO "George Goble,Purdue"
+COOPER ANY UID 94
+COOPER ANY GID 10
+COOPER ANY UINFO "Eric &,461E,7780,8457952"
+ROB ANY UID 95
+ROB ANY GID 10
+ROB ANY UINFO "& Pike,2015827854"
+SHOEMAKE ANY UID 97
+SHOEMAKE ANY GID 10
+SHOEMAKE ANY UINFO "Tim &r,5408492"
+SOURCES ANY UID 198
+SOURCES ANY GID 198
+SOURCES ANY UINFO "The & Program"
+FINGER ANY UID 199
+FINGER ANY GID 199
+FINGER ANY UINFO "The & Program"
+W ANY UID 199
+W ANY GID 199
+W ANY UINFO "The & Program"
+WHO ANY UID 199
+WHO ANY GID 199
+WHO ANY UINFO "The & Program"
+YANK ANY UID 199
+YANK ANY GID 199
+YANK ANY UINFO "The & Program"
+RUPTIME ANY UID 199
+RUPTIME ANY GID 199
+RUPTIME ANY UINFO "The & Program"
+VPQ ANY UID 197
+VPQ ANY GID 199
+VPQ ANY UINFO "The & Program"
+SLEEPER ANY UID 199
+SLEEPER ANY GID 199
+SLEEPER ANY UINFO "Woody Allen"
+PS300 ANY UID 199
+PS300 ANY GID 199
+PS300 ANY UINFO "PS300 Sleeper"
+MCKUSICK ANY UID 201
+MCKUSICK ANY GID 10
+MCKUSICK ANY UINFO "Kirk &,513E,4611,8439535"
+PETER ANY UID 202
+PETER ANY GID 10
+PETER ANY UINFO "peter b. kessler,513E,4611,6556558"
+RRH ANY UID 203
+RRH ANY GID 29
+RRH ANY UINFO "Robert R. Henry,Univ. of WA,(206)545-1934,(206)367-7481"
+CHAR ANY UID 204
+CHAR ANY GID 90
+CHAR ANY UINFO "Bruce &,520E,1863"
+WINKLER ANY UID 205
+WINKLER ANY GID 20
+WINKLER ANY UINFO "Tim &,475E,7017,5489216"
+BAIR ANY UID 207
+BAIR ANY GID 20
+BAIR ANY UINFO "Berkeley AI Research,547E,8468"
+TSAI ANY UID 208
+TSAI ANY GID 20
+TSAI ANY UINFO "& Wei-tek,6358,6433067"
+JKF ANY UID 209
+JKF ANY GID 10
+JKF ANY UINFO "John Foderaro,483E,9503,5265429"
+BHATTI ANY UID 218
+BHATTI ANY GID 20
+BHATTI ANY UINFO "M.A. &,8351,209Davis"
+HALBERT ANY UID 226
+HALBERT ANY GID 10
+HALBERT ANY UINFO "Dan &,512E,4611,5275558"
+DCH ANY UID 226
+DCH ANY GID 10
+DCH ANY UINFO "Dan Halbert,512E,4611,5275558"
+SCHULMAN ANY UID 230
+SCHULMAN ANY GID 29
+SCHULMAN ANY UINFO "bob schulman,514E,4611,2612760"
+WALLACE ANY UID 231
+WALLACE ANY GID 20
+WALLACE ANY UINFO "David E. &,508-6E,7288,5406791"
+DEMMEL ANY UID 234
+DEMMEL ANY GID 20
+DEMMEL ANY UINFO "James W. Demmel,521E,1863,5251022"
+POLLEZ ANY UID 236
+POLLEZ ANY GID 20
+POLLEZ ANY UINFO "Polle Zellweger,512E,4611,4932748"
+COONEN ANY UID 237
+COONEN ANY GID 20
+COONEN ANY UINFO "Jerome &,1020E,,7719917"
+FKUNZE ANY UID 242
+FKUNZE ANY GID 20
+FKUNZE ANY UINFO "Fritz Kunze,225E,5974,3392681"
+DEERING ANY UID 247
+DEERING ANY GID 10
+DEERING ANY UINFO "Mike Deering,508-1E,8004,9484956"
+SWENSEN ANY UID 249
+SWENSEN ANY GID 24
+SWENSEN ANY UINFO "John &,412E,7666,8411657"
+RABIN ANY UID 254
+RABIN ANY GID 20
+RABIN ANY UINFO "Henry &owitz,,,2128665662"
+NOTION ANY UID 261
+NOTION ANY GID 20
+NOTION ANY UINFO "Michael Luby,587E,8204,8492354"
+INGRES ANY UID 267
+INGRES ANY GID 20
+INGRES ANY UINFO "& Group"
+DOUGLAS ANY UID 270
+DOUGLAS ANY GID 10
+DOUGLAS ANY UINFO "& Lanam,521E,1863"
+UPSTILL ANY UID 271
+UPSTILL ANY GID 24
+UPSTILL ANY UINFO "Steve Upstill,508-12E,9413,540-8110"
+DBCOOPER ANY UID 272
+DBCOOPER ANY GID 30
+DBCOOPER ANY UINFO "Doug Cooper,473E,4951,5257636"
+SHYAM ANY UID 274
+SHYAM ANY GID 20
+SHYAM ANY UINFO "& Parekh"
+LARUS ANY UID 275
+LARUS ANY GID 20
+LARUS ANY UINFO "James &,521E,1863,5490877"
+DRB ANY UID 279
+DRB ANY GID 20
+DRB ANY UINFO "David Barton,541E,4979,8457212"
+BACH ANY UID 281
+BACH ANY GID 20
+BACH ANY UINFO "Benny Profane,585E,1266,5253661"
+ABAR ANY UID 282
+ABAR ANY GID 25
+ABAR ANY UINFO "Robert &banel,2951,8490921,UCSF"
+TPLEE ANY UID 283
+TPLEE ANY GID 20
+TPLEE ANY UINFO "Tzong-yu Paul Lee,468E,3979,7927966"
+TAMIR ANY UID 284
+TAMIR ANY GID 20
+TAMIR ANY UINFO "Yuval &,529BE,6193,8437952"
+BALLANCE ANY UID 288
+BALLANCE ANY GID 20
+BALLANCE ANY UINFO "Robert A. &,508NE,7686,3227812"
+FUJIMOTO ANY UID 297
+FUJIMOTO ANY GID 20
+FUJIMOTO ANY UINFO "Richard Fujimoto,529BE,6193,5490885"
+VIVIAN ANY UID 298
+VIVIAN ANY GID 20
+VIVIAN ANY UINFO "& Shen,401C,6731,8431936"
+FATEMAN ANY UID 300
+FATEMAN ANY GID 10
+FATEMAN ANY UINFO "Richard &,519E,1879"
+LARRY ANY UID 301
+LARRY ANY GID 30
+LARRY ANY UINFO "Larry Rowe,501E,5117"
+GRAHAM ANY UID 303
+GRAHAM ANY GID 30
+GRAHAM ANY UINFO "Susan &,511E,2059"
+FABRY ANY UID 305
+FABRY ANY GID 30
+FABRY ANY UINFO "Bob &,501E,2714,5277655"
+WASERMAN ANY UID 307
+WASERMAN ANY GID 25
+WASERMAN ANY UINFO "Tony Wasserman"
+CARYN ANY UID 308
+CARYN ANY GID 30
+CARYN ANY UINFO "& Dombroski,573E,1024,6543850"
+PATT ANY UID 311
+PATT ANY GID 30
+PATT ANY UINFO "Yale &,565E,4829"
+KAHAN ANY UID 312
+KAHAN ANY GID 30
+KAHAN ANY UINFO "W &"
+BERLEK ANY UID 313
+BERLEK ANY GID 30
+BERLEK ANY UINFO "Elwyn &amp"
+CHS ANY UID 314
+CHS ANY GID 30
+CHS ANY UINFO "Carlo Sequin,529AE,5103,8454116"
+WILENSKY ANY UID 315
+WILENSKY ANY GID 30
+WILENSKY ANY UINFO "Robert &"
+SMITH ANY UID 316
+SMITH ANY GID 30
+SMITH ANY UINFO "Alan &,531E,5290"
+BLUM ANY UID 317
+BLUM ANY GID 30
+BLUM ANY UINFO "Manuel &"
+FERRARI ANY UID 319
+FERRARI ANY GID 34
+FERRARI ANY UINFO "Domenico &"
+CLANCY ANY UID 320
+CLANCY ANY GID 30
+CLANCY ANY UINFO "Mike &,475E,7017,8435550"
+ALBERTO ANY UID 321
+ALBERTO ANY GID 30
+ALBERTO ANY UINFO "& Sangiovanni,401GC,4882"
+POWELL ANY UID 324
+POWELL ANY GID 26
+POWELL ANY UINFO "Michael L. &,465E,7597,5256870"
+SWEET ANY UID 326
+SWEET ANY GID 30
+SWEET ANY UINFO "Toni Sweet,571E,5244"
+HARRISON ANY UID 327
+HARRISON ANY GID 30
+HARRISON ANY UINFO "Michael &,517E,1469"
+THOMPSON ANY UID 328
+THOMPSON ANY GID 30
+THOMPSON ANY UINFO "Clark &"
+PARLETT ANY UID 331
+PARLETT ANY GID 30
+PARLETT ANY UINFO "Beresford &,799E,6655,8431835"
+KARP ANY UID 332
+KARP ANY GID 30
+KARP ANY UINFO "Richard &"
+DIANA ANY UID 334
+DIANA ANY GID 27
+DIANA ANY UINFO "& Wear,457E,7780"
+TUTTLE ANY UID 335
+TUTTLE ANY GID 30
+TUTTLE ANY UINFO "Mark S. Tuttle,469E,1637,6443184"
+OUSTER ANY UID 341
+OUSTER ANY GID 30
+OUSTER ANY UINFO "John Ousterhout,525E,0865,5267104"
+MIKE ANY UID 343
+MIKE ANY GID 30
+MIKE ANY UINFO "& Stonebraker,265MC,5799"
+CORBETT ANY UID 346
+CORBETT ANY GID 20
+CORBETT ANY UINFO "Robert &,465E,0107,8451084"
+TERRY ANY UID 348
+TERRY ANY GID 27
+TERRY ANY UINFO "Doug Terry,464E,8919,4153267554"
+DON ANY UID 351
+DON ANY GID 20
+DON ANY UINFO "Siyi &,533E,6358,5263667"
+BARSKY ANY UID 352
+BARSKY ANY GID 30
+BARSKY ANY UINFO "Brian A. Barsky,505E,9838,5262394"
+MORTON ANY UID 356
+MORTON ANY GID 30
+MORTON ANY UINFO "Paul &,563E,5319"
+BARCLAY ANY UID 361
+BARCLAY ANY GID 30
+BARCLAY ANY UINFO "Diana &,577E,0930"
+SENDEROW ANY UID 363
+SENDEROW ANY GID 20
+SENDEROW ANY UINFO "Dan &icz,401C,6731,4953"
+VAZIRANI ANY UID 366
+VAZIRANI ANY GID 20
+VAZIRANI ANY UINFO "Umesh Vazirani,587E,8204,8437000"
+GARRISON ANY UID 368
+GARRISON ANY GID 20
+GARRISON ANY UINFO "Phil &,514E,4611,4908752"
+DIPPE ANY UID 369
+DIPPE ANY GID 24
+DIPPE ANY UINFO "Ernie Feathermouth,508-14E,3631,4281783"
+DMU ANY UID 372
+DMU ANY GID 33
+DMU ANY UINFO "David Ungar,508-5E,548-2315"
+ALONSO ANY UID 374
+ALONSO ANY GID 27
+ALONSO ANY UINFO "Rafael Alonso,464E,7780,5258707"
+KATEVENI ANY UID 378
+KATEVENI ANY GID 20
+KATEVENI ANY UINFO "Manolis G.H. Katevenis,,,"
+HOFMANN ANY UID 389
+HOFMANN ANY GID 20
+HOFMANN ANY UINFO "Mark &,321C,4973,8452593"
+HALPERN ANY UID 395
+HALPERN ANY GID 20
+HALPERN ANY UINFO "James D. &,434E,5260305"
+SOIFFER ANY UID 397
+SOIFFER ANY GID 20
+SOIFFER ANY UINFO "Neil Soiffer,485E,4694,5275558"
+FREUND ANY UID 398
+FREUND ANY GID 20
+FREUND ANY UINFO "Mark &,"
+PATTRSN ANY UID 400
+PATTRSN ANY GID 40
+PATTRSN ANY UINFO "Dave Patterson,6587,527E,5260447"
+DESPAIN ANY UID 401
+DESPAIN ANY GID 40
+DESPAIN ANY UINFO "Al &,503E,5615,8491223"
+AL ANY UID 402
+AL ANY GID 40
+AL ANY UINFO "& Despain,503E,5615,8491223"
+PRESOTTO ANY UID 404
+PRESOTTO ANY GID 26
+PRESOTTO ANY UINFO "Dave Presotto,467E,9587,3260848"
+SEQUIN ANY UID 405
+SEQUIN ANY GID 40
+SEQUIN ANY UINFO "Carlo &,529AE,5103,8454116"
+PELEGRI ANY UID 407
+PELEGRI ANY GID 33
+PELEGRI ANY UINFO "Eduardo &-Llopart,477E,9669,8494991"
+CARLOCK ANY UID 410
+CARLOCK ANY GID 90
+CARLOCK ANY UINFO "Ken &,583E,4624"
+NEWTON ANY UID 411
+NEWTON ANY GID 40
+NEWTON ANY UINFO "Richard &,443C"
+DAVE ANY UID 414
+DAVE ANY GID 10
+DAVE ANY UINFO "& Ditzel,2015823655"
+FRODO ANY UID 416
+FRODO ANY GID 10
+FRODO ANY UINFO "Ted Kowalski"
+JIMBO ANY UID 417
+JIMBO ANY GID 40
+JIMBO ANY UINFO "Jim Kleckner,321AC,8186,6582483"
+BART ANY UID 418
+BART ANY GID 26
+BART ANY UINFO "& Miller,467E,9587,8483557"
+RR ANY UID 419
+RR ANY GID 40
+RR ANY UINFO "Bob Rodriguez,2013863503"
+HANSEN ANY UID 421
+HANSEN ANY GID 40
+HANSEN ANY UINFO "Paul Hansen,508-2E,5422,5278764"
+TAYLOR ANY UID 422
+TAYLOR ANY GID 35
+TAYLOR ANY UINFO "George &,508-7E,9716,5275558"
+HAMACHI ANY UID 424
+HAMACHI ANY GID 40
+HAMACHI ANY UINFO "Gordon &,508-7E,9716,8494991"
+MARGIE ANY UID 425
+MARGIE ANY GID 40
+MARGIE ANY UINFO "& Murphy,444E,5485828"
+CAD ANY UID 427
+CAD ANY GID 40
+CAD ANY UINFO "CAD Toolbox librarian"
+CARY ANY UID 429
+CARY ANY GID 35
+CARY ANY UINFO "Dave &,508-1E,8004,4156545770"
+BADEN ANY UID 432
+BADEN ANY GID 33
+BADEN ANY UINFO "Scott B. Baden,508-2E,5422,5400266"
+MAYO ANY UID 434
+MAYO ANY GID 40
+MAYO ANY UINFO "Bob Mayo,508-7E,9716,5305482"
+RISCIT ANY UID 439
+RISCIT ANY GID 40
+RISCIT ANY UINFO "Robert Sherburne,581E,6437915,8492322"
+HODGES ANY UID 451
+HODGES ANY GID 30
+HODGES ANY UINFO "David &,463C,3948"
+HOWARD ANY UID 452
+HOWARD ANY GID 30
+HOWARD ANY UINFO "Howard Karloff,585E,1266,8418451"
+SHENG ANY UID 456
+SHENG ANY GID 20
+SHENG ANY UINFO "Richard &,557E,5259523"
+MCCARTY ANY UID 458
+MCCARTY ANY GID 20
+MCCARTY ANY UINFO "Perry McCarty,557E,5029,5492739"
+HOBEN ANY UID 460
+HOBEN ANY GID 20
+HOBEN ANY UINFO "John &,367E,5491245"
+LISA ANY UID 462
+LISA ANY GID 20
+LISA ANY UINFO "& Rau,508-18E,9076,5481118"
+LAWLER ANY UID 469
+LAWLER ANY GID 30
+LAWLER ANY UINFO "Eugene &,591E,4019"
+CRYO ANY UID 470
+CRYO ANY GID 20
+CRYO ANY UINFO "Herbert Ko,355C,0502,6442584"
+MHA ANY UID 478
+MHA ANY GID 20
+MHA ANY UINFO "Michael Arnold,508-7E,9716,8488724"
+LINTON ANY UID 479
+LINTON ANY GID 26
+LINTON ANY UINFO "Mark &,467E,9587"
+LYLE ANY UID 485
+LYLE ANY GID 30
+LYLE ANY UINFO "Michael &,538E,8447"
+WILHELMS ANY UID 487
+WILHELMS ANY GID 24
+WILHELMS ANY UINFO "Jane &,508-12E,0344,5306210"
+MESSER ANY UID 492
+MESSER ANY GID 30
+MESSER ANY UINFO "David G &schmitt,483C,1090"
+HAGMANN ANY UID 494
+HAGMANN ANY GID 33
+HAGMANN ANY UINFO "Bob &,547E,1845,5250848"
+JOHNSON ANY UID 496
+JOHNSON ANY GID 26
+JOHNSON ANY UINFO "Stephen &,467E,9587,9167534655"
+CHOW ANY UID 497
+CHOW ANY GID 20
+CHOW ANY UINFO "& Ey-Chih,301C,1094,5487470"
+XTREE ANY UID 499
+XTREE ANY GID 40
+XTREE ANY UINFO "Xtree Group"
+NETWORK ANY UID 501
+NETWORK ANY GID 50
+NETWORK ANY UINFO "& Program "
+TTY ANY UID 504
+TTY ANY GID 50
+TTY ANY UINFO "&"
+ALEX ANY UID 505
+ALEX ANY GID 10
+ALEX ANY UINFO "&ander Para,140AC,6926"
+WOLD ANY UID 510
+WOLD ANY GID 40
+WOLD ANY UINFO "Erling &,508-2E,5422,6555261"
+HELENA ANY UID 511
+HELENA ANY GID 20
+HELENA ANY UINFO "& Winkler,608-17E,8149,8411657"
+BAHRAM ANY UID 512
+BAHRAM ANY GID 20
+BAHRAM ANY UINFO "& Nour-Omid,410Davis,0749,2541836"
+POTONG ANY UID 513
+POTONG ANY GID 20
+POTONG ANY UINFO "Po Tong,585E,1266,6432851"
+HARRY ANY UID 514
+HARRY ANY GID 40
+HARRY ANY UINFO "& I. Rubin,468E,3979,5405160"
+HARUYAMA ANY UID 520
+HARUYAMA ANY GID 20
+HARUYAMA ANY UINFO "Shinichiro Haruyama,,,"
+AIGRAIN ANY UID 521
+AIGRAIN ANY GID 90
+AIGRAIN ANY UINFO "Philippe &,569E,4554,2859341"
+RESNIKOF ANY UID 523
+RESNIKOF ANY GID 90
+RESNIKOF ANY UINFO "Carl &f,432E,9542,283-1826"
+PROBST ANY UID 525
+PROBST ANY GID 40
+PROBST ANY UINFO "Richard & ,5254785"
+ASPIN ANY UID 527
+ASPIN ANY GID 20
+ASPIN ANY UINFO "David &wall,521E,1863,564-7263"
+GROSH ANY UID 529
+GROSH ANY GID 90
+GROSH ANY UINFO "Pat &,469E,1637"
+LIHR ANY UID 530
+LIHR ANY GID 26
+LIHR ANY UINFO "Luis Ivan Hernandez,414E,9117,6429117"
+PARKER ANY UID 531
+PARKER ANY GID 30
+PARKER ANY UINFO "Allene M. &,533E,5399,"
+JANET ANY UID 533
+JANET ANY GID 10
+JANET ANY UINFO "& Henry,509E,8487,"
+JANICE ANY UID 536
+JANICE ANY GID 30
+JANICE ANY UINFO "& Anthony,577E,1024"
+WOODSON ANY UID 539
+WOODSON ANY GID 90
+WOODSON ANY UINFO "Chas &,471E,8311,1024"
+ANN ANY UID 540
+ANN ANY GID 30
+ANN ANY UINFO "& Di Fruscia,569E,4600,8488108"
+ZADEH ANY UID 541
+ZADEH ANY GID 30
+ZADEH ANY UINFO "Lotfi Zadeh,561E"
+GILL ANY UID 542
+GILL ANY GID 30
+GILL ANY UINFO "Arthur Gill,559E,3936"
+RAM ANY UID 543
+RAM ANY GID 30
+RAM ANY UINFO "C. V. Ramamoorthy,537E,24751"
+PKL ANY UID 545
+PKL ANY GID 20
+PKL ANY UINFO "Peter K. Lee,510E,,8484983"
+UG ANY UID 546
+UG ANY GID 20
+UG ANY UINFO "UNIGRAFIX librarian,508-6E,7288,"
+DEROSE ANY UID 550
+DEROSE ANY GID 20
+DEROSE ANY UINFO "Tony DeRose,508-14E,9413,8492423"
+WEIJIN ANY UID 553
+WEIJIN ANY GID 26
+WEIJIN ANY UINFO "Dai Wei-Jin,,,8487142"
+COMAY ANY UID 554
+COMAY ANY GID 90
+COMAY ANY UINFO "David S. &,,,2133953390"
+DAMBROSI ANY UID 561
+DAMBROSI ANY GID 20
+DAMBROSI ANY UINFO "Bruce D'Ambrosio,,5482713"
+SANTOS ANY UID 563
+SANTOS ANY GID 20
+SANTOS ANY UINFO "Joe Santos,,6556980"
+SHMOYS ANY UID 565
+SHMOYS ANY GID 20
+SHMOYS ANY UINFO "David Shmoys,585E,1266,5491839"
+TEDRICK ANY UID 567
+TEDRICK ANY GID 20
+TEDRICK ANY UINFO "Tom Tedrick,935E"
+COX ANY UID 572
+COX ANY GID 20
+COX ANY UINFO "Charles A. Cox,545E,8468,5407690"
+FOSTER ANY UID 575
+FOSTER ANY GID 20
+FOSTER ANY UINFO "Gregg Foster,481E,6509,5275578"
+PERALTA ANY UID 576
+PERALTA ANY GID 20
+PERALTA ANY UINFO "Rene Peralta,587E,8204,5281316"
+HILFINGR ANY UID 578
+HILFINGR ANY GID 30
+HILFINGR ANY UINFO "Paul Hilfinger,515E,8401,8415476"
+CONROY ANY UID 580
+CONROY ANY GID 20
+CONROY ANY UINFO "Thomas Conroy,,,4302519"
+SHEU ANY UID 581
+SHEU ANY GID 20
+SHEU ANY UINFO "Phillip Chen-Yu Sheu,608-15E,8143,"
+PONDER ANY UID 583
+PONDER ANY GID 20
+PONDER ANY UINFO "Carl Ponder,412E,7666,5406143"
+RAGHAVAN ANY UID 587
+RAGHAVAN ANY GID 20
+RAGHAVAN ANY UINFO "Prabhakar Raghavan,516E,4662,"
+ELAINE ANY UID 592
+ELAINE ANY GID 20
+ELAINE ANY UINFO "Elaine M. Newman,262M Cory,1891"
+ALICE ANY UID 594
+ALICE ANY GID 20
+ALICE ANY UINFO "Alice Wong,585E,1266,5499858"
+MARKHILL ANY UID 595
+MARKHILL ANY GID 20
+MARKHILL ANY UINFO "Mark D. Hill,547E,1845,5490762"
+CITRIN ANY UID 596
+CITRIN ANY GID 25
+CITRIN ANY UINFO "Wayne &,508-3E,7233,8488568"
+EVEN ANY UID 597
+EVEN ANY GID 90
+EVEN ANY UINFO "Shimon Even,543E,9955,"
+PUA ANY UID 602
+PUA ANY GID 10
+PUA ANY UINFO "& Mitchell,535E,1898,5484143"
+VIRGINIA ANY UID 603
+VIRGINIA ANY GID 90
+VIRGINIA ANY UINFO "& Bates,UniSoft,,,"
+JCBEATTY ANY UID 605
+JCBEATTY ANY GID 24
+JCBEATTY ANY UINFO "John C. Beatty,509E,,519-7432938"
+BARSKY2 ANY UID 607
+BARSKY2 ANY GID 90
+BARSKY2 ANY UINFO "Guest of Barsky"
+VESTEY ANY UID 608
+VESTEY ANY GID 10
+VESTEY ANY UINFO "Sylvia Vestey,573E,1024,5234302"
+KIRK ANY UID 610
+KIRK ANY GID 90
+KIRK ANY UINFO "Kirk Thege,390C,0312,,"
+PASQUALE ANY UID 611
+PASQUALE ANY GID 20
+PASQUALE ANY UINFO "Joe Pasquale,466E,8905,526-6894"
+WILDBILL ANY UID 613
+WILDBILL ANY GID 60
+WILDBILL ANY UINFO "William J. Laubenheimer,508E,5493089"
+WSS ANY UID 614
+WSS ANY GID 60
+WSS ANY UINFO "Walter S. Scott,477E,9669,5405874"
+LOFTS ANY UID 616
+LOFTS ANY GID 20
+LOFTS ANY UINFO "Haflidi Loftsson,5255162,2103Etch"
+SPEER ANY UID 619
+SPEER ANY GID 20
+SPEER ANY UINFO "Rick Speer,508-16E,0344,"
+EGGERS ANY UID 620
+EGGERS ANY GID 20
+EGGERS ANY UINFO "Susan Eggers,508-6E,7288,5254442"
+LEARMONT ANY UID 621
+LEARMONT ANY GID 20
+LEARMONT ANY UINFO "Tim &,593E,0572,5253179"
+JGROSS ANY UID 622
+JGROSS ANY GID 20
+JGROSS ANY UINFO "John R. Gross,508-20E,9542,8484829"
+GREER ANY UID 624
+GREER ANY GID 20
+GREER ANY UINFO "Douglas S. Greer,608E,,5485063"
+BK ANY UID 625
+BK ANY GID 20
+BK ANY UINFO "B. K. Bose,5248928"
+JHCHANG ANY UID 626
+JHCHANG ANY GID 20
+JHCHANG ANY UINFO "Jung-Herng Chang,5247350"
+ALTMAN ANY UID 627
+ALTMAN ANY GID 20
+ALTMAN ANY UINFO "Boris &,608E,,6432490"
+BITAR ANY UID 629
+BITAR ANY GID 20
+BITAR ANY UINFO "Philip &,508-3E,7233,8480906"
+BUSH ANY UID 631
+BUSH ANY GID 20
+BUSH ANY UINFO "Bill &,,9669,"
+BUTLER ANY UID 632
+BUTLER ANY GID 20
+BUTLER ANY UINFO "Margaret H. Butler,608-13E,8072,5253179"
+CANNING ANY UID 633
+CANNING ANY GID 20
+CANNING ANY UINFO "Peter Canning,467E,9587,8494931"
+KIMMAN ANY UID 635
+KIMMAN ANY GID 20
+KIMMAN ANY UINFO "Kimman Chang,,,"
+CHENG ANY UID 636
+CHENG ANY GID 20
+CHENG ANY UINFO "Doreen Yining &,608E,,5275676"
+CHOU ANY UID 637
+CHOU ANY GID 20
+CHOU ANY UINFO "Hongtai &,608E,,"
+BERGER ANY UID 638
+BERGER ANY GID 20
+BERGER ANY UINFO "RiChard Berger,608-16E,8155,8484760"
+DUFFY ANY UID 641
+DUFFY ANY GID 20
+DUFFY ANY UINFO "Judy Duffy,434E,3560,5248118"
+FAGIN ANY UID 642
+FAGIN ANY GID 20
+FAGIN ANY UINFO "Barry Steven Fagin,508-3E,7233,6443577"
+FENG ANY UID 643
+FENG ANY GID 20
+FENG ANY UINFO "john,608E,,6441212"
+FISHKIN ANY UID 644
+FISHKIN ANY GID 20
+FISHKIN ANY UINFO "Ken &,508-12E,0344,8451741"
+GROSS ANY UID 647
+GROSS ANY GID 20
+GROSS ANY UINFO "Jonathan &,608E,,"
+HERNANDE ANY UID 648
+HERNANDE ANY GID 20
+HERNANDE ANY UINFO "Maurice &,608E,,"
+HUANG ANY UID 649
+HUANG ANY GID 20
+HUANG ANY UINFO "Conrad &,608E,,"
+HUGHES ANY UID 650
+HUGHES ANY GID 20
+HUGHES ANY UINFO "Craig &,608E,,"
+KOO ANY UID 652
+KOO ANY GID 20
+KOO ANY UINFO "Richard &,608E,,"
+KUBE ANY UID 653
+KUBE ANY GID 20
+KUBE ANY UINFO "Paul Richard &,608E,,6422270"
+MENG ANY UID 654
+MENG ANY GID 20
+MENG ANY UINFO "& Lee,608E,,6432700"
+LIU ANY UID 655
+LIU ANY GID 20
+LIU ANY UINFO "Ralph &,608E,,"
+MELVIN ANY UID 658
+MELVIN ANY GID 20
+MELVIN ANY UINFO "Steve &,412E,7666,6442742"
+MMURPHY ANY UID 659
+MMURPHY ANY GID 20
+MMURPHY ANY UINFO "mike murphy,410E,6432895"
+NG ANY UID 660
+NG ANY GID 20
+NG ANY UINFO "Pui &,608E,,"
+ONG ANY UID 661
+ONG ANY GID 20
+ONG ANY UINFO "William &,608E,,"
+PAINTER ANY UID 662
+PAINTER ANY GID 20
+PAINTER ANY UINFO "Mark &,608E,8457468,"
+TONI ANY UID 663
+TONI ANY GID 20
+TONI ANY UINFO "Antonin Guttman,,,"
+RAGDE ANY UID 665
+RAGDE ANY GID 20
+RAGDE ANY UINFO "Prabhakar Ragde,516E,4662,5406143"
+RIEWE ANY UID 667
+RIEWE ANY GID 20
+RIEWE ANY UINFO "Linda Marcella &,608E,,8459672"
+RIGGLE ANY UID 668
+RIGGLE ANY GID 20
+RIGGLE ANY UINFO "David &,B-50E,,6852199"
+BRADR ANY UID 670
+BRADR ANY GID 20
+BRADR ANY UINFO "Brad Rubenstein,608-17E,8149,8439743"
+SAMPLES ANY UID 671
+SAMPLES ANY GID 20
+SAMPLES ANY UINFO "A. Dain &,477E,9669,4651579"
+SEGAL ANY UID 672
+SEGAL ANY GID 20
+SEGAL ANY UINFO "Mark Segal,608E,,6442782"
+SHEM ANY UID 673
+SHEM ANY GID 20
+SHEM ANY UINFO "Elliott Bud &,608E,,8489313"
+SLATTENG ANY UID 674
+SLATTENG ANY GID 20
+SLATTENG ANY UINFO "David L. Slattengren,0E,,5274463"
+ZORN ANY UID 675
+ZORN ANY GID 20
+ZORN ANY UINFO "Ben Zorn,510E,,8480101"
+WENSLEY ANY UID 679
+WENSLEY ANY GID 20
+WENSLEY ANY UINFO "Paul Robert &,508-6E,7288,5259311"
+ZHOU ANY UID 680
+ZHOU ANY GID 20
+ZHOU ANY UINFO "Songnian &,608E,,8491825"
+WRABETZ ANY UID 681
+WRABETZ ANY GID 20
+WRABETZ ANY UINFO "Joan &,608E,,"
+YEN ANY UID 683
+YEN ANY GID 20
+YEN ANY UINFO "John &,557E,,5485077"
+MILLS ANY UID 684
+MILLS ANY GID 20
+MILLS ANY UINFO "Charlie &,,,4158436154"
+ENG ANY UID 686
+ENG ANY GID 20
+ENG ANY UINFO "Daniel W. Eng,8416747"
+SUSANNE ANY UID 690
+SUSANNE ANY GID 90
+SUSANNE ANY UINFO "Wolfgang Maass,509E,4554,8411376"
+GOLDBERG ANY UID 691
+GOLDBERG ANY GID 20
+GOLDBERG ANY UINFO "Andrey &,587E,8204,8418731"
+ODAY ANY UID 695
+ODAY ANY GID 20
+ODAY ANY UINFO "Vicki O'Day,477E,,2854790"
+SECHREST ANY UID 697
+SECHREST ANY GID 20
+SECHREST ANY UINFO "Stuart &,464E,8919,5490762"
+BLOMSETH ANY UID 698
+BLOMSETH ANY GID 20
+BLOMSETH ANY UINFO "Rich &,,,5058228166"
+ZLIU ANY UID 699
+ZLIU ANY GID 20
+ZLIU ANY UINFO "Zhishun Alex Liu,716E,7416,5283105"
+DOE ANY UID 701
+DOE ANY GID 90
+DOE ANY UINFO "Dept of Energy users"
+SHALLIT ANY UID 706
+SHALLIT ANY GID 20
+SHALLIT ANY UINFO "Jeffrey Shallit,,,3126676113"
+PTANG ANY UID 714
+PTANG ANY GID 20
+PTANG ANY UINFO "Ping Tak Tang,840E,,5254239"
+GUSELLA ANY UID 715
+GUSELLA ANY GID 90
+GUSELLA ANY UINFO "Riccardo Gusella,457E,3979,8492332"
+LEBLANC ANY UID 716
+LEBLANC ANY GID 20
+LEBLANC ANY UINFO "Emile LeBlanc,1010E,,8417745"
+CHRIS ANY UID 717
+CHRIS ANY GID 10
+CHRIS ANY UINFO "Chris Guthrie,175MC"
+FRANKLE ANY UID 720
+FRANKLE ANY GID 20
+FRANKLE ANY UINFO "Jon Frankle,585E,1266,5277493"
+NISHIZAK ANY UID 721
+NISHIZAK ANY GID 20
+NISHIZAK ANY UINFO "Carol L. Nishizaki,608E,7974732"
+MOUSE ANY UID 722
+MOUSE ANY GID 40
+MOUSE ANY UINFO "Calvin Young"
+KSUT ANY UID 723
+KSUT ANY GID 20
+KSUT ANY UINFO "Sutner Klaus,6432913"
+TEP ANY UID 724
+TEP ANY GID 20
+TEP ANY UINFO "Tep Dobry,508-3E,7233,9309701"
+TONG ANY UID 725
+TONG ANY GID 90
+TONG ANY UINFO "Richard Tong,5483085,9413912,"
+BILBO ANY UID 726
+BILBO ANY GID 20
+BILBO ANY UINFO "William Beringer"
+KUHG ANY UID 729
+KUHG ANY GID 20
+KUHG ANY UINFO "E.S. Kuh,257MC,2689"
+CHERTOK ANY UID 730
+CHERTOK ANY GID 30
+CHERTOK ANY UINFO "Paula Chertok,bldg T-4 rm.218,8461,"
+MARINA ANY UID 731
+MARINA ANY GID 20
+MARINA ANY UINFO "Marina Meyer,8491025"
+VAL ANY UID 732
+VAL ANY GID 20
+VAL ANY UINFO "Valerie King,479E,8299,5489460"
+FAUSTUS ANY UID 734
+FAUSTUS ANY GID 90
+FAUSTUS ANY UINFO "Wayne A. Christopher,325C,3221,3398235"
+HYERLE ANY UID 735
+HYERLE ANY GID 20
+HYERLE ANY UINFO "Robert H. Hyerle,,,"
+NORMAN ANY UID 738
+NORMAN ANY GID 20
+NORMAN ANY UINFO "Norman Bookstein,436E,5267982"
+SINGER ANY UID 744
+SINGER ANY GID 90
+SINGER ANY UINFO "J.R. Singer,267C,6360,8416048"
+CROOK ANY UID 746
+CROOK ANY GID 20
+CROOK ANY UINFO "Jim Crook,000E,0000,0000000"
+WEIMING ANY UID 747
+WEIMING ANY GID 20
+WEIMING ANY UINFO "Wei-Ming Dai,7521572"
+YOSHIOKA ANY UID 748
+YOSHIOKA ANY GID 20
+YOSHIOKA ANY UINFO "Alan Yoshioka,<408>2252309"
+OKU ANY UID 749
+OKU ANY GID 20
+OKU ANY UINFO "Darin Okuyama,5490487"
+TOPRAMEN ANY UID 750
+TOPRAMEN ANY GID 20
+TOPRAMEN ANY UINFO "Oliver Grillmeyer,459E,2714,8492468"
+BLAKKAN ANY UID 751
+BLAKKAN ANY GID 20
+BLAKKAN ANY UINFO "John A. Blakkan,608-4E,8282,8458732"
+SHEBANOW ANY UID 754
+SHEBANOW ANY GID 20
+SHEBANOW ANY UINFO "Mike Shebanow,479E,8299,5255096"
+NELSON ANY UID 755
+NELSON ANY GID 26
+NELSON ANY UINFO "Michael Nelson,,,5282040"
+SHELDON ANY UID 756
+SHELDON ANY GID 26
+SHELDON ANY UINFO "Robert G.Sheldon,434E,3560,8483775"
+KLEIN ANY UID 757
+KLEIN ANY GID 20
+KLEIN ANY UINFO "Michael F. Klein,338C,8216,4811169"
+FRISH ANY UID 758
+FRISH ANY GID 20
+FRISH ANY UINFO "Gary Frischling,175MC,6744"
+CHAN ANY UID 759
+CHAN ANY GID 20
+CHAN ANY UINFO "Bor Y. Chan,5302107,,"
+EDJAMES ANY UID 760
+EDJAMES ANY GID 10
+EDJAMES ANY UINFO "Ed James,199BC,7447,6557231"
+PETERSEN ANY UID 761
+PETERSEN ANY GID 20
+PETERSEN ANY UINFO "David A. Petersen,367C,8489665"
+SHIBO ANY UID 763
+SHIBO ANY GID 20
+SHIBO ANY UINFO "Shibo Lou,557E"
+REINHARD ANY UID 765
+REINHARD ANY GID 30
+REINHARD ANY UINFO "& Wilhelm,543E,9955,5243144"
+OSBORNE ANY UID 766
+OSBORNE ANY GID 20
+OSBORNE ANY UINFO "Alex &,,,5480505"
+MEYER ANY UID 768
+MEYER ANY GID 20
+MEYER ANY UINFO "Carl &,593E,0572,8414031"
+EWB ANY UID 769
+EWB ANY GID 20
+EWB ANY UINFO "Emil William Brown,508-5E,6008,8417423"
+NEE ANY UID 772
+NEE ANY GID 20
+NEE ANY UINFO "Anthony C. Carpentieri,453E,,5241446"
+GRACE ANY UID 773
+GRACE ANY GID 20
+GRACE ANY UINFO "& Mah,321AC,8186"
+RAMSAY ANY UID 774
+RAMSAY ANY GID 20
+RAMSAY ANY UINFO "Girard R. &,6432514"
+CLAIRE ANY UID 776
+CLAIRE ANY GID 20
+CLAIRE ANY UINFO "& Bono,475E,7017,8411577"
+DAPLOM ANY UID 778
+DAPLOM ANY GID 20
+DAPLOM ANY UINFO "David Plomgren,8453756"
+GUZMAN ANY UID 780
+GUZMAN ANY GID 20
+GUZMAN ANY UINFO "Robert &,8417845"
+VAXIMA ANY UID 801
+VAXIMA ANY GID 10
+VAXIMA ANY UINFO "& source"
+ARENS ANY UID 810
+ARENS ANY GID 20
+ARENS ANY UINFO "Yigal &,545E,8468,5275676"
+CHIN ANY UID 811
+CHIN ANY GID 20
+CHIN ANY UINFO "David &"
+JACOBS ANY UID 813
+JACOBS ANY GID 20
+JACOBS ANY UINFO "Paul &,508-18E,9076,5481118"
+LURIA ANY UID 814
+LURIA ANY GID 20
+LURIA ANY UINFO "Marc &,545E,8468,8481353"
+MARTIN ANY UID 815
+MARTIN ANY GID 20
+MARTIN ANY UINFO "Jim &,508-18E,9076,8453756"
+MAYFIELD ANY UID 816
+MAYFIELD ANY GID 20
+MAYFIELD ANY UINFO "Jim &,508-18E,9076,8453850"
+NORVIG ANY UID 817
+NORVIG ANY GID 20
+NORVIG ANY UINFO "Peter &,545E,8468,8412599"
+OKSENIUK ANY UID 818
+OKSENIUK ANY GID 20
+OKSENIUK ANY UINFO "Anna &,557E"
+GLA ANY UID 820
+GLA ANY GID 90
+GLA ANY UINFO "Dr. Donald Glaser,337 Stanley,7231,"
+ANNA ANY UID 821
+ANNA ANY GID 90
+ANNA ANY UINFO "& Hac,468E,3979,"
+FORSEY ANY UID 822
+FORSEY ANY GID 90
+FORSEY ANY UINFO "Dale &,337 Stanley,7231,"
+NATVIG ANY UID 823
+NATVIG ANY GID 50
+NATVIG ANY UINFO "Jon &,410Davis,0749,5255489"
+ORIARD ANY UID 824
+ORIARD ANY GID 20
+ORIARD ANY UINFO "Philip &,6559526"
+NAKANO ANY UID 843
+NAKANO ANY GID 90
+NAKANO ANY UINFO "Hideo &,8455084"
+SHEILA ANY UID 844
+SHEILA ANY GID 36
+SHEILA ANY UINFO "& Humphreys,555E,1390,6542835"
+NICK ANY UID 845
+NICK ANY GID 30
+NICK ANY UINFO "& Tredennick,541E,4979,7716457"
+TEXP ANY UID 847
+TEXP ANY GID 20
+TEXP ANY UINFO "Octaviano M. Romano,,8864,6546969"
+WJCHENG ANY UID 849
+WJCHENG ANY GID 20
+WJCHENG ANY UINFO "Wunjei J. Cheng,508E,0000,5278459"
+RANDY ANY UID 850
+RANDY ANY GID 30
+RANDY ANY UINFO "& Katz,507E,,"
+KALEN ANY UID 851
+KALEN ANY GID 30
+KALEN ANY UINFO "& Kronenthal,440E,5281039,"
+KAZUO ANY UID 853
+KAZUO ANY GID 30
+KAZUO ANY UINFO "Iwama & ,543E,9955,5405844"
+SANDSTRO ANY UID 854
+SANDSTRO ANY GID 20
+SANDSTRO ANY UINFO "Bob Sandstrom,608-14E,8228,5245633"
+AVI ANY UID 856
+AVI ANY GID 30
+AVI ANY UINFO "& Wigderson,479E,8299"
+RONSHA ANY UID 857
+RONSHA ANY GID 20
+RONSHA ANY UINFO "Ron Shamir,3112Etcheverry,8255,8413597"
+ASATA ANY UID 859
+ASATA ANY GID 30
+ASATA ANY UINFO "& Iman,509E,8395,"
+KORDA ANY UID 860
+KORDA ANY GID 30
+KORDA ANY UINFO "& Kordes,179C,6744"
+COHEN ANY UID 861
+COHEN ANY GID 30
+COHEN ANY UINFO "Shimon Cohen,459E,2714,6440461"
+JF ANY UID 862
+JF ANY GID 20
+JF ANY UINFO "Jay Fenlason,,,5407418"
+TSO ANY UID 863
+TSO ANY GID 20
+TSO ANY UINFO "Pauline Y. Tso,457E,,6432691"
+BLANCHE ANY UID 900
+BLANCHE ANY GID 30
+BLANCHE ANY UINFO "& Groves,512E,8667"
+KBH ANY UID 901
+KBH ANY GID 90
+KBH ANY UINFO "P. Ngai"
+ELI ANY UID 902
+ELI ANY GID 90
+ELI ANY UINFO "Upfal Eli,608E,,"
+MO ANY UID 905
+MO ANY GID 90
+MO ANY UINFO "Michael D. O'Dell,LBL,4865583"
+RWB ANY UID 906
+RWB ANY GID 30
+RWB ANY UINFO "Robert Broderson,UCB"
+WILLIAM ANY UID 907
+WILLIAM ANY GID 90
+WILLIAM ANY UINFO "& Jolitz,,,4083533259"
+KRE ANY UID 909
+KRE ANY GID 90
+KRE ANY UINFO "Robert Elz,457E"
+LIEBMAN ANY UID 910
+LIEBMAN ANY GID 90
+LIEBMAN ANY UINFO "Mark Van Cleef Liebman, Esq.,,7231,6433418"
+HANIA ANY UID 911
+HANIA ANY GID 29
+HANIA ANY UINFO "& Gajewska,2015823720"
+BAASE ANY UID 912
+BAASE ANY GID 90
+BAASE ANY UINFO "Sara &,471E,845-7070,"
+JEHUDA ANY UID 913
+JEHUDA ANY GID 90
+JEHUDA ANY UINFO "Julian Dinur,,,"
+WALL ANY UID 939
+WALL ANY GID 40
+WALL ANY UINFO "Steve &,461E,7780,8451572"
+SMALLTALK ANY UID 941
+SMALLTALK ANY GID 33
+SMALLTALK ANY UINFO "The & System"
+PIEPER ANY UID 942
+PIEPER ANY GID 20
+PIEPER ANY UINFO "Steve Pieper,,5483043"
+RMITTMAN ANY UID 943
+RMITTMAN ANY GID 20
+RMITTMAN ANY UINFO "Robert Mittman,2607Hearst,4670"
+SAM ANY UID 953
+SAM ANY GID 90
+SAM ANY UINFO "& Leffler,461E,7780,5485270"
+LEE ANY UID 954
+LEE ANY GID 90
+LEE ANY UINFO "Bill &,U. of Texas"
+SFISK ANY UID 955
+SFISK ANY GID 90
+SFISK ANY UINFO "Steve Fisk,895E,,5266761"
+SANBORN ANY UID 956
+SANBORN ANY GID 90
+SANBORN ANY UINFO "Greg Sanborn,,5401228"
+CMPLRES ANY UID 958
+CMPLRES ANY GID 90
+CMPLRES ANY UINFO "Andrew Purshottam,5264458"
+SHAPERO ANY UID 959
+SHAPERO ANY GID 90
+SHAPERO ANY UINFO "Don Shapero,517E,202-3343520"
+TORDA ANY UID 960
+TORDA ANY GID 90
+TORDA ANY UINFO "Clara Torda,2571LSB,,5491412"
+ZATTI ANY UID 962
+ZATTI ANY GID 90
+ZATTI ANY UINFO "Stefano &,468E,3979,8488568"
+CECILIA ANY UID 971
+CECILIA ANY GID 20
+CECILIA ANY UINFO "& Rodriguez Aragon,508-20E,9542,5486055"
+KIERONS ANY UID 985
+KIERONS ANY GID 20
+KIERONS ANY UINFO "Henry Kieronski,,,"
+KUPFER ANY UID 986
+KUPFER ANY GID 20
+KUPFER ANY UINFO "Mike &,466E,8905,5275558"
+MBERN ANY UID 987
+MBERN ANY GID 20
+MBERN ANY UINFO "Marshall Bern,440E,9585,8439222"
+MDAVIS ANY UID 988
+MDAVIS ANY GID 20
+MDAVIS ANY UINFO "Michael Davis,593E,5072,5242784"
+MLVDV ANY UID 989
+MLVDV ANY GID 20
+MLVDV ANY UINFO "Michael Van De Vanter,608-14E,8228,6556900"
+MICK ANY UID 990
+MICK ANY GID 20
+MICK ANY UINFO "Joel &,,,"
+MOCK ANY UID 991
+MOCK ANY GID 20
+MOCK ANY UINFO "Jeffrey Craig Mock,508-6E,7288,4562725"
+KMORGAN ANY UID 992
+KMORGAN ANY GID 20
+KMORGAN ANY UINFO "Kevin Morgan,,,8414036"
+MOTS ANY UID 993
+MOTS ANY GID 20
+MOTS ANY UINFO "Rajeev Motwani,410E,9583,6443450"
+NIGEL ANY UID 994
+NIGEL ANY GID 20
+NIGEL ANY UINFO "& Ward,,,5407550"
+OPCODE ANY UID 995
+OPCODE ANY GID 20
+OPCODE ANY UINFO "Mark Opperman,,,"
+CLP ANY UID 996
+CLP ANY GID 20
+CLP ANY UINFO "Charles L. Perkins,608-16E,8155,4936804"
+PINCUS ANY UID 997
+PINCUS ANY GID 20
+PINCUS ANY UINFO "Jonathan &,,,8491195"
+PRAKASH ANY UID 998
+PRAKASH ANY GID 20
+PRAKASH ANY UINFO "Atul &,608-12E,8234,8459226"
+RAMON ANY UID 999
+RAMON ANY GID 20
+RAMON ANY UINFO "& Caceres,457E,3979,6432786"
+RITCHIE ANY UID 1000
+RITCHIE ANY GID 20
+RITCHIE ANY UINFO "Scott &,479E,8299,8491768"
+SANTHA ANY UID 1001
+SANTHA ANY GID 20
+SANTHA ANY UINFO "Miklos &,,,"
+SEYMOUR ANY UID 1002
+SEYMOUR ANY GID 20
+SEYMOUR ANY UINFO "Harlan &,608-5E,3437,5482736"
+SHEN ANY UID 1003
+SHEN ANY GID 20
+SHEN ANY UINFO "Hsiao-lin &,,,"
+VANROY ANY UID 1004
+VANROY ANY GID 20
+VANROY ANY UINFO "Peter Van Roy,508-3E,7223,6432847"
+WANG ANY UID 1005
+WANG ANY GID 20
+WANG ANY UINFO "Pu-Lan &,,,"
+WHITE ANY UID 1006
+WHITE ANY GID 20
+WHITE ANY UINFO "Karen &,464E,8919,6550793"
+DAVID ANY UID 1007
+DAVID ANY GID 20
+DAVID ANY UINFO "& Wood,,,"
+ZIV ANY UID 1008
+ZIV ANY GID 20
+ZIV ANY UINFO "& Gigus,529-BE,6193,8491984"
+YFCHEN ANY UID 1011
+YFCHEN ANY GID 20
+YFCHEN ANY UINFO "Yih-Farn Chen,608-15E,8143,5248651"
+TERMINAL ANY UID 1012
+TERMINAL ANY GID 20
+TERMINAL ANY UINFO "Program for remotely logging into"
+CM ANY UID 1013
+CM ANY GID 20
+CM ANY UINFO "Katie Macrander,468E,3979,6432908"
+BEIN ANY UID 1014
+BEIN ANY GID 20
+BEIN ANY UINFO "Edward &,,,"
+MARCKS ANY UID 1015
+MARCKS ANY GID 20
+MARCKS ANY UINFO "John E. Marciszewski,297C,9552,9342638"
+WFANG ANY UID 1016
+WFANG ANY GID 20
+WFANG ANY UINFO "Weiping Fang,,,8481204"
+PHR ANY UID 1017
+PHR ANY GID 20
+PHR ANY UINFO "Paul Rubin,,,"
+KATES ANY UID 1018
+KATES ANY GID 20
+KATES ANY UINFO "Michael Kates,,,"
+HWU ANY UID 1019
+HWU ANY GID 20
+HWU ANY UINFO "Wen-mei William Hwu,412E,7666,8494459"
+BRENT ANY UID 1020
+BRENT ANY GID 20
+BRENT ANY UINFO "Brent Welch,,,"
+ANPC ANY UID 1021
+ANPC ANY GID 20
+ANPC ANY UINFO "Antony Ng,,5480988"
+SHILIU ANY UID 1022
+SHILIU ANY GID 20
+SHILIU ANY UINFO "Shao-Hung Gerald Liu,,4082576284"
+PHC ANY UID 1023
+PHC ANY GID 20
+PHC ANY UINFO "Peehong Chen,608-16E,8155,5271739"
+CHEE ANY UID 1024
+CHEE ANY GID 20
+CHEE ANY UINFO "Chye Lin &,608-12E,8234,5252193"
+RGBROWN ANY UID 1026
+RGBROWN ANY GID 20
+RGBROWN ANY UINFO "Rick Brown,608-8E,8248,"
+CLIFF ANY UID 1027
+CLIFF ANY GID 20
+CLIFF ANY UINFO "Cliff Lob,6441215"
+SOBEK ANY UID 1029
+SOBEK ANY GID 20
+SOBEK ANY UINFO "Ralph P. &"
+SRINI ANY UID 1030
+SRINI ANY GID 90
+SRINI ANY UINFO "Vason P. Srini,503E,5252124"
+PS ANY UID 1031
+PS ANY GID 30
+PS ANY UINFO "Peggy Spaugh ,569E,4600,548-8255"
+KEBI ANY UID 1032
+KEBI ANY GID 90
+KEBI ANY UINFO "Gary E.Clark,517E,1469"
+FEIGBAUM ANY UID 1033
+FEIGBAUM ANY GID 20
+FEIGBAUM ANY UINFO "Carol Feigbaum,,6431830"
+ORIORDAN ANY UID 1034
+ORIORDAN ANY GID 20
+ORIORDAN ANY UINFO "Peter O`riordan,161MC,6432616,"
+PIRCHER ANY UID 1035
+PIRCHER ANY GID 90
+PIRCHER ANY UINFO "Peter Pircher,,,"
+USUDA ANY UID 1036
+USUDA ANY GID 20
+USUDA ANY UINFO "Yutaka Usuda,533E 6358,6546859"
+MCHOW ANY UID 1037
+MCHOW ANY GID 20
+MCHOW ANY UINFO "Michelle Chow,438E,7214,,"
+GAETANO ANY UID 1039
+GAETANO ANY GID 20
+GAETANO ANY UINFO "& Borriello,608-8E,8248,3272028"
+STURGIS ANY UID 1040
+STURGIS ANY GID 20
+STURGIS ANY UINFO "Larraine &,,,8459041"
+BWEI ANY UID 1041
+BWEI ANY GID 20
+BWEI ANY UINFO "Belle Wei,307C,9594,8414810"
+BANNAI ANY UID 1042
+BANNAI ANY GID 90
+BANNAI ANY UINFO "Kozo Bannai,444E,1898,2333190"
+JLO ANY UID 1044
+JLO ANY GID 90
+JLO ANY UINFO "Jeff Lo,,,8483804"
+DORIT ANY UID 1045
+DORIT ANY GID 30
+DORIT ANY UINFO "Dorit Hochbaum,350 Barrows,4952,,"
+AMM ANY UID 1047
+AMM ANY GID 90
+AMM ANY UINFO "Morgan Milligan, 175M Cory, 6744"
+ASIMOV ANY UID 1048
+ASIMOV ANY GID 30
+ASIMOV ANY UINFO "Daniel Asimov,1067E,2149,5270704"
+SJS ANY UID 1049
+SJS ANY GID 90
+SJS ANY UINFO "Steve Schllsinger"
+CHAOS2 ANY UID 1050
+CHAOS2 ANY GID 90
+CHAOS2 ANY UINFO "Jim Crutchfield,,,"
+MARTIND ANY UID 1051
+MARTIND ANY GID 90
+MARTIND ANY UINFO "Martin Davis,721E,,"
+PRABHAKA ANY UID 1052
+PRABHAKA ANY GID 90
+PRABHAKA ANY UINFO "Aloke Prabhakar,444E,2265,5281102"
+LAI ANY UID 1053
+LAI ANY GID 90
+LAI ANY UINFO "Nick Lai,175MC,6744,8433333"
+TAKAGI ANY UID 1055
+TAKAGI ANY GID 90
+TAKAGI ANY UINFO "Tomohiro Takagi,557E,,5273703"
+ALBERTC ANY UID 1899
+ALBERTC ANY GID 40
+ALBERTC ANY UINFO "Lung Albert Chen,,,"
+ARDEN ANY UID 1901
+ARDEN ANY GID 40
+ARDEN ANY UINFO "Michelle &,468E,3979,8411341"
+BASKER ANY UID 1902
+BASKER ANY GID 40
+BASKER ANY UINFO "David Baskerville,608-14E,8228,32885"
+BERTLO ANY UID 1903
+BERTLO ANY GID 40
+BERTLO ANY UINFO "Bertrand Lo,,,"
+BIER ANY UID 1904
+BIER ANY GID 40
+BIER ANY UINFO "Eric &,,,"
+BRAUN ANY UID 1905
+BRAUN ANY GID 40
+BRAUN ANY UINFO "Douglas &,325C,9008,6537579"
+CARVALHO ANY UID 1906
+CARVALHO ANY GID 40
+CARVALHO ANY UINFO "Marcio deCarvalho,410E,9583,5261119"
+DACOSTA ANY UID 1909
+DACOSTA ANY GID 40
+DACOSTA ANY UINFO "Herve Da Costa,,,"
+DANNYS ANY UID 1910
+DANNYS ANY GID 40
+DANNYS ANY UINFO "Danny Soroker,585E,1266,8482063"
+DURAN ANY UID 1911
+DURAN ANY GID 40
+DURAN ANY UINFO "Raul &,,,"
+EDH ANY UID 1912
+EDH ANY GID 40
+EDH ANY UINFO "Edward Hunter,,,5480143"
+FWO ANY UID 1914
+FWO ANY GID 40
+FWO ANY UINFO "Fred W. Obermeier,608-8E,8248,2377339"
+HADDIX ANY UID 1916
+HADDIX ANY GID 40
+HADDIX ANY UINFO "Rita &,608-14E,8228,5481096"
+HAIT ANY UID 1917
+HAIT ANY GID 40
+HAIT ANY UINFO "David J. Hait,436E,,8435028"
+HANSON ANY UID 1918
+HANSON ANY GID 40
+HANSON ANY UINFO "Eric &,608-17E,8149,8451741"
+HB ANY UID 1919
+HB ANY GID 40
+HB ANY UINFO "H. B. Siegel,,,4860387"
+HIBDON ANY UID 1920
+HIBDON ANY GID 40
+HIBDON ANY UINFO "Alan &,,,"
+MCOHEN ANY UID 1908
+MCOHEN ANY GID 40
+MCOHEN ANY UINFO "Michael Cohen,410E,9583,8439222"
+MICHAELF ANY UID 1913
+MICHAELF ANY GID 40
+MICHAELF ANY UINFO "Michael Freedman,,,"
+SERGE ANY UID 1963
+SERGE ANY GID 40
+SERGE ANY UINFO "& Granik,2-7393,4174 Etch"
+TENG ANY UID 1955
+TENG ANY GID 60
+TENG ANY UINFO "Min Teng"
+YEE ANY UID 1961
+YEE ANY GID 40
+YEE ANY UINFO "Peter E. Yee"
+IJCOX ANY UID 1056
+IJCOX ANY GID 30
+IJCOX ANY UINFO "Ingemar J. Cox"
+LIPPMAN ANY UID 1057
+LIPPMAN ANY GID 30
+LIPPMAN ANY UINFO "Gary Lippman,6086E,,6539231"
+WEILI ANY UID 1058
+WEILI ANY GID 40
+WEILI ANY UINFO " "
+GAL ANY UID 1060
+GAL ANY GID 40
+GAL ANY UINFO "& Nachshon,508-20E,9542,8489458"
+FLOYD ANY UID 1061
+FLOYD ANY GID 40
+FLOYD ANY UINFO "Sally &,,,"
+LAKOS ANY UID 1062
+LAKOS ANY GID 30
+LAKOS ANY UINFO "Charles &,477E,9669,6442048"
+RENE ANY UID 1063
+RENE ANY GID 30
+RENE ANY UINFO "Rene C. Smith,522E"
+DUNLAP ANY UID 1064
+DUNLAP ANY GID 20
+DUNLAP ANY UINFO "Frank Dunlap,490C,3824,6441418"
+CABRERA ANY UID 1065
+CABRERA ANY GID 30
+CABRERA ANY UINFO "Luis Felipe Cabrera,507E,8900,5277279"
+ANDLER ANY UID 1066
+ANDLER ANY GID 30
+ANDLER ANY UINFO "Sten Andler,507E,408-2819717"
+CURTIS ANY UID 1067
+CURTIS ANY GID 20
+CURTIS ANY UINFO "& Abbott,,4990165"
+GIBSON ANY UID 1068
+GIBSON ANY GID 20
+GIBSON ANY UINFO "Garth &,8492423,,"
+REGHU ANY UID 1069
+REGHU ANY GID 20
+REGHU ANY UINFO "P. Reghunathan,4087463103,4082588667"
+DAHI ANY UID 1070
+DAHI ANY GID 20
+DAHI ANY UINFO "Khosrow &,608-15E,8410821"
+JAIDEEP ANY UID 1071
+JAIDEEP ANY GID 20
+JAIDEEP ANY UINFO "& Srivastava,608-12E,,5252639"
+SCHOET ANY UID 1072
+SCHOET ANY GID 20
+SCHOET ANY UINFO "Steve Schoettler,,5406345x144,5409368"
+KHUA ANY UID 1073
+KHUA ANY GID 20
+KHUA ANY UINFO "Kuolin Hua,608-6E,8277,5261850"
+LUIS ANY UID 1074
+LUIS ANY GID 36
+LUIS ANY UINFO "& Miguel,,,916-753-6292"
+ELDR ANY UID 1075
+ELDR ANY GID 36
+ELDR ANY UINFO "Maribeth Eldridge,,,8241085"
+TALI ANY UID 1077
+TALI ANY GID 36
+TALI ANY UINFO "Zehavit Friedman,,,5429632"
+DIANE ANY UID 1078
+DIANE ANY GID 36
+DIANE ANY UINFO "& Greene,,,5247231"
+GENE ANY UID 1079
+GENE ANY GID 20
+GENE ANY UINFO "Eugene K. Ressler,,,9385254"
+LINDY ANY UID 1080
+LINDY ANY GID 10
+LINDY ANY UINFO "& Foster,533E,6037,5260531"
+CSSG ANY UID 1081
+CSSG ANY GID 10
+CSSG ANY UINFO "computer systems support"
+FALES ANY UID 1082
+FALES ANY GID 36
+FALES ANY UINFO "Christina &,,,4861895"
+CWONG ANY UID 1083
+CWONG ANY GID 36
+CWONG ANY UINFO "Carolyn Wong,,,8491456"
+CLO ANY UID 1085
+CLO ANY GID 36
+CLO ANY UINFO "Carolyn Overhoff,SSC247A,8389,5280023"
+AAHM ANY UID 1086
+AAHM ANY GID 36
+AAHM ANY UINFO "Betty J. Hopper,,5487473"
+RIGGS ANY UID 1087
+RIGGS ANY GID 30
+RIGGS ANY UINFO "Kathryn &,569E,8271,"
+HOMBURGR ANY UID 1088
+HOMBURGR ANY GID 20
+HOMBURGR ANY UINFO "Paul &,161MC,8598,5407541"
+NUNNX ANY UID 1089
+NUNNX ANY GID 36
+NUNNX ANY UINFO "Curtis Nunnally,,4866346,2542478"
+TAI ANY UID 1090
+TAI ANY GID 20
+TAI ANY UINFO "Wen-perng Tai,,,6440417"
+MARRA ANY UID 1091
+MARRA ANY GID 20
+MARRA ANY UINFO "Jennifer Marra,,,5491382"
+TERESA ANY UID 1092
+TERESA ANY GID 20
+TERESA ANY UINFO "Teresa H.Y. Meng,307C,,6432898"
+HILARY ANY UID 1093
+HILARY ANY GID 20
+HILARY ANY UINFO "& Beech,,,8489855"
+TAMOTSU ANY UID 1094
+TAMOTSU ANY GID 20
+TAMOTSU ANY UINFO "& Yamagami,,,5254559"
+ORION ANY UID 1095
+ORION ANY GID 20
+ORION ANY UINFO "Theodore Yu"
+PHIL ANY UID 1096
+PHIL ANY GID 20
+PHIL ANY UINFO "& Lapsley,,,6431587"
+HOMAYOON ANY UID 1097
+HOMAYOON ANY GID 20
+HOMAYOON ANY UINFO "& Ansari,197MC,0744,5408807"
+JOEB ANY UID 1098
+JOEB ANY GID 20
+JOEB ANY UINFO "Joe Barnhart"
+VILLA ANY UID 1099
+VILLA ANY GID 20
+VILLA ANY UINFO "Tiziano &,,,8456635"
+MISHA ANY UID 1100
+MISHA ANY GID 20
+MISHA ANY UINFO "Michael Kharitonov,,,8437517"
+REISER ANY UID 1101
+REISER ANY GID 20
+REISER ANY UINFO "Hans Reiser,,,4822483"
+ELE ANY UID 1102
+ELE ANY GID 30
+ELE ANY UINFO "Alex J.C. Para,187C,6952"
+SHLIU ANY UID 1103
+SHLIU ANY GID 20
+SHLIU ANY UINFO "Shao-Hung Liu,Fairchild,9623773,4082576284"
+PORCARJ ANY UID 1104
+PORCARJ ANY GID 20
+PORCARJ ANY UINFO "Juan M. Porcar,LBL-50B-3238,4866704,5269642"
+MCDONALD ANY UID 1105
+MCDONALD ANY GID 20
+MCDONALD ANY UINFO "Stuart &,,,6531353"
+ROG ANY UID 1106
+ROG ANY GID 20
+ROG ANY UINFO "Roger Kilday,,,8487160"
+AGB ANY UID 1107
+AGB ANY GID 20
+AGB ANY UINFO "Alexander G. Burchell,,,"
+GRAFF ANY UID 1108
+GRAFF ANY GID 90
+GRAFF ANY UINFO "Charles &,537E,,"
+JOPLIN ANY UID 1109
+JOPLIN ANY GID 30
+JOPLIN ANY UINFO "Anita Joplin,524E,8296,8434133"
+FRANKY ANY UID 1110
+FRANKY ANY GID 20
+FRANKY ANY UINFO "Franky Ho-Ming Leung,999C,0000,4082497861"
+GRAY-CAD ANY UID 1111
+GRAY-CAD ANY GID 30
+GRAY-CAD ANY UINFO "Paul Gray,491C,5179,254-4210"
+SKAHAN ANY UID 1112
+SKAHAN ANY GID 20
+SKAHAN ANY UINFO "Simon Kahan"
+MANUELBR ANY UID 1113
+MANUELBR ANY GID 20
+MANUELBR ANY UINFO "Manuel Bronstein,846E,,6432792"
+RHYU ANY UID 1114
+RHYU ANY GID 20
+RHYU ANY UINFO "Yong &,,,8484834"
+JCOKER ANY UID 1115
+JCOKER ANY GID 20
+JCOKER ANY UINFO "John Coker,,,"
+TBERGER ANY UID 1116
+TBERGER ANY GID 90
+TBERGER ANY UINFO "Thomas Berger,332C,1003,5488006"
+ZAK ANY UID 1117
+ZAK ANY GID 20
+ZAK ANY UINFO "zak mc carrell,608-16E,8155,8482492"
+OIVIND ANY UID 1118
+OIVIND ANY GID 20
+OIVIND ANY UINFO "& Kure,3112 Etcheverry,8255,"
+DEBRA ANY UID 1120
+DEBRA ANY GID 20
+DEBRA ANY UINFO "& Lewis,,,658-7490"
+BGLEE ANY UID 1121
+BGLEE ANY GID 20
+BGLEE ANY UINFO "Bertram G. Lee,,,5409426"
+RLW ANY UID 1122
+RLW ANY GID 20
+RLW ANY UINFO "Robert L. Williams,508-3E,7233,6534222"
+ZURAV ANY UID 1123
+ZURAV ANY GID 20
+ZURAV ANY UINFO "William Zuravleff,,4089805682,4087325045"
+GALLUP ANY UID 1124
+GALLUP ANY GID 90
+GALLUP ANY UINFO "Luis F. Cabrera/Brian Bershad/Eric Mowat/Brian Marsh,507E,8900,"
+RUDICH ANY UID 1125
+RUDICH ANY GID 20
+RUDICH ANY UINFO "Steven &,587E,8204,8438432"
+HUIE ANY UID 1126
+HUIE ANY GID 20
+HUIE ANY UINFO "Elliot &,,,5239078"
+TRAUB ANY UID 1127
+TRAUB ANY GID 90
+TRAUB ANY UINFO "J. F. &,543E,9955,8436163"
+SHUM ANY UID 1128
+SHUM ANY GID 20
+SHUM ANY UINFO "Doreen &,479E,8299,8490286"
+BUTTER ANY UID 1129
+BUTTER ANY GID 20
+BUTTER ANY UINFO "Cynthia Will Butterfield,,4692140,8491308"
+CSUDF ANY UID 1130
+CSUDF ANY GID 90
+CSUDF ANY UINFO "Urszula Frydman,221E,8590,6530516"
+EDMOY ANY UID 1131
+EDMOY ANY GID 90
+EDMOY ANY UINFO "Ed Moy,219E,1307,4699099"
+WOLFF ANY UID 1132
+WOLFF ANY GID 90
+WOLFF ANY UINFO "Jane &,219E,6716,8434824"
+FARROW ANY UID 1133
+FARROW ANY GID 90
+FARROW ANY UINFO "Rodney &,,,"
+MFEITEL ANY UID 1134
+MFEITEL ANY GID 36
+MFEITEL ANY UINFO "Marcia Feitel,,,8546357"
+JADE ANY UID 1135
+JADE ANY GID 36
+JADE ANY UINFO "& Goldstein,,8415083,8417376"
+JENNY ANY UID 1136
+JENNY ANY GID 36
+JENNY ANY UINFO "Kathryn Hargreaves,,,6524401x662"
+GARDNER ANY UID 1137
+GARDNER ANY GID 36
+GARDNER ANY UINFO "Laura &,,1986,5279670"
+AMIRAM ANY UID 1138
+AMIRAM ANY GID 20
+AMIRAM ANY UINFO "& Yehudai,539E,8447,5256529"
+READER ANY UID 1139
+READER ANY GID 20
+READER ANY UINFO "Elliott K. Huie,,,"
+SCHARDT ANY UID 1140
+SCHARDT ANY GID 20
+SCHARDT ANY UINFO "Christopher &,440E,,5409200"
+DSTEVENS ANY UID 1141
+DSTEVENS ANY GID 36
+DSTEVENS ANY UINFO "Dana Stevens,555E,1390,5279094"
+FONG ANY UID 1142
+FONG ANY GID 10
+FONG ANY UINFO "Gene & (DEC),442E,8865,"
+MOWAT ANY UID 1143
+MOWAT ANY GID 90
+MOWAT ANY UINFO "Eric &,,,8489499"
+SHOPPEL ANY UID 1144
+SHOPPEL ANY GID 31
+SHOPPEL ANY UINFO "Michael &,442E,8865,5256216"
+KANNAN ANY UID 1145
+KANNAN ANY GID 20
+KANNAN ANY UINFO "Sampath &,597E,8204,5250736"
+BRAND ANY UID 1146
+BRAND ANY GID 20
+BRAND ANY UINFO "Russell L. Brand,,,5282183"
+SPIVAK ANY UID 1147
+SPIVAK ANY GID 90
+SPIVAK ANY UINFO "Mike &,1067E,,"
+SCHMITT ANY UID 1148
+SCHMITT ANY GID 90
+SCHMITT ANY UINFO "Fred &,,,6555829"
+BINGHAM ANY UID 1149
+BINGHAM ANY GID 20
+BINGHAM ANY UINFO "Bill Bingham,436E,,8417423"
+SUSAN ANY UID 1150
+SUSAN ANY GID 10
+SUSAN ANY UINFO "& Senger,555E,1390,8492109"
+FREKSA ANY UID 1151
+FREKSA ANY GID 90
+FREKSA ANY UINFO "Christian &,557E,5029"
+BAHADORI ANY UID 1152
+BAHADORI ANY GID 20
+BAHADORI ANY UINFO "Hamid R. &,468E,3979"
+FARBEROV ANY UID 1153
+FARBEROV ANY GID 90
+FARBEROV ANY UINFO "Dimitry &"
+DAYEN ANY UID 1154
+DAYEN ANY GID 90
+DAYEN ANY UINFO "Igor &"
+WHIT ANY UID 1155
+WHIT ANY GID 36
+WHIT ANY UINFO "Susan Whitford,,,"
+PHAM ANY UID 1156
+PHAM ANY GID 10
+PHAM ANY UINFO "& Huu Dong,608-11E,8306,5483158"
+KARA ANY UID 1157
+KARA ANY GID 10
+KARA ANY UINFO "Kara Marie Kapczynski,434E,3560,5499522"
+GLENN ANY UID 1158
+GLENN ANY GID 20
+GLENN ANY UINFO "& Adams"
+ALBERT ANY UID 1159
+ALBERT ANY GID 20
+ALBERT ANY UINFO "Anthony &"
+JEFF ANY UID 1160
+JEFF ANY GID 20
+JEFF ANY UINFO "Jeffrey Anderson,,,5246744"
+RAY ANY UID 1161
+RAY ANY GID 20
+RAY ANY UINFO "David & Bearden"
+BELL ANY UID 1162
+BELL ANY GID 20
+BELL ANY UINFO "Mark &"
+BHIDE ANY UID 1163
+BHIDE ANY GID 20
+BHIDE ANY UINFO "Anupam K. &,,,6443579"
+GUNTHER ANY UID 1164
+GUNTHER ANY GID 20
+GUNTHER ANY UINFO "Oliver &"
+BRAVER ANY UID 1165
+BRAVER ANY GID 20
+BRAVER ANY UINFO "Michael Braverman,508-18E,,6433444"
+BRON ANY UID 1166
+BRON ANY GID 20
+BRON ANY UINFO "Manuel Bronstein,846E,,6432792"
+CALLEY ANY UID 1167
+CALLEY ANY GID 20
+CALLEY ANY UINFO "John N. &,440E,9585,6586521"
+CHANG ANY UID 1168
+CHANG ANY GID 20
+CHANG ANY UINFO "Ellis E-Li &"
+CHEN ANY UID 1169
+CHEN ANY GID 20
+CHEN ANY UINFO "Chien &"
+ANDREW ANY UID 1170
+ANDREW ANY GID 20
+ANDREW ANY UINFO "& R. Cherenson,,,"
+DANZIG ANY UID 1171
+DANZIG ANY GID 20
+DANZIG ANY UINFO "Peter &,,,5279868"
+DOUGLIS ANY UID 1172
+DOUGLIS ANY GID 20
+DOUGLIS ANY UINFO "Fred &,,,4308284"
+#EHLER ANY UID 1173
+#EHLER ANY GID 20
+#EHLER ANY UINFO "Herbert &"
+FILIP ANY UID 1174
+FILIP ANY GID 20
+FILIP ANY UINFO "Daniel J. &"
+#ANIL ANY UID 1175
+#ANIL ANY GID 20
+#ANIL ANY UINFO "& Ramesh Gangolli"
+GARG ANY UID 1176
+GARG ANY GID 20
+GARG ANY UINFO "Vijay K. Garg,608-15E,8143,5487017"
+GIBBONS ANY UID 1177
+GIBBONS ANY GID 20
+GIBBONS ANY UINFO "Philip B. &"
+MGROSS ANY UID 1178
+MGROSS ANY GID 20
+MGROSS ANY UINFO "Mark William Gross"
+DAVIDH ANY UID 1180
+DAVIDH ANY GID 20
+DAVIDH ANY UINFO "David S. Harrison,321C,9008,5265968"
+HSTEIN ANY UID 1181
+HSTEIN ANY GID 20
+HSTEIN ANY UINFO "Lisa Hellerstein"
+IYER ANY UID 1182
+IYER ANY GID 20
+IYER ANY UINFO "Venkatraman &"
+CORI ANY UID 1183
+CORI ANY GID 20
+CORI ANY UINFO "Corinna Lee,,,6535681"
+YLEE ANY UID 1184
+YLEE ANY GID 20
+YLEE ANY UINFO "Yuhshiow A. Lee"
+STEVEN ANY UID 1185
+STEVEN ANY GID 20
+STEVEN ANY UINFO "& R. Leonard"
+LEWIS ANY UID 1186
+LEWIS ANY GID 20
+LEWIS ANY UINFO "James D. &"
+JWL ANY UID 1187
+JWL ANY GID 20
+JWL ANY UINFO "James Wilbur Lewis,457E,3979,6536002"
+MARSH ANY UID 1188
+MARSH ANY GID 20
+MARSH ANY UINFO "Donald M. &"
+MORRISON ANY UID 1189
+MORRISON ANY GID 20
+MORRISON ANY UINFO "Scott C. &,608-5E,3437,8453529"
+NEWMAN ANY UID 1190
+NEWMAN ANY GID 20
+NEWMAN ANY UINFO "Lawrence &"
+TAM ANY UID 1191
+TAM ANY GID 20
+TAM ANY UINFO "& M. Nguyen"
+ARVIND ANY UID 1192
+ARVIND ANY GID 20
+ARVIND ANY UINFO "& Raghunathan,593E,0572,6432739"
+REMER ANY UID 1193
+REMER ANY GID 20
+REMER ANY UINFO "Janet &"
+REPPY ANY UID 1194
+REPPY ANY GID 20
+REPPY ANY UINFO "John H. &"
+RIMEY ANY UID 1195
+RIMEY ANY GID 20
+RIMEY ANY UINFO "Kenneth E. &"
+SHIM ANY UID 1196
+SHIM ANY GID 20
+SHIM ANY UINFO "Young Chul &"
+JAMES ANY UID 1197
+JAMES ANY GID 20
+JAMES ANY UINFO "& G. Thompson"
+WAGNER ANY UID 1198
+WAGNER ANY GID 20
+WAGNER ANY UINFO "Richard F. &"
+AWANG ANY UID 1199
+AWANG ANY GID 20
+AWANG ANY UINFO "Albert Ren Rui Wang"
+EDWARD ANY UID 1200
+EDWARD ANY GID 20
+EDWARD ANY UINFO "& Wang,,,8491508"
+PAUL ANY UID 1202
+PAUL ANY GID 20
+PAUL ANY UINFO "& Emerson Wright"
+DEKAI ANY UID 1203
+DEKAI ANY GID 20
+DEKAI ANY UINFO "& Wu"
+ZHANG ANY UID 1204
+ZHANG ANY GID 20
+ZHANG ANY UINFO "Yanjun &,436E,,6432837"
+COLIN ANY UID 1205
+COLIN ANY GID 36
+COLIN ANY UINFO "Cathi &,,,8480462"
+ALKEMIST ANY UID 1206
+ALKEMIST ANY GID 90
+ALKEMIST ANY UINFO "Pat Monardo,274 Hearst,5041,5409363"
+MAB ANY UID 1207
+MAB ANY GID 20
+MAB ANY UINFO "Mark Bedau,237 Bechtel,8790,,"
+PHILIP ANY UID 1208
+PHILIP ANY GID 20
+PHILIP ANY UINFO "& Chang,,,8326617"
+DK ANY UID 1209
+DK ANY GID 20
+DK ANY UINFO "Denise Kiser,237 Bechtel,8790,4825040"
+ASHANY ANY UID 1210
+ASHANY ANY GID 30
+ASHANY ANY UINFO "Ron &,,,"
+RUBY ANY UID 1211
+RUBY ANY GID 30
+RUBY ANY UINFO "Lawrence &,,,"
+SCHNORR ANY UID 1212
+SCHNORR ANY GID 30
+SCHNORR ANY UINFO "C. P. &,,,"
+SVENTEK ANY UID 1213
+SVENTEK ANY GID 30
+SVENTEK ANY UINFO "Joseph &,,,"
+CAMPBELL ANY UID 1214
+CAMPBELL ANY GID 20
+CAMPBELL ANY UINFO "James &,475E,7017,8454405"
+MARION ANY UID 1215
+MARION ANY GID 36
+MARION ANY UINFO "& Piller,T-2241,5975,5277739"
+CALL ANY UID 1216
+CALL ANY GID 90
+CALL ANY UINFO "Lisa Call,,,"
+IEEECS ANY UID 1217
+IEEECS ANY GID 90
+IEEECS ANY UINFO "David Fong,508-13E,,4742126"
+ADRION ANY UID 1218
+ADRION ANY GID 90
+ADRION ANY UINFO "Rick &"
+HASHIM ANY UID 1219
+HASHIM ANY GID 20
+HASHIM ANY UINFO "Safaa H. &,,,7244181"
+GOTTHOLD ANY UID 1220
+GOTTHOLD ANY GID 30
+GOTTHOLD ANY UINFO "Gary Lippman,551E,9522,6539231"
+TURKSEN ANY UID 1221
+TURKSEN ANY GID 30
+TURKSEN ANY UINFO "Ismail B. &,557E,5029,8457323"
+MCC ANY UID 1222
+MCC ANY GID 90
+MCC ANY UINFO "Maria Carla Calzarossa,466E,8905"
+AGGARWAL ANY UID 1223
+AGGARWAL ANY GID 20
+AGGARWAL ANY UINFO "Rajeev &,608-12E,8234,5861330"
+WISDOM ANY UID 1224
+WISDOM ANY GID 20
+WISDOM ANY UINFO "Tom &,,,5243249"
+HAHN ANY UID 1225
+HAHN ANY GID 10
+HAHN ANY UINFO "Tim Hahn,151C,,8487084"
+YEUNG ANY UID 1226
+YEUNG ANY GID 90
+YEUNG ANY UINFO "Grace C.N. &,459E,2714,2375313"
+GUEST ANY UID 1227
+GUEST ANY GID 90
+GUEST ANY UINFO "Unix Workshop"
+KHOJESTA ANY UID 1228
+KHOJESTA ANY GID 30
+KHOJESTA ANY UINFO "& Beverleigh,571E,5244"
+ADLASS ANY UID 1229
+ADLASS ANY GID 30
+ADLASS ANY UINFO "Peter Adlassnig,608-14E,8228,6443008"
+MCGEER ANY UID 1230
+MCGEER ANY GID 20
+MCGEER ANY UINFO "Rick &,485E,4694,2368262"
+DNS ANY UID 1231
+DNS ANY GID 20
+DNS ANY UINFO "David Neel Smith,5303 Dwinelle,24218,5483706"
+RAIDER ANY UID 1232
+RAIDER ANY GID 20
+RAIDER ANY UINFO "Don Ahn,B4A Latimer,4594,6431266"
+JEAN ANY UID 1233
+JEAN ANY GID 10
+JEAN ANY UINFO "& Root,573E,1042"
+IRINA ANY UID 1234
+IRINA ANY GID 90
+IRINA ANY UINFO "& Bercovich,,,5482451"
+KROHN ANY UID 1235
+KROHN ANY GID 10
+KROHN ANY UINFO "Marina &,555E,1390,"
diff --git a/usr.sbin/named/testdomain/test.boot b/usr.sbin/named/testdomain/test.boot
new file mode 100644
index 00000000000..caae4edaef2
--- /dev/null
+++ b/usr.sbin/named/testdomain/test.boot
@@ -0,0 +1,9 @@
+;
+; boot file for name server
+; Note that there should be one primary entry for each SOA record.
+;
+; type domain source file or host
+;
+domain TEST
+primary TEST testhosts
+cache . testcache
diff --git a/usr.sbin/named/testdomain/testcache b/usr.sbin/named/testdomain/testcache
new file mode 100644
index 00000000000..aa77a47d4e1
--- /dev/null
+++ b/usr.sbin/named/testdomain/testcache
@@ -0,0 +1,5 @@
+UCBVAX.BERKELEY.EDU. 99999999 IN A 128.32.0.10
+UCBARPA.BERKELEY.EDU. 99999999 IN A 128.32.0.4
+BERKELEY.EDU. 99999999 IN A 10.2.0.78
+BERKELEY.EDU. 99999999 IN NS UCBVAX.BERKELEY.EDU
+ 99999999 IN NS UCBARPA.BERKELEY.EDU
diff --git a/usr.sbin/named/testdomain/testhosts b/usr.sbin/named/testdomain/testhosts
new file mode 100644
index 00000000000..0a552337f3e
--- /dev/null
+++ b/usr.sbin/named/testdomain/testhosts
@@ -0,0 +1,17 @@
+;
+; @(#)testhosts 1.17 (berkeley) 86/02/05
+;
+
+@ IN SOA UCBVAX.Berkeley.EDU. KJD.UCBVAX.Berkeley.EDU. (
+ 1.17 ; Serial
+ 3600 ; Refresh
+ 300 ; Retry
+ 3600000 ; Expire
+ 3600 ) ; Minimum
+h1.t1 IN MX 10 t2
+h2.t1 IN MX 10 t2
+*.t1 IN MX 5 t3
+*.t4 IN MX 7 t2
+c1.t1 IN CNAME monet.berkeley.edu.
+c2.t1 IN CNAME rip.berkeley.edu.
+c3.t1 IN CNAME matisse.berkeley.edu.
diff --git a/usr.sbin/named/tools/Makefile b/usr.sbin/named/tools/Makefile
new file mode 100644
index 00000000000..e865b31b38c
--- /dev/null
+++ b/usr.sbin/named/tools/Makefile
@@ -0,0 +1,6 @@
+# from: @(#)Makefile 4.10 (Berkeley) 5/29/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $
+
+SUBDIR= nslookup nsquery nstest
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/named/tools/nslookup/Makefile b/usr.sbin/named/tools/nslookup/Makefile
new file mode 100644
index 00000000000..b5f08bf7c1e
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/Makefile
@@ -0,0 +1,19 @@
+# from: @(#)Makefile 5.23 (Berkeley) 6/24/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $
+
+PROG= nslookup
+SRCS= main.c getinfo.c debug.c send.c skip.c list.c subr.c
+OBJS+= commands.o
+MAN= nslookup.8
+LFLAGS= -I
+CFLAGS+=-I${.CURDIR}
+LDADD= -ll
+DPADD= ${LIBL}
+CLEANFILES+=commands.c lex.yy.c lex.yy.o
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/nslookup.help \
+ ${DESTDIR}/usr/share/misc
+
+.include "../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/tools/nslookup/commands.l b/usr.sbin/named/tools/nslookup/commands.l
new file mode 100644
index 00000000000..c8ec5558d2a
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/commands.l
@@ -0,0 +1,197 @@
+%{
+
+/*-
+ * Copyright (c) 1985 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[] = "from: @(#)commands.l 5.13 (Berkeley) 7/24/90";*/
+static char rcsid[] = "$Id: commands.l,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * commands.l
+ *
+ * Andrew Cherenson CS298-26 Fall 1985
+ *
+ * Lex input file for the nslookup program command interpreter.
+ * When a sequence is recognized, the associated action
+ * routine is called. The action routine may need to
+ * parse the string for additional information.
+ *
+ * Recognized commands: (identifiers are shown in uppercase)
+ *
+ * server NAME - set default server to NAME, using default server
+ * lserver NAME - set default server to NAME, using initial server
+ * finger [NAME] - finger the optional NAME
+ * exit - exit the program
+ * root - set default server to the root
+ * ls NAME - list the domain NAME
+ * view FILE - sorts and view the file with more
+ * set OPTION - set an option
+ * help - print help information
+ * ? - print help information
+ * NAME - print info about the host/domain NAME
+ * using default server.
+ * NAME1 NAME2 - as above, but use NAME2 as server
+ *
+ *
+ * yylex Results:
+ * 0 upon end-of-file.
+ * 1 after each command.
+ *
+ *******************************************************************************
+ */
+
+#include "res.h"
+extern char rootServerName[];
+
+%}
+WS [ \t]
+FLET [A-Za-z0-9.*\\]
+LET [A-Za-z0-9.*]
+NAME [A-Za-z0-9.*=_/-]
+%%
+^{WS}*server{WS}+{LET}{NAME}*{WS}*$ {
+ /*
+ * 0 == use current server to find
+ * the new one.
+ * 1 == use original server to find
+ * the new one.
+ */
+ SetDefaultServer(yytext, 0);
+ return(1);
+ }
+^{WS}*lserver{WS}+{LET}{NAME}*{WS}*$ {
+ SetDefaultServer(yytext, 1);
+ return(1);
+ }
+^{WS}*exit{WS}*$ {
+ return(0);
+ }
+^{WS}*root{WS}*$ {
+ SetDefaultServer(rootServerName, 1);
+ return(1);
+ }
+^{WS}*finger({WS}+{LET}{NAME}*)?{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ Finger(yytext, 1);
+ return(1);
+ }
+^{WS}*finger({WS}+{LET}{NAME}*)?{WS}*$ {
+ Finger(yytext, 0);
+ return(1);
+ }
+^{WS}*view{WS}+{NAME}+{WS}*$ {
+ ViewList(yytext);
+ return(1);
+ }
+^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ ListHosts(yytext, 1);
+ return(1);
+ }
+^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}*$ {
+ ListHosts(yytext, 0);
+ return(1);
+ }
+^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ ListHostsByType(yytext, 1);
+ return(1);
+ }
+^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}*$ {
+ ListHostsByType(yytext, 0);
+ return(1);
+ }
+^{WS}*set{WS}+{NAME}+{WS}*$ {
+ SetOption(yytext);
+ return(1);
+ }
+^{WS}*help{WS}*$ {
+ extern void PrintHelp();
+ PrintHelp();
+ return(1);
+ }
+^{WS}*"?"{WS}*$ {
+ extern void PrintHelp();
+ PrintHelp();
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ LookupHost(yytext, 1);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}*$ {
+ LookupHost(yytext, 0);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ LookupHostWithServer(yytext, 1);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}*$ {
+ LookupHostWithServer(yytext, 0);
+ return(1);
+ }
+^{WS}*\n {
+ return(1);
+ }
+^.*\n {
+ printf("Unrecognized command: %s",
+ yytext);
+ return(1);
+ }
+\n { ; }
+%%
diff --git a/usr.sbin/named/tools/nslookup/debug.c b/usr.sbin/named/tools/nslookup/debug.c
new file mode 100644
index 00000000000..a199e19a172
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/debug.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 1985,1989 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[] = "from: @(#)debug.c 5.26 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: debug.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * debug.c --
+ *
+ * Routines to print out packets received from a name server query.
+ *
+ * Modified version of 4.3BSD BIND res_debug.c 5.30 6/27/90
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include "res.h"
+
+extern char ctime();
+
+/*
+ * Imported from res_debug.c
+ */
+extern char *_res_resultcodes[];
+extern char *_res_opcodes[];
+
+/*
+ * Used to highlight the start of a record when printing it.
+ */
+#define INDENT " -> "
+
+
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+
+Print_query(msg, eom, printHeader)
+ char *msg, *eom;
+ int printHeader;
+{
+ Fprint_query(msg, eom, printHeader,stdout);
+}
+
+Fprint_query(msg, eom, printHeader,file)
+ char *msg, *eom;
+ int printHeader;
+ FILE *file;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int n;
+ short class;
+ short type;
+
+ /*
+ * Print header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + sizeof(HEADER);
+ if (printHeader || (_res.options & RES_DEBUG2)) {
+ fprintf(file," HEADER:\n");
+ fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]);
+ fprintf(file,", id = %d", ntohs(hp->id));
+ fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]);
+ fprintf(file,"\theader flags: ");
+ if (hp->qr) {
+ fprintf(file," response");
+ } else {
+ fprintf(file," query");
+ }
+ if (hp->aa)
+ fprintf(file,", auth. answer");
+ if (hp->tc)
+ fprintf(file,", truncation");
+ if (hp->rd)
+ fprintf(file,", want recursion");
+ if (hp->ra)
+ fprintf(file,", recursion avail.");
+ if (hp->pr)
+ fprintf(file,", primary");
+ fprintf(file,"\n\tquestions = %d", ntohs(hp->qdcount));
+ fprintf(file,", answers = %d", ntohs(hp->ancount));
+ fprintf(file,", authority records = %d", ntohs(hp->nscount));
+ fprintf(file,", additional = %d\n\n", ntohs(hp->arcount));
+ }
+
+ /*
+ * Print question records.
+ */
+ if (n = ntohs(hp->qdcount)) {
+ fprintf(file," QUESTIONS:\n");
+ while (--n >= 0) {
+ fprintf(file,"\t");
+ cp = Print_cdname(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ type = _getshort(cp);
+ cp += sizeof(u_short);
+ class = _getshort(cp);
+ cp += sizeof(u_short);
+ fprintf(file,", type = %s", p_type(type));
+ fprintf(file,", class = %s\n", p_class(class));
+ }
+ }
+ /*
+ * Print authoritative answer records
+ */
+ if (n = ntohs(hp->ancount)) {
+ fprintf(file," ANSWERS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ /*
+ * print name server records
+ */
+ if (n = ntohs(hp->nscount)) {
+ fprintf(file," AUTHORITY RECORDS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ /*
+ * print additional records
+ */
+ if (n = ntohs(hp->arcount)) {
+ fprintf(file," ADDITIONAL RECORDS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ fprintf(file,"\n------------\n");
+}
+
+
+char *
+Print_cdname_sub(cp, msg, eom, file, format)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+ int format;
+{
+ int n;
+ u_char name[MAXDNAME];
+ extern char *strcpy();
+
+ if ((n = dn_expand(msg, eom, cp, name, sizeof(name))) < 0)
+ return (NULL);
+ if (name[0] == '\0') {
+ (void) strcpy(name, "(root)");
+ }
+ if (format) {
+ fprintf(file, "%-30s", name);
+ } else {
+ fputs((char *)name, file);
+ }
+ return ((char *)cp + n);
+}
+
+char *
+Print_cdname(cp, msg, eom, file)
+ char *cp, *msg, *eom;
+ FILE *file;
+{
+ return(Print_cdname_sub(cp, msg, eom, file, 0));
+}
+
+char *
+Print_cdname2(cp, msg, eom, file)
+ char *cp, *msg, *eom;
+ FILE *file;
+{
+ return(Print_cdname_sub(cp, msg, eom, file, 1));
+}
+
+/*
+ * Print resource record fields in human readable form.
+ */
+char *
+Print_rr(cp, msg, eom, file)
+ char *cp, *msg, *eom;
+ FILE *file;
+{
+ int type, class, dlen, n, c;
+ unsigned long rrttl, ttl;
+ struct in_addr inaddr;
+ char *cp1, *cp2;
+ int debug;
+
+ if ((cp = Print_cdname(cp, msg, eom, file)) == NULL) {
+ fprintf(file, "(name truncated?)\n");
+ return (NULL); /* compression error */
+ }
+
+ type = _getshort(cp);
+ cp += sizeof(u_short);
+ class = _getshort(cp);
+ cp += sizeof(u_short);
+ rrttl = _getlong(cp);
+ cp += sizeof(u_long);
+ dlen = _getshort(cp);
+ cp += sizeof(u_short);
+
+ debug = _res.options & (RES_DEBUG|RES_DEBUG2);
+ if (debug) {
+ if (_res.options & RES_DEBUG2) {
+ fprintf(file,"\n\ttype = %s, class = %s, dlen = %d",
+ p_type(type), p_class(class), dlen);
+ }
+ if (type == T_SOA) {
+ fprintf(file,"\n\tttl = %lu (%s)", rrttl, p_time(rrttl));
+ }
+ (void) putc('\n', file);
+ }
+
+ cp1 = cp;
+
+ /*
+ * Print type specific data, if appropriate
+ */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (dlen == 4) {
+ fprintf(file,"\tinternet address = %s\n",
+ inet_ntoa(inaddr));
+ cp += dlen;
+ } else if (dlen == 7) {
+ fprintf(file,"\tinternet address = %s",
+ inet_ntoa(inaddr));
+ fprintf(file,", protocol = %d", cp[4]);
+ fprintf(file,", port = %d\n",
+ (cp[5] << 8) + cp[6]);
+ cp += dlen;
+ }
+ break;
+ default:
+ fprintf(file,"\taddress, class = %d, len = %d\n",
+ class, dlen);
+ cp += dlen;
+ }
+ break;
+
+ case T_CNAME:
+ fprintf(file,"\tcanonical name = ");
+ goto doname;
+
+ case T_MG:
+ fprintf(file,"\tmail group member = ");
+ goto doname;
+ case T_MB:
+ fprintf(file,"\tmail box = ");
+ goto doname;
+ case T_MR:
+ fprintf(file,"\tmailbox rename = ");
+ goto doname;
+ case T_MX:
+ fprintf(file,"\tpreference = %u",_getshort(cp));
+ cp += sizeof(u_short);
+ fprintf(file,", mail exchanger = ");
+ goto doname;
+ case T_NS:
+ fprintf(file,"\tnameserver = ");
+ goto doname;
+ case T_PTR:
+ fprintf(file,"\tname = ");
+doname:
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+
+ case T_HINFO:
+ if (n = *cp++) {
+ fprintf(file,"\tCPU = %.*s", n, cp);
+ cp += n;
+ }
+ if (n = *cp++) {
+ fprintf(file,"\tOS = %.*s\n", n, cp);
+ cp += n;
+ }
+ break;
+
+ case T_SOA:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\torigin = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\tmail addr = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\tserial = %lu", _getlong(cp));
+ cp += sizeof(u_long);
+ ttl = _getlong(cp);
+ fprintf(file,"\n\trefresh = %lu (%s)", ttl, p_time(ttl));
+ cp += sizeof(u_long);
+ ttl = _getlong(cp);
+ fprintf(file,"\n\tretry = %lu (%s)", ttl, p_time(ttl));
+ cp += sizeof(u_long);
+ ttl = _getlong(cp);
+ fprintf(file,"\n\texpire = %lu (%s)", ttl, p_time(ttl));
+ cp += sizeof(u_long);
+ ttl = _getlong(cp);
+ fprintf(file,
+ "\n\tminimum ttl = %lu (%s)\n", ttl, p_time(ttl));
+ cp += sizeof(u_long);
+ break;
+
+ case T_MINFO:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\trequests = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\terrors = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+
+ case T_TXT:
+ (void) fputs("\ttext = \"", file);
+ cp2 = cp1 + dlen;
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if (*cp == '\n') {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ (void) fputs("\"\n", file);
+ break;
+
+ case T_UINFO:
+ fprintf(file,"\tuser info = %s\n", cp);
+ cp += dlen;
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dlen == 4) {
+ fprintf(file,"\t%cid = %lu\n",type == T_UID ? 'u' : 'g',
+ _getlong(cp));
+ cp += sizeof(int);
+ } else {
+ fprintf(file,"\t%cid of length %d?\n",
+ type == T_UID ? 'u' : 'g', dlen);
+ cp += dlen;
+ }
+ break;
+
+ case T_WKS: {
+ struct protoent *protoPtr;
+
+ if (dlen < sizeof(u_long) + 1)
+ break;
+ if (!debug)
+ (void) putc('\n', file);
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ cp += sizeof(u_long);
+ if ((protoPtr = getprotobynumber(*cp)) != NULL) {
+ fprintf(file,"\tinet address = %s, protocol = %s\n\t",
+ inet_ntoa(inaddr), protoPtr->p_name);
+ } else {
+ fprintf(file,"\tinet address = %s, protocol = %d\n\t",
+ inet_ntoa(inaddr), *cp);
+ }
+ cp++;
+ n = 0;
+ while (cp < cp1 + dlen) {
+ c = *cp++;
+ do {
+ struct servent *s;
+
+ if (c & 0200) {
+ s = getservbyport((int)htons(n),
+ protoPtr ? protoPtr->p_name : NULL);
+ if (s != NULL) {
+ fprintf(file," %s", s->s_name);
+ } else {
+ fprintf(file," #%d", n);
+ }
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ putc('\n',file);
+ }
+ break;
+
+ case T_NULL:
+ fprintf(file, "\tNULL (dlen %d)\n", dlen);
+ cp += dlen;
+ break;
+
+ default:
+ fprintf(file,"\t??? unknown type %d ???\n", type);
+ cp += dlen;
+ }
+ if (_res.options & RES_DEBUG && type != T_SOA) {
+ fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl));
+ }
+ if (cp != cp1 + dlen) {
+ fprintf(file,
+ "\n*** Error: record size incorrect (%d != %d)\n\n",
+ cp - cp1, dlen);
+ cp = NULL;
+ }
+ return (cp);
+}
diff --git a/usr.sbin/named/tools/nslookup/getinfo.c b/usr.sbin/named/tools/nslookup/getinfo.c
new file mode 100644
index 00000000000..e2ff8930fbd
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/getinfo.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 1985,1989 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[] = "from: @(#)getinfo.c 5.26 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: getinfo.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * getinfo.c --
+ *
+ * Routines to create requests to name servers
+ * and interpret the answers.
+ *
+ * Adapted from 4.3BSD BIND gethostnamadr.c
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "res.h"
+
+extern char *_res_resultcodes[];
+extern char *res_skip();
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define MAXDOMAINS 35
+#define MAXSERVERS 10
+
+static char *addr_list[MAXADDRS + 1];
+
+static char *host_aliases[MAXALIASES];
+static int host_aliases_len[MAXALIASES];
+static u_char hostbuf[BUFSIZ+1];
+
+typedef struct {
+ char *name;
+ char *domain[MAXDOMAINS];
+ int numDomains;
+ char *address[MAXADDRS];
+ int numAddresses;
+} ServerTable;
+
+ServerTable server[MAXSERVERS];
+
+typedef union {
+ HEADER qb1;
+ char qb2[PACKETSZ];
+} querybuf;
+
+typedef union {
+ long al;
+ char ac;
+} align;
+
+#define GetShort(cp) _getshort(cp); cp += sizeof(unsigned short);
+
+
+/*
+ *******************************************************************************
+ *
+ * GetAnswer --
+ *
+ * Interprets an answer packet and retrieves the following
+ * information:
+ *
+ * Results:
+ * SUCCESS the info was retrieved.
+ * NO_INFO the packet did not contain an answer.
+ * NONAUTH non-authoritative information was found.
+ * ERROR the answer was malformed.
+ * Other errors returned in the packet header.
+ *
+ *******************************************************************************
+ */
+
+static int
+GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ char *msg;
+ int queryType;
+ int msglen;
+ Boolean iquery;
+ register HostInfo *hostPtr;
+ Boolean isServer;
+{
+ register HEADER *headerPtr;
+ register u_char *cp;
+ querybuf answer;
+ char **aliasPtr;
+ u_char *eom, *bp;
+ char **addrPtr;
+ char *namePtr;
+ char *dnamePtr;
+ int type, class;
+ int qdcount, ancount, arcount, nscount, buflen;
+ int origClass;
+ int numAliases = 0;
+ int numAddresses = 0;
+ int n, i, j;
+ int len;
+ int dlen;
+ int status;
+ int numServers;
+ Boolean haveAnswer;
+ Boolean printedAnswers = FALSE;
+
+
+ /*
+ * If the hostPtr was used before, free up the calloc'd areas.
+ */
+ FreeHostInfoPtr(hostPtr);
+
+ status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer,
+ sizeof(answer), &n);
+
+ if (status != SUCCESS) {
+ if (_res.options & RES_DEBUG2)
+ printf("SendRequest failed\n");
+ return (status);
+ }
+ eom = (u_char *) &answer + n;
+
+ headerPtr = (HEADER *) &answer;
+
+ if (headerPtr->rcode != NOERROR) {
+ return (headerPtr->rcode);
+ }
+
+ qdcount = ntohs(headerPtr->qdcount);
+ ancount = ntohs(headerPtr->ancount);
+ arcount = ntohs(headerPtr->arcount);
+ nscount = ntohs(headerPtr->nscount);
+
+ /*
+ * If there are no answer, n.s. or additional records
+ * then return with an error.
+ */
+ if (ancount == 0 && nscount == 0 && arcount == 0) {
+ return (NO_INFO);
+ }
+
+
+ bp = hostbuf;
+ buflen = sizeof(hostbuf);
+ cp = (u_char *) &answer + sizeof(HEADER);
+
+ /* Skip over question section. */
+ while (qdcount-- > 0) {
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ }
+
+ aliasPtr = host_aliases;
+ addrPtr = addr_list;
+ haveAnswer = FALSE;
+
+ /*
+ * Scan through the answer resource records.
+ * Answers for address query types are saved.
+ * Other query type answers are just printed.
+ */
+ if (ancount != 0) {
+ if (!isServer && !headerPtr->aa) {
+ printf("Non-authoritative answer:\n");
+ }
+
+ if (queryType != T_A && !(iquery && queryType == T_PTR)) {
+ while (--ancount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *)&answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ printedAnswers = TRUE;
+ } else {
+ while (--ancount >= 0 && cp < eom) {
+ if ((n =
+ dn_expand((u_char *)&answer, eom, cp, bp, buflen)) < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += sizeof(u_long); /* skip TTL */
+ dlen = GetShort(cp);
+ if (type == T_CNAME) {
+ /*
+ * Found an alias.
+ */
+ cp += dlen;
+ if (aliasPtr >= &host_aliases[MAXALIASES-1]) {
+ continue;
+ }
+ *aliasPtr++ = (char *)bp;
+ n = strlen((char *)bp) + 1;
+ host_aliases_len[numAliases] = n;
+ numAliases++;
+ bp += n;
+ buflen -= n;
+ continue;
+ } else if (type == T_PTR) {
+ /*
+ * Found a "pointer" to the real name.
+ */
+ if ((n =
+ dn_expand((u_char *)&answer, eom, cp, bp,buflen)) < 0) {
+ cp += n;
+ continue;
+ }
+ cp += n;
+ len = strlen(bp) + 1;
+ hostPtr->name = Calloc(1, len);
+ bcopy(bp, hostPtr->name, len);
+ haveAnswer = TRUE;
+ break;
+ } else if (type != T_A) {
+ cp += dlen;
+ continue;
+ }
+ if (haveAnswer) {
+ /*
+ * If we've already got 1 address, we aren't interested
+ * in addresses with a different length or class.
+ */
+ if (dlen != hostPtr->addrLen) {
+ cp += dlen;
+ continue;
+ }
+ if (class != origClass) {
+ cp += dlen;
+ continue;
+ }
+ } else {
+ /*
+ * First address: record its length and class so we
+ * only save additonal ones with the same attributes.
+ */
+ hostPtr->addrLen = dlen;
+ origClass = class;
+ hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC;
+ len = strlen(bp) + 1;
+ hostPtr->name = Calloc(1, len);
+ bcopy(bp, hostPtr->name, len);
+ }
+ bp += (((u_long)bp) % sizeof(align));
+
+ if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) {
+ if (_res.options & RES_DEBUG) {
+ printf("Size (%d) too big\n", dlen);
+ }
+ break;
+ }
+ bcopy(cp, *addrPtr++ = (char *)bp, dlen);
+ bp +=dlen;
+ cp += dlen;
+ numAddresses++;
+ haveAnswer = TRUE;
+ }
+ }
+ }
+
+ if ((queryType == T_A || queryType == T_PTR) && haveAnswer) {
+
+ /*
+ * Go through the alias and address lists and return them
+ * in the hostPtr variable.
+ */
+
+ if (numAliases > 0) {
+ hostPtr->aliases = (char **) Calloc(1 + numAliases, sizeof(char *));
+ for (i = 0; i < numAliases; i++) {
+ hostPtr->aliases[i] = Calloc(1, host_aliases_len[i]);
+ bcopy(host_aliases[i], hostPtr->aliases[i],host_aliases_len[i]);
+ }
+ hostPtr->aliases[i] = NULL;
+ }
+ if (numAddresses > 0) {
+ hostPtr->addrList = (char **)Calloc(1+numAddresses, sizeof(char *));
+ for (i = 0; i < numAddresses; i++) {
+ hostPtr->addrList[i] = Calloc(1, hostPtr->addrLen);
+ bcopy(addr_list[i], hostPtr->addrList[i], hostPtr->addrLen);
+ }
+ hostPtr->addrList[i] = NULL;
+ }
+#ifdef verbose
+ if (headerPtr->aa || nscount == 0) {
+ hostPtr->servers = NULL;
+ return (SUCCESS);
+ }
+#else
+ hostPtr->servers = NULL;
+ return (SUCCESS);
+#endif
+ }
+
+ /*
+ * At this point, for the T_A query type, only empty answers remain.
+ * For other query types, additional information might be found
+ * in the additional resource records part.
+ */
+
+ if (!headerPtr->aa && (queryType != T_A) && (nscount > 0 || arcount > 0)) {
+ if (printedAnswers) {
+ putchar('\n');
+ }
+ printf("Authoritative answers can be found from:\n");
+ }
+
+ cp = (u_char *)res_skip((char *) &answer, 2, eom);
+
+ numServers = 0;
+ if (queryType != T_A) {
+ /*
+ * If we don't need to save the record, just print it.
+ */
+ while (--nscount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *) &answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ } else {
+ while (--nscount >= 0 && cp < eom) {
+ /*
+ * Go through the NS records and retrieve the names of hosts
+ * that serve the requested domain.
+ */
+
+ if ((n = dn_expand((u_char *) &answer, eom, cp, bp, buflen)) < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen(bp) + 1;
+ dnamePtr = Calloc(1, len); /* domain name */
+ bcopy(bp, dnamePtr, len);
+
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += sizeof(u_long); /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_NS) {
+ cp += dlen;
+ } else {
+ Boolean found;
+
+ if ((n =
+ dn_expand((u_char *) &answer, eom, cp, bp, buflen)) < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen(bp) + 1;
+ namePtr = Calloc(1, len); /* server host name */
+ bcopy(bp, namePtr, len);
+
+ /*
+ * Store the information keyed by the server host name.
+ */
+ found = FALSE;
+ for (j = 0; j < numServers; j++) {
+ if (strcmp(namePtr, server[j].name) == 0) {
+ found = TRUE;
+ free(namePtr);
+ break;
+ }
+ }
+ if (found) {
+ server[j].numDomains++;
+ if (server[j].numDomains <= MAXDOMAINS) {
+ server[j].domain[server[j].numDomains-1] = dnamePtr;
+ }
+ } else {
+ if (numServers >= MAXSERVERS) {
+ break;
+ }
+ server[numServers].name = namePtr;
+ server[numServers].domain[0] = dnamePtr;
+ server[numServers].numDomains = 1;
+ server[numServers].numAddresses = 0;
+ numServers++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Additional resource records contain addresses of servers.
+ */
+ cp = (u_char *)res_skip((char *) &answer, 3, eom);
+
+ if (queryType != T_A) {
+ /*
+ * If we don't need to save the record, just print it.
+ */
+ while (--arcount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *) &answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ } else {
+ while (--arcount >= 0 && cp < eom) {
+ if ((n = dn_expand((u_char *) &answer, eom, cp, bp, buflen)) < 0) {
+ break;
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += sizeof(u_long); /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_A) {
+ cp += dlen;
+ continue;
+ } else {
+ for (j = 0; j < numServers; j++) {
+ if (strcmp(bp, server[j].name) == 0) {
+ server[j].numAddresses++;
+ if (server[j].numAddresses <= MAXADDRS) {
+ server[j].address[server[j].numAddresses-1] =
+ Calloc(1,dlen);
+ bcopy(cp,
+ server[j].address[server[j].numAddresses-1],dlen);
+ break;
+ }
+ }
+ }
+ cp += dlen;
+ }
+ }
+ }
+
+ /*
+ * If we are returning name server info, transfer it to the hostPtr.
+ */
+ if (numServers > 0) {
+ hostPtr->servers = (ServerInfo **)
+ Calloc(numServers+1, sizeof(ServerInfo *));
+
+ for (i = 0; i < numServers; i++) {
+ hostPtr->servers[i] = (ServerInfo *) Calloc(1, sizeof(ServerInfo));
+ hostPtr->servers[i]->name = server[i].name;
+
+
+ hostPtr->servers[i]->domains = (char **)
+ Calloc(server[i].numDomains+1,sizeof(char *));
+ for (j = 0; j < server[i].numDomains; j++) {
+ hostPtr->servers[i]->domains[j] = server[i].domain[j];
+ }
+ hostPtr->servers[i]->domains[j] = NULL;
+
+
+ hostPtr->servers[i]->addrList = (char **)
+ Calloc(server[i].numAddresses+1,sizeof(char *));
+ for (j = 0; j < server[i].numAddresses; j++) {
+ hostPtr->servers[i]->addrList[j] = server[i].address[j];
+ }
+ hostPtr->servers[i]->addrList[j] = NULL;
+
+ }
+ hostPtr->servers[i] = NULL;
+ }
+
+ switch (queryType) {
+ case T_A:
+ return NONAUTH;
+ case T_PTR:
+ if (iquery)
+ return NO_INFO;
+ /* fall through */
+ default:
+ return SUCCESS;
+ }
+}
+
+/*
+*******************************************************************************
+*
+* GetHostInfo --
+*
+* Retrieves host name, address and alias information
+* for a domain.
+*
+* Algorithm from res_search().
+*
+* Results:
+* ERROR - res_mkquery failed.
+* + return values from GetAnswer()
+*
+*******************************************************************************
+*/
+
+int
+GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ int queryClass;
+ int queryType;
+ char *name;
+ HostInfo *hostPtr;
+ Boolean isServer;
+{
+ int n;
+ register int result;
+ register char *cp, **domain;
+ Boolean got_nodata = FALSE;
+ struct in_addr ina;
+
+ /* Catch explicit addresses */
+ if ((queryType == T_A) && IsAddr(name, &ina)) {
+ hostPtr->name = Calloc(strlen(name)+3, 1);
+ (void)sprintf(hostPtr->name,"[%s]",name);
+ hostPtr->aliases = NULL;
+ hostPtr->servers = NULL;
+ hostPtr->addrType = AF_INET;
+ hostPtr->addrLen = sizeof(ina);
+ hostPtr->addrList = (char **)Calloc(2, sizeof(char *));
+ hostPtr->addrList[0] = Calloc(1, sizeof(ina));
+ bcopy((char *)&ina, hostPtr->addrList[0], sizeof(ina));
+ hostPtr->addrList[1] = NULL;
+ return(SUCCESS);
+ }
+
+ result = NXDOMAIN;
+ for (cp = name, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+ if (n == 0 && (cp = hostalias(name))) {
+ printf("Aliased to \"%s\"\n\n", cp);
+ return (GetHostDomain(nsAddrPtr, queryClass, queryType,
+ cp, (char *)NULL, hostPtr, isServer));
+ }
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((n == 0 && _res.options & RES_DEFNAMES) ||
+ (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
+ for (domain = _res.dnsrch; *domain; domain++) {
+ result = GetHostDomain(nsAddrPtr, queryClass, queryType,
+ name, *domain, hostPtr, isServer);
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_INFO error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's fully-qualified.
+ */
+ if (result == SUCCESS || result == NO_RESPONSE)
+ return result;
+ if (result == NO_INFO)
+ got_nodata++;
+ if ((result != NXDOMAIN && result != NO_INFO) ||
+ (_res.options & RES_DNSRCH) == 0)
+ break;
+ }
+ /*
+ * If the search/default failed, try the name as fully-qualified,
+ * but only if it contained at least one dot (even trailing).
+ * This is purely a heuristic; we assume that any reasonable query
+ * about a top-level domain (for servers, SOA, etc) will not use
+ * res_search.
+ */
+ if (n && (result = GetHostDomain(nsAddrPtr, queryClass, queryType,
+ name, (char *)NULL, hostPtr, isServer)) == SUCCESS)
+ return result;
+ if (got_nodata)
+ result = NO_INFO;
+ return (result);
+}
+
+/*
+ * Perform a query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ int queryClass;
+ int queryType;
+ char *name, *domain;
+ HostInfo *hostPtr;
+ Boolean isServer;
+{
+ querybuf buf;
+ char nbuf[2*MAXDNAME+2];
+ char *longname = nbuf;
+ int n;
+
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name) - 1;
+ if (name[n] == '.' && n < sizeof(nbuf) - 1) {
+ bcopy(name, nbuf, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ (void)sprintf(nbuf, "%.*s.%.*s",
+ MAXDNAME, name, MAXDNAME, domain);
+ longname = nbuf;
+ }
+ n = res_mkquery(QUERY, longname, queryClass, queryType,
+ (char *)0, 0, 0, (char *) &buf, sizeof(buf));
+ if (n < 0) {
+ if (_res.options & RES_DEBUG) {
+ printf("Res_mkquery failed\n");
+ }
+ return (ERROR);
+ }
+
+ n = GetAnswer(nsAddrPtr, queryType, (char *)&buf, n, 0, hostPtr, isServer);
+
+ /*
+ * GetAnswer didn't find a name, so set it to the specified one.
+ */
+ if (n == NONAUTH) {
+ if (hostPtr->name == NULL) {
+ int len = strlen(longname) + 1;
+ hostPtr->name = Calloc(len, sizeof(char));
+ bcopy(longname, hostPtr->name, len);
+ }
+ }
+ return(n);
+}
+
+
+/*
+*******************************************************************************
+*
+* GetHostInfoByAddr --
+*
+* Performs an inverse query to find the host name
+* that corresponds to the given address.
+*
+* Results:
+* ERROR - res_mkquery failed.
+* + return values from GetAnswer()
+*
+*******************************************************************************
+*/
+
+int
+GetHostInfoByAddr(nsAddrPtr, address, hostPtr)
+ struct in_addr *nsAddrPtr;
+ struct in_addr *address;
+ HostInfo *hostPtr;
+{
+ int n;
+ querybuf buf;
+ char qbuf[MAXDNAME];
+ char *p = (char *) &address->s_addr;
+
+ (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
+ ((unsigned)p[3] & 0xff),
+ ((unsigned)p[2] & 0xff),
+ ((unsigned)p[1] & 0xff),
+ ((unsigned)p[0] & 0xff));
+ n = res_mkquery(QUERY, qbuf, C_IN, T_PTR,
+ NULL, 0, NULL, (char *) &buf, sizeof(buf));
+ if (n < 0) {
+ if (_res.options & RES_DEBUG) {
+ printf("res_mkquery() failed\n");
+ }
+ return (ERROR);
+ }
+ n = GetAnswer(nsAddrPtr, T_PTR, (char *) &buf, n, 1, hostPtr, 1);
+ if (n == SUCCESS) {
+ hostPtr->addrType = AF_INET;
+ hostPtr->addrLen = 4;
+ hostPtr->addrList = (char **)Calloc(2, sizeof(char *));
+ hostPtr->addrList[0] = Calloc(sizeof(long), sizeof(char));
+ bcopy((char *)p, hostPtr->addrList[0], sizeof(struct in_addr));
+ hostPtr->addrList[1] = NULL;
+ }
+ return n;
+}
+
+/*
+*******************************************************************************
+*
+* FreeHostInfoPtr --
+*
+* Deallocates all the calloc'd areas for a HostInfo variable.
+*
+*******************************************************************************
+*/
+
+void
+FreeHostInfoPtr(hostPtr)
+ register HostInfo *hostPtr;
+{
+ int i, j;
+
+ if (hostPtr->name != NULL) {
+ free(hostPtr->name);
+ hostPtr->name = NULL;
+ }
+
+ if (hostPtr->aliases != NULL) {
+ i = 0;
+ while (hostPtr->aliases[i] != NULL) {
+ free(hostPtr->aliases[i]);
+ i++;
+ }
+ free((char *)hostPtr->aliases);
+ hostPtr->aliases = NULL;
+ }
+
+ if (hostPtr->addrList != NULL) {
+ i = 0;
+ while (hostPtr->addrList[i] != NULL) {
+ free(hostPtr->addrList[i]);
+ i++;
+ }
+ free((char *)hostPtr->addrList);
+ hostPtr->addrList = NULL;
+ }
+
+ if (hostPtr->servers != NULL) {
+ i = 0;
+ while (hostPtr->servers[i] != NULL) {
+
+ if (hostPtr->servers[i]->name != NULL) {
+ free(hostPtr->servers[i]->name);
+ }
+
+ if (hostPtr->servers[i]->domains != NULL) {
+ j = 0;
+ while (hostPtr->servers[i]->domains[j] != NULL) {
+ free(hostPtr->servers[i]->domains[j]);
+ j++;
+ }
+ free((char *)hostPtr->servers[i]->domains);
+ }
+
+ if (hostPtr->servers[i]->addrList != NULL) {
+ j = 0;
+ while (hostPtr->servers[i]->addrList[j] != NULL) {
+ free(hostPtr->servers[i]->addrList[j]);
+ j++;
+ }
+ free((char *)hostPtr->servers[i]->addrList);
+ }
+ free((char *)hostPtr->servers[i]);
+ i++;
+ }
+ free((char *)hostPtr->servers);
+ hostPtr->servers = NULL;
+ }
+}
diff --git a/usr.sbin/named/tools/nslookup/list.c b/usr.sbin/named/tools/nslookup/list.c
new file mode 100644
index 00000000000..4b18d4bf5ef
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/list.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright (c) 1985,1989 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[] = "from: @(#)list.c 5.23 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: list.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * list.c --
+ *
+ * Routines to obtain info from name and finger servers.
+ *
+ * Adapted from 4.3BSD BIND ns_init.c and from finger.c.
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "res.h"
+
+/*
+ * Imported from res_debug.c
+ */
+extern char *_res_resultcodes[];
+
+extern int errno;
+
+typedef union {
+ HEADER qb1;
+ char qb2[PACKETSZ];
+} querybuf;
+
+extern HostInfo *defaultPtr;
+extern HostInfo curHostInfo;
+extern int curHostValid;
+extern int queryType;
+extern int queryClass;
+
+static int sockFD = -1;
+static int ListSubr();
+
+/*
+ * During a listing to a file, hash marks are printed
+ * every HASH_SIZE records.
+ */
+
+#define HASH_SIZE 50
+
+
+/*
+ *******************************************************************************
+ *
+ * ListHosts --
+ * ListHostsByType --
+ *
+ * Requests the name server to do a zone transfer so we
+ * find out what hosts it knows about.
+ *
+ * For ListHosts, there are five types of output:
+ * - Internet addresses (default)
+ * - cpu type and operating system (-h option)
+ * - canonical and alias names (-a option)
+ * - well-known service names (-s option)
+ * - ALL records (-d option)
+ * ListHostsByType prints records of the default type or of a speicific
+ * type.
+ *
+ * To see all types of information sorted by name, do the following:
+ * ls -d domain.edu > file
+ * view file
+ *
+ * Results:
+ * SUCCESS the listing was successful.
+ * ERROR the server could not be contacted because
+ * a socket could not be obtained or an error
+ * occured while receiving, or the output file
+ * could not be opened.
+ *
+ *******************************************************************************
+ */
+
+void
+ListHostsByType(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ int i, qtype, result;
+ char *namePtr;
+ char name[NAME_LEN];
+ char option[NAME_LEN];
+
+ /*
+ * Parse the command line. It maybe of the form "ls -t domain"
+ * or "ls -t type domain".
+ */
+
+ i = sscanf(string, " ls -t %s %s", option, name);
+ if (putToFile && i == 2 && name[0] == '>') {
+ i--;
+ }
+ if (i == 2) {
+ qtype = StringToType(option, -1);
+ if (qtype == -1)
+ return;
+ namePtr = name;
+ } else if (i == 1) {
+ namePtr = option;
+ qtype = queryType;
+ } else {
+ fprintf(stderr, "*** ls: invalid request %s\n",string);
+ return;
+ }
+ result = ListSubr(qtype, namePtr, putToFile ? string : NULL);
+ if (result != SUCCESS)
+ fprintf(stderr, "*** Can't list domain %s: %s\n",
+ namePtr, DecodeError(result));
+}
+
+void
+ListHosts(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ int i, qtype, result;
+ char *namePtr;
+ char name[NAME_LEN];
+ char option[NAME_LEN];
+
+ /*
+ * Parse the command line. It maybe of the form "ls domain",
+ * "ls -X domain".
+ */
+ i = sscanf(string, " ls %s %s", option, name);
+ if (putToFile && i == 2 && name[0] == '>') {
+ i--;
+ }
+ if (i == 2) {
+ if (strcmp("-a", option) == 0) {
+ qtype = T_CNAME;
+ } else if (strcmp("-h", option) == 0) {
+ qtype = T_HINFO;
+ } else if (strcmp("-m", option) == 0) {
+ qtype = T_MX;
+ } else if (strcmp("-s", option) == 0) {
+ qtype = T_WKS;
+ } else if (strcmp("-d", option) == 0) {
+ qtype = T_ANY;
+ } else {
+ qtype = T_A;
+ }
+ namePtr = name;
+ } else if (i == 1) {
+ namePtr = option;
+ qtype = T_A;
+ } else {
+ fprintf(stderr, "*** ls: invalid request %s\n",string);
+ return;
+ }
+ result = ListSubr(qtype, namePtr, putToFile ? string : NULL);
+ if (result != SUCCESS)
+ fprintf(stderr, "*** Can't list domain %s: %s\n",
+ namePtr, DecodeError(result));
+}
+
+static int
+ListSubr(qtype, domain, cmd)
+ int qtype;
+ char *domain;
+ char *cmd;
+{
+ querybuf buf;
+ struct sockaddr_in sin;
+ HEADER *headerPtr;
+ int msglen;
+ int amtToRead;
+ int numRead;
+ int numAnswers = 0;
+ int result;
+ int soacnt = 0;
+ u_short len;
+ char *cp, *nmp;
+ char dname[2][NAME_LEN];
+ char file[NAME_LEN];
+ static char *answer = NULL;
+ static int answerLen = 0;
+ enum {
+ NO_ERRORS,
+ ERR_READING_LEN,
+ ERR_READING_MSG,
+ ERR_PRINTING,
+ } error = NO_ERRORS;
+
+ /*
+ * Create a query packet for the requested domain name.
+ */
+ msglen = res_mkquery(QUERY, domain, queryClass, T_AXFR,
+ (char *)0, 0, 0,
+ (char *) &buf, sizeof(buf));
+ if (msglen < 0) {
+ if (_res.options & RES_DEBUG) {
+ fprintf(stderr, "*** ls: res_mkquery failed\n");
+ }
+ return (ERROR);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(nsport);
+
+ /*
+ * Check to see if we have the address of the server or the
+ * address of a server who knows about this domain.
+ *
+ * For now, just use the first address in the list.
+ */
+
+ if (defaultPtr->addrList != NULL) {
+ sin.sin_addr = *(struct in_addr *) defaultPtr->addrList[0];
+ } else {
+ sin.sin_addr = *(struct in_addr *)defaultPtr->servers[0]->addrList[0];
+ }
+
+ /*
+ * Set up a virtual circuit to the server.
+ */
+ if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("ls: socket");
+ return(ERROR);
+ }
+ if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ int e;
+ if (errno == ECONNREFUSED) {
+ e = NO_RESPONSE;
+ } else {
+ perror("ls: connect");
+ e = ERROR;
+ }
+ (void) close(sockFD);
+ sockFD = -1;
+ return e;
+ }
+
+ /*
+ * Send length & message for zone transfer
+ */
+
+ len = htons(msglen);
+
+ if (write(sockFD, (char *)&len, sizeof(len)) != sizeof(len) ||
+ write(sockFD, (char *) &buf, msglen) != msglen) {
+ perror("ls: write");
+ (void) close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+
+ fprintf(stdout,"[%s]\n",
+ (defaultPtr->addrList != NULL) ? defaultPtr->name :
+ defaultPtr->servers[0]->name);
+
+ if (cmd == NULL) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(cmd, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ (void) close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+ fprintf(filePtr, "> %s\n", cmd);
+ fprintf(filePtr,"[%s]\n",
+ (defaultPtr->addrList != NULL) ? defaultPtr->name :
+ defaultPtr->servers[0]->name);
+ }
+
+#if 0
+ if (qtype == T_CNAME) {
+ fprintf(filePtr, "%-30s", "Alias");
+ } else if (qtype == T_TXT) {
+ fprintf(filePtr, "%-30s", "Key");
+ } else {
+ fprintf(filePtr, "%-30s", "Host or domain name");
+ }
+ switch (qtype) {
+ case T_A:
+ fprintf(filePtr, " %-30s\n", "Internet Address");
+ break;
+ case T_HINFO:
+ fprintf(filePtr, " %-30s\n", "CPU & OS");
+ break;
+ case T_CNAME:
+ fprintf(filePtr, " %-30s\n", "Canonical Name");
+ break;
+ case T_MX:
+ fprintf(filePtr, " %-30s\n", "Metric & Host");
+ break;
+ case T_WKS:
+ fprintf(filePtr, " %-4s %s\n", "Protocol", "Services");
+ break;
+ case T_MB:
+ fprintf(filePtr, " %-30s\n", "Mailbox");
+ break;
+ case T_MG:
+ fprintf(filePtr, " %-30s\n", "Mail Group");
+ break;
+ case T_MR:
+ fprintf(filePtr, " %-30s\n", "Mail Rename");
+ break;
+ case T_MINFO:
+ fprintf(filePtr, " %-30s\n", "Mail List Requests & Errors");
+ break;
+ case T_UINFO:
+ fprintf(filePtr, " %-30s\n", "User Information");
+ break;
+ case T_UID:
+ fprintf(filePtr, " %-30s\n", "User ID");
+ break;
+ case T_GID:
+ fprintf(filePtr, " %-30s\n", "Group ID");
+ break;
+ case T_TXT:
+ fprintf(filePtr, " %-30s\n", "Text");
+ break;
+ case T_NS:
+ fprintf(filePtr, " %-30s\n", "Name Servers");
+ break;
+ case T_PTR:
+ fprintf(filePtr, " %-30s\n", "Pointers");
+ break;
+ case T_SOA:
+ fprintf(filePtr, " %-30s\n", "Start of Authority");
+ break;
+ case T_ANY:
+ fprintf(filePtr, " %-30s\n", "Resource Record Info.");
+ break;
+ }
+#endif
+
+
+ dname[0][0] = '\0';
+ while (1) {
+ unsigned short tmp;
+
+ /*
+ * Read the length of the response.
+ */
+
+ cp = (char *) &tmp;
+ amtToRead = sizeof(u_short);
+ while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ amtToRead -= numRead;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_LEN;
+ break;
+ }
+
+ if ((len = htons(tmp)) == 0) {
+ break; /* nothing left to read */
+ }
+
+ /*
+ * The server sent too much data to fit the existing buffer --
+ * allocate a new one.
+ */
+ if (len > answerLen) {
+ if (answerLen != 0) {
+ free(answer);
+ }
+ answerLen = len;
+ answer = Malloc(answerLen);
+ }
+
+ /*
+ * Read the response.
+ */
+
+ amtToRead = len;
+ cp = answer;
+ while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ amtToRead -= numRead;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_MSG;
+ break;
+ }
+
+ result = PrintListInfo(filePtr, answer, cp, qtype, dname[0]);
+ if (result != SUCCESS) {
+ error = ERR_PRINTING;
+ break;
+ }
+
+ numAnswers++;
+ if (cmd != NULL && ((numAnswers % HASH_SIZE) == 0)) {
+ fprintf(stdout, "#");
+ fflush(stdout);
+ }
+ cp = answer + sizeof(HEADER);
+ if (ntohs(((HEADER* )answer)->qdcount) > 0)
+ cp += dn_skipname((u_char *)cp,
+ (u_char *)answer + len) + QFIXEDSZ;
+ nmp = cp;
+ cp += dn_skipname((u_char *)cp, (u_char *)answer + len);
+ if ((_getshort(cp) == T_SOA)) {
+ dn_expand((u_char *)answer, (u_char *)answer + len,
+ (u_char *)nmp, (u_char *)dname[soacnt],
+ sizeof(dname[0]));
+ if (soacnt) {
+ if (strcmp(dname[0], dname[1]) == 0)
+ break;
+ } else
+ soacnt++;
+ }
+ }
+
+ if (cmd != NULL) {
+ fprintf(stdout, "%sReceived %d record%s.\n",
+ (numAnswers >= HASH_SIZE) ? "\n" : "",
+ numAnswers,
+ (numAnswers != 1) ? "s" : "");
+ }
+
+ (void) close(sockFD);
+ sockFD = -1;
+ if (cmd != NULL && filePtr != NULL) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+
+ switch (error) {
+ case NO_ERRORS:
+ return (SUCCESS);
+
+ case ERR_READING_LEN:
+ return(ERROR);
+
+ case ERR_PRINTING:
+ return(result);
+
+ case ERR_READING_MSG:
+ headerPtr = (HEADER *) answer;
+ fprintf(stderr,"*** ls: error receiving zone transfer:\n");
+ fprintf(stderr,
+ " result: %s, answers = %d, authority = %d, additional = %d\n",
+ _res_resultcodes[headerPtr->rcode],
+ ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
+ ntohs(headerPtr->arcount));
+ return(ERROR);
+ default:
+ return(ERROR);
+ }
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * PrintListInfo --
+ *
+ * Used by the ListInfo routine to print the answer
+ * received from the name server. Only the desired
+ * information is printed.
+ *
+ * Results:
+ * SUCCESS the answer was printed without a problem.
+ * NO_INFO the answer packet did not contain an answer.
+ * ERROR the answer was malformed.
+ * Misc. errors returned in the packet header.
+ *
+ *******************************************************************************
+ */
+
+#define NAME_FORMAT " %-30s"
+
+static Boolean
+strip_domain(string, domain)
+ char *string, *domain;
+{
+ register char *dot;
+
+ if (*domain != '\0') {
+ dot = string;
+ while ((dot = strchr(dot, '.')) != NULL && strcasecmp(domain, ++dot))
+ ;
+ if (dot != NULL) {
+ dot[-1] = '\0';
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+PrintListInfo(file, msg, eom, qtype, domain)
+ FILE *file;
+ u_char *msg, *eom;
+ int qtype;
+ char *domain;
+{
+ register u_char *cp;
+ HEADER *headerPtr;
+ int type, class, dlen, nameLen;
+ u_long ttl;
+ int n, pref;
+ struct in_addr inaddr;
+ char name[NAME_LEN];
+ char name2[NAME_LEN];
+ Boolean stripped;
+
+ /*
+ * Read the header fields.
+ */
+ headerPtr = (HEADER *)msg;
+ cp = msg + sizeof(HEADER);
+ if (headerPtr->rcode != NOERROR) {
+ return(headerPtr->rcode);
+ }
+
+ /*
+ * We are looking for info from answer resource records.
+ * If there aren't any, return with an error. We assume
+ * there aren't any question records.
+ */
+
+ if (ntohs(headerPtr->ancount) == 0) {
+ return(NO_INFO);
+ } else {
+ if (ntohs(headerPtr->qdcount) > 0) {
+ nameLen = dn_skipname(cp, eom);
+ if (nameLen < 0)
+ return (ERROR);
+ cp += nameLen + QFIXEDSZ;
+ }
+ if ((nameLen =
+ dn_expand(msg, eom, cp, (u_char *)name, sizeof(name))) < 0)
+ return (ERROR);
+ cp += nameLen;
+
+ type = _getshort(cp);
+ cp += sizeof(u_short);
+
+ if (!(type == qtype || qtype == T_ANY) &&
+ !((type == T_NS || type == T_PTR) && qtype == T_A))
+ return(SUCCESS);
+
+ class = _getshort(cp);
+ cp += sizeof(u_short);
+ ttl = _getlong(cp);
+ cp += sizeof(u_long);
+ dlen = _getshort(cp);
+ cp += sizeof(u_short);
+
+ if (name[0] == 0)
+ strcpy(name, "(root)");
+
+ /* Strip the domain name from the data, if desired. */
+ stripped = FALSE;
+ if ((_res.options & RES_DEBUG) == 0) {
+ if (type != T_SOA) {
+ stripped = strip_domain(name, domain);
+ }
+ }
+ if (!stripped && nameLen < sizeof(name)-1) {
+ strcat(name, ".");
+ }
+
+ fprintf(file, NAME_FORMAT, name);
+
+ if (qtype == T_ANY) {
+ if (_res.options & RES_DEBUG) {
+ fprintf(file,"\t%lu %-5s", ttl, p_class(queryClass));
+ }
+ fprintf(file," %-5s", p_type(type));
+ }
+
+ /* XXX merge this into debug.c's print routines */
+
+ switch (type) {
+ case T_A:
+ if (class == C_IN) {
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (dlen == 4) {
+ fprintf(file," %s", inet_ntoa(inaddr));
+ } else if (dlen == 7) {
+ fprintf(file," %s", inet_ntoa(inaddr));
+ fprintf(file," (%d, %d)", cp[4],(cp[5] << 8) + cp[6]);
+ } else
+ fprintf(file, " (dlen = %d?)", dlen);
+ }
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ if ((nameLen = dn_expand(msg, eom,
+ cp, (u_char *)name2, sizeof(name2))) < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_NS:
+ case T_PTR:
+ putc(' ', file);
+ if (qtype != T_ANY)
+ fprintf(file,"%s = ", type == T_PTR ? "host" : "server");
+ cp = (u_char *)Print_cdname2(cp, msg, eom, file);
+ break;
+
+ case T_HINFO:
+ if (n = *cp++) {
+ (void)sprintf(name,"%.*s", n, cp);
+ fprintf(file," %-10s", name);
+ cp += n;
+ } else {
+ fprintf(file," %-10s", " ");
+ }
+ if (n = *cp++) {
+ fprintf(file," %.*s", n, cp);
+ cp += n;
+ }
+ break;
+
+ case T_SOA:
+ if ((nameLen = dn_expand(msg,
+ eom, cp, (u_char *)name2, sizeof(name2))) < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s", name2);
+ if ((nameLen = dn_expand(msg,
+ eom, cp, (u_char *)name2, sizeof(name2))) < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s. (", name2);
+ for (n = 0; n < 5; n++) {
+ u_long u;
+
+ u = _getlong(cp);
+ cp += sizeof(u_long);
+ fprintf(file,"%s%lu", n? " " : "", u);
+ }
+ fprintf(file, ")");
+ break;
+
+ case T_MX:
+ pref = _getshort(cp);
+ cp += sizeof(u_short);
+ fprintf(file," %-3d ",pref);
+ if ((nameLen = dn_expand(msg,
+ eom, cp, (u_char *)name2, sizeof(name2))) < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_TXT:
+ {
+ u_char *cp2 = cp + dlen;
+ int c;
+
+ (void) fputs(" \"", file);
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if (*cp == '\n') {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ (void) putc('"', file);
+ }
+ break;
+
+ case T_MINFO:
+ (void) putc(' ', file);
+ cp = (u_char *)Print_cdname(cp, msg, eom, file);
+ fprintf(file, " ");
+ cp = (u_char *)Print_cdname(cp, msg, eom, file);
+ break;
+
+ case T_UINFO:
+ fprintf(file, " %s", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ fprintf(file, " %lu", _getlong(cp));
+ break;
+
+ case T_WKS:
+ if (class == C_IN) {
+ struct protoent *pp;
+ struct servent *ss;
+ u_short port;
+
+ cp += 4; /* skip inet address */
+ dlen -= 4;
+
+ setprotoent(1);
+ setservent(1);
+ n = *cp & 0377;
+ pp = getprotobynumber(n);
+ if (pp == 0)
+ fprintf(file," %-3d ", n);
+ else
+ fprintf(file," %-3s ", pp->p_name);
+ cp++; dlen--;
+
+ port = 0;
+ while (dlen-- > 0) {
+ n = *cp++;
+ do {
+ if (n & 0200) {
+ ss = getservbyport((int)htons(port),
+ pp->p_name);
+ if (ss == 0)
+ fprintf(file," %u", port);
+ else
+ fprintf(file," %s", ss->s_name);
+ }
+ n <<= 1;
+ } while (++port & 07);
+ }
+ endprotoent();
+ endservent();
+ }
+ break;
+ }
+ fprintf(file,"\n");
+ }
+ return(SUCCESS);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * ViewList --
+ *
+ * A hack to view the output of the ls command in sorted
+ * order using more.
+ *
+ *******************************************************************************
+ */
+
+ViewList(string)
+ char *string;
+{
+ char file[NAME_LEN];
+ char command[NAME_LEN];
+
+ sscanf(string, " view %s", file);
+ (void)sprintf(command, "grep \"^ \" %s | sort | more", file);
+ system(command);
+}
+
+/*
+ *******************************************************************************
+ *
+ * Finger --
+ *
+ * Connects with the finger server for the current host
+ * to request info on the specified person (long form)
+ * who is on the system (short form).
+ *
+ * Results:
+ * SUCCESS the finger server was contacted.
+ * ERROR the server could not be contacted because
+ * a socket could not be obtained or connected
+ * to or the service could not be found.
+ *
+ *******************************************************************************
+ */
+
+Finger(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ struct servent *sp;
+ struct sockaddr_in sin;
+ register FILE *f;
+ register int c;
+ register int lastc;
+ char name[NAME_LEN];
+ char file[NAME_LEN];
+
+ /*
+ * We need a valid current host info to get an inet address.
+ */
+ if (!curHostValid) {
+ fprintf(stderr, "Finger: no current host defined.\n");
+ return (ERROR);
+ }
+
+ if (sscanf(string, " finger %s", name) == 1) {
+ if (putToFile && (name[0] == '>')) {
+ name[0] = '\0';
+ }
+ } else {
+ name[0] = '\0';
+ }
+
+ sp = getservbyname("finger", "tcp");
+ if (sp == 0) {
+ fprintf(stderr, "Finger: unknown service\n");
+ return (ERROR);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = curHostInfo.addrType;
+ sin.sin_port = sp->s_port;
+ bcopy(curHostInfo.addrList[0], (char *)&sin.sin_addr,
+ curHostInfo.addrLen);
+
+ /*
+ * Set up a virtual circuit to the host.
+ */
+
+ sockFD = socket(curHostInfo.addrType, SOCK_STREAM, 0);
+ if (sockFD < 0) {
+ fflush(stdout);
+ perror("finger: socket");
+ return (ERROR);
+ }
+
+ if (connect(sockFD, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ fflush(stdout);
+ perror("finger: connect");
+ close(sockFD);
+ sockFD = -1;
+ return (ERROR);
+ }
+
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+ fprintf(filePtr, "[%s]\n", curHostInfo.name);
+
+ if (name[0] != '\0') {
+ write(sockFD, "/W ", 3);
+ }
+ write(sockFD, name, strlen(name));
+ write(sockFD, "\r\n", 2);
+ f = fdopen(sockFD, "r");
+ while ((c = getc(f)) != EOF) {
+ switch (c) {
+ case 0210:
+ case 0211:
+ case 0212:
+ case 0214:
+ c -= 0200;
+ break;
+ case 0215:
+ c = '\n';
+ break;
+ }
+ putc(lastc = c, filePtr);
+ }
+ if (lastc != '\n') {
+ putc('\n', filePtr);
+ }
+ putc('\n', filePtr);
+
+ close(sockFD);
+ sockFD = -1;
+
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return (SUCCESS);
+}
+
+ListHost_close()
+{
+ if (sockFD != -1) {
+ (void) close(sockFD);
+ sockFD = -1;
+ }
+}
diff --git a/usr.sbin/named/tools/nslookup/main.c b/usr.sbin/named/tools/nslookup/main.c
new file mode 100644
index 00000000000..4c7f6b6b9a9
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/main.c
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (c) 1985,1989 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
+char copyright[] =
+"@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)main.c 5.42 (Berkeley) 3/3/91";*/
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * main.c --
+ *
+ * Main routine and some action routines for the name server
+ * lookup program.
+ *
+ * Andrew Cherenson
+ * U.C. Berkeley Computer Science Div.
+ * CS298-26, Fall 1985
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "res.h"
+#include "pathnames.h"
+
+/*
+ * Default Internet address of the current host.
+ */
+
+#if BSD < 43
+#define LOCALHOST "127.0.0.1"
+#endif
+
+
+/*
+ * Name of a top-level name server. Can be changed with
+ * the "set root" command.
+ */
+
+#ifndef ROOT_SERVER
+#define ROOT_SERVER "ns.nic.ddn.mil."
+#endif
+char rootServerName[NAME_LEN] = ROOT_SERVER;
+
+
+/*
+ * Info about the most recently queried host.
+ */
+
+HostInfo curHostInfo;
+int curHostValid = FALSE;
+
+
+/*
+ * Info about the default name server.
+ */
+
+HostInfo *defaultPtr = NULL;
+char defaultServer[NAME_LEN];
+struct in_addr defaultAddr;
+
+
+/*
+ * Initial name server query type is Address.
+ */
+
+int queryType = T_A;
+int queryClass = C_IN;
+
+/*
+ * Stuff for Interrupt (control-C) signal handler.
+ */
+
+extern void IntrHandler();
+FILE *filePtr;
+jmp_buf env;
+
+static void CvtAddrToPtr();
+static void ReadRC();
+
+
+/*
+ *******************************************************************************
+ *
+ * main --
+ *
+ * Initializes the resolver library and determines the address
+ * of the initial name server. The yylex routine is used to
+ * read and perform commands.
+ *
+ *******************************************************************************
+ */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *wantedHost = NULL;
+ Boolean useLocalServer;
+ int result;
+ int i;
+ struct hostent *hp;
+ extern int h_errno;
+
+ /*
+ * Initialize the resolver library routines.
+ */
+
+ if (res_init() == -1) {
+ fprintf(stderr,"*** Can't initialize resolver.\n");
+ exit(1);
+ }
+
+ /*
+ * Allocate space for the default server's host info and
+ * find the server's address and name. If the resolver library
+ * already has some addresses for a potential name server,
+ * then use them. Otherwise, see if the current host has a server.
+ * Command line arguments may override the choice of initial server.
+ */
+
+ defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
+
+ /*
+ * Parse the arguments:
+ * no args = go into interactive mode, use default host as server
+ * 1 arg = use as host name to be looked up, default host will be server
+ * non-interactive mode
+ * 2 args = 1st arg:
+ * if it is '-', then
+ * ignore but go into interactive mode
+ * else
+ * use as host name to be looked up,
+ * go into non-interactive mode
+ * 2nd arg: name or inet address of server
+ *
+ * "Set" options are specified with a leading - and must come before
+ * any arguments. For example, to find the well-known services for
+ * a host, type "nslookup -query=wks host"
+ */
+
+ ReadRC(); /* look for options file */
+
+ ++argv; --argc; /* skip prog name */
+
+ while (argc && *argv[0] == '-' && argv[0][1]) {
+ (void) SetOption (&(argv[0][1]));
+ ++argv; --argc;
+ }
+ if (argc > 2) {
+ Usage();
+ }
+ if (argc && *argv[0] != '-') {
+ wantedHost = *argv; /* name of host to be looked up */
+ }
+
+ useLocalServer = FALSE;
+ if (argc == 2) {
+ struct in_addr addr;
+
+ /*
+ * Use an explicit name server. If the hostname lookup fails,
+ * default to the server(s) in resolv.conf.
+ */
+
+ if (inet_aton(*++argv, &addr) != 0) {
+ _res.nscount = 1;
+ _res.nsaddr.sin_addr = addr;
+ } else {
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "*** Can't find server address for '%s': ",
+ *argv);
+ herror((char *)NULL);
+ fputc('\n', stderr);
+ } else {
+#if BSD < 43
+ bcopy(hp->h_addr, (char *)&_res.nsaddr.sin_addr, hp->h_length);
+ _res.nscount = 1;
+#else
+ for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) {
+ bcopy(hp->h_addr_list[i],
+ (char *)&_res.nsaddr_list[i].sin_addr,
+ hp->h_length);
+ }
+ _res.nscount = i;
+#endif
+ }
+ }
+ }
+
+
+ if (_res.nscount == 0 || useLocalServer) {
+ LocalServer(defaultPtr);
+ } else {
+ for (i = 0; i < _res.nscount; i++) {
+ if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) {
+ LocalServer(defaultPtr);
+ break;
+ } else {
+ result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr),
+ &(_res.nsaddr_list[i].sin_addr),
+ defaultPtr);
+ if (result != SUCCESS) {
+ fprintf(stderr,
+ "*** Can't find server name for address %s: %s\n",
+ inet_ntoa(_res.nsaddr_list[i].sin_addr),
+ DecodeError(result));
+ } else {
+ defaultAddr = _res.nsaddr_list[i].sin_addr;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If we have exhausted the list, tell the user about the
+ * command line argument to specify an address.
+ */
+
+ if (i == _res.nscount) {
+ fprintf(stderr, "*** Default servers are not available\n");
+ exit(1);
+ }
+
+ }
+ strcpy(defaultServer, defaultPtr->name);
+
+
+#ifdef DEBUG
+#ifdef DEBUG2
+ _res.options |= RES_DEBUG2;
+#endif
+ _res.options |= RES_DEBUG;
+ _res.retry = 2;
+#endif DEBUG
+
+ /*
+ * If we're in non-interactive mode, look up the wanted host and quit.
+ * Otherwise, print the initial server's name and continue with
+ * the initialization.
+ */
+
+ if (wantedHost != (char *) NULL) {
+ LookupHost(wantedHost, 0);
+ } else {
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+
+ /*
+ * Setup the environment to allow the interrupt handler to return here.
+ */
+
+ (void) setjmp(env);
+
+ /*
+ * Return here after a longjmp.
+ */
+
+ signal(SIGINT, IntrHandler);
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Read and evaluate commands. The commands are described in commands.l
+ * Yylex returns 0 when ^D or 'exit' is typed.
+ */
+
+ printf("> ");
+ fflush(stdout);
+ while(yylex()) {
+ printf("> ");
+ fflush(stdout);
+ }
+ }
+ exit(0);
+}
+
+
+LocalServer(defaultPtr)
+ HostInfo *defaultPtr;
+{
+ char hostName[NAME_LEN];
+#if BSD < 43
+ int result;
+#endif
+
+ gethostname(hostName, sizeof(hostName));
+
+#if BSD < 43
+ (void) inet_aton(LOCALHOST, &defaultAddr);
+ result = GetHostInfoByName(&defaultAddr, C_IN, T_A,
+ hostName, defaultPtr, 1);
+ if (result != SUCCESS) {
+ fprintf(stderr,
+ "*** Can't find initialize address for server %s: %s\n",
+ defaultServer, DecodeError(result));
+ exit(1);
+ }
+#else
+ defaultAddr.s_addr = htonl(INADDR_ANY);
+ (void) GetHostInfoByName(&defaultAddr, C_IN, T_A, "0.0.0.0", defaultPtr, 1);
+ free(defaultPtr->name);
+ defaultPtr->name = Calloc(1, sizeof(hostName)+1);
+ strcpy(defaultPtr->name, hostName);
+#endif
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * Usage --
+ *
+ * Lists the proper methods to run the program and exits.
+ *
+ *******************************************************************************
+ */
+
+Usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr,
+" nslookup [-opt ...] # interactive mode using default server\n");
+ fprintf(stderr,
+" nslookup [-opt ...] - server # interactive mode using 'server'\n");
+ fprintf(stderr,
+" nslookup [-opt ...] host # just look up 'host' using default server\n");
+ fprintf(stderr,
+" nslookup [-opt ...] host server # just look up 'host' using 'server'\n");
+ exit(1);
+}
+
+/*
+ *******************************************************************************
+ *
+ * IsAddr --
+ *
+ * Returns TRUE if the string looks like an Internet address.
+ * A string with a trailing dot is not an address, even if it looks
+ * like one.
+ *
+ *******************************************************************************
+ */
+
+Boolean
+IsAddr(host, addrPtr)
+ char *host;
+ struct in_addr *addrPtr; /* If return TRUE, contains IP address */
+{
+ register char *cp;
+
+ if (isdigit(host[0])) {
+ /* Make sure it has only digits and dots. */
+ for (cp = host; *cp; ++cp) {
+ if (!isdigit(*cp) && *cp != '.')
+ return FALSE;
+ }
+ /* If it has a trailing dot, don't treat it as an address. */
+ if (*--cp != '.') {
+ if (inet_aton(host, addrPtr) != 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * SetDefaultServer --
+ *
+ * Changes the default name server to the one specified by
+ * the first argument. The command "server name" uses the current
+ * default server to lookup the info for "name". The command
+ * "lserver name" uses the original server to lookup "name".
+ *
+ * Side effects:
+ * This routine will cause a core dump if the allocation requests fail.
+ *
+ * Results:
+ * SUCCESS The default server was changed successfully.
+ * NONAUTH The server was changed but addresses of
+ * other servers who know about the requested server
+ * were returned.
+ * Errors No info about the new server was found or
+ * requests to the current server timed-out.
+ *
+ *******************************************************************************
+ */
+
+int
+SetDefaultServer(string, local)
+ char *string;
+ Boolean local;
+{
+ register HostInfo *newDefPtr;
+ struct in_addr *servAddrPtr;
+ struct in_addr addr;
+ char newServer[NAME_LEN];
+ int result;
+ int i;
+
+ /*
+ * Parse the command line. It maybe of the form "server name",
+ * "lserver name" or just "name".
+ */
+
+ if (local) {
+ i = sscanf(string, " lserver %s", newServer);
+ } else {
+ i = sscanf(string, " server %s", newServer);
+ }
+ if (i != 1) {
+ i = sscanf(string, " %s", newServer);
+ if (i != 1) {
+ fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string);
+ return(ERROR);
+ }
+ }
+
+ /*
+ * Allocate space for a HostInfo variable for the new server. Don't
+ * overwrite the old HostInfo struct because info about the new server
+ * might not be found and we need to have valid default server info.
+ */
+
+ newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
+
+
+ /*
+ * A 'local' lookup uses the original server that the program was
+ * initialized with.
+ *
+ * Check to see if we have the address of the server or the
+ * address of a server who knows about this domain.
+ * XXX For now, just use the first address in the list.
+ */
+
+ if (local) {
+ servAddrPtr = &defaultAddr;
+ } else if (defaultPtr->addrList != NULL) {
+ servAddrPtr = (struct in_addr *) defaultPtr->addrList[0];
+ } else {
+ servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0];
+ }
+
+ result = ERROR;
+ if (IsAddr(newServer, &addr)) {
+ result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr);
+ /* If we can't get the name, fall through... */
+ }
+ if (result != SUCCESS && result != NONAUTH) {
+ result = GetHostInfoByName(servAddrPtr, C_IN, T_A,
+ newServer, newDefPtr, 1);
+ }
+
+ if (result == SUCCESS || result == NONAUTH) {
+ /*
+ * Found info about the new server. Free the resources for
+ * the old server.
+ */
+
+ FreeHostInfoPtr(defaultPtr);
+ free((char *)defaultPtr);
+ defaultPtr = newDefPtr;
+ strcpy(defaultServer, defaultPtr->name);
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+ return(SUCCESS);
+ } else {
+ fprintf(stderr, "*** Can't find address for server %s: %s\n",
+ newServer, DecodeError(result));
+ free((char *)newDefPtr);
+
+ return(result);
+ }
+}
+
+/*
+ *******************************************************************************
+ *
+ * DoLoookup --
+ *
+ * Common subroutine for LookupHost and LookupHostWithServer.
+ *
+ * Results:
+ * SUCCESS - the lookup was successful.
+ * Misc. Errors - an error message is printed if the lookup failed.
+ *
+ *******************************************************************************
+ */
+
+static int
+DoLookup(host, servPtr, serverName)
+ char *host;
+ HostInfo *servPtr;
+ char *serverName;
+{
+ int result;
+ struct in_addr *servAddrPtr;
+ struct in_addr addr;
+
+ /* Skip escape character */
+ if (host[0] == '\\')
+ host++;
+
+ /*
+ * If the user gives us an address for an address query,
+ * silently treat it as a PTR query. If the query type is already
+ * PTR, then convert the address into the in-addr.arpa format.
+ *
+ * Use the address of the server if it exists, otherwise use the
+ * address of a server who knows about this domain.
+ * XXX For now, just use the first address in the list.
+ */
+
+ if (servPtr->addrList != NULL) {
+ servAddrPtr = (struct in_addr *) servPtr->addrList[0];
+ } else {
+ servAddrPtr = (struct in_addr *) servPtr->servers[0]->addrList[0];
+ }
+
+ /*
+ * RFC1123 says we "SHOULD check the string syntactically for a
+ * dotted-decimal number before looking it up [...]" (p. 13).
+ */
+ if (queryType == T_A && IsAddr(host, &addr)) {
+ result = GetHostInfoByAddr(servAddrPtr, &addr, &curHostInfo);
+ } else {
+ if (queryType == T_PTR) {
+ CvtAddrToPtr(host);
+ }
+ result = GetHostInfoByName(servAddrPtr, queryClass, queryType, host,
+ &curHostInfo, 0);
+ }
+
+ switch (result) {
+ case SUCCESS:
+ /*
+ * If the query was for an address, then the &curHostInfo
+ * variable can be used by Finger.
+ * There's no need to print anything for other query types
+ * because the info has already been printed.
+ */
+ if (queryType == T_A) {
+ curHostValid = TRUE;
+ PrintHostInfo(filePtr, "Name:", &curHostInfo);
+ }
+ break;
+
+ /*
+ * No Authoritative answer was available but we got names
+ * of servers who know about the host.
+ */
+ case NONAUTH:
+ PrintHostInfo(filePtr, "Name:", &curHostInfo);
+ break;
+
+ case NO_INFO:
+ fprintf(stderr, "*** No %s (%s) records available for %s\n",
+ DecodeType(queryType), p_type(queryType), host);
+ break;
+
+ case TIME_OUT:
+ fprintf(stderr, "*** Request to %s timed-out\n", serverName);
+ break;
+
+ default:
+ fprintf(stderr, "*** %s can't find %s: %s\n", serverName, host,
+ DecodeError(result));
+ }
+ return result;
+}
+
+/*
+ *******************************************************************************
+ *
+ * LookupHost --
+ *
+ * Asks the default name server for information about the
+ * specified host or domain. The information is printed
+ * if the lookup was successful.
+ *
+ * Results:
+ * ERROR - the output file could not be opened.
+ * + results of DoLookup
+ *
+ *******************************************************************************
+ */
+
+int
+LookupHost(string, putToFile)
+ char *string;
+ Boolean putToFile;
+{
+ char host[NAME_LEN];
+ char file[NAME_LEN];
+ int result;
+
+ /*
+ * Invalidate the current host information to prevent Finger
+ * from using bogus info.
+ */
+
+ curHostValid = FALSE;
+
+ /*
+ * Parse the command string into the host and
+ * optional output file name.
+ *
+ */
+
+ sscanf(string, " %s", host); /* removes white space */
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+
+ PrintHostInfo(filePtr, "Server:", defaultPtr);
+
+ result = DoLookup(host, defaultPtr, defaultServer);
+
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return(result);
+}
+
+/*
+ *******************************************************************************
+ *
+ * LookupHostWithServer --
+ *
+ * Asks the name server specified in the second argument for
+ * information about the host or domain specified in the first
+ * argument. The information is printed if the lookup was successful.
+ *
+ * Address info about the requested name server is obtained
+ * from the default name server. This routine will return an
+ * error if the default server doesn't have info about the
+ * requested server. Thus an error return status might not
+ * mean the requested name server doesn't have info about the
+ * requested host.
+ *
+ * Comments from LookupHost apply here, too.
+ *
+ * Results:
+ * ERROR - the output file could not be opened.
+ * + results of DoLookup
+ *
+ *******************************************************************************
+ */
+
+int
+LookupHostWithServer(string, putToFile)
+ char *string;
+ Boolean putToFile;
+{
+ char file[NAME_LEN];
+ char host[NAME_LEN];
+ char server[NAME_LEN];
+ int result;
+ static HostInfo serverInfo;
+
+ curHostValid = FALSE;
+
+ sscanf(string, " %s %s", host, server);
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+
+ result = GetHostInfoByName(
+ defaultPtr->addrList ?
+ (struct in_addr *) defaultPtr->addrList[0] :
+ (struct in_addr *) defaultPtr->servers[0]->addrList[0],
+ C_IN, T_A, server, &serverInfo, 1);
+
+ if (result != SUCCESS) {
+ fprintf(stderr,"*** Can't find address for server %s: %s\n", server,
+ DecodeError(result));
+ } else {
+ PrintHostInfo(filePtr, "Server:", &serverInfo);
+
+ result = DoLookup(host, &serverInfo, server);
+ }
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return(result);
+}
+
+/*
+ *******************************************************************************
+ *
+ * SetOption --
+ *
+ * This routine is used to change the state information
+ * that affect the lookups. The command format is
+ * set keyword[=value]
+ * Most keywords can be abbreviated. Parsing is very simplistic--
+ * A value must not be separated from its keyword by white space.
+ *
+ * Valid keywords: Meaning:
+ * all lists current values of options.
+ * ALL lists current values of options, including
+ * hidden options.
+ * [no]d2 turn on/off extra debugging mode.
+ * [no]debug turn on/off debugging mode.
+ * [no]defname use/don't use default domain name.
+ * [no]search use/don't use domain search list.
+ * domain=NAME set default domain name to NAME.
+ * [no]ignore ignore/don't ignore trunc. errors.
+ * query=value set default query type to value,
+ * value is one of the query types in RFC883
+ * without the leading T_. (e.g., A, HINFO)
+ * [no]recurse use/don't use recursive lookup.
+ * retry=# set number of retries to #.
+ * root=NAME change root server to NAME.
+ * time=# set timeout length to #.
+ * [no]vc use/don't use virtual circuit.
+ * port TCP/UDP port to server.
+ *
+ * Deprecated:
+ * [no]primary use/don't use primary server.
+ *
+ * Results:
+ * SUCCESS the command was parsed correctly.
+ * ERROR the command was not parsed correctly.
+ *
+ *******************************************************************************
+ */
+
+int
+SetOption(option)
+ register char *option;
+{
+ char type[NAME_LEN];
+ char *ptr;
+ int tmp;
+
+ while (isspace(*option))
+ ++option;
+ if (strncmp (option, "set ", 4) == 0)
+ option += 4;
+ while (isspace(*option))
+ ++option;
+
+ if (*option == 0) {
+ fprintf(stderr, "*** Invalid set command\n");
+ return(ERROR);
+ } else {
+ if (strncmp(option, "all", 3) == 0) {
+ ShowOptions();
+ } else if (strncmp(option, "ALL", 3) == 0) {
+ ShowOptions();
+ } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
+ _res.options |= (RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "nod2", 4) == 0) {
+ _res.options &= ~RES_DEBUG2;
+ printf("d2 mode disabled; still in debug mode\n");
+ } else if (strncmp(option, "def", 3) == 0) { /* defname */
+ _res.options |= RES_DEFNAMES;
+ } else if (strncmp(option, "nodef", 5) == 0) {
+ _res.options &= ~RES_DEFNAMES;
+ } else if (strncmp(option, "do", 2) == 0) { /* domain */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", _res.defdname);
+ res_re_init();
+ }
+ } else if (strncmp(option, "deb", 1) == 0) { /* debug */
+ _res.options |= RES_DEBUG;
+ } else if (strncmp(option, "nodeb", 5) == 0) {
+ _res.options &= ~(RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "ig", 2) == 0) { /* ignore */
+ _res.options |= RES_IGNTC;
+ } else if (strncmp(option, "noig", 4) == 0) {
+ _res.options &= ~RES_IGNTC;
+ } else if (strncmp(option, "po", 2) == 0) { /* port */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%hu", &nsport);
+ }
+#ifdef deprecated
+ } else if (strncmp(option, "pri", 3) == 0) { /* primary */
+ _res.options |= RES_PRIMARY;
+ } else if (strncmp(option, "nopri", 5) == 0) {
+ _res.options &= ~RES_PRIMARY;
+#endif
+ } else if (strncmp(option, "q", 1) == 0 || /* querytype */
+ strncmp(option, "ty", 2) == 0) { /* type */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", type);
+ queryType = StringToType(type, queryType);
+ }
+ } else if (strncmp(option, "cl", 2) == 0) { /* query class */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", type);
+ queryClass = StringToClass(type, queryClass);
+ }
+ } else if (strncmp(option, "rec", 3) == 0) { /* recurse */
+ _res.options |= RES_RECURSE;
+ } else if (strncmp(option, "norec", 5) == 0) {
+ _res.options &= ~RES_RECURSE;
+ } else if (strncmp(option, "ret", 3) == 0) { /* retry */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &tmp);
+ if (tmp >= 0) {
+ _res.retry = tmp;
+ }
+ }
+ } else if (strncmp(option, "ro", 2) == 0) { /* root */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", rootServerName);
+ }
+ } else if (strncmp(option, "sea", 3) == 0) { /* search list */
+ _res.options |= RES_DNSRCH;
+ } else if (strncmp(option, "nosea", 5) == 0) {
+ _res.options &= ~RES_DNSRCH;
+ } else if (strncmp(option, "srchl", 5) == 0) { /* domain search list */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ res_dnsrch(++ptr);
+ }
+ } else if (strncmp(option, "ti", 2) == 0) { /* timeout */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &tmp);
+ if (tmp >= 0) {
+ _res.retrans = tmp;
+ }
+ }
+ } else if (strncmp(option, "v", 1) == 0) { /* vc */
+ _res.options |= RES_USEVC;
+ } else if (strncmp(option, "nov", 3) == 0) {
+ _res.options &= ~RES_USEVC;
+ } else {
+ fprintf(stderr, "*** Invalid option: %s\n", option);
+ return(ERROR);
+ }
+ }
+ return(SUCCESS);
+}
+
+/*
+ * Fake a reinitialization when the domain is changed.
+ */
+res_re_init()
+{
+ register char *cp, **pp;
+ int n;
+
+ /* find components of local domain that might be searched */
+ pp = _res.dnsrch;
+ *pp++ = _res.defdname;
+ for (cp = _res.defdname, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+ cp = _res.defdname;
+ for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) {
+ cp = strchr(cp, '.');
+ *pp++ = ++cp;
+ }
+ *pp = 0;
+ _res.options |= RES_INIT;
+}
+
+#define SRCHLIST_SEP '/'
+
+res_dnsrch(cp)
+ register char *cp;
+{
+ register char **pp;
+ int n;
+
+ (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+ if ((cp = strchr(_res.defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = _res.defdname;
+ pp = _res.dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == SRCHLIST_SEP) {
+ *cp = '\0';
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) {
+ *cp = '\0';
+ }
+ *pp = NULL;
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * ShowOptions --
+ *
+ * Prints out the state information used by the resolver
+ * library and other options set by the user.
+ *
+ *******************************************************************************
+ */
+
+void
+ShowOptions()
+{
+ register char **cp;
+
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+ if (curHostValid) {
+ PrintHostInfo(stdout, "Host:", &curHostInfo);
+ }
+
+ printf("Set options:\n");
+ printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no");
+ printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no");
+ printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no");
+ printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no");
+
+ printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no");
+ printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no");
+ printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no");
+ printf(" port=%u\n", nsport);
+
+ printf(" querytype=%s\t", p_type(queryType));
+ printf(" class=%s\t", p_class(queryClass));
+ printf(" timeout=%d\t", _res.retrans);
+ printf(" retry=%d\n", _res.retry);
+ printf(" root=%s\n", rootServerName);
+ printf(" domain=%s\n", _res.defdname);
+
+ if (cp = _res.dnsrch) {
+ printf(" srchlist=%s", *cp);
+ for (cp++; *cp; cp++) {
+ printf("%c%s", SRCHLIST_SEP, *cp);
+ }
+ putchar('\n');
+ }
+ putchar('\n');
+}
+#undef SRCHLIST_SEP
+
+/*
+ *******************************************************************************
+ *
+ * PrintHelp --
+ *
+ * Prints out the help file.
+ * (Code taken from Mail.)
+ *
+ *******************************************************************************
+ */
+
+void
+PrintHelp()
+{
+ register int c;
+ register FILE *helpFilePtr;
+
+ if ((helpFilePtr = fopen(_PATH_HELPFILE, "r")) == NULL) {
+ perror(_PATH_HELPFILE);
+ return;
+ }
+ while ((c = getc(helpFilePtr)) != EOF) {
+ putchar((char) c);
+ }
+ fclose(helpFilePtr);
+}
+
+/*
+ *******************************************************************************
+ *
+ * CvtAddrToPtr --
+ *
+ * Convert a dotted-decimal Internet address into the standard
+ * PTR format (reversed address with .in-arpa. suffix).
+ *
+ * Assumes the argument buffer is large enougth to hold the result.
+ *
+ *******************************************************************************
+ */
+
+static void
+CvtAddrToPtr(name)
+ char *name;
+{
+ char *p;
+ int ip[4];
+ struct in_addr addr;
+
+ if (IsAddr(name, &addr)) {
+ p = inet_ntoa(addr);
+ if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
+ sprintf(name, "%d.%d.%d.%d.in-addr.arpa.",
+ ip[3], ip[2], ip[1], ip[0]);
+ }
+ }
+}
+
+/*
+ *******************************************************************************
+ *
+ * ReadRC --
+ *
+ * Use the contents of ~/.nslookuprc as options.
+ *
+ *******************************************************************************
+ */
+
+static void
+ReadRC()
+{
+ register FILE *fp;
+ register char *cp;
+ char buf[NAME_LEN];
+
+ if ((cp = getenv("HOME")) != NULL) {
+ (void) strcpy(buf, cp);
+ (void) strcat(buf, "/.nslookuprc");
+
+ if ((fp = fopen(buf, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if ((cp = strchr(buf, '\n')) != NULL) {
+ *cp = '\0';
+ }
+ (void) SetOption(buf);
+ }
+ (void) fclose(fp);
+ }
+ }
+}
diff --git a/usr.sbin/named/tools/nslookup/nslookup.8 b/usr.sbin/named/tools/nslookup/nslookup.8
new file mode 100644
index 00000000000..23399f2063a
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/nslookup.8
@@ -0,0 +1,364 @@
+.\" Copyright (c) 1986,1990 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.
+.\"
+.\" from: @(#)nslookup.8 5.3 (Berkeley) 6/24/90
+.\" $Id: nslookup.8,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $
+.\"
+.TH NSLOOKUP 8 "June 24, 1990"
+.UC 6
+.SH NAME
+nslookup \- query Internet name servers interactively
+.SH SYNOPSIS
+.B nslookup
+[
+.I \-option ...
+]
+[
+.I host-to-find
+| \- [
+.I server
+]]
+.SH DESCRIPTION
+.I Nslookup
+is a program to query Internet domain name servers.
+Nslookup has two modes: interactive and non-interactive.
+Interactive mode allows the user to query name servers for
+information about various hosts and domains or to print a list of hosts
+in a domain.
+Non-interactive mode is used to print just the name and requested information
+for a host or domain.
+.sp 1
+.SH ARGUMENTS
+Interactive mode is entered in the following cases:
+.IP a) 4
+when no arguments are given (the default name server will be used),
+.IP b) 4
+when the first argument is a hyphen (\-) and the second argument
+is the host name or Internet address of a name server.
+.LP
+Non-interactive mode is used when the name or Internet address
+of the host to be looked up
+is given as the first argument. The optional second argument specifies
+the host name or address of a name server.
+.LP
+The options listed under the ``set'' command below can be specified in
+the .nslookuprc file in the user's home directory if they are listed
+one per line. Options can also be specified
+on the command line if they precede the arguments and are prefixed with
+a hyphen. For example, to change the default query type to host information,
+and the initial timeout to 10 seconds, type:
+.sp .5v
+ nslookup \-query=hinfo \-timeout=10
+.sp .5v
+.SH "INTERACTIVE COMMANDS"
+Commands may be interrupted at any time by typing a control-C.
+To exit, type a control-D (EOF) or type exit.
+The command line length must be less than 256 characters.
+To treat a built-in command as a host name,
+precede it with an escape character (\e).
+\fBN.B.\fP an unrecognized command will be interpreted as a host name.
+.sp .5v
+.IP "\fIhost\fP [\fIserver\fP]"
+Look up information for \fIhost\fP using the current default server
+or using \fIserver\fP if specified.
+If \fIhost\fP is an Internet address and the query type is A or PTR, the
+name of the host is returned.
+If \fIhost\fP is a name and does not have a trailing period, the default
+domain name is appended to the name. (This behavior depends on the state of the
+\fBset\fP options \fBdomain\fP, \fBsrchlist\fP,
+\fBdefname\fP, and \fBsearch\fP).
+To look up a host not in the current domain, append a period to
+the name.
+.sp 1
+.IP "\fBserver\fP \fIdomain\fP"
+.ns
+.IP "\fBlserver\fP \fIdomain\fP"
+Change the default server to \fIdomain\fP.
+\fBLserver\fP uses the initial server to look up
+information about \fIdomain\fP while \fBserver\fP
+uses the current default server.
+If an authoritative answer can't be found, the names of servers
+that might have the answer are returned.
+.sp 1
+.IP \fBroot\fP
+Changes the default server to the server for the root of the domain name space.
+Currently, the host ns.nic.ddn.mil is used.
+(This command is a synonym for \fBlserver ns.nic.ddn.mil.\fP)
+The name of the root server can be changed with the \fBset root\fP command.
+.sp 1
+.IP "\fBfinger\fP [\fIname\fP] [\fB>\fP \fIfilename\fP]"
+.ns
+.IP "\fBfinger\fP [\fIname\fP] [\fB>>\fP \fIfilename\fP]"
+Connects with the finger server on the current host.
+The current host is defined when a previous lookup for a host
+was successful and returned address information (see the
+\fBset querytype=A\fP command).
+\fIName\fP is optional.
+\fB>\fP and \fB>>\fP can be used to redirect output in the
+usual manner.
+.sp 1
+.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>\fR \fIfilename\fR]"
+.ns
+.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>>\fR \fIfilename\fR]"
+List the information available for \fIdomain\fP, optionally creating
+or appending to \fIfilename\fP.
+The default output contains host names and their Internet addresses.
+.I Option
+can be one of the following:
+.RS
+.IP "\fB\-t \fIquerytype\fP" 4
+lists all records of the specified type (see \fIquerytype\fP below).
+.IP \fB\-a\fP 4
+lists aliases of hosts in the domain.
+synonym for \fB\-t\ \ CNAME\fP.
+.IP \fB\-d\fP 4
+lists all records for the domain.
+synonym for \fB\-t\ \ ANY\fP.
+.IP \fB\-h\fP 4
+lists CPU and operating system information for the domain.
+synonym for \fB\-t\ \ HINFO\fP.
+.IP \fB\-s\fP 4
+lists well-known services of hosts in the domain.
+synonym for \fB\-t\ \ WKS\fP.
+.P
+When output is directed to a file, hash marks are printed for every
+50 records received from the server.
+.RE
+.sp 1
+.IP "\fBview\fP \fIfilename\fP"
+Sorts and lists the output of previous \fBls\fP command(s) with \fImore\fP(1).
+.sp 1
+.ne 4
+.IP "\fBhelp\fP"
+.ns
+.IP "\fB?\fP"
+Prints a brief summary of commands.
+.sp 1
+.IP "\fBexit\fP"
+Exits the program.
+.sp 1
+.IP "\fBset\fP \fIkeyword\fP[=\fIvalue\fP]"
+This command is used to change state information that affects the lookups.
+Valid keywords are:
+.RS
+.IP "\fBall\fP"
+Prints the current values of the frequently-used options to \fBset\fP.
+Information about the current default server and host is also printed.
+.IP "\fBclass=\fIvalue\fR"
+Change the query class to one of:
+.RS
+.IP IN 10
+the Internet class.
+.IP CHAOS 10
+the Chaos class.
+.IP HESIOD 10
+the MIT Athena Hesiod class.
+.IP ANY 10
+wildcard (any of the above).
+.P
+The class specifies the protocol group of the information.
+.br
+(Default = IN, abbreviation = cl)
+.RE
+.IP "\fB[no]debug\fP"
+Turn debugging mode on. A lot more information is printed about the
+packet sent to the server and the resulting answer.
+.br
+(Default = nodebug, abbreviation = [no]deb)
+.IP "\fB[no]d2\fP"
+Turn exhaustive debugging mode on.
+Essentially all fields of every packet are printed.
+.br
+(Default = nod2)
+.IP "\fBdomain=\fIname\fR"
+Change the default domain name to \fIname\fP.
+The default domain name is appended to a lookup request depending on the
+state of the \fBdefname\fP and \fBsearch\fP options.
+The domain search list contains the parents of the default domain if it has
+at least two components in its name.
+For example, if the default domain
+is CC.Berkeley.EDU, the search list is CC.Berkeley.EDU and Berkeley.EDU.
+Use the \fBset srchlist\fP command to specify a different list.
+Use the \fBset all\fP command to display the list.
+.br
+(Default = value from hostname, /etc/resolv.conf or LOCALDOMAIN,
+abbreviation = do)
+.IP "\fBsrchlist=\fIname1/name2/...\fR"
+Change the default domain name to \fIname1\fP and the domain search list
+to \fIname1\fP, \fIname2\fP, etc. A maximum of 6 names separated by slashes (/)
+can be specified.
+For example,
+.sp .5v
+ set\ srchlist=lcs.MIT.EDU/ai.MIT.EDU/MIT.EDU
+.sp .5v
+sets the domain to lcs.MIT.EDU and the search list to the three names.
+This command overrides the
+default domain name and search list of the \fBset domain\fP command.
+Use the \fBset all\fP command to display the list.
+.br
+(Default = value based on hostname, /etc/resolv.conf or LOCALDOMAIN,
+abbreviation = srchl)
+.IP "\fB[no]defname\fP"
+If set, append the default domain name to a single-component lookup request
+(i.e., one that does not contain a period).
+.br
+(Default = defname, abbreviation = [no]def)
+.IP "\fB[no]search\fP"
+If the lookup request contains at least one period but doesn't end
+with a trailing period,
+append the domain names in the domain search list
+to the request until an answer is received.
+.br
+(Default = search, abbreviation = [no]sea)
+.IP "\fBport=\fIvalue\fR"
+Change the default TCP/UDP name server port to \fIvalue\fP.
+.br
+(Default = 53, abbreviation = po)
+.IP "\fBquerytype=\fIvalue\fR"
+.ns
+.IP "\fBtype=\fIvalue\fR"
+.ns
+Change the type of information query to one of:
+.RS
+.IP A 10
+the host's Internet address.
+.IP CNAME 10
+the canonical name for an alias.
+.IP HINFO 10
+the host CPU and operating system type.
+.IP MINFO 10
+the mailbox or mail list information.
+.IP MX 10
+the mail exchanger.
+.IP NS 10
+the name server for the named zone.
+.IP PTR 10
+the host name if the query is an Internet address,
+otherwise the pointer to other information.
+.IP SOA 10
+the domain's ``start-of-authority'' information.
+.IP TXT 10
+the text information.
+.IP UINFO 10
+the user information.
+.IP WKS 10
+the supported well-known services.
+.P
+Other types (ANY, AXFR, MB, MD, MF, NULL) are described in the
+RFC-1035 document.
+.br
+(Default = A, abbreviations = q, ty)
+.RE
+.IP "\fB[no]recurse\fP"
+Tell the name server to query other servers if it does not have the
+information.
+.br
+(Default = recurse, abbreviation = [no]rec)
+.IP \fBretry=\fInumber\fR
+Set the number of retries to \fInumber\fP.
+When a reply to a request is not received within a certain
+amount of time (changed with \fBset timeout\fP),
+the timeout period is doubled and the request is resent.
+The retry value controls how many times a request is resent before giving up.
+.br
+(Default = 4, abbreviation = ret)
+.IP \fBroot=\fIhost\fR
+Change the name of the root server to \fIhost\fP. This
+affects the \fBroot\fP command.
+.br
+(Default = ns.nic.ddn.mil., abbreviation = ro)
+.IP \fBtimeout=\fInumber\fR
+Change the initial timeout interval
+for waiting for a reply
+to \fInumber\fP seconds.
+Each retry doubles the timeout period.
+.br
+(Default = 5 seconds, abbreviation = ti)
+.IP "\fB[no]vc\fP"
+Always use a virtual circuit when sending requests to the server.
+.br
+(Default = novc, abbreviation = [no]v)
+.IP "\fB[no]ignoretc\fP"
+Ignore packet truncation errors.
+.br
+(Default = noignoretc, abbreviation = [no]ig)
+.RE
+.SH DIAGNOSTICS
+If the lookup request was not successful, an error message is printed.
+Possible errors are:
+.IP "Timed out" 5
+The server did not respond to a request after a certain amount of
+time (changed with \fBset timeout=\fIvalue\fR)
+and a certain number of retries (changed with \fBset retry=\fIvalue\fR).
+.IP "No response from server" 5
+No name server is running on the server machine.
+.IP "No records" 5
+The server does not have resource records of the current query type for the
+host, although the host name is valid.
+The query type is specified with the \fBset querytype\fP command.
+.IP "Non-existent domain" 5
+The host or domain name does not exist.
+.IP "Connection refused" 5
+.ns
+.IP "Network is unreachable" 5
+The connection to the name or finger server could not be made
+at the current time.
+This error commonly occurs with \fBls\fP and \fBfinger\fP requests.
+.IP "Server failure" 5
+The name server found an internal inconsistency in its database
+and could not return a valid answer.
+.IP "Refused" 5
+The name server refused to service the request.
+.IP "Format error" 5
+The name server found that the request packet was not in the proper format.
+It may indicate an error in \fInslookup\fP.
+.sp 1
+.SH FILES
+.ta \w'/usr/share/misc/nslookup.helpXXX'u
+/etc/resolv.conf initial domain name and
+ name server addresses.
+.br
+$HOME/.nslookuprc user's initial options.
+.br
+/usr/share/misc/nslookup.help summary of commands.
+.SH ENVIRONMENT
+.ta \w'HOSTALIASESXXXX'u
+HOSTALIASES file containing host aliases.
+.br
+LOCALDOMAIN overrides default domain.
+.SH SEE ALSO
+resolver(3), resolv.conf(5), named(8),
+.br
+RFC-1034 ``Domain Names \- Concepts and Facilities''
+.br
+RFC-1035 ``Domain Names \- Implementation and Specification''
+.SH AUTHOR
+Andrew Cherenson
diff --git a/usr.sbin/named/tools/nslookup/nslookup.help b/usr.sbin/named/tools/nslookup/nslookup.help
new file mode 100644
index 00000000000..9c92635ebc1
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/nslookup.help
@@ -0,0 +1,31 @@
+Commands: (identifiers are shown in uppercase, [] means optional)
+NAME - print info about the host/domain NAME using default server
+NAME1 NAME2 - as above, but use NAME2 as server
+help or ? - print info on common commands; see nslookup(1) for details
+set OPTION - set an option
+ all - print options, current server and host
+ [no]debug - print debugging information
+ [no]d2 - print exhaustive debugging information
+ [no]defname - append domain name to each query
+ [no]recurse - ask for recursive answer to query
+ [no]vc - always use a virtual circuit
+ domain=NAME - set default domain name to NAME
+ srchlist=N1[/N2/.../N6] - set domain to N1 and search list to N1,N2, etc.
+ root=NAME - set root server to NAME
+ retry=X - set number of retries to X
+ timeout=X - set initial time-out interval to X seconds
+ querytype=X - set query type, e.g., A,ANY,CNAME,HINFO,MX,NS,PTR,SOA,WKS
+ type=X - synonym for querytype
+ class=X - set query class to one of IN (Internet), CHAOS, HESIOD or ANY
+server NAME - set default server to NAME, using current default server
+lserver NAME - set default server to NAME, using initial server
+finger [USER] - finger the optional NAME at the current default host
+root - set current default server to the root
+ls [opt] DOMAIN [> FILE] - list addresses in DOMAIN (optional: output to FILE)
+ -a - list canonical names and aliases
+ -h - list HINFO (CPU type and operating system)
+ -s - list well-known services
+ -d - list all records
+ -t TYPE - list records of the given type (e.g., A,CNAME,MX, etc.)
+view FILE - sort an 'ls' output file and view it with more
+exit - exit the program, ^D also exits
diff --git a/usr.sbin/named/tools/nslookup/pathnames.h b/usr.sbin/named/tools/nslookup/pathnames.h
new file mode 100644
index 00000000000..e780c30f1ec
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/pathnames.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 1990 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.
+ *
+ * from: @(#)pathnames.h 5.1 (Berkeley) 5/28/90
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $
+ */
+
+#define _PATH_HELPFILE "/usr/share/misc/nslookup.help"
diff --git a/usr.sbin/named/tools/nslookup/res.h b/usr.sbin/named/tools/nslookup/res.h
new file mode 100644
index 00000000000..c52f497bedf
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/res.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1985,1989 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.
+ *
+ * from: @(#)res.h 5.10 (Berkeley) 6/1/90
+ * $Id: res.h,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $
+ */
+
+/*
+ *******************************************************************************
+ *
+ * res.h --
+ *
+ * Definitions used by modules of the name server lookup program.
+ *
+ * Copyright (c) 1985
+ * Andrew Cherenson
+ * U.C. Berkeley
+ * CS298-26 Fall 1985
+ *
+ *******************************************************************************
+ */
+
+#define TRUE 1
+#define FALSE 0
+typedef int Boolean;
+
+/*
+ * Define return statuses in addtion to the ones defined in namserv.h
+ * let SUCCESS be a synonym for NOERROR
+ *
+ * TIME_OUT - a socket connection timed out.
+ * NO_INFO - the server didn't find any info about the host.
+ * ERROR - one of the following types of errors:
+ * dn_expand, res_mkquery failed
+ * bad command line, socket operation failed, etc.
+ * NONAUTH - the server didn't have the desired info but
+ * returned the name(s) of some servers who should.
+ * NO_RESPONSE - the server didn't respond.
+ *
+ */
+
+#define SUCCESS 0
+#define TIME_OUT -1
+#define NO_INFO -2
+#define ERROR -3
+#define NONAUTH -4
+#define NO_RESPONSE -5
+
+/*
+ * Define additional options for the resolver state structure.
+ *
+ * RES_DEBUG2 more verbose debug level
+ */
+
+#define RES_DEBUG2 0x80000000
+
+/*
+ * Maximum length of server, host and file names.
+ */
+
+#define NAME_LEN 256
+
+
+/*
+ * Modified struct hostent from <netdb.h>
+ *
+ * "Structures returned by network data base library. All addresses
+ * are supplied in host order, and returned in network order (suitable
+ * for use in system calls)."
+ */
+
+typedef struct {
+ char *name; /* official name of host */
+ char **domains; /* domains it serves */
+ char **addrList; /* list of addresses from name server */
+} ServerInfo;
+
+typedef struct {
+ char *name; /* official name of host */
+ char **aliases; /* alias list */
+ char **addrList; /* list of addresses from name server */
+ int addrType; /* host address type */
+ int addrLen; /* length of address */
+ ServerInfo **servers;
+} HostInfo;
+
+
+/*
+ * FilePtr is used for directing listings to a file.
+ * It is global so the Control-C handler can close it.
+ */
+
+extern FILE *filePtr;
+
+/*
+ * TCP/UDP port of server.
+ */
+extern unsigned short nsport;
+
+/*
+ * External routines:
+ */
+
+extern Boolean IsAddr();
+extern int Print_query();
+extern char *Print_cdname();
+extern char *Print_cdname2(); /* fixed width */
+extern char *Print_rr();
+extern char *DecodeType(); /* descriptive version of p_type */
+extern char *DecodeError();
+extern char *Calloc();
+extern char *Malloc();
+extern void NsError();
+extern void PrintServer();
+extern void PrintHostInfo();
+extern void ShowOptions();
+extern void FreeHostInfoPtr();
+extern FILE *OpenFile();
+extern char *res_skip();
diff --git a/usr.sbin/named/tools/nslookup/send.c b/usr.sbin/named/tools/nslookup/send.c
new file mode 100644
index 00000000000..1c65c616bc3
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/send.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 1985, 1989 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[] = "from: @(#)send.c 5.18 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: send.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * send.c --
+ *
+ * Routine to send request packets to a name server.
+ *
+ * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90".
+ *
+ *******************************************************************************
+ */
+
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "res.h"
+
+extern int errno;
+
+static int s = -1; /* socket used for communications */
+
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SETSIZE 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+#endif
+
+#define SR 1 /* SendRequest style */
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+unsigned short nsport = NAMESERVER_PORT;
+
+
+
+/*
+ *******************************************************************************
+ *
+ * SendRequest --
+ *
+ * Sends a request packet to a name server whose address
+ * is specified by the first argument and returns with
+ * the answer packet.
+ *
+ * Results:
+ * SUCCESS - the request was sent and an answer
+ * was received.
+ * TIME_OUT - the virtual circuit connection timed-out
+ * or a reply to a datagram wasn't received.
+ *
+ *
+ *******************************************************************************
+ */
+
+int
+SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
+ struct in_addr *nsAddrPtr;
+ char *buf;
+ int buflen;
+ char *answer;
+ u_int anslen;
+ int *trueLenPtr;
+{
+ register int n;
+ int try, v_circuit, resplen, ns;
+ int gotsomewhere = 0, connected = 0;
+ int connreset = 0;
+ u_short id, len;
+ char *cp;
+ fd_set dsmask;
+ struct timeval timeout;
+ HEADER *hp = (HEADER *) buf;
+ HEADER *anhp = (HEADER *) answer;
+ struct iovec iov[2];
+ int terrno = ETIMEDOUT;
+ char junk[512];
+
+#if SR
+ struct sockaddr_in sin;
+
+ if (_res.options & RES_DEBUG2) {
+ printf("------------\nSendRequest(), len %d\n", buflen);
+ Print_query(buf, buf+buflen, 1);
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(nsport);
+ sin.sin_addr = *nsAddrPtr;
+#else
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG) {
+ printf("res_send()\n");
+ p_query(buf);
+ }
+#endif DEBUG
+ if (!(_res.options & RES_INIT))
+ if (res_init() == -1) {
+ return(-1);
+ }
+#endif /* SR */
+ v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
+ id = hp->id;
+ /*
+ * Send request, RETRY times, or until successful
+ */
+ for (try = 0; try < _res.retry; try++) {
+#if !SR
+ for (ns = 0; ns < _res.nscount; ns++) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ printf("Querying server (# %d) address = %s\n", ns+1,
+ inet_ntoa(_res.nsaddr_list[ns].sin_addr));
+#endif DEBUG
+#endif /* !SR */
+ usevc:
+ if (v_circuit) {
+ int truncated = 0;
+
+ /*
+ * Use virtual circuit;
+ * at most one attempt per server.
+ */
+ try = _res.retry;
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("socket (vc) failed");
+#endif DEBUG
+ continue;
+ }
+#if SR
+ if (connect(s, (struct sockaddr *)&sin,
+#else
+ if (connect(s,
+ (struct sockaddr *)&(_res.nsaddr_list[ns]),
+#endif
+ sizeof(struct sockaddr)) < 0) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("connect failed");
+#endif DEBUG
+ (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) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("write failed");
+#endif DEBUG
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ /*
+ * Receive length & response
+ */
+ cp = answer;
+ len = sizeof(short);
+ while (len != 0 &&
+ (n = read(s, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+#endif DEBUG
+ (void) close(s);
+ s = -1;
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (terrno == ECONNRESET && !connreset) {
+ connreset = 1;
+ ns--;
+ }
+ continue;
+ }
+ cp = answer;
+ if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ fprintf(stderr, "response truncated\n");
+#endif DEBUG
+ len = anslen;
+ truncated = 1;
+ } else
+ len = resplen;
+ while (len != 0 &&
+ (n = read(s, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+#endif DEBUG
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ if (truncated) {
+ /*
+ * Flush rest of answer
+ * so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - anslen;
+ while (len != 0) {
+ n = (len > sizeof(junk) ?
+ sizeof(junk) : len);
+ if ((n = read(s, junk, n)) > 0)
+ len -= n;
+ else
+ break;
+ }
+ }
+ } else {
+ /*
+ * Use datagrams.
+ */
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ terrno = errno;
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("socket (dg) failed");
+#endif DEBUG
+ continue;
+ }
+ }
+#if SR
+ /*
+ * Special case the send code below
+ * since we have just 1 server.
+ */
+#if BSD >= 43
+ if (connected == 0) {
+ if (connect(s, (struct sockaddr *)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ if (_res.options & RES_DEBUG)
+ perror("connect");
+ continue;
+ }
+ connected = 1;
+ }
+ if (send(s, buf, buflen, 0) != buflen) {
+ if (_res.options & RES_DEBUG)
+ perror("send");
+ continue;
+ }
+#else /* BSD */
+ if (sendto(s, buf, buflen, 0, &sin,
+ sizeof(struct sockaddr)) != buflen) {
+ if (_res.options & RES_DEBUG)
+ perror("sendto");
+ continue;
+ }
+#endif
+#else /* SR */
+#if BSD >= 43
+ /*
+ * I'm tired of answering this question, so:
+ * On a 4.3BSD+ machine (client and server,
+ * actually), sending to a nameserver datagram
+ * port with no nameserver will cause an
+ * ICMP port unreachable message to be returned.
+ * If our datagram socket is "connected" to the
+ * server, we get an ECONNREFUSED error on the next
+ * socket operation, and select returns if the
+ * error message is received. We can thus detect
+ * the absence of a nameserver without timing out.
+ * If we have sent queries to at least two servers,
+ * however, we don't want to remain connected,
+ * as we wish to receive answers from the first
+ * server to respond.
+ */
+ if (_res.nscount == 1 || (try == 0 && ns == 0)) {
+ /*
+ * Don't use connect if we might
+ * still receive a response
+ * from another server.
+ */
+ if (connected == 0) {
+ if (connect(s, &_res.nsaddr_list[ns],
+ sizeof(struct sockaddr)) < 0) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("connect");
+#endif DEBUG
+ continue;
+ }
+ connected = 1;
+ }
+ if (send(s, buf, buflen, 0) != buflen) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("send");
+#endif DEBUG
+ continue;
+ }
+ } else {
+ /*
+ * Disconnect if we want to listen
+ * for responses from more than one server.
+ */
+ if (connected) {
+ (void) connect(s, &no_addr,
+ sizeof(no_addr));
+ connected = 0;
+ }
+#endif BSD
+ if (sendto(s, buf, buflen, 0,
+ &_res.nsaddr_list[ns],
+ sizeof(struct sockaddr)) != buflen) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("sendto");
+#endif DEBUG
+ continue;
+ }
+#if BSD >= 43
+ }
+#endif
+#endif /* SR */
+
+ /*
+ * Wait for reply
+ */
+ timeout.tv_sec = (_res.retrans << try);
+#if !SR
+ if (try > 0)
+ timeout.tv_sec /= _res.nscount;
+#endif /* SR */
+ if (timeout.tv_sec <= 0)
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+wait:
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ n = select(s+1, &dsmask, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout);
+ if (n < 0) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("select");
+#endif DEBUG
+ continue;
+ }
+ if (n == 0) {
+ /*
+ * timeout
+ */
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ printf("timeout (%d secs)\n",
+ timeout.tv_sec);
+#endif DEBUG
+#if BSD >= 43
+ gotsomewhere = 1;
+#endif
+ continue;
+ }
+ if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ perror("recvfrom");
+#endif DEBUG
+ continue;
+ }
+ gotsomewhere = 1;
+ if (id != anhp->id) {
+ /*
+ * response from old query, ignore it
+ */
+#if SR
+ if (_res.options & RES_DEBUG2) {
+ printf("------------\nOld answer:\n");
+ Print_query(answer, answer+resplen, 1);
+ }
+#else
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG) {
+ printf("old answer:\n");
+ p_query(answer);
+ }
+#endif DEBUG
+#endif
+ goto wait;
+ }
+ if (!(_res.options & RES_IGNTC) && anhp->tc) {
+ /*
+ * get rest of answer;
+ * use TCP with same server.
+ */
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ printf("truncated answer\n");
+#endif DEBUG
+ (void) close(s);
+ s = -1;
+ v_circuit = 1;
+ goto usevc;
+ }
+ }
+#if SR
+ if (_res.options & RES_DEBUG) {
+ if (_res.options & RES_DEBUG2)
+ printf("------------\nGot answer (%d bytes):\n",
+ resplen);
+ else
+ printf("------------\nGot answer:\n");
+ Print_query(answer, answer+resplen, 1);
+ }
+ (void) close(s);
+ s = -1;
+ *trueLenPtr = resplen;
+ return (SUCCESS);
+#else
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG) {
+ printf("got answer:\n");
+ p_query(answer);
+ }
+#endif DEBUG
+ /*
+ * If using virtual circuits, we assume that the first server
+ * is preferred * over the rest (i.e. it is on the local
+ * machine) and only keep that one open.
+ * If we have temporarily opened a virtual circuit,
+ * or if we haven't been asked to keep a socket open,
+ * close the socket.
+ */
+ if ((v_circuit &&
+ ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
+ (_res.options & RES_STAYOPEN) == 0) {
+ (void) close(s);
+ s = -1;
+ }
+ return (resplen);
+ }
+#endif /* SR */
+ }
+ if (s >= 0) {
+ (void) close(s);
+ s = -1;
+ }
+#if SR
+ if (v_circuit == 0)
+ if (gotsomewhere == 0)
+ return NO_RESPONSE; /* no nameservers found */
+ else
+ return TIME_OUT; /* no answer obtained */
+ else
+ if (errno == ECONNREFUSED)
+ return NO_RESPONSE;
+ else
+ return ERROR;
+#else
+ if (v_circuit == 0)
+ if (gotsomewhere == 0)
+ errno = ECONNREFUSED; /* no nameservers found */
+ else
+ errno = ETIMEDOUT; /* no answer obtained */
+ else
+ errno = terrno;
+ return (-1);
+#endif
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.
+ *
+ * Called from the interrupt handler.
+ */
+SendRequest_close()
+{
+ if (s != -1) {
+ (void) close(s);
+ s = -1;
+ }
+}
diff --git a/usr.sbin/named/tools/nslookup/skip.c b/usr.sbin/named/tools/nslookup/skip.c
new file mode 100644
index 00000000000..db997d9172c
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/skip.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1985 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[] = "from: @(#)skip.c 5.12 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: skip.c,v 1.1.1.1 1995/10/18 08:47:55 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * skip.c --
+ *
+ * Routines to skip over portions of a query buffer.
+ *
+ * Note: this file has been submitted for inclusion in
+ * BIND resolver library. When this has been done, this file
+ * is no longer necessary (assuming there haven't been any
+ * changes).
+ *
+ * Adapted from 4.3BSD BIND res_debug.c
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+
+char *res_skip_rr();
+
+
+/*
+ *******************************************************************************
+ *
+ * res_skip --
+ *
+ * Skip the contents of a query.
+ *
+ * Interpretation of numFieldsToSkip argument:
+ * res_skip returns pointer to:
+ * 1 -> start of question records.
+ * 2 -> start of authoritative answer records.
+ * 3 -> start of additional records.
+ * 4 -> first byte after end of additional records.
+ *
+ * Results:
+ * (address) - success operation.
+ * NULL - a resource record had an incorrect format.
+ *
+ *******************************************************************************
+ */
+
+char *
+res_skip(msg, numFieldsToSkip, eom)
+ char *msg;
+ int numFieldsToSkip;
+ char *eom;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int tmp;
+ register int n;
+
+ /*
+ * Skip the header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + sizeof(HEADER);
+
+ /*
+ * skip question records.
+ */
+ if (n = ntohs(hp->qdcount) ) {
+ while (--n >= 0 && cp < eom) {
+ tmp = dn_skipname((u_char *)cp, (u_char *)eom);
+ if (tmp == -1) return(NULL);
+ cp += tmp;
+ cp += sizeof(u_short); /* type */
+ cp += sizeof(u_short); /* class */
+ }
+ }
+ if (--numFieldsToSkip <= 0) return(cp);
+
+ /*
+ * skip authoritative answer records
+ */
+ if (n = ntohs(hp->ancount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+ if (--numFieldsToSkip == 0) return(cp);
+
+ /*
+ * skip name server records
+ */
+ if (n = ntohs(hp->nscount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+ if (--numFieldsToSkip == 0) return(cp);
+
+ /*
+ * skip additional records
+ */
+ if (n = ntohs(hp->arcount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+
+ return(cp);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * res_skip_rr --
+ *
+ * Skip over resource record fields.
+ *
+ * Results:
+ * (address) - success operation.
+ * NULL - a resource record had an incorrect format.
+ *******************************************************************************
+ */
+
+char *
+res_skip_rr(cp, eom)
+ char *cp;
+ char *eom;
+{
+ int tmp;
+ int dlen;
+
+ if ((tmp = dn_skipname((u_char *)cp, (u_char *)eom)) == -1)
+ return (NULL); /* compression error */
+ cp += tmp;
+ if ((cp + RRFIXEDSZ) > eom)
+ return (NULL);
+ cp += sizeof(u_short); /* type */
+ cp += sizeof(u_short); /* class */
+ cp += sizeof(u_long); /* ttl */
+ dlen = _getshort(cp);
+ cp += sizeof(u_short); /* dlen */
+ cp += dlen;
+ if (cp > eom)
+ return (NULL);
+ return (cp);
+}
diff --git a/usr.sbin/named/tools/nslookup/subr.c b/usr.sbin/named/tools/nslookup/subr.c
new file mode 100644
index 00000000000..89492b8f4ce
--- /dev/null
+++ b/usr.sbin/named/tools/nslookup/subr.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 1985,1989 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[] = "from: @(#)subr.c 5.24 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: subr.c,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * subr.c --
+ *
+ * Miscellaneous subroutines for the name server
+ * lookup program.
+ *
+ * Copyright (c) 1985
+ * Andrew Cherenson
+ * U.C. Berkeley
+ * CS298-26 Fall 1985
+ *
+ *******************************************************************************
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "res.h"
+
+
+
+/*
+ *******************************************************************************
+ *
+ * IntrHandler --
+ *
+ * This routine is called whenever a control-C is typed.
+ * It performs three main functions:
+ * - closes an open socket connection,
+ * - closes an open output file (used by LookupHost, et al.),
+ * - jumps back to the main read-eval loop.
+ *
+ * If a user types a ^C in the middle of a routine that uses a socket,
+ * the routine would not be able to close the socket. To prevent an
+ * overflow of the process's open file table, the socket and output
+ * file descriptors are closed by the interrupt handler.
+ *
+ * Side effects:
+ * Open file descriptors are closed.
+ * If filePtr is valid, it is closed.
+ * Flow of control returns to the main() routine.
+ *
+ *******************************************************************************
+ */
+
+void
+IntrHandler()
+{
+ extern jmp_buf env;
+#if defined(BSD) && BSD >= 199006
+ extern FILE *yyin; /* scanner input file */
+ extern void yyrestart(); /* routine to restart scanner after interrupt */
+#endif
+
+ SendRequest_close();
+ ListHost_close();
+ if (filePtr != NULL && filePtr != stdout) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ printf("\n");
+#if defined(BSD) && BSD >= 199006
+ yyrestart(yyin);
+#endif
+ longjmp(env, 1);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * Malloc --
+ * Calloc --
+ *
+ * Calls the malloc library routine with SIGINT blocked to prevent
+ * corruption of malloc's data structures. We need to do this because
+ * a control-C doesn't kill the program -- it causes a return to the
+ * main command loop.
+ *
+ * NOTE: This method doesn't prevent the pointer returned by malloc
+ * from getting lost, so it is possible to get "core leaks".
+ *
+ * If malloc fails, the program exits.
+ *
+ * Results:
+ * (address) - address of new buffer.
+ *
+ *******************************************************************************
+ */
+
+char *
+Malloc(size)
+ int size;
+{
+ char *ptr;
+
+#ifdef SYSV
+#ifdef SVR3
+ sighold(SIGINT);
+ ptr = malloc((unsigned) size);
+ sigrelse(SIGINT);
+#else
+ { int (*old)();
+ old = signal(SIGINT, SIG_IGN);
+ ptr = malloc((unsigned) size);
+ signal(SIGINT, old);
+ }
+#endif
+#else
+ { int saveMask;
+ saveMask = sigblock(sigmask(SIGINT));
+ ptr = malloc((unsigned) size);
+ (void) sigsetmask(saveMask);
+ }
+#endif
+ if (ptr == NULL) {
+ fflush(stdout);
+ fprintf(stderr, "*** Can't allocate memory\n");
+ fflush(stderr);
+ abort();
+ /*NOTREACHED*/
+ } else {
+ return(ptr);
+ }
+}
+
+char *
+Calloc(num, size)
+ register int num, size;
+{
+ char *ptr = Malloc(num*size);
+ bzero(ptr, num*size);
+ return(ptr);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * PrintHostInfo --
+ *
+ * Prints out the HostInfo structure for a host.
+ *
+ *******************************************************************************
+ */
+
+void
+PrintHostInfo(file, title, hp)
+ FILE *file;
+ char *title;
+ register HostInfo *hp;
+{
+ register char **cp;
+ register ServerInfo **sp;
+ char comma;
+ int i;
+
+ fprintf(file, "%-7s %s", title, hp->name);
+
+ if (hp->addrList != NULL) {
+ if (hp->addrList[1] != NULL) {
+ fprintf(file, "\nAddresses:");
+ } else {
+ fprintf(file, "\nAddress:");
+ }
+ comma = ' ';
+ i = 0;
+ for (cp = hp->addrList; cp && *cp; cp++) {
+ i++;
+ if (i > 4) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 0;
+ }
+ fprintf(file,"%c %s", comma, inet_ntoa(*(struct in_addr *)*cp));
+ comma = ',';
+ }
+ }
+
+ if (hp->aliases != NULL) {
+ fprintf(file, "\nAliases:");
+ comma = ' ';
+ i = 10;
+ for (cp = hp->aliases; cp && *cp && **cp; cp++) {
+ i += strlen(*cp) + 2;
+ if (i > 75) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 10;
+ }
+ fprintf(file, "%c %s", comma, *cp);
+ comma = ',';
+ }
+ }
+
+ if (hp->servers != NULL) {
+ fprintf(file, "\nServed by:\n");
+ for (sp = hp->servers; *sp != NULL ; sp++) {
+
+ fprintf(file, "- %s\n\t", (*sp)->name);
+
+ comma = ' ';
+ i = 0;
+ for (cp = (*sp)->addrList; cp && *cp && **cp; cp++) {
+ i++;
+ if (i > 4) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 0;
+ }
+ fprintf(file,
+ "%c %s", comma, inet_ntoa(*(struct in_addr *)*cp));
+ comma = ',';
+ }
+ fprintf(file, "\n\t");
+
+ comma = ' ';
+ i = 10;
+ for (cp = (*sp)->domains; cp && *cp && **cp; cp++) {
+ i += strlen(*cp) + 2;
+ if (i > 75) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 10;
+ }
+ fprintf(file, "%c %s", comma, *cp);
+ comma = ',';
+ }
+ fprintf(file, "\n");
+ }
+ }
+
+ fprintf(file, "\n\n");
+}
+
+/*
+ *******************************************************************************
+ *
+ * OpenFile --
+ *
+ * Parses a command string for a file name and opens
+ * the file.
+ *
+ * Results:
+ * file pointer - the open was successful.
+ * NULL - there was an error opening the file or
+ * the input string was invalid.
+ *
+ *******************************************************************************
+ */
+
+FILE *
+OpenFile(string, file)
+ char *string;
+ char *file;
+{
+ char *redirect;
+ FILE *tmpPtr;
+
+ /*
+ * Open an output file if we see '>' or >>'.
+ * Check for overwrite (">") or concatenation (">>").
+ */
+
+ redirect = strchr(string, '>');
+ if (redirect == NULL) {
+ return(NULL);
+ }
+ if (redirect[1] == '>') {
+ sscanf(redirect, ">> %s", file);
+ tmpPtr = fopen(file, "a+");
+ } else {
+ sscanf(redirect, "> %s", file);
+ tmpPtr = fopen(file, "w");
+ }
+
+ if (tmpPtr != NULL) {
+ redirect[0] = '\0';
+ }
+
+ return(tmpPtr);
+}
+
+/*
+ *******************************************************************************
+ *
+ * DecodeError --
+ *
+ * Converts an error code into a character string.
+ *
+ *******************************************************************************
+ */
+
+char *
+DecodeError(result)
+ int result;
+{
+ switch (result) {
+ case NOERROR: return("Success"); break;
+ case FORMERR: return("Format error"); break;
+ case SERVFAIL: return("Server failed"); break;
+ case NXDOMAIN: return("Non-existent domain"); break;
+ case NOTIMP: return("Not implemented"); break;
+ case REFUSED: return("Query refused"); break;
+ case NOCHANGE: return("No change"); break;
+ case TIME_OUT: return("Timed out"); break;
+ case NO_INFO: return("No information"); break;
+ case ERROR: return("Unspecified error"); break;
+ case NONAUTH: return("Non-authoritative answer"); break;
+ case NO_RESPONSE: return("No response from server"); break;
+ default: break;
+ }
+ return("BAD ERROR VALUE");
+}
+
+
+int
+StringToClass(class, dflt)
+ char *class;
+ int dflt;
+{
+ if (strcasecmp(class, "IN") == 0)
+ return(C_IN);
+ if (strcasecmp(class, "HESIOD") == 0 ||
+ strcasecmp(class, "HS") == 0)
+ return(C_HS);
+ if (strcasecmp(class, "CHAOS") == 0)
+ return(C_CHAOS);
+ if (strcasecmp(class, "ANY") == 0)
+ return(C_ANY);
+ fprintf(stderr, "unknown query class: %s\n", class);
+ return(dflt);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * StringToType --
+ *
+ * Converts a string form of a query type name to its
+ * corresponding integer value.
+ *
+ *******************************************************************************
+ */
+
+int
+StringToType(type, dflt)
+ char *type;
+ int dflt;
+{
+ if (strcasecmp(type, "A") == 0)
+ return(T_A);
+ if (strcasecmp(type, "NS") == 0)
+ return(T_NS); /* authoritative server */
+ if (strcasecmp(type, "MX") == 0)
+ return(T_MX); /* mail exchanger */
+ if (strcasecmp(type, "CNAME") == 0)
+ return(T_CNAME); /* canonical name */
+ if (strcasecmp(type, "SOA") == 0)
+ return(T_SOA); /* start of authority zone */
+ if (strcasecmp(type, "MB") == 0)
+ return(T_MB); /* mailbox domain name */
+ if (strcasecmp(type, "MG") == 0)
+ return(T_MG); /* mail group member */
+ if (strcasecmp(type, "MR") == 0)
+ return(T_MR); /* mail rename name */
+ if (strcasecmp(type, "WKS") == 0)
+ return(T_WKS); /* well known service */
+ if (strcasecmp(type, "PTR") == 0)
+ return(T_PTR); /* domain name pointer */
+ if (strcasecmp(type, "HINFO") == 0)
+ return(T_HINFO); /* host information */
+ if (strcasecmp(type, "MINFO") == 0)
+ return(T_MINFO); /* mailbox information */
+ if (strcasecmp(type, "AXFR") == 0)
+ return(T_AXFR); /* zone transfer */
+ if (strcasecmp(type, "MAILA") == 0)
+ return(T_MAILA); /* mail agent */
+ if (strcasecmp(type, "MAILB") == 0)
+ return(T_MAILB); /* mail box */
+ if (strcasecmp(type, "ANY") == 0)
+ return(T_ANY); /* matches any type */
+ if (strcasecmp(type, "UINFO") == 0)
+ return(T_UINFO); /* user info */
+ if (strcasecmp(type, "UID") == 0)
+ return(T_UID); /* user id */
+ if (strcasecmp(type, "GID") == 0)
+ return(T_GID); /* group id */
+ if (strcasecmp(type, "TXT") == 0)
+ return(T_TXT); /* text */
+ fprintf(stderr, "unknown query type: %s\n", type);
+ return(dflt);
+}
+
+/*
+ *******************************************************************************
+ *
+ * DecodeType --
+ *
+ * Converts a query type to a descriptive name.
+ * (A more verbose form of p_type.)
+ *
+ *
+ *******************************************************************************
+ */
+
+static char nbuf[20];
+
+char *
+DecodeType(type)
+ int type;
+{
+ switch (type) {
+ case T_A:
+ return("address");
+ case T_NS:
+ return("name server");
+ case T_CNAME:
+ return("canonical name");
+ case T_SOA:
+ return("start of authority");
+ case T_MB:
+ return("mailbox");
+ case T_MG:
+ return("mail group member");
+ case T_MR:
+ return("mail rename");
+ case T_NULL:
+ return("null");
+ case T_WKS:
+ return("well-known service");
+ case T_PTR:
+ return("domain name pointer");
+ case T_HINFO:
+ return("host information");
+ case T_MINFO:
+ return("mailbox information");
+ case T_MX:
+ return("mail exchanger");
+ case T_TXT:
+ return("text");
+ case T_UINFO:
+ return("user information");
+ case T_UID:
+ return("user ID");
+ case T_GID:
+ return("group ID");
+ case T_AXFR:
+ return("zone transfer");
+ case T_MAILB:
+ return("mailbox-related data");
+ case T_MAILA:
+ return("mail agent");
+ case T_ANY:
+ return("\"any\"");
+ default:
+ (void) sprintf(nbuf, "%d", type);
+ return (nbuf);
+ }
+}
diff --git a/usr.sbin/named/tools/nsquery/Makefile b/usr.sbin/named/tools/nsquery/Makefile
new file mode 100644
index 00000000000..35b086467ea
--- /dev/null
+++ b/usr.sbin/named/tools/nsquery/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.1 (Berkeley) 5/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $
+
+PROG= nsquery
+NOMAN= noman
+
+.include "../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/tools/nsquery/nsquery.c b/usr.sbin/named/tools/nsquery/nsquery.c
new file mode 100644
index 00000000000..2a43e818efe
--- /dev/null
+++ b/usr.sbin/named/tools/nsquery/nsquery.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1986 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
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)nsquery.c 4.8 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: nsquery.c,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <stdio.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register struct hostent *hp;
+ register char *s;
+
+ if (argc >= 2 && strcmp(argv[1], "-d") == 0) {
+ _res.options |= RES_DEBUG;
+ argc--;
+ argv++;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "usage: nsquery [-d] host [server]\n");
+ exit(1);
+ }
+ if (argc == 3) {
+ hp = gethostbyname(argv[2]);
+ if (hp == NULL) {
+ fprintf(stderr, "nsquery:");
+ herror(argv[2]);
+ exit(1);
+ }
+ printf("\nServer:\n");
+ printanswer(hp);
+ _res.nsaddr.sin_addr = *(struct in_addr *)hp->h_addr;
+ }
+
+ hp = gethostbyname(argv[1]);
+ if (hp == NULL) {
+ fprintf(stderr, "nsquery: %s: ", argv[1]);
+ herror((char *)NULL);
+ exit(1);
+ }
+ printanswer(hp);
+ exit(0);
+}
+
+printanswer(hp)
+ register struct hostent *hp;
+{
+ register char **cp;
+ extern char *inet_ntoa();
+
+ printf("Name: %s\n", hp->h_name);
+#if BSD >= 43 || defined(h_addr)
+ printf("Addresses:");
+ for (cp = hp->h_addr_list; cp && *cp; cp++)
+ printf(" %s", inet_ntoa(*(struct in_addr *)(*cp)));
+ printf("\n");
+#else
+ printf("Address: %s\n", inet_ntoa(*(struct in_addr *)hp->h_addr));
+#endif
+ printf("Aliases:");
+ for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
+ printf(" %s", *cp);
+ printf("\n\n");
+}
diff --git a/usr.sbin/named/tools/nstest/Makefile b/usr.sbin/named/tools/nstest/Makefile
new file mode 100644
index 00000000000..bde53d0cb5c
--- /dev/null
+++ b/usr.sbin/named/tools/nstest/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.1 (Berkeley) 5/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $
+
+PROG= nstest
+NOMAN= noman
+
+.include "../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/tools/nstest/nstest.c b/usr.sbin/named/tools/nstest/nstest.c
new file mode 100644
index 00000000000..e9ee33cb21a
--- /dev/null
+++ b/usr.sbin/named/tools/nstest/nstest.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1986, 1989 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
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)nstest.c 4.15 (Berkeley) 3/21/91";*/
+static char rcsid[] = "$Id: nstest.c,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char *inet_ntoa();
+char *progname;
+FILE *log;
+#define MAXDATA 256 /* really should get definition from named/db.h */
+main(argc, argv)
+ char **argv;
+{
+ register char *cp;
+ struct hostent *hp;
+ u_short port = htons(NAMESERVER_PORT);
+ char buf[BUFSIZ];
+ char packet[PACKETSZ];
+ char answer[PACKETSZ];
+ struct rrec NewRR;
+ char OldRRData[MAXDATA];
+ int n, dump_packet;
+
+ NewRR.r_data = (char *) malloc(MAXDATA);
+ NewRR.r_data = (char *) malloc(MAXDATA);
+ progname = argv[0];
+ dump_packet = 0;
+ _res.options |= RES_DEBUG|RES_RECURSE;
+ (void) res_init();
+ while (argc > 1 && argv[1][0] == '-') {
+ argc--;
+ cp = *++argv;
+ while (*++cp)
+ switch (*cp) {
+ case 'p':
+ if (--argc <= 0)
+ usage();
+ port = htons(atoi(*++argv));
+ break;
+
+ case 'i':
+ _res.options |= RES_IGNTC;
+ break;
+
+ case 'v':
+ _res.options |= RES_USEVC|RES_STAYOPEN;
+ break;
+
+ case 'r':
+ _res.options &= ~RES_RECURSE;
+ break;
+
+ case 'd':
+ dump_packet++;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ _res.nsaddr.sin_family = AF_INET;
+ _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
+ _res.nsaddr.sin_port = port;
+ if (argc > 1) {
+ _res.nsaddr.sin_addr.s_addr = inet_addr(argv[1]);
+ if (_res.nsaddr.sin_addr.s_addr == (u_long) -1)
+ usage();
+ }
+ if (argc > 2) {
+ log = fopen(argv[2],"w");
+ if (log == NULL) perror(argv[2]);
+ }
+ for (;;) {
+ printf("> ");
+ fflush(stdout);
+ if ((cp = (char *)gets(buf)) == NULL)
+ break;
+ switch (*cp++) {
+ case 'a':
+ n = res_mkquery(QUERY, cp, C_IN, T_A, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'A':
+ n = ntohl(inet_addr(cp));
+ putlong((u_long)n, (u_char *)cp);
+ n = res_mkquery(IQUERY, "", C_IN, T_A, cp, sizeof(long),
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'f':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UINFO, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'g':
+ n = res_mkquery(QUERY, cp, C_ANY, T_GID, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'G':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_GID, cp,
+ sizeof(int), NULL, packet, sizeof(packet));
+ break;
+
+ case 'c':
+ n = res_mkquery(QUERY, cp, C_IN, T_CNAME, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'h':
+ n = res_mkquery(QUERY, cp, C_IN, T_HINFO, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'm':
+ n = res_mkquery(QUERY, cp, C_IN, T_MX, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'M':
+ n = res_mkquery(QUERY, cp, C_IN, T_MAILB, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'n':
+ n = res_mkquery(QUERY, cp, C_IN, T_NS, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'p':
+ n = res_mkquery(QUERY, cp, C_IN, T_PTR, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 's':
+ n = res_mkquery(QUERY, cp, C_IN, T_SOA, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'T':
+ n = res_mkquery(QUERY, cp, C_IN, T_TXT, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'u':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UID, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'U':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_UID, cp,
+ sizeof(int), NULL, packet, sizeof(packet));
+ break;
+
+ case 'x':
+ n = res_mkquery(QUERY, cp, C_IN, T_AXFR, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'w':
+ n = res_mkquery(QUERY, cp, C_IN, T_WKS, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'b':
+ n = res_mkquery(QUERY, cp, C_IN, T_MB, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'B':
+ n = res_mkquery(QUERY, cp, C_IN, T_MG, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'i':
+ n = res_mkquery(QUERY, cp, C_IN, T_MINFO, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case 'r':
+ n = res_mkquery(QUERY, cp, C_IN, T_MR, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+ case '*':
+ n = res_mkquery(QUERY, cp, C_IN, T_ANY, (char *)0, 0,
+ NULL, packet, sizeof(packet));
+ break;
+
+#ifdef ALLOW_UPDATES
+ case '^':
+ {
+ char IType[10], TempStr[50];
+ int Type, oldnbytes, nbytes, i;
+#ifdef ALLOW_T_UNSPEC
+ printf("Data type (a = T_A, u = T_UNSPEC): ");
+ gets(IType);
+ if (IType[0] == 'u') {
+ Type = T_UNSPEC;
+ printf("How many data bytes? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &nbytes);
+ for (i = 0; i < nbytes; i++) {
+ (NewRR.r_data)[i] = (char) i;
+ }
+ } else {
+#endif ALLOW_T_UNSPEC
+ Type = T_A;
+ nbytes = sizeof(u_long);
+ printf("Inet addr for new dname (e.g., 192.4.3.2): ");
+ gets(TempStr);
+ putlong(ntohl(inet_addr(TempStr)),
+ NewRR.r_data);
+#ifdef ALLOW_T_UNSPEC
+ }
+#endif ALLOW_T_UNSPEC
+ NewRR.r_class = C_IN;
+ NewRR.r_type = Type;
+ NewRR.r_size = nbytes;
+ NewRR.r_ttl = 99999999;
+ printf("Add, modify, or modify all (a/m/M)? ");
+ gets(TempStr);
+ if (TempStr[0] == 'a') {
+ n = res_mkquery(UPDATEA, cp, C_IN, Type,
+ OldRRData, nbytes,
+ &NewRR, packet,
+ sizeof(packet));
+ } else {
+ if (TempStr[0] == 'm') {
+ printf("How many data bytes in old RR? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &oldnbytes);
+ for (i = 0; i < oldnbytes; i++) {
+ OldRRData[i] = (char) i;
+ }
+ n = res_mkquery(UPDATEM, cp, C_IN, Type,
+ OldRRData, oldnbytes,
+ &NewRR, packet,
+ sizeof(packet));
+ } else { /* Modify all */
+ n = res_mkquery(UPDATEMA, cp,
+ C_IN, Type, NULL, 0,
+ &NewRR, packet,
+ sizeof(packet));
+
+ }
+ }
+ }
+ break;
+
+#ifdef ALLOW_T_UNSPEC
+ case 'D':
+ n = res_mkquery(UPDATEDA, cp, C_IN, T_UNSPEC, (char *)0,
+ 0, NULL, packet, sizeof(packet));
+ break;
+
+ case 'd':
+ {
+ char TempStr[100];
+ int nbytes, i;
+ printf("How many data bytes in oldrr data? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &nbytes);
+ for (i = 0; i < nbytes; i++) {
+ OldRRData[i] = (char) i;
+ }
+ n = res_mkquery(UPDATED, cp, C_IN, T_UNSPEC,
+ OldRRData, nbytes, NULL, packet,
+ sizeof(packet));
+ }
+ break;
+#endif ALLOW_T_UNSPEC
+#endif ALLOW_UPDATES
+
+ default:
+ printf("a{host} - query T_A\n");
+ printf("A{addr} - iquery T_A\n");
+ printf("b{user} - query T_MB\n");
+ printf("B{user} - query T_MG\n");
+ printf("f{host} - query T_UINFO\n");
+ printf("g{host} - query T_GID\n");
+ printf("G{gid} - iquery T_GID\n");
+ printf("h{host} - query T_HINFO\n");
+ printf("i{host} - query T_MINFO\n");
+ printf("p{host} - query T_PTR\n");
+ printf("m{host} - query T_MX\n");
+ printf("M{host} - query T_MAILB\n");
+ printf("n{host} - query T_NS\n");
+ printf("r{host} - query T_MR\n");
+ printf("s{host} - query T_SOA\n");
+ printf("T{host} - query T_TXT\n");
+ printf("u{host} - query T_UID\n");
+ printf("U{uid} - iquery T_UID\n");
+ printf("x{host} - query T_AXFR\n");
+ printf("w{host} - query T_WKS\n");
+ printf("c{host} - query T_CNAME\n");
+ printf("*{host} - query T_ANY\n");
+#ifdef ALLOW_UPDATES
+ printf("^{host} - add/mod/moda (T_A/T_UNSPEC)\n");
+#ifdef ALLOW_T_UNSPEC
+ printf("D{host} - deletea T_UNSPEC\n");
+ printf("d{host} - delete T_UNSPEC\n");
+#endif ALLOW_T_UNSPEC
+#endif ALLOW_UPDATES
+ continue;
+ }
+ if (n < 0) {
+ printf("res_mkquery: buffer too small\n");
+ continue;
+ }
+ if (log) {
+ fprintf(log,"SEND QUERY\n");
+ fp_query(packet, log);
+ }
+ n = res_send(packet, n, answer, sizeof(answer));
+ if (n < 0) {
+ printf("res_send: send error\n");
+ if (log) fprintf(log, "res_send: send error\n");
+ }
+ else {
+ if (dump_packet) {
+ int f;
+ f = creat("ns_packet.dump", 0644);
+ write(f, answer, n);
+ (void) close(f);
+ }
+ if (log) {
+ fprintf(log, "GOT ANSWER\n");
+ fp_query(answer, log);
+ }
+ }
+ }
+}
+
+usage()
+{
+ fprintf(stderr, "Usage: %s [-v] [-i] [-r] [-d] [-p port] hostaddr\n",
+ progname);
+ exit(1);
+}
diff --git a/usr.sbin/named/xfer/Makefile b/usr.sbin/named/xfer/Makefile
new file mode 100644
index 00000000000..2e5f16f3a07
--- /dev/null
+++ b/usr.sbin/named/xfer/Makefile
@@ -0,0 +1,12 @@
+# from: @(#)Makefile 5.1 (Berkeley) 5/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $
+
+PROG= named-xfer
+SRCS= named-xfer.c db_glue.c
+CFLAGS+=-I${.CURDIR}/..
+.PATH: ${.CURDIR}/..
+BINDIR= /usr/libexec
+MAN= named-xfer.8
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/xfer/named-xfer.8 b/usr.sbin/named/xfer/named-xfer.8
new file mode 100644
index 00000000000..d12700ea823
--- /dev/null
+++ b/usr.sbin/named/xfer/named-xfer.8
@@ -0,0 +1,148 @@
+.\" ++Copyright++ 1985
+.\" -
+.\" Copyright (c) 1985
+.\" 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.
+.\" -
+.\" Portions Copyright (c) 1993 by Digital Equipment Corporation.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies, and that
+.\" the name of Digital Equipment Corporation not be used in advertising or
+.\" publicity pertaining to distribution of the document or software without
+.\" specific, written prior permission.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+.\" WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+.\" CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+.\" SOFTWARE.
+.\" -
+.\" --Copyright--
+.\"
+.\" from: named.8 6.6 (Berkeley) 2/14/89
+.\" $NetBSD: named-xfer.8,v 1.2 1994/11/29 23:56:29 glass Exp $
+.\"
+.TH NAMED-XFER 8 "June 26, 1993"
+.UC 4
+.SH NAME
+named-xfer \- ancillary agent for inbound zone transfers
+.SH SYNOPSIS
+.B named-xfer
+.B \-z
+.I zone_to_transfer
+.B \-f
+.I db_file
+.B \-s
+.I serial_no
+[
+.B \-d
+.I debuglevel
+] [
+.B \-l
+.I debug_log_file
+] [
+.B \-t
+.I trace_file
+] [
+.B \-p
+.I port#
+] [
+.B \-S
+]
+.I nameserver
+...
+.SH DESCRIPTION
+.I Named-xfer
+is an ancillary program executed by
+.IR named (8)
+to perform an inbound zone transfer. It is rarely executed directly, and
+only by system administrators who are trying to debug a zone transfer problem.
+See RFC's 1033, 1034, and 1035 for more information on the Internet
+name-domain system.
+.PP
+Options are:
+.TP
+.B \-z
+specifies the name of the zone to be transferred.
+.TP
+.B \-f
+specifies the name of the file into which the zone should be dumped
+when it is received from the primary server.
+.TP
+.B \-s
+specifies the serial number of our current copy of this zone. If the
+\s-1SOA RR\s+1 we get from the primary server does not have a serial
+number higher than this, the transfer will be aborted.
+.TP
+.B \-d
+Print debugging information.
+A number after the ``d'' determines the level of
+messages printed.
+.TP
+.B \-l
+Specifies a log file for debugging messages. The default is system-
+dependent but is usually in
+.I /var/tmp
+or
+.IR /usr/tmp .
+Note that this only applies if
+.I \-d
+is also specified.
+.TP
+.B \-t
+Specifies a trace file which will contain a protocol trace of the zone
+transfer. This is probably only of interest to people debugging the name
+server itself.
+.TP
+.B \-p
+Use a different port number. The default is the standard port number
+as returned by getservbyname(3) for service ``domain''.
+.TP
+.B \-S
+Perform a restricted transfer of only the SOA, NS records and glue A
+records for the zone. The SOA record will not be loaded by named but
+will be used to determine when to verify the NS records.
+the ``stubs'' directive in
+.IR named (8)
+for more information.
+.PP
+Additional arguments are taken as name server addresses in so-called
+``dotted-quad'' syntax only; no host name are allowed here. At least
+one address must be specified. Any additional addresses will be tried
+in order if the first one fails to transfer to us successfully.
+.SH "SEE ALSO"
+named(8), resolver(3), resolver(5), hostname(7),
+RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, RFC 1123,
+\fIName Server Operations Guide for \s-1BIND\s+1\fR
diff --git a/usr.sbin/named/xfer/named-xfer.c b/usr.sbin/named/xfer/named-xfer.c
new file mode 100644
index 00000000000..5f6bc0122ab
--- /dev/null
+++ b/usr.sbin/named/xfer/named-xfer.c
@@ -0,0 +1,1233 @@
+/*-
+ * Copyright (c) 1988, 1990 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.
+ *
+ * The original version of xfer by Kevin Dunlap.
+ * Completed and integrated with named by David Waitzman
+ * (dwaitzman@bbn.com) 3/14/88.
+ * Modified by M. Karels and O. Kure 10-88.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)named-xfer.c 4.18 (Berkeley) 3/7/91";*/
+static char rcsid[] = "$Id: named-xfer.c,v 1.1.1.1 1995/10/18 08:47:56 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/signal.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#define XFER /* modifies the ns.h include file */
+#include "ns.h"
+#include "pathnames.h"
+
+char *savestr();
+
+/* max length of data in RR data field */
+#define MAXDATA 2048 /* from db.h */
+
+int debug = 0;
+int quiet = 0;
+int read_interrupted = 0;
+struct zoneinfo zones; /* zone information */
+struct timeval tt;
+
+static char ddtfilename[] = _PATH_TMPXFER;
+static char *ddtfile = ddtfilename;
+static char *tmpname;
+FILE *fp = 0, *ddt, *dbfp;
+char *domain; /* domain being xfered */
+int domain_len; /* strlen(domain) */
+
+extern int errno;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct zoneinfo *zp;
+ register struct hostent *hp;
+ char *dbfile = NULL, *tracefile = NULL, *tm = NULL;
+ int dbfd, ddtd, result, c;
+ u_long serial_no = 0;
+ extern char *optarg;
+ extern int optind, getopt();
+ u_short port = htons(NAMESERVER_PORT);
+
+ (void) umask(022);
+#ifdef LOG_DAEMON
+ openlog("named-xfer", LOG_PID|LOG_CONS, LOG_DAEMON);
+#else
+ openlog("named-xfer", LOG_PID);
+#endif
+ while ((c = getopt(argc, argv, "d:l:s:t:z:f:p:P:q")) != EOF)
+ switch (c) {
+ case 'd':
+ debug = atoi(optarg);
+ break;
+ case 'l':
+ ddtfile = (char *)malloc(strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+ (void) strcpy(ddtfile, optarg);
+ (void) strcat(ddtfile, ".XXXXXX");
+ break;
+ case 's':
+ serial_no = (u_long) atol(optarg);
+ break;
+ case 't':
+ tracefile = optarg;
+ break;
+ case 'z': /* zone == domain */
+ domain = optarg;
+ domain_len = strlen(domain);
+ break;
+ case 'f':
+ dbfile = optarg;
+ tmpname = (char *)malloc((unsigned)strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+ (void) strcpy(tmpname, optarg);
+ break;
+ case 'p':
+ port = htons((u_short)atoi(optarg));
+ break;
+ case 'P':
+ port = (u_short)atoi(optarg);
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (!domain || !dbfile || optind >= argc) {
+ usage();
+ /* NOTREACHED */
+ }
+ if (tracefile && (fp = fopen(tracefile, "w")) == NULL)
+ perror(tracefile);
+ (void) strcat(tmpname, ".XXXXXX");
+ /* tmpname is now something like "/etc/named/named.bu.db.XXXXXX" */
+ if ((dbfd = mkstemp(tmpname)) == -1) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't make tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+ if (fchmod(dbfd, 0644) == -1) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't fchmod tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+ if ((dbfp = fdopen(dbfd, "r+")) == NULL) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname);
+ exit(XFER_FAIL);
+ }
+#ifdef DEBUG
+ if (debug) {
+ /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */
+ if ((ddtd = mkstemp(ddtfile)) == -1) {
+ perror(ddtfile);
+ debug = 0;
+ } else if (fchmod(ddtd, 0644) == -1) {
+ perror(ddtfile);
+ debug = 0;
+ } else if ((ddt = fdopen(ddtd, "w")) == NULL) {
+ perror(ddtfile);
+ debug = 0;
+ } else {
+#if defined(SYSV)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ }
+ }
+#endif
+ /*
+ * Ignore many types of signals that named (assumed to be our parent)
+ * considers important- if not, the user controlling named with
+ * signals usually kills us.
+ */
+ (void) signal(SIGHUP, SIG_IGN);
+ (void) signal(SIGSYS, SIG_IGN);
+ if (debug == 0) {
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ }
+ (void) signal(SIGIOT, SIG_IGN);
+
+#if defined(SIGUSR1) && defined(SIGUSR2)
+ (void) signal(SIGUSR1, SIG_IGN);
+ (void) signal(SIGUSR2, SIG_IGN);
+#else SIGUSR1&&SIGUSR2
+ (void) signal(SIGEMT, SIG_IGN);
+ (void) signal(SIGFPE, SIG_IGN);
+#endif SIGUSR1&&SIGUSR2
+
+#ifdef DEBUG
+ if (debug) (void)fprintf(ddt, "domain `%s' file `%s' ser no %lu \n",
+ domain, dbfile,serial_no);
+#endif
+ buildservicelist();
+ buildprotolist();
+
+ /* init zone data */
+
+ zp = &zones;
+ zp->z_type = Z_SECONDARY;
+ zp->z_origin = domain;
+ zp->z_source = dbfile;
+ zp->z_addrcnt = 0;
+#ifdef DEBUG
+ if (debug) {
+ (void)fprintf(ddt,"zone found (%d): ", zp->z_type);
+ if (zp->z_origin[0] == '\0')
+ (void)fprintf(ddt,"'.'");
+ else
+ (void)fprintf(ddt,"'%s'", zp->z_origin);
+ (void)fprintf(ddt,", source = %s\n", zp->z_source);
+ }
+#endif
+ for (; optind != argc; optind++,zp->z_addrcnt++) {
+ tm = argv[optind];
+ zp->z_addr[zp->z_addrcnt].s_addr = inet_addr(tm);
+
+ if (zp->z_addr[zp->z_addrcnt].s_addr == (unsigned)-1) {
+ hp = gethostbyname(tm);
+ if (hp == NULL) {
+ syslog(LOG_ERR, "uninterpretable server %s\n",
+ tm);
+ continue;
+ }
+ bcopy(hp->h_addr,
+ (char *)&zp->z_addr[zp->z_addrcnt].s_addr,
+ sizeof(zp->z_addr[zp->z_addrcnt].s_addr));
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,", %s",tm);
+#endif
+ }
+ if (zp->z_addrcnt >= NSMAX) {
+ zp->z_addrcnt = NSMAX;
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt, "\nns.h NSMAX reached\n");
+#endif
+ break;
+ }
+ }
+#ifdef DEBUG
+ if (debug) (void)fprintf(ddt," (addrcnt) = %d\n", zp->z_addrcnt);
+#endif
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+ result = getzone(zp, serial_no, port);
+ (void) fclose(dbfp);
+ switch (result) {
+
+ case XFER_SUCCESS: /* ok exit */
+ if (rename(tmpname, dbfile) == -1) {
+ perror("rename");
+ if (!quiet)
+ syslog(LOG_ERR, "rename %s to %s: %m",
+ tmpname, dbfile);
+ exit(XFER_FAIL);
+ }
+ exit(XFER_SUCCESS);
+
+ case XFER_UPTODATE: /* the zone was already uptodate */
+ (void) unlink(tmpname);
+ exit(XFER_UPTODATE);
+
+ case XFER_TIMEOUT:
+#ifdef DEBUG
+ if (!debug)
+#endif
+ (void) unlink(tmpname);
+ exit(XFER_TIMEOUT); /* servers not reachable exit */
+
+ case XFER_FAIL:
+ default:
+#ifdef DEBUG
+ if (!debug)
+#endif
+ (void) unlink(tmpname);
+ exit(XFER_FAIL); /* yuck exit */
+ }
+}
+
+usage()
+{
+ (void)fprintf(stderr,
+"Usage: xfer\n\
+\t-z zone_to_transfer\n\
+\t-f db_file\n\
+\t-s serial_no\n\
+\t[-d debug_level]\n\
+\t[-l debug_log_file (default %s)]\n\
+\t[-t trace_file]\n\
+\t[-p port]\n\
+\tservers...\n", ddtfile);
+ exit(XFER_FAIL);
+}
+
+int minimum_ttl = 0, got_soa = 0;
+char prev_origin[MAXDNAME];
+char prev_dname[MAXDNAME];
+
+getzone(zp, serial_no, port)
+ struct zoneinfo *zp;
+ u_long serial_no;
+ u_short port;
+{
+ HEADER *hp;
+ u_short len;
+ u_long serial;
+ int s, n, l, cnt, soacnt, error = 0;
+ u_char *cp, *nmp, *eom, *tmp ;
+ u_char *buf = NULL;
+ int bufsize;
+ u_char name[MAXDNAME], name2[MAXDNAME];
+ struct sockaddr_in sin;
+ struct zoneinfo zp_start, zp_finish;
+ struct itimerval ival, zeroival;
+ extern SIG_FN read_alarm();
+ struct sigvec sv, osv;
+ int ancount, aucount;
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,"getzone() %s\n", zp->z_origin);
+#endif
+ bzero((char *)&zeroival, sizeof(zeroival));
+ ival = zeroival;
+ ival.it_value.tv_sec = 120;
+ sv.sv_handler = read_alarm;
+ sv.sv_onstack = 0;
+ sv.sv_mask = ~0;
+ (void) sigvec(SIGALRM, &sv, &osv);
+
+ strcpy(prev_origin, zp->z_origin);
+
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ error = 0;
+ if (buf == NULL) {
+ if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) {
+ syslog(LOG_ERR, "malloc(%u) failed",
+ 2 * PACKETSZ);
+ error++;
+ break;
+ }
+ bufsize = 2 * PACKETSZ;
+ }
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = port;
+ sin.sin_addr = zp->z_addr[cnt];
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ error++;
+ break;
+ }
+#ifdef DEBUG
+ if (debug >= 2) {
+ (void)fprintf(ddt,"connecting to server #%d %s, %d\n",
+ cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ }
+#endif
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ (void) close(s);
+ error++;
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt, "connect failed, %s\n",
+ strerror(errno));
+#endif
+ continue;
+ }
+ if ((n = res_mkquery(QUERY, zp->z_origin, C_IN,
+ T_SOA, (char *)NULL, 0, NULL, (char *)buf, bufsize)) < 0) {
+ if (!quiet)
+ syslog(LOG_ERR, "zone %s: res_mkquery T_SOA failed",
+ zp->z_origin);
+ (void) close(s);
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+ return XFER_FAIL;
+ }
+ /*
+ * Send length & message for zone transfer
+ */
+ if (writemsg(s, buf, n) < 0) {
+ (void) close(s);
+ error++;
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt,"writemsg failed\n");
+#endif
+ continue;
+ }
+ /*
+ * Get out your butterfly net and catch the SOA
+ */
+ cp = buf;
+ l = sizeof(u_short);
+ read_interrupted = 0;
+ while (l > 0) {
+#ifdef DEBUG
+ if (debug > 10) (void)fprintf(ddt,"Before setitimer\n");
+#endif
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+#ifdef DEBUG
+ if (debug > 10) (void)fprintf(ddt,"Before recv(l = %d)\n",n);
+#endif
+ errno = 0;
+ if ((n = recv(s, (char *)cp, l, 0)) > 0) {
+ cp += n;
+ l -= n;
+ } else {
+#ifdef DEBUG
+ if (debug > 10)
+ (void)fprintf(ddt,
+"bad recv->%d, errno= %d, read_interrupt=%d\n", n, errno, read_interrupted);
+#endif
+ if (n == -1 && errno == EINTR
+ && !read_interrupted)
+ continue;
+ error++;
+ break;
+ }
+ }
+
+ (void) setitimer(ITIMER_REAL, &zeroival,
+ (struct itimerval *)NULL);
+ if (error) {
+ (void) close(s);
+ continue;
+ }
+ if ((len = htons(*(u_short *)buf)) == 0) {
+ (void) close(s);
+ continue;
+ }
+ if (len > bufsize) {
+ if ((buf = (u_char *)realloc(buf, len)) == NULL) {
+ syslog(LOG_ERR,
+ "malloc(%u) failed for SOA from server %s, zone %s\n",
+ len, inet_ntoa(sin.sin_addr), zp->z_origin);
+ (void) close(s);
+ continue;
+ }
+ bufsize = len;
+ }
+ l = len;
+ cp = buf;
+ while (l > 0) {
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ errno = 0;
+ if ((n = recv(s, (char *)cp, l, 0)) > 0) {
+ cp += n;
+ l -= n;
+ } else {
+ if (errno == EINTR && !read_interrupted)
+ continue;
+ error++;
+#ifdef DEBUG
+ if (debug > 10)
+ (void)fprintf(ddt,
+ "recv failed: n= %d, errno = %d\n",
+ n, errno);
+#endif
+ break;
+ }
+ }
+ (void) setitimer(ITIMER_REAL, &zeroival,
+ (struct itimerval *)NULL);
+ if (error) {
+ (void) close(s);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_query(buf, ddt);
+ }
+#endif DEBUG
+ hp = (HEADER *) buf;
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount);
+
+ /*
+ * close socket if:
+ * 1) rcode != NOERROR
+ * 2) not an authority response
+ * 3) both the number of answers and authority count < 1)
+ */
+ if (hp->rcode != NOERROR || !(hp->aa) ||
+ (ancount < 1 && aucount < 1)) {
+ if (!quiet)
+ syslog(LOG_ERR,
+ "%s from %s, zone %s: rcode %d, aa %d, ancount %d, aucount %d\n",
+ "bad response to SOA query",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ hp->rcode, hp->aa, ancount, aucount);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "%s from %s, zone %s: rcode %d, aa %d, ancount %d, aucount %d\n",
+ "bad response to SOA query",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ hp->rcode, hp->aa, ancount, aucount);
+#endif DEBUG
+ (void) close(s);
+ error++;
+ continue;
+ }
+ zp_start = *zp;
+ if (len < sizeof(HEADER) + QFIXEDSZ) {
+ badsoa:
+ if (!quiet)
+ syslog(LOG_ERR,
+ "malformed SOA from %s, zone %s: too short\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "malformed SOA from %s: too short\n",
+ inet_ntoa(sin.sin_addr));
+#endif DEBUG
+ (void) close(s);
+ error++;
+ continue;
+ }
+ tmp = buf + sizeof(HEADER);
+ eom = buf + len;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n + QFIXEDSZ;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if (soa_zinfo(&zp_start, tmp, eom) == -1)
+ goto badsoa;
+ if (zp_start.z_serial > serial_no || serial_no == 0) {
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt, "need update, serial %d\n",
+ zp_start.z_serial);
+#endif DEBUG
+ hp = (HEADER *) buf;
+ soacnt = 0;
+ for (;;) {
+ if (soacnt == 0) {
+ if ((n = res_mkquery(QUERY, zp->z_origin, C_IN,
+ T_AXFR, (char *)NULL, 0, NULL,
+ (char *)buf, bufsize)) < 0) {
+ if (!quiet)
+ syslog(LOG_ERR,
+ "zone %s: res_mkquery T_AXFR failed",
+ zp->z_origin);
+ (void) close(s);
+ (void) sigvec(SIGALRM, &osv,
+ (struct sigvec *)0);
+ return XFER_FAIL;
+ }
+ /*
+ * Send length & message for zone transfer
+ */
+ if (writemsg(s, buf, n) < 0) {
+ (void) close(s);
+ error++;
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt,"writemsg failed\n");
+#endif
+ break;
+ }
+ }
+ /*
+ * Receive length & response
+ */
+ cp = buf;
+ l = sizeof(u_short);
+ /* allow extra time for the fork on first read */
+ if (soacnt == 0)
+ ival.it_value.tv_sec = 300;
+ while (l > 0) {
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ errno = 0;
+ if ((n = recv(s, (char *)cp, l, 0)) > 0) {
+ cp += n;
+ l -= n;
+ } else {
+ if (errno == EINTR && !read_interrupted)
+ continue;
+ error++;
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt,
+ "recv failed: n= %d, errno = %d\n",
+ n, errno);
+#endif
+ break;
+ }
+ }
+ if (soacnt == 0)
+ ival.it_value.tv_sec = 120;
+ (void) setitimer(ITIMER_REAL, &zeroival,
+ (struct itimerval *)NULL);
+ if (error)
+ break;
+ if ((len = htons(*(u_short *)buf)) == 0)
+ break;
+ l = len;
+ cp = buf;
+ eom = buf + len;
+ while (l > 0) {
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ errno = 0;
+ if ((n = recv(s, (char *)cp, l, 0)) > 0) {
+ cp += n;
+ l -= n;
+ } else {
+ if (errno == EINTR && !read_interrupted)
+ continue;
+ error++;
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt,"recv failed\n");
+#endif
+ break;
+ }
+ }
+ (void) setitimer(ITIMER_REAL, &zeroival,
+ (struct itimerval *)NULL);
+ if (error)
+ break;
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_query(buf, ddt);
+ }
+ if (fp) fp_query(buf,fp);
+#endif
+ if (len < sizeof(HEADER)) {
+ badrec:
+ error++;
+ if (!quiet)
+ syslog(LOG_ERR,
+ "record too short from %s, zone %s\n",
+ inet_ntoa(sin.sin_addr),
+ zp->z_source);
+#ifdef DEBUG
+ if (debug)
+ fprintf(ddt,
+ "record too short from %s\n",
+ inet_ntoa(sin.sin_addr));
+#endif DEBUG
+ break;
+ }
+ cp = buf + sizeof(HEADER);
+ if (hp->qdcount) {
+ if ((n = dn_skipname(cp, eom)) == -1 ||
+ n + QFIXEDSZ >= eom - cp)
+ goto badrec;
+ cp += n + QFIXEDSZ;
+ }
+ nmp = cp;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ goto badrec;
+ tmp = cp + n;
+
+ n = print_output(buf, bufsize, cp);
+ if (cp + n != eom) {
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,
+ "getzone: print_update failed (%d, %d)\n",
+ cp - buf, n);
+#endif
+ error++;
+ break;
+ }
+ GETSHORT(n, tmp);
+ if (n == T_SOA) {
+ if (soacnt == 0) {
+ soacnt++;
+ if (dn_expand(buf, buf + 512, nmp,
+ name, sizeof(name)) == -1)
+ goto badsoa;
+ if (eom - tmp <= 2 * sizeof(u_short) +
+ sizeof(u_long))
+ goto badsoa;
+ tmp += 2 * sizeof(u_short)
+ + sizeof(u_long);
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if (eom - tmp <= sizeof(u_long))
+ goto badsoa;
+ GETLONG(serial, tmp);
+#ifdef DEBUG
+ if (debug > 2)
+ (void)fprintf(ddt,
+ "first SOA for %s, serial %d\n",
+ name, serial);
+#endif DEBUG
+ continue;
+ }
+ if (dn_expand(buf, buf + 512, nmp, name2,
+ sizeof(name2)) == -1)
+ goto badsoa;
+ if (strcasecmp((char *)name, (char *)name2) != 0) {
+#ifdef DEBUG
+ if (debug > 1)
+ (void)fprintf(ddt,
+ "extraneous SOA for %s\n",
+ name2);
+#endif DEBUG
+ continue;
+ }
+ tmp -= sizeof(u_short);
+ if (soa_zinfo(&zp_finish, tmp, eom) == -1)
+ goto badsoa;
+#ifdef DEBUG
+ if (debug > 1)
+ (void)fprintf(ddt,
+ "SOA, serial %d\n", zp_finish.z_serial);
+#endif DEBUG
+ if (serial != zp_finish.z_serial) {
+ soacnt = 0;
+ got_soa = 0;
+ minimum_ttl = 0;
+ strcpy(prev_origin, zp->z_origin);
+ prev_dname[0] = 0;
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,
+ "serial changed, restart\n");
+#endif DEBUG
+ /*
+ * Flush buffer, truncate file
+ * and seek to beginning to restart.
+ */
+ fflush(dbfp);
+ if (ftruncate(fileno(dbfp), 0) != 0) {
+ if (!quiet)
+ syslog(LOG_ERR,
+ "ftruncate %s: %m\n",
+ tmpname);
+ return(XFER_FAIL);
+ }
+ fseek(dbfp, 0L, 0);
+ } else
+ break;
+ }
+ }
+ (void) close(s);
+ if (error == 0) {
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+ return XFER_SUCCESS;
+ }
+#ifdef DEBUG
+ if (debug >= 2)
+ (void)fprintf(ddt,"error receiving zone transfer\n");
+#endif
+ } else {
+ (void) close(s);
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,
+ "zone up-to-date, serial %d\n", zp_start.z_serial);
+#endif DEBUG
+ return XFER_UPTODATE;
+ }
+ }
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+ if (error)
+ return XFER_TIMEOUT;
+ return XFER_FAIL;
+}
+
+/*
+ * Set flag saying to read was interrupted
+ * used for a read timer
+ */
+SIG_FN
+read_alarm()
+{
+ extern int read_interrupted;
+ read_interrupted = 1;
+}
+
+writemsg(rfd, msg, msglen)
+ int rfd;
+ u_char *msg;
+ int msglen;
+{
+ struct iovec iov[2];
+ u_short len = htons((u_short)msglen);
+
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = sizeof(len);
+ iov[1].iov_base = (caddr_t)msg;
+ iov[1].iov_len = msglen;
+ if (writev(rfd, iov, 2) != sizeof(len) + msglen) {
+#ifdef DEBUG
+ if (debug)
+ (void)fprintf(ddt,"write failed %d\n", errno);
+#endif
+ return (-1);
+ }
+ return (0);
+}
+
+
+soa_zinfo(zp, cp, eom)
+ register struct zoneinfo *zp;
+ register u_char *cp;
+ u_char *eom;
+{
+ register int n;
+
+ if (eom - cp < 3 * sizeof(u_short) + sizeof(u_long))
+ return (-1);
+ cp += 3 * sizeof(u_short) + sizeof(u_long);
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return (-1);
+ cp += n;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return (-1);
+ cp += n;
+ if (eom - cp < 5 * sizeof(u_long))
+ return (-1);
+ GETLONG(zp->z_serial, cp);
+ GETLONG(zp->z_refresh, cp);
+ gettime(&tt);
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ GETLONG(zp->z_retry, cp);
+ GETLONG(zp->z_expire, cp);
+ GETLONG(zp->z_minimum, cp);
+ return (0);
+}
+
+gettime(ttp)
+struct timeval *ttp;
+{
+ if (gettimeofday(ttp, (struct timezone *)0) < 0)
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+}
+
+/*
+ * Parse the message, determine if it should be printed, and if so, print it
+ * in .db file form.
+ * Does minimal error checking on the message content.
+ */
+print_output(msg, msglen, rrp)
+ u_char *msg;
+ int msglen;
+ u_char *rrp;
+{
+ register u_char *cp;
+ register HEADER *hp = (HEADER *) msg;
+ u_long addr, ttl;
+ int i, j, tab, result, class, type, dlen, n1;
+ long n;
+ u_char *cp1, data[BUFSIZ];
+ u_char *temp_ptr; /* used to get ttl for RR */
+ char *cdata, *origin, *proto, dname[MAXDNAME];
+ extern char *inet_ntoa(), *protocolname(), *servicename();
+
+ cp = rrp;
+ if ((n = dn_expand(msg, msg + msglen, cp, (u_char *) dname,
+ sizeof(dname))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+
+ origin = index(dname, '.');
+ if (origin == NULL)
+ origin = "";
+ else
+ origin++; /* move past the '.' */
+#ifdef DEBUG
+ if (debug > 2)
+ (void) fprintf(ddt, "print_output: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl);
+#endif
+ /*
+ * Convert the resource record data into the internal database format.
+ */
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_TXT:
+ case T_UID:
+ case T_GID:
+ cp1 = cp;
+ n = dlen;
+ cp += n;
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ if ((n = dn_expand(msg, msg + msglen, cp, data,
+ sizeof(data))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *) data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ if ((n = dn_expand(msg, msg + msglen, cp, data,
+ sizeof(data))) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data + (n = strlen((char *) data) + 1);
+ n1 = sizeof(data) - n;
+ if (type == T_SOA)
+ n1 -= 5 * sizeof(u_long);
+ if ((n = dn_expand(msg, msg + msglen, cp, cp1, n1)) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *) cp1) + 1;
+ if (type == T_SOA) {
+ temp_ptr = cp + 4 * sizeof(u_long);
+ GETLONG(minimum_ttl, temp_ptr);
+ bcopy((char *) cp, (char *) cp1,
+ n = 5 * sizeof(u_long));
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ /* grab preference */
+ bcopy((char *) cp, (char *) data, sizeof(u_short));
+ cp1 = data + sizeof(u_short);
+ cp += sizeof(u_short);
+
+ /* get name */
+ if ((n = dn_expand(msg, msg + msglen, cp, cp1,
+ sizeof(data) - sizeof(u_short))) < 0)
+ return (-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *) cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+#ifdef DEBUG
+ if (debug >= 3)
+ (void) fprintf(ddt, "unknown type %d\n", type);
+#endif
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+#ifdef DEBUG
+ if (debug)
+ (void) fprintf(ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n);
+#endif
+ hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */
+ return (-1);
+ }
+ cdata = (char *) cp1;
+ result = cp - rrp;
+
+ /*
+ * Only print one SOA per db file
+ */
+ if (type == T_SOA) {
+ if (got_soa)
+ return result;
+ else
+ got_soa++;
+ }
+ /*
+ * If the origin has changed, print the new origin
+ */
+ if (strcasecmp(prev_origin, origin)) {
+ (void) strcpy(prev_origin, origin);
+ (void) fprintf(dbfp, "$ORIGIN %s.\n", origin);
+ }
+ tab = 0;
+
+ if (strcasecmp(prev_dname, dname)) {
+ /*
+ * set the prev_dname to be the current dname, then cut off all
+ * characters of dname after (and including) the first '.'
+ */
+ char *cutp = index(dname, '.');
+
+ (void) strcpy(prev_dname, dname);
+ if (cutp)
+ *cutp = NULL;
+
+ if (dname[0] == 0) {
+ if (origin[0] == 0)
+ (void) fprintf(dbfp, ".\t");
+ else
+ (void) fprintf(dbfp, ".%s.\t", origin); /* ??? */
+ } else
+ (void) fprintf(dbfp, "%s\t", dname);
+ if (strlen(dname) < 8)
+ tab = 1;
+ } else {
+ (void) putc('\t', dbfp);
+ tab = 1;
+ }
+
+ if (ttl != 0 && ttl != minimum_ttl)
+ (void) fprintf(dbfp, "%d\t", (int) ttl);
+ else if (tab)
+ (void) putc('\t', dbfp);
+
+ (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type));
+ cp = (u_char *) cdata;
+
+ /*
+ * Print type specific data
+ */
+ switch (type) {
+
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ GETLONG(n, cp);
+ n = htonl(n);
+ (void) fprintf(dbfp, "%s",
+ inet_ntoa(*(struct in_addr *) & n));
+ break;
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\n");
+ else
+ (void) fprintf(dbfp, "%s.\n", cp);
+ break;
+
+ case T_NS:
+ cp = (u_char *) cdata;
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\t");
+ else
+ (void) fprintf(dbfp, "%s.", cp);
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_HINFO:
+ if (n = *cp++) {
+ (void) fprintf(dbfp, "\"%.*s\"", (int) n, cp);
+ cp += n;
+ } else
+ (void) fprintf(dbfp, "\"\"");
+ if (n = *cp++)
+ (void) fprintf(dbfp, " \"%.*s\"", (int) n, cp);
+ else
+ (void) fprintf(dbfp, "\"\"");
+ (void) putc('\n', dbfp);
+ break;
+
+ case T_SOA:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s. (\n", cp);
+ cp += strlen((char *) cp) + 1;
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, "\t\t%lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu )\n", n);
+ break;
+
+ case T_MX:
+ GETSHORT(n, cp);
+ (void) fprintf(dbfp, "%lu", n);
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_TXT:
+ cp1 = cp + n;
+ (void) putc('"', dbfp);
+ while (cp < cp1) {
+ if (i = *cp++) {
+ for (j = i ; j > 0 && cp < cp1 ; j--)
+ if (*cp == '\n') {
+ (void) putc('\\', dbfp);
+ (void) putc(*cp++, dbfp);
+ } else
+ (void) putc(*cp++, dbfp);
+ }
+ }
+ (void) fputs("\"\n", dbfp);
+ break;
+
+ case T_UINFO:
+ (void) fprintf(dbfp, "\"%s\"\n", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (n == sizeof(u_long)) {
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, "%lu\n", n);
+ }
+ break;
+
+ case T_WKS:
+ GETLONG(addr, cp);
+ addr = htonl(addr);
+ (void) fprintf(dbfp, "%s ",
+ inet_ntoa(*(struct in_addr *) & addr));
+ proto = protocolname(*cp);
+ cp += sizeof(char);
+ (void) fprintf(dbfp, "%s ", proto);
+ i = 0;
+ while (cp < (u_char *) cdata + n) {
+ j = *cp++;
+ do {
+ if (j & 0200)
+ (void) fprintf(dbfp, " %s",
+ servicename(i, proto));
+ j <<= 1;
+ } while (++i & 07);
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_MINFO:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ default:
+ (void) fprintf(dbfp, "???\n");
+ }
+ if (ferror(dbfp)) {
+ syslog(LOG_ERR, "%s: %m", tmpname);
+ exit(XFER_FAIL);
+ }
+ return result;
+}
+
+/*
+ * Make a copy of a string and return a pointer to it.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *cp;
+
+ cp = (char *)malloc((unsigned)strlen(str) + 1);
+ if (cp == NULL) {
+ syslog(LOG_ERR, "savestr: %m");
+ exit(XFER_FAIL);
+ }
+ (void) strcpy(cp, str);
+ return (cp);
+}
diff --git a/usr.sbin/netgroup_mkdb/Makefile b/usr.sbin/netgroup_mkdb/Makefile
new file mode 100644
index 00000000000..b6d8c60f00f
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.1 (Berkeley) 3/8/91
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $
+
+PROG= netgroup_mkdb
+SRCS= netgroup_mkdb.c util.c str.c
+MAN= netgroup_mkdb.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/netgroup_mkdb/netgroup_mkdb.8 b/usr.sbin/netgroup_mkdb/netgroup_mkdb.8
new file mode 100644
index 00000000000..52efd63e490
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/netgroup_mkdb.8
@@ -0,0 +1,88 @@
+.\"
+.\" Copyright (c) 1994 Christos Zoulas
+.\" 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 Christos Zoulas.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: netgroup_mkdb.8,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $
+.\"
+.Dd February 3, 1994
+.Dt NETGROUP_MKDB 8
+.Os
+.Sh NAME
+.Nm netgroup_mkdb
+.Nd generate the netgroup databases
+.Sh SYNOPSIS
+.Nm netgroup_mkdb
+.Op Fl o Ar database
+.Op file
+.Sh DESCRIPTION
+.Nm Netgroup_mkdb
+creates
+.Xr db 3
+style databases for the specified file. If no file is specified, then
+.Pa /etc/netgroup
+is used.
+These databases are then installed into
+.Pa /etc/netgroup.db.
+The file must be in the correct format (see
+.Xr netgroup 5 ).
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o Ar database
+Put the output databases in the named file.
+.El
+.Pp
+The databases are used by the C library netgroup routines (see
+.Xr getnetgrent 3 ).
+.Pp
+.Nm Netgroup_mkdb
+exits zero on success, non-zero on failure.
+.Sh FILES
+.Bl -tag -width 24n -compact
+.It Pa /etc/netgroup.db
+The current netgroup database
+.It Pa /etc/netgroup.db.tmp
+A temporary file
+.It Pa /etc/netgroup
+The current netgroup file
+.El
+.Sh BUGS
+Because
+.Nm netgroup_mkdb
+guarantees not to install a partial destination file it must
+build a temporary file in the same file system and if successful use
+.Xr rename 2
+to install over the destination file.
+.Pp
+If
+.Nm netgroup_mkdb
+fails it will leave the previous version of the destination file intact.
+.Sh SEE ALSO
+.Xr db 3 ,
+.Xr getnetgrent 3 ,
+.Xr netgroup 5
diff --git a/usr.sbin/netgroup_mkdb/netgroup_mkdb.c b/usr.sbin/netgroup_mkdb/netgroup_mkdb.c
new file mode 100644
index 00000000000..7bbdffeff83
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/netgroup_mkdb.c
@@ -0,0 +1,715 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef lint
+static char *rcsid = "$Id: netgroup_mkdb.c,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <netgroup.h>
+#include <assert.h>
+
+#include "str.h"
+#include "util.h"
+
+#define NEW(a) (a *) emalloc(sizeof(a))
+
+struct nentry {
+ int n_type;
+ size_t n_size; /* Buffer size required for printing */
+ union {
+ char *_name;
+ struct netgroup *_group;
+ } _n;
+#define n_name _n._name
+#define n_group _n._group
+ struct nentry *n_next;
+};
+
+
+struct stringlist;
+
+extern struct stringlist
+ *_ng_sl_init __P((void));
+extern void _ng_sl_add __P((struct stringlist *, char *));
+extern void _ng_sl_free __P((struct stringlist *, int));
+extern char *_ng_sl_find __P((struct stringlist *, char *));
+
+extern char *_ng_makekey __P((const char *, const char *, size_t));
+extern int _ng_parse __P((char **, char **, struct netgroup **));
+
+static DB *ng_insert __P((DB *, const char *));
+static void ng_reventry __P((DB *, DB *, struct nentry *, char *,
+ size_t, struct stringlist *));
+
+static void ng_print __P((struct nentry *, struct string *));
+static void ng_rprint __P((DB *, struct string *));
+static DB *ng_reverse __P((DB *, size_t));
+static DB *ng_load __P((const char *));
+static void ng_write __P((DB *, DB *, int));
+static void ng_rwrite __P((DB *, DB *, int));
+static void usage __P((void));
+static void cleanup __P((void));
+
+#ifdef DEBUG_NG
+static void ng_dump __P((DB *));
+static void ng_rdump __P((DB *));
+#endif /* DEBUG_NG */
+
+static const char ng_empty[] = "";
+#define NG_EMPTY(a) ((a) ? (a) : ng_empty)
+
+static char *dbname = _PATH_NETGROUP_DB;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ DB *db, *ndb, *hdb, *udb;
+ int ch;
+ char buf[MAXPATHLEN];
+ char *fname = _PATH_NETGROUP;
+
+
+ while ((ch = getopt(argc, argv, "o:")) != EOF)
+ switch (ch) {
+ case 'o':
+ dbname = optarg;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1)
+ fname = *argv;
+ else if (argc > 1)
+ usage();
+
+ if (atexit(cleanup))
+ err(1, "Cannot install exit handler");
+
+ /* Read and parse the netgroup file */
+ ndb = ng_load(fname);
+#ifdef DEBUG_NG
+ (void) fprintf(stderr, "#### Database\n");
+ ng_dump(ndb);
+#endif
+
+ /* Reverse the database by host */
+ hdb = ng_reverse(ndb, offsetof(struct netgroup, ng_host));
+#ifdef DEBUG_NG
+ (void) fprintf(stderr, "#### Reverse by host\n");
+ ng_rdump(hdb);
+#endif
+
+ /* Reverse the database by user */
+ udb = ng_reverse(ndb, offsetof(struct netgroup, ng_user));
+#ifdef DEBUG_NG
+ (void) fprintf(stderr, "#### Reverse by user\n");
+ ng_rdump(udb);
+#endif
+
+ (void) snprintf(buf, sizeof(buf), "%s.tmp", dbname);
+
+ db = dbopen(buf, O_RDWR | O_CREAT | O_EXCL,
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, NULL);
+ if (!db)
+ err(1, buf);
+
+ ng_write(db, ndb, _NG_KEYBYNAME);
+ ng_rwrite(db, udb, _NG_KEYBYUSER);
+ ng_rwrite(db, hdb, _NG_KEYBYHOST);
+
+ if ((db->close)(db))
+ err(1, "Error closing database");
+
+ if (rename(buf, dbname) == -1)
+ err(1, "Cannot rename `%s' to `%s'", buf, dbname);
+
+ return 0;
+}
+
+
+/*
+ * cleanup(): Remove temporary files upon exit
+ */
+static void
+cleanup()
+{
+ char buf[MAXPATHLEN];
+ (void) snprintf(buf, sizeof(buf), "%s.tmp", dbname);
+ (void) unlink(buf);
+}
+
+
+
+/*
+ * ng_load(): Load the netgroup database from a file
+ */
+static DB *
+ng_load(fname)
+ const char *fname;
+{
+ FILE *fp;
+ DB *db;
+ char *buf;
+ size_t size;
+ struct nentry *tail, *head, *e;
+ char *p, *name;
+ struct netgroup *ng;
+ DBT data, key;
+
+ /* Open the netgroup file */
+ if ((fp = fopen(fname, "r")) == NULL)
+ err(1, fname);
+
+ db = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL);
+
+ if (db == NULL)
+ err(1, "dbopen");
+
+ while ((buf = getline(fp, &size)) != NULL) {
+ tail = head = NULL;
+ p = buf;
+
+ while (p != NULL) {
+ switch (_ng_parse(&p, &name, &ng)) {
+ case _NG_NONE:
+ /* done with this one */
+ p = NULL;
+ free(buf);
+ if (head == NULL)
+ break;
+
+ key.data = (u_char *) head->n_name;
+ key.size = strlen(head->n_name) + 1;
+ data.data = (u_char *) & head;
+ data.size = sizeof(head);
+ switch ((db->put)(db, &key, &data,
+ R_NOOVERWRITE)) {
+ case 0:
+ break;
+
+ case 1:
+ warnx("Duplicate entry netgroup `%s'\n",
+ head->n_name);
+ break;
+
+ case -1:
+ err(1, "put");
+ break;
+
+ default:
+ abort();
+ break;
+ }
+ break;
+
+ case _NG_NAME:
+ e = NEW(struct nentry);
+ e->n_type = _NG_NAME;
+ e->n_name = name;
+ e->n_next = NULL;
+ e->n_size = size;
+ if (tail == NULL)
+ head = tail = e;
+ else {
+ tail->n_next = e;
+ tail = e;
+ }
+ break;
+
+ case _NG_GROUP:
+ if (tail == NULL)
+ errx(1, "no netgroup key");
+ else {
+ e = NEW(struct nentry);
+ e->n_type = _NG_GROUP;
+ e->n_group = ng;
+ e->n_next = NULL;
+ e->n_size = size;
+ tail->n_next = e;
+ tail = e;
+ }
+ break;
+
+ default:
+ abort();
+ break;
+ }
+ }
+ }
+ (void) fclose(fp);
+ return db;
+}
+
+
+/*
+ * ng_insert(): Insert named key into the database, and return its associated
+ * string database
+ */
+static DB *
+ng_insert(db, name)
+ DB *db;
+ const char *name;
+{
+ DB *xdb = NULL;
+ DBT key, data;
+
+ key.data = (u_char *) name;
+ key.size = strlen(name) + 1;
+
+ switch ((db->get)(db, &key, &data, 0)) {
+ case 0:
+ memcpy(&xdb, data.data, sizeof(xdb));
+ break;
+
+ case 1:
+ xdb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL);
+ if (xdb == NULL)
+ err(1, "dbopen");
+
+ data.data = (u_char *) & xdb;
+ data.size = sizeof(xdb);
+ switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
+ case 0:
+ break;
+
+ case -1:
+ err(1, "db put `%s'", name);
+ break;
+
+ case 1:
+ default:
+ abort();
+ }
+ break;
+
+ case -1:
+ err(1, "db get `%s'", name);
+ break;
+
+ default:
+ abort();
+ break;
+ }
+
+ return xdb;
+}
+
+
+/*
+ * ng_reventry(): Recursively add all the netgroups to the group entry.
+ */
+static void
+ng_reventry(db, udb, fe, name, s, ss)
+ DB *db, *udb;
+ struct nentry *fe;
+ char *name;
+ size_t s;
+ struct stringlist *ss;
+{
+ DBT key, data;
+ struct nentry *e;
+ struct netgroup *ng;
+ char *p;
+ DB *xdb;
+
+ if (_ng_sl_find(ss, name) != NULL) {
+ warnx("Cycle in netgroup `%s'", name);
+ return;
+ }
+ _ng_sl_add(ss, name);
+
+ for (e = fe->n_next; e != NULL; e = e->n_next)
+ switch (e->n_type) {
+ case _NG_GROUP:
+ ng = e->n_group;
+ p = _ng_makekey(*((char **)(((char *) ng) + s)),
+ ng->ng_domain, e->n_size);
+ xdb = ng_insert(udb, p);
+ key.data = (u_char *) name;
+ key.size = strlen(name) + 1;
+ data.data = NULL;
+ data.size = 0;
+ switch ((xdb->put)(xdb, &key, &data, R_NOOVERWRITE)) {
+ case 0:
+ case 1:
+ break;
+
+ case -1:
+ err(1, "db put `%s'", name);
+ return;
+
+ default:
+ abort();
+ break;
+ }
+ free(p);
+ break;
+
+ case _NG_NAME:
+ key.data = (u_char *) e->n_name;
+ key.size = strlen(e->n_name) + 1;
+ switch ((db->get)(db, &key, &data, 0)) {
+ case 0:
+ memcpy(&fe, data.data, sizeof(fe));
+ ng_reventry(db, udb, fe, e->n_name, s, ss);
+ break;
+
+ case 1:
+ break;
+
+ case -1:
+ err(1, "db get `%s'", e->n_name);
+ return;
+
+ default:
+ abort();
+ return;
+ }
+ break;
+
+ default:
+ abort();
+ break;
+ }
+}
+
+
+/*
+ * ng_reverse(): Reverse the database
+ */
+static DB *
+ng_reverse(db, s)
+ DB *db;
+ size_t s;
+{
+ int pos;
+ struct stringlist *sl;
+ DBT key, data;
+ struct nentry *fe;
+ DB *udb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0,
+ DB_HASH, NULL);
+
+ if (udb == NULL)
+ err(1, "dbopen");
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((db->seq)(db, &key, &data, pos)) {
+ case 0:
+ sl = _ng_sl_init();
+ memcpy(&fe, data.data, sizeof(fe));
+ ng_reventry(db, udb, fe, (char *) key.data, s, sl);
+ _ng_sl_free(sl, 0);
+ break;
+
+ case 1:
+ return udb;
+
+ case -1:
+ err(1, "seq");
+ return udb;
+ }
+
+ return udb;
+}
+
+
+/*
+ * ng_print(): Pretty print a netgroup entry
+ */
+static void
+ng_print(e, str)
+ struct nentry *e;
+ struct string *str;
+{
+ char *ptr = emalloc(e->n_size);
+
+ for (e = e->n_next; e != NULL; e = e->n_next) {
+ switch (e->n_type) {
+ case _NG_NAME:
+ (void) snprintf(ptr, e->n_size, "%s", e->n_name);
+ break;
+
+ case _NG_GROUP:
+ (void) snprintf(ptr, e->n_size, "(%s,%s,%s)",
+ NG_EMPTY(e->n_group->ng_host),
+ NG_EMPTY(e->n_group->ng_user),
+ NG_EMPTY(e->n_group->ng_domain));
+ break;
+
+ default:
+ errx(1, "Internal error: Bad netgroup type\n");
+ break;
+ }
+ str_append(str, ptr, ' ');
+ }
+ free(ptr);
+}
+
+
+/*
+ * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry
+ */
+static void
+ng_rprint(db, str)
+ DB *db;
+ struct string *str;
+{
+ int pos;
+ DBT key, data;
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((db->seq)(db, &key, &data, pos)) {
+ case 0:
+ str_append(str, (char *) key.data, ',');
+ break;
+
+ case 1:
+ return;
+
+ default:
+ err(1, "seq");
+ break;
+ }
+}
+
+
+#ifdef DEBUG_NG
+/*
+ * ng_dump(): Pretty print all netgroups in the given database
+ */
+static void
+ng_dump(db)
+ DB *db;
+{
+ int pos;
+ DBT key, data;
+ struct nentry *e;
+ struct string buf;
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((db->seq)(db, &key, &data, pos)) {
+ case 0:
+ memcpy(&e, data.data, sizeof(e));
+ str_init(&buf);
+ assert(e->n_type == _NG_NAME);
+
+ ng_print(e, &buf);
+ (void) fprintf(stderr, "%s\t%s\n", e->n_name,
+ buf.s_str ? buf.s_str : "");
+ str_free(&buf);
+ break;
+
+ case 1:
+ return;
+
+ default:
+ err(1, "seq");
+ return;
+ }
+}
+
+
+/*
+ * ng_rdump(): Pretty print all reverse mappings in the given database
+ */
+static void
+ng_rdump(db)
+ DB *db;
+{
+ int pos;
+ DBT key, data;
+ DB *xdb;
+ struct string buf;
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((db->seq)(db, &key, &data, pos)) {
+ case 0:
+ memcpy(&xdb, data.data, sizeof(xdb));
+ str_init(&buf);
+ ng_rprint(xdb, &buf);
+ (void) fprintf(stderr, "%s\t%s\n",
+ (char *) key.data,
+ buf.s_str ? buf.s_str : "");
+ str_free(&buf);
+ break;
+
+ case 1:
+ return;
+
+ default:
+ err(1, "seq");
+ return;
+ }
+}
+#endif /* DEBUG_NG */
+
+
+/*
+ * ng_write(): Dump the database into a file.
+ */
+static void
+ng_write(odb, idb, k)
+ DB *odb, *idb;
+ int k;
+{
+ int pos;
+ DBT key, data;
+ struct nentry *e;
+ struct string skey, sdata;
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((idb->seq)(idb, &key, &data, pos)) {
+ case 0:
+ memcpy(&e, data.data, sizeof(e));
+ str_init(&skey);
+ str_init(&sdata);
+ assert(e->n_type == _NG_NAME);
+
+ str_prepend(&skey, e->n_name, k);
+ ng_print(e, &sdata);
+ key.data = (u_char *) skey.s_str;
+ key.size = skey.s_len + 1;
+ data.data = (u_char *) sdata.s_str;
+ data.size = sdata.s_len + 1;
+
+ switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
+ case 0:
+ break;
+
+ case -1:
+ err(1, "put");
+ break;
+
+ case 1:
+ default:
+ abort();
+ break;
+ }
+
+ str_free(&skey);
+ str_free(&sdata);
+ break;
+
+ case 1:
+ return;
+
+ default:
+ err(1, "seq");
+ return;
+ }
+}
+
+
+/*
+ * ng_rwrite(): Write the database
+ */
+static void
+ng_rwrite(odb, idb, k)
+ DB *odb;
+ DB *idb;
+ int k;
+{
+ int pos;
+ DBT key, data;
+ DB *xdb;
+ struct string skey, sdata;
+
+ for (pos = R_FIRST;; pos = R_NEXT)
+ switch ((idb->seq)(idb, &key, &data, pos)) {
+ case 0:
+ memcpy(&xdb, data.data, sizeof(xdb));
+ str_init(&skey);
+ str_init(&sdata);
+
+ str_prepend(&skey, (char *) key.data, k);
+ ng_rprint(xdb, &sdata);
+ key.data = (u_char *) skey.s_str;
+ key.size = skey.s_len + 1;
+ data.data = (u_char *) sdata.s_str;
+ data.size = sdata.s_len + 1;
+
+ switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
+ case 0:
+ break;
+
+ case -1:
+ err(1, "put");
+ break;
+
+ case 1:
+ default:
+ abort();
+ break;
+ }
+
+ str_free(&skey);
+ str_free(&sdata);
+ break;
+
+ case 1:
+ return;
+
+ default:
+ err(1, "seq");
+ return;
+ }
+}
+
+
+/*
+ * usage(): Print usage message and exit
+ */
+static void
+usage()
+{
+ extern const char *__progname;
+ fprintf(stderr, "usage: %s [-o db] file\n", __progname);
+ exit(1);
+}
diff --git a/usr.sbin/netgroup_mkdb/str.c b/usr.sbin/netgroup_mkdb/str.c
new file mode 100644
index 00000000000..e107d409c98
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/str.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char *rcsid = "$Id: str.c,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $";
+#endif
+
+/*
+ * Counted strings
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "str.h"
+
+/*
+ * str_init(): Initialize string
+ */
+void
+str_init(s)
+ struct string *s;
+{
+ s->s_str = NULL;
+ s->s_len = 0;
+}
+
+
+/*
+ * str_append(): Append string allocating buffer as necessary
+ */
+void
+str_append(buf, str, del)
+ struct string *buf;
+ const char *str;
+ int del;
+{
+ size_t len = strlen(str) + 1;
+
+ if (buf->s_str == NULL)
+ buf->s_str = emalloc(len);
+ else {
+ buf->s_str = erealloc(buf->s_str, buf->s_len + len +
+ (del ? 2 : 1));
+ if (del)
+ buf->s_str[buf->s_len++] = del;
+ }
+
+ memcpy(&buf->s_str[buf->s_len], str, len);
+ buf->s_len += len - 1;
+}
+
+/*
+ * str_prepend(): Prepend string allocating buffer as necessary
+ */
+void
+str_prepend(buf, str, del)
+ struct string *buf;
+ const char *str;
+ int del;
+{
+ char *ptr, *sptr;
+ size_t len = strlen(str) + 1;
+
+ sptr = ptr = emalloc(buf->s_len + len + (del ? 2 : 1));
+
+ if (del)
+ *ptr++ = del;
+
+ memcpy(ptr, str, len);
+
+ if (buf->s_str) {
+ memcpy(&ptr[len - 1], buf->s_str, buf->s_len + 1);
+ free(buf->s_str);
+ }
+
+ buf->s_str = sptr;
+ buf->s_len += del ? len : len - 1;
+}
+
+/*
+ * str_free(): Free a string
+ */
+void
+str_free(s)
+ struct string *s;
+{
+ free(s->s_str);
+ s->s_str = NULL;
+ s->s_len = 0;
+}
diff --git a/usr.sbin/netgroup_mkdb/str.h b/usr.sbin/netgroup_mkdb/str.h
new file mode 100644
index 00000000000..92f0b1dc27f
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/str.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: str.h,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+struct string {
+ char *s_str;
+ size_t s_len;
+};
+
+__BEGIN_DECLS
+void str_init __P((struct string *));
+void str_append __P((struct string *, const char *, int));
+void str_prepend __P((struct string *, const char *, int));
+void str_free __P((struct string *));
+__END_DECLS
diff --git a/usr.sbin/netgroup_mkdb/util.c b/usr.sbin/netgroup_mkdb/util.c
new file mode 100644
index 00000000000..66909a3f2f8
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/util.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char *rcsid = "$Id: util.c,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $";
+#endif
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+/* emalloc():
+ * Error checked malloc
+ */
+void *
+emalloc(s)
+ size_t s;
+{
+ void *ptr = malloc(s);
+ if (ptr == NULL)
+ /* Crappy gcc warning! */
+ err(1, "%s", "");
+ return ptr;
+}
+
+
+/* erealloc():
+ * Error checked realloc
+ */
+void *
+erealloc(p, s)
+ void *p;
+ size_t s;
+{
+ void *ptr = realloc(p, s);
+ if (ptr == NULL)
+ /* Crappy gcc warning! */
+ err(1, "%s", "");
+ return ptr;
+}
+
+
+/* getline():
+ * Read a line from a file parsing continuations ending in \
+ * and eliminating trailing newlines.
+ */
+char *
+getline(fp, size)
+ FILE *fp;
+ size_t *size;
+{
+ size_t s, len = 0;
+ char *buf = NULL;
+ char *ptr;
+ int cnt = 1;
+
+ while (cnt) {
+ if ((ptr = fgetln(fp, &s)) == NULL) {
+ *size = len;
+ return buf;
+ }
+ if (ptr[s - 1] == '\n') /* the newline may be missing at EOF */
+ s--; /* forget newline */
+ if ((cnt = (ptr[s - 1] == '\\'))) /* check for \\ */
+ s--; /* forget \\ */
+
+ buf = erealloc(buf, len + s + 1);
+ memcpy(buf + len, ptr, s);
+ len += s;
+ buf[len] = '\0';
+ }
+ *size = len;
+ return buf;
+}
diff --git a/usr.sbin/netgroup_mkdb/util.h b/usr.sbin/netgroup_mkdb/util.h
new file mode 100644
index 00000000000..a9773fa2cb5
--- /dev/null
+++ b/usr.sbin/netgroup_mkdb/util.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void *emalloc __P((size_t));
+void *erealloc __P((void *, size_t));
+char *getline __P((FILE *, size_t *));
+__END_DECLS
diff --git a/usr.sbin/portmap/Makefile b/usr.sbin/portmap/Makefile
new file mode 100644
index 00000000000..b1c6d22feac
--- /dev/null
+++ b/usr.sbin/portmap/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.2 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $
+
+PROG= portmap
+MAN= portmap.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/portmap.8 b/usr.sbin/portmap/portmap.8
new file mode 100644
index 00000000000..30d8db7763e
--- /dev/null
+++ b/usr.sbin/portmap/portmap.8
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1987 Sun Microsystems
+.\" Copyright (c) 1990, 1991 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.
+.\"
+.\" from: @(#)portmap.8 5.3 (Berkeley) 3/16/91
+.\" $Id: portmap.8,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt PORTMAP 8
+.Os BSD 4.3
+.Sh NAME
+.Nm portmap
+.Nd
+.Tn DARPA
+port to
+.Tn RPC
+program number mapper
+.Sh SYNOPSIS
+.Nm portmap
+.Op Fl d
+.Sh DESCRIPTION
+.Nm Portmap
+is a server that converts
+.Tn RPC
+program numbers into
+.Tn DARPA
+protocol port numbers.
+It must be running in order to make
+.Tn RPC
+calls.
+.Pp
+When an
+.Tn RPC
+server is started, it will tell
+.Nm portmap
+what port number it is listening to, and what
+.Tn RPC
+program numbers it is prepared to serve.
+When a client wishes to make an
+.Tn RPC
+call to a given program number,
+it will first contact
+.Nm portmap
+on the server machine to determine
+the port number where
+.Tn RPC
+packets should be sent.
+.Pp
+.Nm Portmap
+must be started before any
+.Tn RPC
+servers are invoked.
+.Pp
+Normally
+.Nm portmap
+forks and dissociates itself from the terminal
+like any other daemon.
+.Nm Portmap
+then logs errors using
+.Xr syslog 3 .
+.Pp
+Option available:
+.Bl -tag -width Ds
+.It Fl d
+(debug) prevents
+.Nm portmap
+from running as a daemon,
+and causes errors and debugging information
+to be printed to the standard error output.
+.El
+.Sh SEE ALSO
+.Xr inetd.conf 5 ,
+.Xr rpcinfo 8 ,
+.Xr inetd 8
+.Sh BUGS
+If
+.Nm portmap
+crashes, all servers must be restarted.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3
diff --git a/usr.sbin/portmap/portmap.c b/usr.sbin/portmap/portmap.c
new file mode 100644
index 00000000000..facd27e8b1f
--- /dev/null
+++ b/usr.sbin/portmap/portmap.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 1990 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
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)portmap.c 5.4 (Berkeley) 4/19/91";*/
+static char rcsid[] = "$Id: portmap.c,v 1.1.1.1 1995/10/18 08:47:57 deraadt Exp $";
+#endif /* not lint */
+
+/*
+@(#)portmap.c 2.3 88/08/11 4.0 RPCSRC
+static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
+*/
+
+/*
+ * portmap.c, Implements the program,version to port number mapping for
+ * rpc.
+ */
+
+/*
+ * 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
+ */
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include <sys/resource.h>
+
+void reg_service __P((struct svc_req *, SVCXPRT *));
+void reap __P(());
+static void callit __P((struct svc_req *, SVCXPRT *));
+
+struct pmaplist *pmaplist;
+int debugging = 0;
+extern int errno;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SVCXPRT *xprt;
+ int sock, c;
+ struct sockaddr_in addr;
+ int len = sizeof(struct sockaddr_in);
+ register struct pmaplist *pml;
+
+ while ((c = getopt(argc, argv, "d")) != EOF) {
+ switch (c) {
+
+ case 'd':
+ debugging = 1;
+ break;
+
+ default:
+ (void) fprintf(stderr, "usage: %s [-d]\n", argv[0]);
+ exit(1);
+ }
+ }
+
+ if (!debugging && daemon(0, 0)) {
+ (void) fprintf(stderr, "portmap: fork: %s", strerror(errno));
+ exit(1);
+ }
+
+ openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID,
+ LOG_DAEMON);
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ syslog(LOG_ERR, "cannot create udp socket: %m");
+ exit(1);
+ }
+
+ bzero((char *)&addr, sizeof addr);
+ addr.sin_addr.s_addr = 0;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(PMAPPORT);
+ if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
+ syslog(LOG_ERR, "cannot bind udp: %m");
+ exit(1);
+ }
+
+ if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
+ syslog(LOG_ERR, "couldn't do udp_create");
+ exit(1);
+ }
+ /* make an entry for ourself */
+ pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
+ pml->pml_next = 0;
+ pml->pml_map.pm_prog = PMAPPROG;
+ pml->pml_map.pm_vers = PMAPVERS;
+ pml->pml_map.pm_prot = IPPROTO_UDP;
+ pml->pml_map.pm_port = PMAPPORT;
+ pmaplist = pml;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ syslog(LOG_ERR, "cannot create tcp socket: %m");
+ exit(1);
+ }
+ if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
+ syslog(LOG_ERR, "cannot bind udp: %m");
+ exit(1);
+ }
+ if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
+ == (SVCXPRT *)NULL) {
+ syslog(LOG_ERR, "couldn't do tcp_create");
+ exit(1);
+ }
+ /* make an entry for ourself */
+ pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
+ pml->pml_map.pm_prog = PMAPPROG;
+ pml->pml_map.pm_vers = PMAPVERS;
+ pml->pml_map.pm_prot = IPPROTO_TCP;
+ pml->pml_map.pm_port = PMAPPORT;
+ pml->pml_next = pmaplist;
+ pmaplist = pml;
+
+ (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
+
+ (void)signal(SIGCHLD, reap);
+ svc_run();
+ syslog(LOG_ERR, "run_svc returned unexpectedly");
+ abort();
+}
+
+#ifndef lint
+/* need to override perror calls in rpc library */
+void
+perror(what)
+ const char *what;
+{
+
+ syslog(LOG_ERR, "%s: %m", what);
+}
+#endif
+
+static struct pmaplist *
+find_service(prog, vers, prot)
+ u_long prog, vers, prot;
+{
+ register struct pmaplist *hit = NULL;
+ register struct pmaplist *pml;
+
+ for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
+ if ((pml->pml_map.pm_prog != prog) ||
+ (pml->pml_map.pm_prot != prot))
+ continue;
+ hit = pml;
+ if (pml->pml_map.pm_vers == vers)
+ break;
+ }
+ return (hit);
+}
+
+/*
+ * 1 OK, 0 not
+ */
+void
+reg_service(rqstp, xprt)
+ struct svc_req *rqstp;
+ SVCXPRT *xprt;
+{
+ struct pmap reg;
+ struct pmaplist *pml, *prevpml, *fnd;
+ int ans, port;
+ caddr_t t;
+
+ if (debugging)
+ (void) fprintf(stderr, "server: about to do a switch\n");
+ switch (rqstp->rq_proc) {
+
+ case PMAPPROC_NULL:
+ /*
+ * Null proc call
+ */
+ if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
+ abort();
+ }
+ break;
+
+ case PMAPPROC_SET:
+ /*
+ * Set a program,version to port mapping
+ */
+ if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
+ svcerr_decode(xprt);
+ else {
+ /*
+ * check to see if already used
+ * find_service returns a hit even if
+ * the versions don't match, so check for it
+ */
+ fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
+ if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
+ if (fnd->pml_map.pm_port == reg.pm_port) {
+ ans = 1;
+ goto done;
+ }
+ else {
+ ans = 0;
+ goto done;
+ }
+ } else {
+ /*
+ * add to END of list
+ */
+ pml = (struct pmaplist *)
+ malloc((u_int)sizeof(struct pmaplist));
+ pml->pml_map = reg;
+ pml->pml_next = 0;
+ if (pmaplist == 0) {
+ pmaplist = pml;
+ } else {
+ for (fnd= pmaplist; fnd->pml_next != 0;
+ fnd = fnd->pml_next);
+ fnd->pml_next = pml;
+ }
+ ans = 1;
+ }
+ done:
+ if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
+ debugging) {
+ (void) fprintf(stderr, "svc_sendreply\n");
+ abort();
+ }
+ }
+ break;
+
+ case PMAPPROC_UNSET:
+ /*
+ * Remove a program,version to port mapping.
+ */
+ if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
+ svcerr_decode(xprt);
+ else {
+ ans = 0;
+ for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
+ if ((pml->pml_map.pm_prog != reg.pm_prog) ||
+ (pml->pml_map.pm_vers != reg.pm_vers)) {
+ /* both pml & prevpml move forwards */
+ prevpml = pml;
+ pml = pml->pml_next;
+ continue;
+ }
+ /* found it; pml moves forward, prevpml stays */
+ ans = 1;
+ t = (caddr_t)pml;
+ pml = pml->pml_next;
+ if (prevpml == NULL)
+ pmaplist = pml;
+ else
+ prevpml->pml_next = pml;
+ free(t);
+ }
+ if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
+ debugging) {
+ (void) fprintf(stderr, "svc_sendreply\n");
+ abort();
+ }
+ }
+ break;
+
+ case PMAPPROC_GETPORT:
+ /*
+ * Lookup the mapping for a program,version and return its port
+ */
+ if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
+ svcerr_decode(xprt);
+ else {
+ fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
+ if (fnd)
+ port = fnd->pml_map.pm_port;
+ else
+ port = 0;
+ if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
+ debugging) {
+ (void) fprintf(stderr, "svc_sendreply\n");
+ abort();
+ }
+ }
+ break;
+
+ case PMAPPROC_DUMP:
+ /*
+ * Return the current set of mapped program,version
+ */
+ if (!svc_getargs(xprt, xdr_void, NULL))
+ svcerr_decode(xprt);
+ else {
+ if ((!svc_sendreply(xprt, xdr_pmaplist,
+ (caddr_t)&pmaplist)) && debugging) {
+ (void) fprintf(stderr, "svc_sendreply\n");
+ abort();
+ }
+ }
+ break;
+
+ case PMAPPROC_CALLIT:
+ /*
+ * Calls a procedure on the local machine. If the requested
+ * procedure is not registered this procedure does not return
+ * error information!!
+ * This procedure is only supported on rpc/udp and calls via
+ * rpc/udp. It passes null authentication parameters.
+ */
+ callit(rqstp, xprt);
+ break;
+
+ default:
+ svcerr_noproc(xprt);
+ break;
+ }
+}
+
+
+/*
+ * Stuff for the rmtcall service
+ */
+#define ARGSIZE 9000
+
+struct encap_parms {
+ u_int arglen;
+ char *args;
+};
+
+static bool_t
+xdr_encap_parms(xdrs, epp)
+ XDR *xdrs;
+ struct encap_parms *epp;
+{
+
+ return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
+}
+
+struct rmtcallargs {
+ u_long rmt_prog;
+ u_long rmt_vers;
+ u_long rmt_port;
+ u_long rmt_proc;
+ struct encap_parms rmt_args;
+};
+
+static bool_t
+xdr_rmtcall_args(xdrs, cap)
+ register XDR *xdrs;
+ register struct rmtcallargs *cap;
+{
+
+ /* does not get a port number */
+ if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
+ xdr_u_long(xdrs, &(cap->rmt_vers)) &&
+ xdr_u_long(xdrs, &(cap->rmt_proc))) {
+ return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
+ }
+ return (FALSE);
+}
+
+static bool_t
+xdr_rmtcall_result(xdrs, cap)
+ register XDR *xdrs;
+ register struct rmtcallargs *cap;
+{
+ if (xdr_u_long(xdrs, &(cap->rmt_port)))
+ return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
+ return (FALSE);
+}
+
+/*
+ * only worries about the struct encap_parms part of struct rmtcallargs.
+ * The arglen must already be set!!
+ */
+static bool_t
+xdr_opaque_parms(xdrs, cap)
+ XDR *xdrs;
+ struct rmtcallargs *cap;
+{
+
+ return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
+}
+
+/*
+ * This routine finds and sets the length of incoming opaque paraters
+ * and then calls xdr_opaque_parms.
+ */
+static bool_t
+xdr_len_opaque_parms(xdrs, cap)
+ register XDR *xdrs;
+ struct rmtcallargs *cap;
+{
+ register u_int beginpos, lowpos, highpos, currpos, pos;
+
+ beginpos = lowpos = pos = xdr_getpos(xdrs);
+ highpos = lowpos + ARGSIZE;
+ while ((int)(highpos - lowpos) >= 0) {
+ currpos = (lowpos + highpos) / 2;
+ if (xdr_setpos(xdrs, currpos)) {
+ pos = currpos;
+ lowpos = currpos + 1;
+ } else {
+ highpos = currpos - 1;
+ }
+ }
+ xdr_setpos(xdrs, beginpos);
+ cap->rmt_args.arglen = pos - beginpos;
+ return (xdr_opaque_parms(xdrs, cap));
+}
+
+/*
+ * Call a remote procedure service
+ * This procedure is very quiet when things go wrong.
+ * The proc is written to support broadcast rpc. In the broadcast case,
+ * a machine should shut-up instead of complain, less the requestor be
+ * overrun with complaints at the expense of not hearing a valid reply ...
+ *
+ * This now forks so that the program & process that it calls can call
+ * back to the portmapper.
+ */
+static void
+callit(rqstp, xprt)
+ struct svc_req *rqstp;
+ SVCXPRT *xprt;
+{
+ struct rmtcallargs a;
+ struct pmaplist *pml;
+ u_short port;
+ struct sockaddr_in me;
+ int pid, so = -1, dontblock = 1;
+ CLIENT *client;
+ struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
+ struct timeval timeout;
+ char buf[ARGSIZE];
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ a.rmt_args.args = buf;
+ if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a))
+ return;
+ if ((pml = find_service(a.rmt_prog, a.rmt_vers,
+ (u_long)IPPROTO_UDP)) == NULL)
+ return;
+ /*
+ * fork a child to do the work. Parent immediately returns.
+ * Child exits upon completion.
+ */
+ if ((pid = fork()) != 0) {
+ if (pid == -1)
+ syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m",
+ a.rmt_prog);
+ return;
+ }
+ port = pml->pml_map.pm_port;
+ get_myaddress(&me);
+ me.sin_port = htons(port);
+
+ /* Avoid implicit binding to reserved port by clntudp_create() */
+ so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (so == -1)
+ exit(1);
+ if (ioctl(so, FIONBIO, &dontblock) == -1)
+ exit(1);
+
+ client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
+ if (client != (CLIENT *)NULL) {
+ if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
+ client->cl_auth = authunix_create(au->aup_machname,
+ au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
+ }
+ a.rmt_port = (u_long)port;
+ if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
+ xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
+ svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a);
+ }
+ AUTH_DESTROY(client->cl_auth);
+ clnt_destroy(client);
+ }
+ (void)close(so);
+ exit(0);
+}
+
+void
+reap()
+{
+ int save_errno = errno;
+
+ while (wait3(NULL, WNOHANG, NULL) != -1)
+ ;
+ errno = save_errno;
+}
diff --git a/usr.sbin/pppd/Makefile b/usr.sbin/pppd/Makefile
new file mode 100644
index 00000000000..12a0c42e0c8
--- /dev/null
+++ b/usr.sbin/pppd/Makefile
@@ -0,0 +1,15 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $
+
+PROG= pppd
+SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+ auth.c options.c sys-bsd.c
+MAN= pppd.8
+SUBDIR= pppstats chat
+BINMODE=4555
+BINOWN= root
+
+LDADD= -lcrypt -lutil
+DPADD= ${LIBCRYPT} ${LIBUTIL}
+CFLAGS+= -DHAVE_PATHS_H
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pppd/auth.c b/usr.sbin/pppd/auth.c
new file mode 100644
index 00000000000..620199ff851
--- /dev/null
+++ b/usr.sbin/pppd/auth.c
@@ -0,0 +1,934 @@
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: auth.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef HAS_SHADOW
+#include <shadow.h>
+#include <shadow/pwauth.h>
+#ifndef PW_PPP
+#define PW_PPP PW_LOGIN
+#endif
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ipcp.h"
+#include "ccp.h"
+#include "pathnames.h"
+
+#if defined(sun) && defined(sparc)
+#include <alloca.h>
+#endif /*sparc*/
+
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char word[1];
+};
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER 1
+#define NONWILD_CLIENT 2
+
+#define ISWILD(word) (word[0] == '*' && word[1] == 0)
+
+#define FALSE 0
+#define TRUE 1
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+static int logged_in;
+static struct wordlist *addresses[NUM_PPP];
+
+/* Bits in auth_pending[] */
+#define UPAP_WITHPEER 1
+#define UPAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+/* Prototypes */
+void check_access __P((FILE *, char *));
+
+static void network_phase __P((int));
+static int login __P((char *, char *, char **, int *));
+static void logout __P((void));
+static int null_login __P((int));
+static int get_upap_passwd __P((void));
+static int have_upap_secret __P((void));
+static int have_chap_secret __P((char *, char *));
+static int scan_authfile __P((FILE *, char *, char *, char *,
+ struct wordlist **, char *));
+static void free_wordlist __P((struct wordlist *));
+
+extern char *crypt __P((char *, char *));
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(unit)
+ int unit;
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(unit)
+ int unit;
+{
+ if (phase == PHASE_DEAD)
+ return;
+ if (logged_in)
+ logout();
+ phase = PHASE_DEAD;
+ syslog(LOG_NOTICE, "Connection terminated.");
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void
+link_down(unit)
+ int unit;
+{
+ ipcp_close(0);
+ ccp_close(0);
+ phase = PHASE_TERMINATE;
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(unit)
+ int unit;
+{
+ int auth;
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ho = &lcp_hisoptions[unit];
+
+ if (auth_required && !(go->neg_chap || go->neg_upap)) {
+ /*
+ * We wanted the peer to authenticate itself, and it refused:
+ * treat it as though it authenticated with PAP using a username
+ * of "" and a password of "". If that's not OK, boot it out.
+ */
+ if (!wo->neg_upap || !null_login(unit)) {
+ syslog(LOG_WARNING, "peer refused to authenticate");
+ lcp_close(unit);
+ phase = PHASE_TERMINATE;
+ return;
+ }
+ }
+
+ phase = PHASE_AUTHENTICATE;
+ auth = 0;
+ if (go->neg_chap) {
+ ChapAuthPeer(unit, our_name, go->chap_mdtype);
+ auth |= CHAP_PEER;
+ } else if (go->neg_upap) {
+ upap_authpeer(unit);
+ auth |= UPAP_PEER;
+ }
+ if (ho->neg_chap) {
+ ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
+ auth |= CHAP_WITHPEER;
+ } else if (ho->neg_upap) {
+ upap_authwithpeer(unit, user, passwd);
+ auth |= UPAP_WITHPEER;
+ }
+ auth_pending[unit] = auth;
+
+ if (!auth)
+ network_phase(unit);
+}
+
+/*
+ * Proceed to the network phase.
+ */
+static void
+network_phase(unit)
+ int unit;
+{
+ phase = PHASE_NETWORK;
+ ipcp_open(unit);
+ ccp_open(unit);
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * Authentication failure: take the link down
+ */
+ lcp_close(unit);
+ phase = PHASE_TERMINATE;
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case PPP_CHAP:
+ bit = CHAP_PEER;
+ break;
+ case PPP_PAP:
+ bit = UPAP_PEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ return;
+ }
+
+ /*
+ * If there is no more authentication still to be done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0) {
+ phase = PHASE_NETWORK;
+ ipcp_open(unit);
+ ccp_open(unit);
+ }
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * We've failed to authenticate ourselves to our peer.
+ * He'll probably take the link down, and there's not much
+ * we can do except wait for that.
+ */
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case PPP_CHAP:
+ bit = CHAP_WITHPEER;
+ break;
+ case PPP_PAP:
+ bit = UPAP_WITHPEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ bit = 0;
+ }
+
+ /*
+ * If there is no more authentication still being done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ network_phase(unit);
+}
+
+
+/*
+ * check_auth_options - called to check authentication options.
+ */
+void
+check_auth_options()
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ lcp_options *ao = &lcp_allowoptions[0];
+
+ /* Default our_name to hostname, and user to our_name */
+ if (our_name[0] == 0 || usehostname)
+ strcpy(our_name, hostname);
+ if (user[0] == 0)
+ strcpy(user, our_name);
+
+ /* If authentication is required, ask peer for CHAP or PAP. */
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ wo->neg_chap = 1;
+ wo->neg_upap = 1;
+ }
+
+ /*
+ * Check whether we have appropriate secrets to use
+ * to authenticate ourselves and/or the peer.
+ */
+ if (ao->neg_upap && passwd[0] == 0 && !get_upap_passwd())
+ ao->neg_upap = 0;
+ if (wo->neg_upap && !uselogin && !have_upap_secret())
+ wo->neg_upap = 0;
+ if (ao->neg_chap && !have_chap_secret(our_name, remote_name))
+ ao->neg_chap = 0;
+ if (wo->neg_chap && !have_chap_secret(remote_name, our_name))
+ wo->neg_chap = 0;
+
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ fprintf(stderr, "\
+pppd: peer authentication required but no authentication files accessible\n");
+ exit(1);
+ }
+
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file. If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Authentication failed.
+ * UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
+ int unit;
+ char *auser;
+ int userlen;
+ char *apasswd;
+ int passwdlen;
+ char **msg;
+ int *msglen;
+{
+ int ret;
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char passwd[256], user[256];
+ char secret[MAXWORDLEN];
+ static int attempts = 0;
+
+ /*
+ * Make copies of apasswd and auser, then null-terminate them.
+ */
+ BCOPY(apasswd, passwd, passwdlen);
+ passwd[passwdlen] = '\0';
+ BCOPY(auser, user, userlen);
+ user[userlen] = '\0';
+
+ /*
+ * Open the file of upap secrets and scan for a suitable secret
+ * for authenticating this user.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ ret = UPAP_AUTHACK;
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ if (!uselogin) {
+ syslog(LOG_ERR, "Can't open upap password file %s: %m", filename);
+ ret = UPAP_AUTHNAK;
+ }
+
+ } else {
+ check_access(f, filename);
+ if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0
+ || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0)
+ && strcmp(crypt(passwd, secret), secret) != 0)) {
+ syslog(LOG_WARNING, "upap authentication failure for %s", user);
+ ret = UPAP_AUTHNAK;
+ }
+ fclose(f);
+ }
+
+ if (uselogin && ret == UPAP_AUTHACK) {
+ ret = login(user, passwd, msg, msglen);
+ if (ret == UPAP_AUTHNAK) {
+ syslog(LOG_WARNING, "upap login failure for %s", user);
+ }
+ }
+
+ if (ret == UPAP_AUTHNAK) {
+ *msg = "Login incorrect";
+ *msglen = strlen(*msg);
+ /*
+ * Frustrate passwd stealer programs.
+ * Allow 10 tries, but start backing off after 3 (stolen from login).
+ * On 10'th, drop the connection.
+ */
+ if (attempts++ >= 10) {
+ syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
+ attempts, devnam, user);
+ quit();
+ }
+ if (attempts > 3)
+ sleep((u_int) (attempts - 3) * 5);
+ if (addrs != NULL)
+ free_wordlist(addrs);
+
+ } else {
+ attempts = 0; /* Reset count */
+ *msg = "Login ok";
+ *msglen = strlen(*msg);
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ return ret;
+}
+
+
+/*
+ * login - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+static int
+login(user, passwd, msg, msglen)
+ char *user;
+ char *passwd;
+ char **msg;
+ int *msglen;
+{
+ struct passwd *pw;
+ char *epasswd;
+ char *tty;
+
+#ifdef HAS_SHADOW
+ struct spwd *spwd;
+ struct spwd *getspnam();
+#endif
+
+ if ((pw = getpwnam(user)) == NULL) {
+ return (UPAP_AUTHNAK);
+ }
+
+#ifdef HAS_SHADOW
+ if ((spwd = getspnam(user)) == NULL) {
+ pw->pw_passwd = "";
+ } else {
+ pw->pw_passwd = spwd->sp_pwdp;
+ }
+#endif
+
+ /*
+ * XXX If no passwd, let them login without one.
+ */
+ if (pw->pw_passwd == '\0') {
+ return (UPAP_AUTHACK);
+ }
+
+#ifdef HAS_SHADOW
+ if ((pw->pw_passwd && pw->pw_passwd[0] == '@'
+ && pw_auth (pw->pw_passwd+1, pw->pw_name, PW_PPP, NULL))
+ || !valid (passwd, pw)) {
+ return (UPAP_AUTHNAK);
+ }
+#else
+ epasswd = crypt(passwd, pw->pw_passwd);
+ if (strcmp(epasswd, pw->pw_passwd)) {
+ return (UPAP_AUTHNAK);
+ }
+#endif
+
+ syslog(LOG_INFO, "user %s logged in", user);
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+ tty = devnam;
+ if (strncmp(tty, "/dev/", 5) == 0)
+ tty += 5;
+ logwtmp(tty, user, ""); /* Add wtmp login entry */
+ logged_in = TRUE;
+
+ return (UPAP_AUTHACK);
+}
+
+/*
+ * logout - Logout the user.
+ */
+static void
+logout()
+{
+ char *tty;
+
+ tty = devnam;
+ if (strncmp(tty, "/dev/", 5) == 0)
+ tty += 5;
+ logwtmp(tty, "", ""); /* Wipe out wtmp logout entry */
+ logged_in = FALSE;
+}
+
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int
+null_login(unit)
+ int unit;
+{
+ char *filename;
+ FILE *f;
+ int i, ret;
+ struct wordlist *addrs;
+ char secret[MAXWORDLEN];
+
+ /*
+ * Open the file of upap secrets and scan for a suitable secret.
+ * We don't accept a wildcard client.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+
+ i = scan_authfile(f, "", our_name, secret, &addrs, filename);
+ ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0;
+
+ if (ret) {
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ fclose(f);
+ return ret;
+}
+
+
+/*
+ * get_upap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP. Returns 1 on success, 0 if no suitable password
+ * could be found.
+ */
+static int
+get_upap_passwd()
+{
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char secret[MAXWORDLEN];
+
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+ if (scan_authfile(f, user, remote_name, secret, NULL, filename) < 0)
+ return 0;
+ strncpy(passwd, secret, MAXSECRETLEN);
+ passwd[MAXSECRETLEN-1] = 0;
+ return 1;
+}
+
+
+/*
+ * have_upap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_upap_secret()
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_UPAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ ret = scan_authfile(f, NULL, our_name, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'. Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(client, server)
+ char *client;
+ char *server;
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_CHAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ if (client[0] == 0)
+ client = NULL;
+ else if (server[0] == 0)
+ server = NULL;
+
+ ret = scan_authfile(f, client, server, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(unit, client, server, secret, secret_len, save_addrs)
+ int unit;
+ char *client;
+ char *server;
+ char *secret;
+ int *secret_len;
+ int save_addrs;
+{
+ FILE *f;
+ int ret, len;
+ char *filename;
+ struct wordlist *addrs;
+ char secbuf[MAXWORDLEN];
+
+ filename = _PATH_CHAPFILE;
+ addrs = NULL;
+ secbuf[0] = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ syslog(LOG_ERR, "Can't open chap secret file %s: %m", filename);
+ return 0;
+ }
+ check_access(f, filename);
+
+ ret = scan_authfile(f, client, server, secbuf, &addrs, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ if (save_addrs) {
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ len = strlen(secbuf);
+ if (len > MAXSECRETLEN) {
+ syslog(LOG_ERR, "Secret for %s on %s is too long", client, server);
+ len = MAXSECRETLEN;
+ }
+ BCOPY(secbuf, secret, len);
+ *secret_len = len;
+
+ return 1;
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address. Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(unit, addr)
+ int unit;
+ u_int32_t addr;
+{
+ u_int32_t a;
+ struct hostent *hp;
+ struct wordlist *addrs;
+
+ /* don't allow loopback or multicast address */
+ if (bad_ip_adrs(addr))
+ return 0;
+
+ if ((addrs = addresses[unit]) == NULL)
+ return 1; /* no restriction */
+
+ for (; addrs != NULL; addrs = addrs->next) {
+ /* "-" means no addresses authorized */
+ if (strcmp(addrs->word, "-") == 0)
+ break;
+ if ((a = inet_addr(addrs->word)) == -1) {
+ if ((hp = gethostbyname(addrs->word)) == NULL) {
+ syslog(LOG_WARNING, "unknown host %s in auth. address list",
+ addrs->word);
+ continue;
+ } else
+ a = *(u_int32_t *)hp->h_addr;
+ }
+ if (addr == a)
+ return 1;
+ }
+ return 0; /* not in list => can't have it */
+}
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int
+bad_ip_adrs(addr)
+ u_int32_t addr;
+{
+ addr = ntohl(addr);
+ return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+ || IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+void
+check_access(f, filename)
+ FILE *f;
+ char *filename;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(f), &sbuf) < 0) {
+ syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename);
+ } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename);
+ }
+}
+
+
+/*
+ * scan_authfile - Scan an authorization file for a secret suitable
+ * for authenticating `client' on `server'. The return value is -1
+ * if no secret is found, otherwise >= 0. The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line (i.e. address authorization
+ * info) are placed in a wordlist and returned in *addrs.
+ */
+static int
+scan_authfile(f, client, server, secret, addrs, filename)
+ FILE *f;
+ char *client;
+ char *server;
+ char *secret;
+ struct wordlist **addrs;
+ char *filename;
+{
+ int newline, xxx;
+ int got_flag, best_flag;
+ FILE *sf;
+ struct wordlist *ap, *addr_list, *addr_last;
+ char word[MAXWORDLEN];
+ char atfile[MAXWORDLEN];
+
+ if (addrs != NULL)
+ *addrs = NULL;
+ addr_list = NULL;
+ if (!getword(f, word, &newline, filename))
+ return -1; /* file is empty??? */
+ newline = 1;
+ best_flag = -1;
+ for (;;) {
+ /*
+ * Skip until we find a word at the start of a line.
+ */
+ while (!newline && getword(f, word, &newline, filename))
+ ;
+ if (!newline)
+ break; /* got to end of file */
+
+ /*
+ * Got a client - check if it's a match or a wildcard.
+ */
+ got_flag = 0;
+ if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
+ newline = 0;
+ continue;
+ }
+ if (!ISWILD(word))
+ got_flag = NONWILD_CLIENT;
+
+ /*
+ * Now get a server and check if it matches.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+ if (server != NULL && strcmp(word, server) != 0 && !ISWILD(word))
+ continue;
+ if (!ISWILD(word))
+ got_flag |= NONWILD_SERVER;
+
+ /*
+ * Got some sort of a match - see if it's better than what
+ * we have already.
+ */
+ if (got_flag <= best_flag)
+ continue;
+
+ /*
+ * Get the secret.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+
+ /*
+ * Special syntax: @filename means read secret from file.
+ */
+ if (word[0] == '@') {
+ strcpy(atfile, word+1);
+ if ((sf = fopen(atfile, "r")) == NULL) {
+ syslog(LOG_WARNING, "can't open indirect secret file %s",
+ atfile);
+ continue;
+ }
+ check_access(sf, atfile);
+ if (!getword(sf, word, &xxx, atfile)) {
+ syslog(LOG_WARNING, "no secret in indirect secret file %s",
+ atfile);
+ fclose(sf);
+ continue;
+ }
+ fclose(sf);
+ }
+ if (secret != NULL)
+ strcpy(secret, word);
+
+ best_flag = got_flag;
+
+ /*
+ * Now read address authorization info and make a wordlist.
+ */
+ if (addr_list)
+ free_wordlist(addr_list);
+ addr_list = addr_last = NULL;
+ for (;;) {
+ if (!getword(f, word, &newline, filename) || newline)
+ break;
+ ap = (struct wordlist *) malloc(sizeof(struct wordlist)
+ + strlen(word));
+ if (ap == NULL)
+ novm("authorized addresses");
+ ap->next = NULL;
+ strcpy(ap->word, word);
+ if (addr_list == NULL)
+ addr_list = ap;
+ else
+ addr_last->next = ap;
+ addr_last = ap;
+ }
+ if (!newline)
+ break;
+ }
+
+ if (addrs != NULL)
+ *addrs = addr_list;
+ else if (addr_list != NULL)
+ free_wordlist(addr_list);
+
+ return best_flag;
+}
+
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(wp)
+ struct wordlist *wp;
+{
+ struct wordlist *next;
+
+ while (wp != NULL) {
+ next = wp->next;
+ free(wp);
+ wp = next;
+ }
+}
diff --git a/usr.sbin/pppd/ccp.c b/usr.sbin/pppd/ccp.c
new file mode 100644
index 00000000000..ca14b6ed9a8
--- /dev/null
+++ b/usr.sbin/pppd/ccp.c
@@ -0,0 +1,652 @@
+/*
+ * ccp.c - PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ccp.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+#include <string.h>
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <net/ppp-comp.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ccp.h"
+
+fsm ccp_fsm[NUM_PPP];
+ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */
+ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
+ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */
+ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */
+
+/*
+ * Callbacks for fsm code.
+ */
+static void ccp_resetci __P((fsm *));
+static int ccp_cilen __P((fsm *));
+static void ccp_addci __P((fsm *, u_char *, int *));
+static int ccp_ackci __P((fsm *, u_char *, int));
+static int ccp_nakci __P((fsm *, u_char *, int));
+static int ccp_rejci __P((fsm *, u_char *, int));
+static int ccp_reqci __P((fsm *, u_char *, int *, int));
+static void ccp_up __P((fsm *));
+static void ccp_down __P((fsm *));
+static int ccp_extcode __P((fsm *, int, int, u_char *, int));
+static void ccp_rack_timeout __P(());
+
+static fsm_callbacks ccp_callbacks = {
+ ccp_resetci,
+ ccp_cilen,
+ ccp_addci,
+ ccp_ackci,
+ ccp_nakci,
+ ccp_rejci,
+ ccp_reqci,
+ ccp_up,
+ ccp_down,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ccp_extcode,
+ "CCP"
+};
+
+/*
+ * Do we want / did we get any compression?
+ */
+#define ANY_COMPRESS(opt) ((opt).bsd_compress)
+
+/*
+ * Local state (mainly for handling reset-reqs and reset-acks
+ */
+static int ccp_localstate[NUM_PPP];
+#define RACK_PENDING 1 /* waiting for reset-ack */
+#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */
+
+#define RACKTIMEOUT 1 /* second */
+
+/*
+ * ccp_init - initialize CCP.
+ */
+void
+ccp_init(unit)
+ int unit;
+{
+ fsm *f = &ccp_fsm[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_CCP;
+ f->callbacks = &ccp_callbacks;
+ fsm_init(f);
+
+ memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options));
+
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = 12; /* default value */
+
+ ccp_allowoptions[0].bsd_compress = 1;
+ ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+}
+
+/*
+ * ccp_open - CCP is allowed to come up.
+ */
+void
+ccp_open(unit)
+ int unit;
+{
+ fsm *f = &ccp_fsm[unit];
+
+ if (f->state != OPENED)
+ ccp_flags_set(unit, 1, 0);
+ if (!ANY_COMPRESS(ccp_wantoptions[unit]))
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
+}
+
+/*
+ * ccp_close - Terminate CCP.
+ */
+void
+ccp_close(unit)
+ int unit;
+{
+ ccp_flags_set(unit, 0, 0);
+ fsm_close(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerup - we may now transmit CCP packets.
+ */
+void
+ccp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerdown - we may not transmit CCP packets.
+ */
+void
+ccp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_input - process a received CCP packet.
+ */
+void
+ccp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm *f = &ccp_fsm[unit];
+ int oldstate;
+
+ /*
+ * Check for a terminate-request so we can print a message.
+ */
+ oldstate = f->state;
+ fsm_input(f, p, len);
+ if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
+ syslog(LOG_NOTICE, "Compression disabled by peer.");
+
+ /*
+ * If we get a terminate-ack and we're not asking for compression,
+ * close CCP.
+ */
+ if (oldstate == REQSENT && p[0] == TERMACK
+ && !ANY_COMPRESS(ccp_gotoptions[unit]))
+ ccp_close(unit);
+}
+
+/*
+ * Handle a CCP-specific code.
+ */
+static int
+ccp_extcode(f, code, id, p, len)
+ fsm *f;
+ int code, id;
+ u_char *p;
+ int len;
+{
+ switch (code) {
+ case CCP_RESETREQ:
+ if (f->state != OPENED)
+ break;
+ /* send a reset-ack, which the transmitter will see and
+ reset its compression state. */
+ fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+ break;
+
+ case CCP_RESETACK:
+ if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
+ ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
+ UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * ccp_protrej - peer doesn't talk CCP.
+ */
+void
+ccp_protrej(unit)
+ int unit;
+{
+ ccp_flags_set(unit, 0, 0);
+ fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_resetci - initialize at start of negotiation.
+ */
+static void
+ccp_resetci(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char opt_buf[16];
+
+ *go = ccp_wantoptions[f->unit];
+ if (go->bsd_compress) {
+ opt_buf[0] = CI_BSD_COMPRESS;
+ opt_buf[1] = CILEN_BSD_COMPRESS;
+ opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+ if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0))
+ go->bsd_compress = 0;
+ }
+}
+
+/*
+ * ccp_cilen - Return total length of our configuration info.
+ */
+static int
+ccp_cilen(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+
+ return (go->bsd_compress? CILEN_BSD_COMPRESS: 0);
+}
+
+/*
+ * ccp_addci - put our requests in a packet.
+ */
+static void
+ccp_addci(f, p, lenp)
+ fsm *f;
+ u_char *p;
+ int *lenp;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char *p0 = p;
+
+ if (go->bsd_compress) {
+ p[0] = CI_BSD_COMPRESS;
+ p[1] = CILEN_BSD_COMPRESS;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+ if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0))
+ p += CILEN_BSD_COMPRESS;
+ else
+ go->bsd_compress = 0;
+ }
+ *lenp = p - p0;
+}
+
+/*
+ * ccp_ackci - process a received configure-ack, and return
+ * 1 iff the packet was OK.
+ */
+static int
+ccp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+
+ if (go->bsd_compress) {
+ if (len < CILEN_BSD_COMPRESS
+ || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
+ || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+ return 0;
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ }
+ if (len != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * ccp_nakci - process received configure-nak.
+ * Returns 1 iff the nak was OK.
+ */
+static int
+ccp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options no; /* options we've seen already */
+ ccp_options try; /* options to ask for next time */
+
+ memset(&no, 0, sizeof(no));
+ try = *go;
+
+ if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS
+ && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+ no.bsd_compress = 1;
+ /*
+ * Peer wants us to use a different number of bits
+ * or a different version.
+ */
+ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
+ try.bsd_compress = 0;
+ else if (BSD_NBITS(p[2]) < go->bsd_bits)
+ try.bsd_bits = BSD_NBITS(p[2]);
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ }
+
+ /*
+ * Have a look at any remaining options...???
+ */
+
+ if (len != 0)
+ return 0;
+
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+}
+
+/*
+ * ccp_rejci - reject some of our suggested compression methods.
+ */
+static int
+ccp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options try; /* options to request next time */
+
+ try = *go;
+
+ if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+ && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+ if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+ return 0;
+ try.bsd_compress = 0;
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ }
+
+ if (len != 0)
+ return 0;
+
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+}
+
+/*
+ * ccp_reqci - processed a received configure-request.
+ * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
+ * appropriately.
+ */
+static int
+ccp_reqci(f, p, lenp, dont_nak)
+ fsm *f;
+ u_char *p;
+ int *lenp;
+ int dont_nak;
+{
+ int ret, newret;
+ u_char *p0, *retp;
+ int len, clen, type, nb;
+ ccp_options *ho = &ccp_hisoptions[f->unit];
+ ccp_options *ao = &ccp_allowoptions[f->unit];
+
+ ret = CONFACK;
+ retp = p0 = p;
+ len = *lenp;
+
+ memset(ho, 0, sizeof(ccp_options));
+
+ while (len > 0) {
+ newret = CONFACK;
+ if (len < 2 || p[1] < 2 || p[1] > len) {
+ /* length is bad */
+ clen = len;
+ newret = CONFREJ;
+
+ } else {
+ type = p[0];
+ clen = p[1];
+
+ switch (type) {
+ case CI_BSD_COMPRESS:
+ if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->bsd_compress = 1;
+ ho->bsd_bits = nb = BSD_NBITS(p[2]);
+ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
+ || nb > ao->bsd_bits) {
+ newret = CONFNAK;
+ nb = ao->bsd_bits;
+ } else if (nb < BSD_MIN_BITS) {
+ newret = CONFREJ;
+ } else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) {
+ if (nb > BSD_MIN_BITS) {
+ --nb;
+ newret = CONFNAK;
+ } else
+ newret = CONFREJ;
+ }
+ if (newret == CONFNAK && !dont_nak) {
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+ }
+
+ break;
+
+ default:
+ newret = CONFREJ;
+ }
+ }
+
+ if (newret == CONFNAK && dont_nak)
+ newret = CONFREJ;
+ if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
+ /* we're returning this option */
+ if (newret == CONFREJ && ret == CONFNAK)
+ retp = p0;
+ ret = newret;
+ if (p != retp)
+ BCOPY(p, retp, clen);
+ retp += clen;
+ }
+
+ p += clen;
+ len -= clen;
+ }
+
+ if (ret != CONFACK)
+ *lenp = retp - p0;
+ return ret;
+}
+
+/*
+ * CCP has come up - inform the kernel driver.
+ */
+static void
+ccp_up(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options *ho = &ccp_hisoptions[f->unit];
+
+ ccp_flags_set(f->unit, 1, 1);
+ if (go->bsd_compress || ho->bsd_compress)
+ syslog(LOG_NOTICE, "%s enabled",
+ go->bsd_compress? ho->bsd_compress? "Compression":
+ "Receive compression": "Transmit compression");
+}
+
+/*
+ * CCP has gone down - inform the kernel driver.
+ */
+static void
+ccp_down(f)
+ fsm *f;
+{
+ if (ccp_localstate[f->unit] & RACK_PENDING)
+ UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
+ ccp_localstate[f->unit] = 0;
+ ccp_flags_set(f->unit, 1, 0);
+}
+
+/*
+ * Print the contents of a CCP packet.
+ */
+char *ccp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej",
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ "ResetReq", "ResetAck",
+};
+
+int
+ccp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ u_char *p0, *optend;
+ int code, id, len;
+ int optlen;
+
+ p0 = p;
+ if (plen < HEADERLEN)
+ return 0;
+ code = p[0];
+ id = p[1];
+ len = (p[2] << 8) + p[3];
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
+ && ccp_codenames[code-1] != NULL)
+ printer(arg, " %s", ccp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ p += HEADERLEN;
+
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print list of possible compression methods */
+ while (len >= 2) {
+ code = p[0];
+ optlen = p[1];
+ if (optlen < 2 || optlen > len)
+ break;
+ printer(arg, " <");
+ len -= optlen;
+ optend = p + optlen;
+ switch (code) {
+ case CI_BSD_COMPRESS:
+ if (optlen >= CILEN_BSD_COMPRESS) {
+ printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
+ BSD_NBITS(p[2]));
+ p += CILEN_BSD_COMPRESS;
+ }
+ break;
+ }
+ while (p < optend)
+ printer(arg, " %.2x", *p++);
+ printer(arg, ">");
+ }
+ break;
+ }
+
+ /* dump out the rest of the packet in hex */
+ while (--len >= 0)
+ printer(arg, " %.2x", *p++);
+
+ return p - p0;
+}
+
+/*
+ * We have received a packet that the decompressor failed to
+ * decompress. Here we would expect to issue a reset-request, but
+ * Motorola has a patent on resetting the compressor as a result of
+ * detecting an error in the decompressed data after decompression.
+ * (See US patent 5,130,993; international patent publication number
+ * WO 91/10289; Australian patent 73296/91.)
+ *
+ * So we ask the kernel whether the error was detected after
+ * decompression; if it was, we take CCP down, thus disabling
+ * compression :-(, otherwise we issue the reset-request.
+ */
+void
+ccp_datainput(unit, pkt, len)
+ int unit;
+ u_char *pkt;
+ int len;
+{
+ fsm *f;
+
+ f = &ccp_fsm[unit];
+ if (f->state == OPENED) {
+ if (ccp_fatal_error(unit)) {
+ /*
+ * Disable compression by taking CCP down.
+ */
+ syslog(LOG_ERR, "Lost compression sync: disabling compression");
+ ccp_close(unit);
+ } else {
+ /*
+ * Send a reset-request to reset the peer's compressor.
+ * We don't do that if we are still waiting for an
+ * acknowledgement to a previous reset-request.
+ */
+ if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
+ fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
+ ccp_localstate[f->unit] |= RACK_PENDING;
+ } else
+ ccp_localstate[f->unit] |= RREQ_REPEAT;
+ }
+ }
+}
+
+/*
+ * Timeout waiting for reset-ack.
+ */
+static void
+ccp_rack_timeout(arg)
+ caddr_t arg;
+{
+ fsm *f = (fsm *) arg;
+
+ if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
+ fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
+ TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
+ ccp_localstate[f->unit] &= ~RREQ_REPEAT;
+ } else
+ ccp_localstate[f->unit] &= ~RACK_PENDING;
+}
+
diff --git a/usr.sbin/pppd/ccp.h b/usr.sbin/pppd/ccp.h
new file mode 100644
index 00000000000..e703a200469
--- /dev/null
+++ b/usr.sbin/pppd/ccp.h
@@ -0,0 +1,51 @@
+/*
+ * ccp.h - Definitions for PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ccp.h,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $
+ */
+
+typedef struct ccp_options {
+ u_int bsd_compress: 1; /* do BSD Compress? */
+ u_short bsd_bits; /* # bits/code for BSD Compress */
+} ccp_options;
+
+extern fsm ccp_fsm[];
+extern ccp_options ccp_wantoptions[];
+extern ccp_options ccp_gotoptions[];
+extern ccp_options ccp_allowoptions[];
+extern ccp_options ccp_hisoptions[];
+
+void ccp_init __P((int unit));
+void ccp_open __P((int unit));
+void ccp_close __P((int unit));
+void ccp_lowerup __P((int unit));
+void ccp_lowerdown __P((int));
+void ccp_input __P((int unit, u_char *pkt, int len));
+void ccp_protrej __P((int unit));
+int ccp_printpkt __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+void ccp_datainput __P((int unit, u_char *pkt, int len));
diff --git a/usr.sbin/pppd/chap.c b/usr.sbin/pppd/chap.c
new file mode 100644
index 00000000000..f8e538d7de6
--- /dev/null
+++ b/usr.sbin/pppd/chap.c
@@ -0,0 +1,805 @@
+/*
+ * chap.c - Crytographic Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: chap.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "md5.h"
+
+chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout __P((caddr_t));
+static void ChapResponseTimeout __P((caddr_t));
+static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
+static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
+static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
+static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
+static void ChapSendStatus __P((chap_state *, int));
+static void ChapSendChallenge __P((chap_state *));
+static void ChapSendResponse __P((chap_state *));
+static void ChapGenChallenge __P((chap_state *));
+
+extern double drand48 __P((void));
+extern void srand48 __P((long));
+
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+void
+ChapInit(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ BZERO(cstate, sizeof(*cstate));
+ cstate->unit = unit;
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+ cstate->timeouttime = CHAP_DEFTIMEOUT;
+ cstate->max_transmits = CHAP_DEFTRANSMITS;
+ /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void
+ChapAuthWithPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->resp_name = our_name;
+ cstate->resp_type = digest;
+
+ if (cstate->clientstate == CHAPCS_INITIAL ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->clientstate = CHAPCS_PENDING;
+ return;
+ }
+
+ /*
+ * We get here as a result of LCP coming up.
+ * So even if CHAP was open before, we will
+ * have to re-authenticate ourselves.
+ */
+ cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void
+ChapAuthPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->chal_name = our_name;
+ cstate->chal_type = digest;
+
+ if (cstate->serverstate == CHAPSS_INITIAL ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->serverstate = CHAPSS_PENDING;
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate); /* crank it up dude! */
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void
+ChapChallengeTimeout(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending challenges, don't worry. then again we */
+ /* probably shouldn't be here either */
+ if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+ cstate->serverstate != CHAPSS_RECHALLENGE)
+ return;
+
+ if (cstate->chal_transmits >= cstate->max_transmits) {
+ /* give up on peer */
+ syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ return;
+ }
+
+ ChapSendChallenge(cstate); /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->clientstate != CHAPCS_RESPONSE)
+ return;
+
+ ChapSendResponse(cstate); /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->serverstate != CHAPSS_OPEN)
+ return;
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+void
+ChapLowerUp(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->clientstate == CHAPCS_INITIAL)
+ cstate->clientstate = CHAPCS_CLOSED;
+ else if (cstate->clientstate == CHAPCS_PENDING)
+ cstate->clientstate = CHAPCS_LISTEN;
+
+ if (cstate->serverstate == CHAPSS_INITIAL)
+ cstate->serverstate = CHAPSS_CLOSED;
+ else if (cstate->serverstate == CHAPSS_PENDING) {
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+ }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+void
+ChapLowerDown(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ /* Timeout(s) pending? Cancel if so. */
+ if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+ cstate->serverstate == CHAPSS_RECHALLENGE)
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+ else if (cstate->serverstate == CHAPSS_OPEN
+ && cstate->chal_interval != 0)
+ UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+void
+ChapProtocolReject(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->serverstate != CHAPSS_INITIAL &&
+ cstate->serverstate != CHAPSS_CLOSED)
+ auth_peer_fail(unit, PPP_CHAP);
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED)
+ auth_withpeer_fail(unit, PPP_CHAP);
+ ChapLowerDown(unit); /* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+void
+ChapInput(unit, inpacket, packet_len)
+ int unit;
+ u_char *inpacket;
+ int packet_len;
+{
+ chap_state *cstate = &chap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (packet_len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
+ return;
+ }
+ if (len > packet_len) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
+ return;
+ }
+ len -= CHAP_HEADERLEN;
+
+ /*
+ * Action depends on code (as in fact it usually does :-).
+ */
+ switch (code) {
+ case CHAP_CHALLENGE:
+ ChapReceiveChallenge(cstate, inp, id, len);
+ break;
+
+ case CHAP_RESPONSE:
+ ChapReceiveResponse(cstate, inp, id, len);
+ break;
+
+ case CHAP_FAILURE:
+ ChapReceiveFailure(cstate, inp, id, len);
+ break;
+
+ case CHAP_SUCCESS:
+ ChapReceiveSuccess(cstate, inp, id, len);
+ break;
+
+ default: /* Need code reject? */
+ syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
+ break;
+ }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void
+ChapReceiveChallenge(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ int rchallenge_len;
+ u_char *rchallenge;
+ int secret_len;
+ char secret[MAXSECRETLEN];
+ char rhostname[256];
+ MD5_CTX mdContext;
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
+ if (cstate->clientstate == CHAPCS_CLOSED ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
+ cstate->clientstate));
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+
+ GETCHAR(rchallenge_len, inp);
+ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+ rchallenge = inp;
+ INCPTR(rchallenge_len, inp);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
+ rhostname));
+
+ /* get secret for authenticating ourselves with the specified host */
+ if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+ secret, &secret_len, 0)) {
+ secret_len = 0; /* assume null secret if can't find one */
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
+ rhostname);
+ }
+
+ /* cancel response send timeout if necessary */
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ cstate->resp_id = id;
+ cstate->resp_transmits = 0;
+
+ /* generate MD based on negotiated type */
+ switch (cstate->resp_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->resp_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, rchallenge, rchallenge_len);
+ MD5Final(&mdContext);
+ BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE);
+ cstate->resp_length = MD5_SIGNATURE_SIZE;
+ break;
+
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
+ return;
+ }
+
+ ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char *remmd, remmd_len;
+ int secret_len, old_state;
+ int code;
+ char rhostname[256];
+ u_char buf[256];
+ MD5_CTX mdContext;
+ u_char msg[256];
+ char secret[MAXSECRETLEN];
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
+
+ if (cstate->serverstate == CHAPSS_CLOSED ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
+ cstate->serverstate));
+ return;
+ }
+
+ if (id != cstate->chal_id)
+ return; /* doesn't match ID of last challenge */
+
+ /*
+ * If we have received a duplicate or bogus Response,
+ * we have to send the same answer (Success/Failure)
+ * as we did for the first Response we saw.
+ */
+ if (cstate->serverstate == CHAPSS_OPEN) {
+ ChapSendStatus(cstate, CHAP_SUCCESS);
+ return;
+ }
+ if (cstate->serverstate == CHAPSS_BADAUTH) {
+ ChapSendStatus(cstate, CHAP_FAILURE);
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+ GETCHAR(remmd_len, inp); /* get length of MD */
+ remmd = inp; /* get pointer to MD */
+ INCPTR(remmd_len, inp);
+
+ len -= sizeof (u_char) + remmd_len;
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
+ rhostname));
+
+ /*
+ * Get secret for authenticating them with us,
+ * do the hash ourselves, and compare the result.
+ */
+ code = CHAP_FAILURE;
+ if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+ secret, &secret_len, 1)) {
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
+ rhostname);
+ } else {
+
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE)
+ break; /* it's not even the right length */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(&mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (memcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0)
+ code = CHAP_SUCCESS; /* they are the same! */
+ break;
+
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
+ }
+ }
+
+ ChapSendStatus(cstate, code);
+
+ if (code == CHAP_SUCCESS) {
+ old_state = cstate->serverstate;
+ cstate->serverstate = CHAPSS_OPEN;
+ if (old_state == CHAPSS_INITIAL_CHAL) {
+ auth_peer_success(cstate->unit, PPP_CHAP);
+ }
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
+
+ } else {
+ syslog(LOG_ERR, "CHAP peer authentication failed");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void
+ChapReceiveSuccess(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
+{
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
+
+ if (cstate->clientstate == CHAPCS_OPEN)
+ /* presumably an answer to a duplicate response */
+ return;
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ cstate->clientstate = CHAPCS_OPEN;
+
+ auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void
+ChapReceiveFailure(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
+{
+ u_char msglen;
+ u_char *msg;
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ syslog(LOG_ERR, "CHAP authentication failed");
+ auth_withpeer_fail(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void
+ChapSendChallenge(cstate)
+ chap_state *cstate;
+{
+ u_char *outp;
+ int chal_len, name_len;
+ int outlen;
+
+ chal_len = cstate->chal_len;
+ name_len = strlen(cstate->chal_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
+
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+
+ PUTCHAR(chal_len, outp); /* put length of challenge */
+ BCOPY(cstate->challenge, outp, chal_len);
+ INCPTR(chal_len, outp);
+
+ BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
+
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
+
+ TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void
+ChapSendStatus(cstate, code)
+ chap_state *cstate;
+ int code;
+{
+ u_char *outp;
+ int outlen, msglen;
+ char msg[256];
+
+ if (code == CHAP_SUCCESS)
+ sprintf(msg, "Welcome to %s.", hostname);
+ else
+ sprintf(msg, "I don't like you. Go 'way.");
+ msglen = strlen(msg);
+
+ outlen = CHAP_HEADERLEN + msglen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
+
+ PUTCHAR(code, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+ BCOPY(msg, outp, msglen);
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
+ cstate->chal_id));
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len. The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void
+ChapGenChallenge(cstate)
+ chap_state *cstate;
+{
+ int chal_len;
+ u_char *ptr = cstate->challenge;
+ unsigned int i;
+
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
+ chal_len = (unsigned) ((drand48() *
+ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+ MIN_CHALLENGE_LENGTH);
+ cstate->chal_len = chal_len;
+ cstate->chal_id = ++cstate->id;
+ cstate->chal_transmits = 0;
+
+ /* generate a random string */
+ for (i = 0; i < chal_len; i++ )
+ *ptr++ = (char) (drand48() * 0xff);
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void
+ChapSendResponse(cstate)
+ chap_state *cstate;
+{
+ u_char *outp;
+ int outlen, md_len, name_len;
+
+ md_len = cstate->resp_length;
+ name_len = strlen(cstate->resp_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP);
+
+ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
+ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+ PUTSHORT(outlen, outp); /* packet length */
+
+ PUTCHAR(md_len, outp); /* length of MD */
+ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
+ INCPTR(md_len, outp);
+
+ BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+ /* send the packet */
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ cstate->clientstate = CHAPCS_RESPONSE;
+ TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+char *ChapCodenames[] = {
+ "Challenge", "Response", "Success", "Failure"
+};
+
+int
+ChapPrintPkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len;
+ int clen, nlen;
+ u_char x;
+
+ if (plen < CHAP_HEADERLEN)
+ return 0;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < CHAP_HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+ printer(arg, " %s", ChapCodenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= CHAP_HEADERLEN;
+ switch (code) {
+ case CHAP_CHALLENGE:
+ case CHAP_RESPONSE:
+ if (len < 1)
+ break;
+ clen = p[0];
+ if (len < clen + 1)
+ break;
+ ++p;
+ nlen = len - clen - 1;
+ printer(arg, " <");
+ for (; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, "%.2x", x);
+ }
+ printer(arg, ">, name = ");
+ print_string((char *)p, nlen, printer, arg);
+ break;
+ case CHAP_FAILURE:
+ case CHAP_SUCCESS:
+ printer(arg, " ");
+ print_string((char *)p, len, printer, arg);
+ break;
+ default:
+ for (clen = len; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, " %.2x", x);
+ }
+ }
+
+ return len + CHAP_HEADERLEN;
+}
diff --git a/usr.sbin/pppd/chap.h b/usr.sbin/pppd/chap.h
new file mode 100644
index 00000000000..41ad8b73eb0
--- /dev/null
+++ b/usr.sbin/pppd/chap.h
@@ -0,0 +1,112 @@
+/*
+ * chap.h - Cryptographic Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.h,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $
+ */
+
+#ifndef __CHAP_INCLUDE__
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN 4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+
+/*
+ * Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH 32
+#define MAX_CHALLENGE_LENGTH 64
+#define MAX_RESPONSE_LENGTH 16 /* sufficient for MD5 */
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+ int unit; /* Interface unit number */
+ int clientstate; /* Client state */
+ int serverstate; /* Server state */
+ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+ u_char chal_len; /* challenge length */
+ u_char chal_id; /* ID of last challenge */
+ u_char chal_type; /* hash algorithm for challenges */
+ u_char id; /* Current id */
+ char *chal_name; /* Our name to use with challenge */
+ int chal_interval; /* Time until we challenge peer again */
+ int timeouttime; /* Timeout time in seconds */
+ int max_transmits; /* Maximum # of challenge transmissions */
+ int chal_transmits; /* Number of transmissions of challenge */
+ int resp_transmits; /* Number of transmissions of response */
+ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
+ u_char resp_length; /* length of response */
+ u_char resp_id; /* ID for response messages */
+ u_char resp_type; /* hash algorithm for responses */
+ char *resp_name; /* Our name to send with response */
+} chap_state;
+
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN 3 /* Listening for a challenge */
+#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
+#define CHAPCS_OPEN 5 /* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPSS_PENDING 2 /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
+#define CHAPSS_OPEN 4 /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
+#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
+
+/*
+ * Timeouts.
+ */
+#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
+
+extern chap_state chap[];
+
+void ChapInit __P((int));
+void ChapAuthWithPeer __P((int, char *, int));
+void ChapAuthPeer __P((int, char *, int));
+void ChapLowerUp __P((int));
+void ChapLowerDown __P((int));
+void ChapInput __P((int, u_char *, int));
+void ChapProtocolReject __P((int));
+int ChapPrintPkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+#define __CHAP_INCLUDE__
+#endif /* __CHAP_INCLUDE__ */
diff --git a/usr.sbin/pppd/chat/Makefile b/usr.sbin/pppd/chat/Makefile
new file mode 100644
index 00000000000..2e040b6e3ae
--- /dev/null
+++ b/usr.sbin/pppd/chat/Makefile
@@ -0,0 +1,8 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $
+
+PROG= chat
+SRCS= chat.c
+MAN= chat.8
+BINDIR= /usr/sbin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pppd/chat/chat.8 b/usr.sbin/pppd/chat/chat.8
new file mode 100644
index 00000000000..7452eb05964
--- /dev/null
+++ b/usr.sbin/pppd/chat/chat.8
@@ -0,0 +1,309 @@
+.\" -*- nroff -*-
+.\" manual page [] for chat 1.8
+.\" $Id: chat.8,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH CHAT 8 "5 May 1995" "Chat Version 1.9"
+.SH NAME
+chat \- Automated conversational script with a modem
+.SH SYNOPSIS
+.B chat
+[
+.I options
+]
+.I script
+.SH DESCRIPTION
+.LP
+The \fIchat\fR program defines a conversational exchange between the
+computer and the modem. Its primary purpose is to establish the
+connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and
+the remote's \fIpppd\fR process.
+.SH OPTIONS
+.TP
+.B -f \fI<chat file>
+Read the chat script from the chat \fIfile\fR. The use of this option
+is mutually exclusive with the chat script parameters. The user must
+have read access to the file. Multiple lines are permitted in the
+file. Space or horizontal tab characters should be used to separate
+the strings.
+.TP
+.B -t \fI<timeout>
+Set the timeout for the expected string to be received. If the string
+is not received within the time limit then the reply string is not
+sent. An alternate reply may be sent or the script will fail if there
+is no alternate reply string. A failed script will cause the
+\fIchat\fR program to terminate with a non-zero error code.
+.TP
+.B -r \fI<report file>
+Set the file for output of the report strings. If you use the keyword
+\fIREPORT\fR, the resulting strings are written to this file. If this
+option is not used and you still use \fIREPORT\fR keywords, the
+\fIstderr\fR file is used for the report strings.
+.TP
+.B -v
+Request that the \fIchat\fR script be executed in a verbose mode. The
+\fIchat\fR program will then log all text received from the modem and
+the output strings which it sends to the SYSLOG.
+.TP
+.B script
+If the script is not specified in a file with the \fI-f\fR option then
+the script is included as parameters to the \fIchat\fR program.
+.SH CHAT SCRIPT
+.LP
+The \fIchat\fR script defines the communications.
+.LP
+A script consists of one or more "expect-send" pairs of strings,
+separated by spaces, with an optional "subexpect-subsend" string pair,
+separated by a dash as in the following example:
+.IP
+ogin:-BREAK-ogin: ppp ssword: hello2u2
+.LP
+This line indicates that the \fIchat\fR program should expect the string
+"ogin:". If it fails to receive a login prompt within the time interval
+allotted, it is to send a break sequence to the remote and then expect the
+string "ogin:". If the first "ogin:" is received then the break sequence is
+not generated.
+.LP
+Once it received the login prompt the \fIchat\fR program will send the
+string ppp and then expect the prompt "ssword:". When it receives the
+prompt for the password, it will send the password hello2u2.
+.LP
+A carriage return is normally sent following the reply string. It is not
+expected in the "expect" string unless it is specifically requested by using
+the \\r character sequence.
+.LP
+The expect sequence should contain only what is needed to identify the
+string. Since it is normally stored on a disk file, it should not contain
+variable information. It is generally not acceptable to look for time
+strings, network identification strings, or other variable pieces of data as
+an expect string.
+.LP
+To help correct for characters which may be corrupted during the initial
+sequence, look for the string "ogin:" rather than "login:". It is possible
+that the leading "l" character may be received in error and you may never
+find the string even though it was sent by the system. For this reason,
+scripts look for "ogin:" rather than "login:" and "ssword:" rather than
+"password:".
+.LP
+A very simple script might look like this:
+.IP
+ogin: ppp ssword: hello2u2
+.LP
+In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2.
+.LP
+In actual practice, simple scripts are rare. At the vary least, you
+should include sub-expect sequences should the original string not be
+received. For example, consider the following script:
+.IP
+ogin:--ogin: ppp ssowrd: hello2u2
+.LP
+This would be a better script than the simple one used earlier. This would look
+for the same login: prompt, however, if one was not received, a single
+return sequence is sent and then it will look for login: again. Should line
+noise obscure the first login prompt then sending the empty line will
+usually generate a login prompt again.
+.SH ABORT STRINGS
+Many modems will report the status of the call as a string. These
+strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It
+is often desirable to terminate the script should the modem fail to
+connect to the remote. The difficulty is that a script would not know
+exactly which modem string it may receive. On one attempt, it may
+receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR.
+.LP
+These "abort" strings may be specified in the script using the \fIABORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT
+.LP
+This sequence will expect nothing; and then send the string ATZ. The
+expected response to this is the string \fIOK\fR. When it receives \fIOK\fR,
+the string ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the
+script is executed. However, should the modem find a busy telephone, it will
+send the string \fIBUSY\fR. This will cause the string to match the abort
+character sequence. The script will then fail because it found a match to
+the abort string. If it received the string \fINO CARRIER\fR, it will abort
+for the same reason. Either string may be received. Either string will
+terminate the \fIchat\fR script.
+
+.SH REPORT STRINGS
+A \fBreport\fR string is similar to the ABORT string. The difference
+is that the strings, and all characters to the next control character
+such as a carriage return, are written to the report file.
+.LP
+The report strings may be used to isolate the transmission rate of the
+modem's connect string and return the value to the chat user. The
+analysis of the report string logic occurs in conjunction with the
+other string processing such as looking for the expect string. The use
+of the same string for a report and abort sequence is probably not
+very useful, however, it is possible.
+.LP
+The report strings to no change the completion code of the program.
+.LP
+These "report" strings may be specified in the script using the \fIREPORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account
+.LP
+This sequence will expect nothing; and then send the string
+ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder
+of the script is executed. In addition the program will write to the
+expect-file the string "CONNECT" plus any characters which follow it
+such as the connection rate.
+.SH TIMEOUT
+The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR
+parameter.
+.LP
+To change the timeout value for the next expect string, the following
+example may be used:
+.IP
+ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assowrd: hello2u2
+.LP
+This will change the timeout to 10 seconds when it expects the login:
+prompt. The timeout is then changed to 5 seconds when it looks for the
+password prompt.
+.LP
+The timeout, once changed, remains in effect until it is changed again.
+.SH SENDING EOT
+The special reply string of \fIEOT\fR indicates that the chat program
+should send an EOT character to the remote. This is normally the
+End-of-file character sequence. A return character is not sent
+following the EOT.
+.PR
+The EOT sequence may be embedded into the send string using the
+sequence \fI^D\fR.
+.SH GENERATING BREAK
+The special reply string of \fIBREAK\fR will cause a break condition
+to be sent. The break is a special signal on the transmitter. The
+normal processing on the receiver is to change the transmission rate.
+It may be used to cycle through the available transmission rates on
+the remote until you are able to receive a valid login prompt.
+.PR
+The break sequence may be embedded into the send string using the
+\fI\\K\fR sequence.
+.SH ESCAPE SEQUENCES
+The expect and reply strings may contain escape sequences. All of the
+sequences are legal in the reply string. Many are legal in the expect.
+Those which are not valid in the expect sequence are so indicated.
+.TP
+.B ''
+Expects or sends a null string. If you send a null string then it will still
+send the return character. This sequence may either be a pair of apostrophe
+or quote characters.
+.TP
+.B \\\\b
+represents a backspace character.
+.TP
+.B \\\\c
+Suppresses the newline at the end of the reply string. This is the only
+method to send a string without a trailing return character. It must
+be at the end of the send string. For example,
+the sequence hello\\c will simply send the characters h, e, l, l, o.
+.I (not valid in expect.)
+.TP
+.B \\\\d
+Delay for one second. The program uses sleep(1) which will delay to a
+maximum of one second.
+.I (not valid in expect.)
+.TP
+.B \\\\K
+Insert a BREAK
+.I (not valid in expect.)
+.TP
+.B \\\\n
+Send a newline or linefeed character.
+.TP
+.B \\\\N
+Send a null character. The same sequence may be represented by \\0.
+.I (not valid in expect.)
+.TP
+.B \\\\p
+Pause for a fraction of a second. The delay is 1/10th of a second.
+.I (not valid in expect.)
+.TP
+.B \\\\q
+Suppress writing the string to the SYSLOG file. The string ?????? is
+written to the log in its place.
+.I (not valid in expect.)
+.TP
+.B \\\\r
+Send or expect a carriage return.
+.TP
+.B \\\\s
+Represents a space character in the string. This may be used when it
+is not desirable to quote the strings which contains spaces. The
+sequence 'HI TIM' and HI\\sTIM are the same.
+.TP
+.B \\\\t
+Send or expect a tab character.
+.TP
+.B \\\\\\\\
+Send or expect a backslash character.
+.TP
+.B \\\\ddd
+Collapse the octal digits (ddd) into a single ASCII character and send that
+character.
+.I (some characters are not valid in expect.)
+.TP
+.B \^^C
+Substitute the sequence with the control character represented by C.
+For example, the character DC1 (17) is shown as \^^Q.
+.I (some characters are not valid in expect.)
+.SH TERMINATION CODES
+The \fIchat\fR program will terminate with the following completion
+codes.
+.TP
+.B 0
+The normal termination of the program. This indicates that the script
+was executed without error to the normal conclusion.
+.TP
+.B 1
+One or more of the parameters are invalid or an expect string was too
+large for the internal buffers. This indicates that the program as not
+properly executed.
+.TP
+.B 2
+An error occurred during the execution of the program. This may be due
+to a read or write operation failing for some reason or chat receiving
+a signal such as SIGINT.
+.TP
+.B 3
+A timeout event occurred when there was an \fIexpect\fR string without
+having a "-subsend" string. This may mean that you did not program the
+script correctly for the condition or that some unexpected event has
+occurred and the expected string could not be found.
+.TP
+.B 4
+The first string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 5
+The second string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 6
+The third string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 7
+The fourth string marked as an \fIABORT\fR condition occurred.
+.TP
+.B ...
+The other termination codes are also strings marked as an \fIABORT\fR
+condition.
+.LP
+Using the termination code, it is possible to determine which event
+terminated the script. It is possible to decide if the string "BUSY"
+was received from the modem as opposed to "NO DIAL TONE". While the
+first event may be retried, the second will probably have little
+chance of succeeding during a retry.
+.SH SEE ALSO
+Additional information about \fIchat\fR scripts may be found with UUCP
+documentation. The \fIchat\fR script was taken from the ideas proposed
+by the scripts used by the \fIuucico\fR program.
+.LP
+uucico(1), uucp(1)
+.SH COPYRIGHT
+The \fIchat\fR program is in public domain. This is not the GNU public
+license. If it breaks then you get to keep both pieces.
diff --git a/usr.sbin/pppd/chat/chat.c b/usr.sbin/pppd/chat/chat.c
new file mode 100644
index 00000000000..29be67b4311
--- /dev/null
+++ b/usr.sbin/pppd/chat/chat.c
@@ -0,0 +1,1349 @@
+/*
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * Standard termination codes:
+ * 0 - successful completion of the script
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condtion.
+ * 3 - timeout waiting for a simple string.
+ * 4 - the first string declared as "ABORT"
+ * 5 - the second string declared as "ABORT"
+ * 6 - ... and so on for successive ABORT strings.
+ *
+ * This software is in the public domain.
+ *
+ * Please send all bug reports, requests for information, etc. to:
+ *
+ * Al Longyear (longyear@netcom.com)
+ * (I was the last person to change this code.)
+ *
+ * Added -r "report file" switch & REPORT keyword.
+ * Robert Geer <bgeer@xmission.com>
+ *
+ * The original author is:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ */
+
+static char rcsid[] = "$Id: chat.c,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $";
+
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#ifndef TERMIO
+#undef TERMIOS
+#define TERMIOS
+#endif
+
+#ifdef TERMIO
+#include <termio.h>
+#endif
+#ifdef TERMIOS
+#include <termios.h>
+#endif
+
+#define STR_LEN 1024
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+#ifdef __STDC__
+#undef __P
+#define __P(x) x
+#else
+#define __P(x) ()
+#define const
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+/*************** Micro getopt() *********************************************/
+#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
+ (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
+ &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
+#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
+ (_O=4,(char*)0):(char*)0)
+#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
+#define ARG(c,v) (c?(--c,*v++):(char*)0)
+
+static int _O = 0; /* Internal state */
+/*************** Micro getopt() *********************************************/
+
+char *program_name;
+
+#define MAX_ABORTS 50
+#define MAX_REPORTS 50
+#define DEFAULT_CHAT_TIMEOUT 45
+
+int verbose = 0;
+int quiet = 0;
+int report = 0;
+int exit_code = 0;
+FILE* report_fp = (FILE *) 0;
+char *report_file = (char *) 0;
+char *chat_file = (char *) 0;
+int timeout = DEFAULT_CHAT_TIMEOUT;
+
+int have_tty_parameters = 0;
+
+#ifdef TERMIO
+#define term_parms struct termio
+#define get_term_param(param) ioctl(0, TCGETA, param)
+#define set_term_param(param) ioctl(0, TCSETA, param)
+struct termio saved_tty_parameters;
+#endif
+
+#ifdef TERMIOS
+#define term_parms struct termios
+#define get_term_param(param) tcgetattr(0, param)
+#define set_term_param(param) tcsetattr(0, TCSANOW, param)
+struct termios saved_tty_parameters;
+#endif
+
+char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
+ fail_buffer[50];
+int n_aborts = 0, abort_next = 0, timeout_next = 0;
+
+char *report_string[MAX_REPORTS] ;
+char report_buffer[50] ;
+int n_reports = 0, report_next = 0, report_gathering = 0 ;
+
+void *dup_mem __P((void *b, size_t c));
+void *copy_of __P((char *s));
+void usage __P((void));
+void logf __P((const char *str));
+void logflush __P((void));
+void fatal __P((const char *msg));
+void sysfatal __P((const char *msg));
+SIGTYPE sigalrm __P((int signo));
+SIGTYPE sigint __P((int signo));
+SIGTYPE sigterm __P((int signo));
+SIGTYPE sighup __P((int signo));
+void unalarm __P((void));
+void init __P((void));
+void set_tty_parameters __P((void));
+void break_sequence __P((void));
+void terminate __P((int status));
+void do_file __P((char *chat_file));
+int get_string __P((register char *string));
+int put_string __P((register char *s));
+int write_char __P((int c));
+int put_char __P((int c));
+int get_char __P((void));
+void chat_send __P((register char *s));
+char *character __P((int c));
+void chat_expect __P((register char *s));
+char *clean __P((register char *s, int sending));
+void break_sequence __P((void));
+void terminate __P((int status));
+void die __P((void));
+
+void *dup_mem(b, c)
+void *b;
+size_t c;
+ {
+ void *ans = malloc (c);
+ if (!ans)
+ {
+ fatal ("memory error!\n");
+ }
+ memcpy (ans, b, c);
+ return ans;
+ }
+
+void *copy_of (s)
+char *s;
+ {
+ return dup_mem (s, strlen (s) + 1);
+ }
+
+/*
+ * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \
+ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
+ *
+ * Perform a UUCP-dialer-like chat script on stdin and stdout.
+ */
+int
+main(argc, argv)
+int argc;
+char **argv;
+ {
+ int option;
+ char *arg;
+
+ program_name = *argv;
+ tzset();
+
+ while (option = OPTION(argc, argv))
+ {
+ switch (option)
+ {
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'f':
+ if (arg = OPTARG(argc, argv))
+ {
+ chat_file = copy_of(arg);
+ }
+ else
+ {
+ usage();
+ }
+ break;
+
+ case 't':
+ if (arg = OPTARG(argc, argv))
+ {
+ timeout = atoi(arg);
+ }
+ else
+ {
+ usage();
+ }
+ break;
+
+ case 'r':
+ arg = OPTARG (argc, argv);
+ if (arg)
+ {
+ if (report_fp != NULL)
+ {
+ fclose (report_fp);
+ }
+ report_file = copy_of (arg);
+ report_fp = fopen (report_file, "a");
+ if (report_fp != NULL)
+ {
+ if (verbose)
+ {
+ fprintf (report_fp, "Opening \"%s\"...\n",
+ report_file);
+ }
+ report = 1;
+ }
+ }
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+/*
+ * Default the report file to the stderr location
+ */
+ if (report_fp == NULL)
+ {
+ report_fp = stderr;
+ }
+
+#ifdef ultrix
+ openlog("chat", LOG_PID);
+#else
+ openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
+
+ if (verbose)
+ {
+ setlogmask(LOG_UPTO(LOG_INFO));
+ }
+ else
+ {
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ }
+#endif
+
+ init();
+
+ if (chat_file != NULL)
+ {
+ arg = ARG(argc, argv);
+ if (arg != NULL)
+ {
+ usage();
+ }
+ else
+ {
+ do_file (chat_file);
+ }
+ }
+ else
+ {
+ while (arg = ARG(argc, argv))
+ {
+ chat_expect(arg);
+
+ if (arg = ARG(argc, argv))
+ {
+ chat_send(arg);
+ }
+ }
+ }
+
+ terminate(0);
+ }
+
+/*
+ * Process a chat script when read from a file.
+ */
+
+void do_file (chat_file)
+char *chat_file;
+ {
+ int linect, len, sendflg;
+ char *sp, *arg, quote;
+ char buf [STR_LEN];
+ FILE *cfp;
+
+ cfp = fopen (chat_file, "r");
+ if (cfp == NULL)
+ {
+ syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
+ terminate (1);
+ }
+
+ linect = 0;
+ sendflg = 0;
+
+ while (fgets(buf, STR_LEN, cfp) != NULL)
+ {
+ sp = strchr (buf, '\n');
+ if (sp)
+ {
+ *sp = '\0';
+ }
+
+ linect++;
+ sp = buf;
+ while (*sp != '\0')
+ {
+ if (*sp == ' ' || *sp == '\t')
+ {
+ ++sp;
+ continue;
+ }
+
+ if (*sp == '"' || *sp == '\'')
+ {
+ quote = *sp++;
+ arg = sp;
+ while (*sp != quote)
+ {
+ if (*sp == '\0')
+ {
+ syslog (LOG_ERR, "unterminated quote (line %d)",
+ linect);
+ terminate (1);
+ }
+
+ if (*sp++ == '\\')
+ {
+ if (*sp != '\0')
+ {
+ ++sp;
+ }
+ }
+ }
+ }
+ else
+ {
+ arg = sp;
+ while (*sp != '\0' && *sp != ' ' && *sp != '\t')
+ {
+ ++sp;
+ }
+ }
+
+ if (*sp != '\0')
+ {
+ *sp++ = '\0';
+ }
+
+ if (sendflg)
+ {
+ chat_send (arg);
+ }
+ else
+ {
+ chat_expect (arg);
+ }
+ sendflg = !sendflg;
+ }
+ }
+ fclose (cfp);
+ }
+
+/*
+ * We got an error parsing the command line.
+ */
+void usage()
+ {
+ fprintf(stderr, "\
+Usage: %s [-v] [-t timeout] [-r report-file] {-f chat-file | chat-script}\n",
+ program_name);
+ exit(1);
+ }
+
+char line[256];
+char *p;
+
+void logf (str)
+const char *str;
+ {
+ p = line + strlen(line);
+ strcat (p, str);
+
+ if (str[strlen(str)-1] == '\n')
+ {
+ syslog (LOG_INFO, "%s", line);
+ line[0] = 0;
+ }
+ }
+
+void logflush()
+ {
+ if (line[0] != 0)
+ {
+ syslog(LOG_INFO, "%s", line);
+ line[0] = 0;
+ }
+ }
+
+/*
+ * Terminate with an error.
+ */
+void die()
+ {
+ terminate(1);
+ }
+
+/*
+ * Print an error message and terminate.
+ */
+
+void fatal (msg)
+const char *msg;
+ {
+ syslog(LOG_ERR, "%s", msg);
+ terminate(2);
+ }
+
+/*
+ * Print an error message along with the system error message and
+ * terminate.
+ */
+
+void sysfatal (msg)
+const char *msg;
+ {
+ syslog(LOG_ERR, "%s: %m", msg);
+ terminate(2);
+ }
+
+int alarmed = 0;
+
+SIGTYPE sigalrm(signo)
+int signo;
+ {
+ int flags;
+
+ alarm(1);
+ alarmed = 1; /* Reset alarm to avoid race window */
+ signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
+
+ logflush();
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ if (verbose)
+ {
+ syslog(LOG_INFO, "alarm");
+ }
+ }
+
+void unalarm()
+ {
+ int flags;
+
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+ }
+
+SIGTYPE sigint(signo)
+int signo;
+ {
+ fatal("SIGINT");
+ }
+
+SIGTYPE sigterm(signo)
+int signo;
+ {
+ fatal("SIGTERM");
+ }
+
+SIGTYPE sighup(signo)
+int signo;
+ {
+ fatal("SIGHUP");
+ }
+
+void init()
+ {
+ signal(SIGINT, sigint);
+ signal(SIGTERM, sigterm);
+ signal(SIGHUP, sighup);
+
+ set_tty_parameters();
+ signal(SIGALRM, sigalrm);
+ alarm(0);
+ alarmed = 0;
+ }
+
+void set_tty_parameters()
+ {
+#if defined(get_term_param)
+ term_parms t;
+
+ if (get_term_param (&t) < 0)
+ {
+ sysfatal("Can't get terminal parameters");
+ }
+
+ saved_tty_parameters = t;
+ have_tty_parameters = 1;
+
+ t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
+ t.c_oflag = 0;
+ t.c_lflag = 0;
+ t.c_cc[VERASE] =
+ t.c_cc[VKILL] = 0;
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+
+ if (set_term_param (&t) < 0)
+ {
+ sysfatal("Can't set terminal parameters");
+ }
+#endif
+ }
+
+void break_sequence()
+ {
+#ifdef TERMIOS
+ tcsendbreak (0, 0);
+#endif
+ }
+
+void terminate(status)
+int status;
+ {
+ if (report_file != (char *) 0 && report_fp != (FILE *) NULL)
+ {
+ if (verbose)
+ {
+ fprintf (report_fp, "Closing \"%s\".\n", report_file);
+ }
+ fclose (report_fp);
+ report_fp = (FILE*) NULL;
+ }
+
+#if defined(get_term_param)
+ if (have_tty_parameters)
+ {
+ if (set_term_param (&saved_tty_parameters) < 0)
+ {
+ syslog(LOG_ERR, "Can't restore terminal parameters: %m");
+ exit(1);
+ }
+ }
+#endif
+
+ exit(status);
+ }
+
+/*
+ * 'Clean up' this string.
+ */
+char *clean(s, sending)
+register char *s;
+int sending;
+ {
+ char temp[STR_LEN], cur_chr;
+ register char *s1;
+ int add_return = sending;
+#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
+
+ s1 = temp;
+ while (*s)
+ {
+ cur_chr = *s++;
+ if (cur_chr == '^')
+ {
+ cur_chr = *s++;
+ if (cur_chr == '\0')
+ {
+ *s1++ = '^';
+ break;
+ }
+ cur_chr &= 0x1F;
+ if (cur_chr != 0)
+ {
+ *s1++ = cur_chr;
+ }
+ continue;
+ }
+
+ if (cur_chr != '\\')
+ {
+ *s1++ = cur_chr;
+ continue;
+ }
+
+ cur_chr = *s++;
+ if (cur_chr == '\0')
+ {
+ if (sending)
+ {
+ *s1++ = '\\';
+ *s1++ = '\\';
+ }
+ break;
+ }
+
+ switch (cur_chr)
+ {
+ case 'b':
+ *s1++ = '\b';
+ break;
+
+ case 'c':
+ if (sending && *s == '\0')
+ {
+ add_return = 0;
+ }
+ else
+ {
+ *s1++ = cur_chr;
+ }
+ break;
+
+ case '\\':
+ case 'K':
+ case 'p':
+ case 'd':
+ if (sending)
+ {
+ *s1++ = '\\';
+ }
+
+ *s1++ = cur_chr;
+ break;
+
+ case 'q':
+ quiet = ! quiet;
+ break;
+
+ case 'r':
+ *s1++ = '\r';
+ break;
+
+ case 'n':
+ *s1++ = '\n';
+ break;
+
+ case 's':
+ *s1++ = ' ';
+ break;
+
+ case 't':
+ *s1++ = '\t';
+ break;
+
+ case 'N':
+ if (sending)
+ {
+ *s1++ = '\\';
+ *s1++ = '\0';
+ }
+ else
+ {
+ *s1++ = 'N';
+ }
+ break;
+
+ default:
+ if (isoctal (cur_chr))
+ {
+ cur_chr &= 0x07;
+ if (isoctal (*s))
+ {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ if (isoctal (*s))
+ {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ }
+ }
+
+ if (cur_chr != 0 || sending)
+ {
+ if (sending && (cur_chr == '\\' || cur_chr == 0))
+ {
+ *s1++ = '\\';
+ }
+ *s1++ = cur_chr;
+ }
+ break;
+ }
+
+ if (sending)
+ {
+ *s1++ = '\\';
+ }
+ *s1++ = cur_chr;
+ break;
+ }
+ }
+
+ if (add_return)
+ {
+ *s1++ = '\r';
+ }
+
+ *s1++ = '\0'; /* guarantee closure */
+ *s1++ = '\0'; /* terminate the string */
+ return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+ }
+
+/*
+ * Process the expect string
+ */
+void chat_expect(s)
+register char *s;
+ {
+ if (strcmp(s, "ABORT") == 0)
+ {
+ ++abort_next;
+ return;
+ }
+
+ if (strcmp(s, "REPORT") == 0)
+ {
+ ++report_next;
+ return;
+ }
+
+ if (strcmp(s, "TIMEOUT") == 0)
+ {
+ ++timeout_next;
+ return;
+ }
+
+ while (*s)
+ {
+ register char *hyphen;
+
+ for (hyphen = s; *hyphen; ++hyphen)
+ {
+ if (*hyphen == '-')
+ {
+ if (hyphen == s || hyphen[-1] != '\\')
+ {
+ break;
+ }
+ }
+ }
+
+ if (*hyphen == '-')
+ {
+ *hyphen = '\0';
+
+ if (get_string(s))
+ {
+ return;
+ }
+ else
+ {
+ s = hyphen + 1;
+
+ for (hyphen = s; *hyphen; ++hyphen)
+ {
+ if (*hyphen == '-')
+ {
+ if (hyphen == s || hyphen[-1] != '\\')
+ {
+ break;
+ }
+ }
+ }
+
+ if (*hyphen == '-')
+ {
+ *hyphen = '\0';
+
+ chat_send(s);
+ s = hyphen + 1;
+ }
+ else
+ {
+ chat_send(s);
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (get_string(s))
+ {
+ return;
+ }
+ else
+ {
+ if (fail_reason)
+ {
+ syslog(LOG_INFO, "Failed (%s)", fail_reason);
+ }
+ else
+ {
+ syslog(LOG_INFO, "Failed");
+ }
+
+ terminate(exit_code);
+ }
+ }
+ }
+ }
+
+char *character(c)
+int c;
+ {
+ static char string[10];
+ char *meta;
+
+ meta = (c & 0x80) ? "M-" : "";
+ c &= 0x7F;
+
+ if (c < 32)
+ {
+ sprintf(string, "%s^%c", meta, (int)c + '@');
+ }
+ else
+ {
+ if (c == 127)
+ {
+ sprintf(string, "%s^?", meta);
+ }
+ else
+ {
+ sprintf(string, "%s%c", meta, c);
+ }
+ }
+
+ return (string);
+ }
+
+/*
+ * process the reply string
+ */
+void chat_send (s)
+register char *s;
+ {
+ if (abort_next)
+ {
+ char *s1;
+
+ abort_next = 0;
+
+ if (n_aborts >= MAX_ABORTS)
+ {
+ fatal("Too many ABORT strings");
+ }
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
+ {
+ syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
+ die();
+ }
+
+ abort_string[n_aborts++] = s1;
+
+ if (verbose)
+ {
+ logf("abort on (");
+
+ for (s1 = s; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+
+ logf(")\n");
+ }
+ return;
+ }
+
+ if (report_next)
+ {
+ char *s1;
+
+ report_next = 0;
+ if (n_reports >= MAX_REPORTS)
+ {
+ fatal("Too many REPORT strings");
+ }
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ {
+ syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s);
+ die();
+ }
+
+ report_string[n_reports++] = s1;
+
+ if (verbose)
+ {
+ logf("report (");
+ s1 = s;
+ while (*s1)
+ {
+ logf(character(*s1));
+ ++s1;
+ }
+ logf(")\n");
+ }
+ return;
+ }
+
+ if (timeout_next)
+ {
+ timeout_next = 0;
+ timeout = atoi(s);
+
+ if (timeout <= 0)
+ {
+ timeout = DEFAULT_CHAT_TIMEOUT;
+ }
+
+ if (verbose)
+ {
+ syslog(LOG_INFO, "timeout set to %d seconds", timeout);
+ }
+ return;
+ }
+
+ if (strcmp(s, "EOT") == 0)
+ {
+ s = "^D\\c";
+ }
+ else
+ {
+ if (strcmp(s, "BREAK") == 0)
+ {
+ s = "\\K\\c";
+ }
+ }
+
+ if (!put_string(s))
+ {
+ syslog(LOG_INFO, "Failed");
+ terminate(1);
+ }
+ }
+
+int get_char()
+ {
+ int status;
+ char c;
+
+ status = read(0, &c, 1);
+
+ switch (status)
+ {
+ case 1:
+ return ((int)c & 0x7F);
+
+ default:
+ syslog(LOG_WARNING, "warning: read() on stdin returned %d",
+ status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ return (-1);
+ }
+ }
+
+int put_char(c)
+int c;
+ {
+ int status;
+ char ch = c;
+
+ usleep(10000); /* inter-character typing delay (?) */
+
+ status = write(1, &ch, 1);
+
+ switch (status)
+ {
+ case 1:
+ return (0);
+
+ default:
+ syslog(LOG_WARNING, "warning: write() on stdout returned %d",
+ status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ {
+ sysfatal("Can't get file mode flags on stdin");
+ }
+ else
+ {
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ {
+ sysfatal("Can't set file mode flags on stdin");
+ }
+ }
+
+ return (-1);
+ }
+ }
+
+int write_char (c)
+int c;
+ {
+ if (alarmed || put_char(c) < 0)
+ {
+ extern int errno;
+
+ alarm(0);
+ alarmed = 0;
+
+ if (verbose)
+ {
+ if (errno == EINTR || errno == EWOULDBLOCK)
+ {
+ syslog(LOG_INFO, " -- write timed out");
+ }
+ else
+ {
+ syslog(LOG_INFO, " -- write failed: %m");
+ }
+ }
+ return (0);
+ }
+ return (1);
+ }
+
+int put_string (s)
+register char *s;
+ {
+ s = clean(s, 1);
+
+ if (verbose)
+ {
+ logf("send (");
+
+ if (quiet)
+ {
+ logf("??????");
+ }
+ else
+ {
+ register char *s1 = s;
+
+ for (s1 = s; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+ }
+
+ logf(")\n");
+ }
+
+ alarm(timeout); alarmed = 0;
+
+ while (*s)
+ {
+ register char c = *s++;
+
+ if (c != '\\')
+ {
+ if (!write_char (c))
+ {
+ return 0;
+ }
+ continue;
+ }
+
+ c = *s++;
+ switch (c)
+ {
+ case 'd':
+ sleep(1);
+ break;
+
+ case 'K':
+ break_sequence();
+ break;
+
+ case 'p':
+ usleep(10000); /* 1/100th of a second (arg is microseconds) */
+ break;
+
+ default:
+ if (!write_char (c))
+ return 0;
+ break;
+ }
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+ }
+
+/*
+ * 'Wait for' this string to appear on this file descriptor.
+ */
+int get_string(string)
+register char *string;
+ {
+ char temp[STR_LEN];
+ int c, printed = 0, len, minlen;
+ register char *s = temp, *end = s + STR_LEN;
+
+ fail_reason = (char *)0;
+ string = clean(string, 0);
+ len = strlen(string);
+ minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
+
+ if (verbose)
+ {
+ register char *s1;
+
+ logf("expect (");
+
+ for (s1 = string; *s1; ++s1)
+ {
+ logf(character(*s1));
+ }
+
+ logf(")\n");
+ }
+
+ if (len > STR_LEN)
+ {
+ syslog(LOG_INFO, "expect string is too long");
+ exit_code = 1;
+ return 0;
+ }
+
+ if (len == 0)
+ {
+ if (verbose)
+ {
+ syslog(LOG_INFO, "got it");
+ }
+
+ return (1);
+ }
+
+ alarm(timeout);
+ alarmed = 0;
+
+ while ( ! alarmed && (c = get_char()) >= 0)
+ {
+ int n, abort_len, report_len;
+
+ if (verbose)
+ {
+ if (c == '\n')
+ {
+ logf("\n");
+ }
+ else
+ {
+ logf(character(c));
+ }
+ }
+
+ *s++ = c;
+
+ if (s - temp >= len &&
+ c == string[len - 1] &&
+ strncmp(s - len, string, len) == 0)
+ {
+ if (verbose)
+ {
+ logf(" -- got it\n");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+ }
+
+ for (n = 0; n < n_aborts; ++n)
+ {
+ if (s - temp >= (abort_len = strlen(abort_string[n])) &&
+ strncmp(s - abort_len, abort_string[n], abort_len) == 0)
+ {
+ if (verbose)
+ {
+ logf(" -- failed\n");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ exit_code = n + 4;
+ strcpy(fail_reason = fail_buffer, abort_string[n]);
+ return (0);
+ }
+ }
+
+ if (!report_gathering)
+ {
+ for (n = 0; n < n_reports; ++n)
+ {
+ if ((report_string[n] != (char*) NULL) &&
+ s - temp >= (report_len = strlen(report_string[n])) &&
+ strncmp(s - report_len, report_string[n], report_len) == 0)
+ {
+ time_t time_now = time ((time_t*) NULL);
+ struct tm* tm_now = localtime (&time_now);
+
+ strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
+ strcat (report_buffer, report_string[n]);
+
+ report_string[n] = (char *) NULL;
+ report_gathering = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!iscntrl (c))
+ {
+ int rep_len = strlen (report_buffer);
+ report_buffer[rep_len] = c;
+ report_buffer[rep_len + 1] = '\0';
+ }
+ else
+ {
+ report_gathering = 0;
+ fprintf (report_fp, "chat: %s\n", report_buffer);
+ }
+ }
+
+ if (s >= end)
+ {
+ strncpy (temp, s - minlen, minlen);
+ s = temp + minlen;
+ }
+
+ if (alarmed && verbose)
+ {
+ syslog(LOG_WARNING, "warning: alarm synchronization problem");
+ }
+ }
+
+ alarm(0);
+
+ if (verbose && printed)
+ {
+ if (alarmed)
+ {
+ logf(" -- read timed out\n");
+ }
+ else
+ {
+ logflush();
+ syslog(LOG_INFO, " -- read failed: %m");
+ }
+ }
+
+ exit_code = 3;
+ alarmed = 0;
+ return (0);
+ }
+
+#ifdef NO_USLEEP
+#include <sys/types.h>
+#include <sys/time.h>
+
+/*
+ usleep -- support routine for 4.2BSD system call emulations
+ last edit: 29-Oct-1984 D A Gwyn
+ */
+
+extern int select();
+
+int
+usleep( usec ) /* returns 0 if ok, else -1 */
+ long usec; /* delay in microseconds */
+{
+ static struct /* `timeval' */
+ {
+ long tv_sec; /* seconds */
+ long tv_usec; /* microsecs */
+ } delay; /* _select() timeout */
+
+ delay.tv_sec = usec / 1000000L;
+ delay.tv_usec = usec % 1000000L;
+
+ return select( 0, (long *)0, (long *)0, (long *)0, &delay );
+}
+#endif
diff --git a/usr.sbin/pppd/fsm.c b/usr.sbin/pppd/fsm.c
new file mode 100644
index 00000000000..3dfeb347a85
--- /dev/null
+++ b/usr.sbin/pppd/fsm.c
@@ -0,0 +1,780 @@
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: fsm.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "fsm.h"
+
+extern char *proto_name();
+
+static void fsm_timeout __P((caddr_t));
+static void fsm_rconfreq __P((fsm *, int, u_char *, int));
+static void fsm_rconfack __P((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
+static void fsm_rtermreq __P((fsm *, int));
+static void fsm_rtermack __P((fsm *));
+static void fsm_rcoderej __P((fsm *, u_char *, int));
+static void fsm_sconfreq __P((fsm *, int));
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(f)
+ fsm *f;
+{
+ f->state = INITIAL;
+ f->flags = 0;
+ f->id = 0; /* XXX Start with random id? */
+ f->timeouttime = DEFTIMEOUT;
+ f->maxconfreqtransmits = DEFMAXCONFREQS;
+ f->maxtermtransmits = DEFMAXTERMREQS;
+ f->maxnakloops = DEFMAXNAKLOOPS;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case INITIAL:
+ f->state = CLOSED;
+ break;
+
+ case STARTING:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case CLOSED:
+ f->state = INITIAL;
+ break;
+
+ case STOPPED:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSING:
+ f->state = INITIAL;
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = STARTING;
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+ f->state = STARTING;
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Down event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case INITIAL:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSED:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
+
+ case CLOSING:
+ f->state = STOPPING;
+ /* fall through */
+ case STOPPED:
+ case OPENED:
+ if( f->flags & OPT_RESTART ){
+ fsm_lowerdown(f);
+ fsm_lowerup(f);
+ }
+ break;
+ }
+}
+
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
+ */
+void
+fsm_close(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case STARTING:
+ f->state = INITIAL;
+ break;
+ case STOPPED:
+ f->state = CLOSED;
+ break;
+ case STOPPING:
+ f->state = CLOSING;
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ case OPENED:
+ if( f->state != OPENED )
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ else if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers we're down */
+
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = CLOSING;
+ break;
+ }
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(arg)
+ caddr_t arg;
+{
+ fsm *f = (fsm *) arg;
+
+ switch (f->state) {
+ case CLOSING:
+ case STOPPING:
+ if( f->retransmits <= 0 ){
+ /*
+ * We've waited for an ack long enough. Peer probably heard us.
+ */
+ f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ } else {
+ /* Send Terminate-Request */
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+ }
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ if (f->retransmits <= 0) {
+ syslog(LOG_WARNING, "%s: timeout sending Config-Requests",
+ PROTO_NAME(f));
+ f->state = STOPPED;
+ if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+
+ } else {
+ /* Retransmit the configure-request */
+ if (f->callbacks->retransmit)
+ (*f->callbacks->retransmit)(f);
+ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void
+fsm_input(f, inpacket, l)
+ fsm *f;
+ u_char *inpacket;
+ int l;
+{
+ u_char *inp, *outp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < HEADERLEN) {
+ FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.",
+ f->protocol));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
+ f->protocol));
+ return;
+ }
+ if (len > l) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
+ f->protocol));
+ return;
+ }
+ len -= HEADERLEN; /* subtract header length */
+
+ if( f->state == INITIAL || f->state == STARTING ){
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
+ f->protocol, f->state));
+ return;
+ }
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case CONFREQ:
+ fsm_rconfreq(f, id, inp, len);
+ break;
+
+ case CONFACK:
+ fsm_rconfack(f, id, inp, len);
+ break;
+
+ case CONFNAK:
+ case CONFREJ:
+ fsm_rconfnakrej(f, code, id, inp, len);
+ break;
+
+ case TERMREQ:
+ fsm_rtermreq(f, id);
+ break;
+
+ case TERMACK:
+ fsm_rtermack(f);
+ break;
+
+ case CODEREJ:
+ fsm_rcoderej(f, inp, len);
+ break;
+
+ default:
+ if( !f->callbacks->extcode
+ || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+ fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void
+fsm_rconfreq(f, id, inp, len)
+ fsm *f;
+ u_char id;
+ u_char *inp;
+ int len;
+{
+ u_char *outp;
+ int code, reject_if_disagree;
+
+ FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
+ switch( f->state ){
+ case CLOSED:
+ /* Go away, we're closed */
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ return;
+ case CLOSING:
+ case STOPPING:
+ return;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ break;
+
+ case STOPPED:
+ /* Negotiation started by our peer */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+
+ /*
+ * Pass the requested configuration options
+ * to protocol-specific code for checking.
+ */
+ if (f->callbacks->reqci){ /* Check CI */
+ reject_if_disagree = (f->nakloops >= f->maxnakloops);
+ code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+ } else if (len)
+ code = CONFREJ; /* Reject all CI */
+ else
+ code = CONFACK;
+
+ /* send the Ack, Nak or Rej to the peer */
+ fsm_sdata(f, code, id, inp, len);
+
+ if (code == CONFACK) {
+ if (f->state == ACKRCVD) {
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ } else
+ f->state = ACKSENT;
+ f->nakloops = 0;
+
+ } else {
+ /* we sent CONFACK or CONFREJ */
+ if (f->state != ACKRCVD)
+ f->state = REQSENT;
+ if( code == CONFNAK )
+ ++f->nakloops;
+ }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void
+fsm_rconfack(f, id, inp, len)
+ fsm *f;
+ int id;
+ u_char *inp;
+ int len;
+{
+ FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid || f->seen_ack) /* Expected id? */
+ return; /* Nope, toss... */
+ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+ (len == 0)) ){
+ /* Ack is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
+ PROTO_NAME(f), len));
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case CLOSED:
+ case STOPPED:
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ break;
+
+ case REQSENT:
+ f->state = ACKRCVD;
+ f->retransmits = f->maxconfreqtransmits;
+ break;
+
+ case ACKRCVD:
+ /* Huh? an extra valid Ack? oh well... */
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ break;
+
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
+ f->retransmits = f->maxconfreqtransmits;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void
+fsm_rconfnakrej(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ int (*proc)();
+
+ FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid || f->seen_ack) /* Expected id? */
+ return; /* Nope, toss... */
+ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+ if (!proc || !proc(f, inp, len)) {
+ /* Nak/reject is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
+ PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case CLOSED:
+ case STOPPED:
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ break;
+
+ case REQSENT:
+ case ACKSENT:
+ /* They didn't agree to what we wanted - try another request */
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
+ break;
+
+ case ACKRCVD:
+ /* Got a Nak/reject when we had already had an Ack?? oh well... */
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void
+fsm_rtermreq(f, id)
+ fsm *f;
+ int id;
+{
+ FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ switch (f->state) {
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = REQSENT; /* Start over but keep trying */
+ break;
+
+ case OPENED:
+ syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f));
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ f->retransmits = 0;
+ f->state = STOPPING;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ break;
+ }
+
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(f)
+ fsm *f;
+{
+ FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
+
+ switch (f->state) {
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f);
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+ case STOPPING:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f);
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case ACKRCVD:
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0);
+ break;
+ }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void
+fsm_rcoderej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_char code, id;
+
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
+
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d",
+ PROTO_NAME(f), code, id);
+
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void
+fsm_protreject(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case CLOSED:
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case STOPPED:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = STOPPING;
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(f, retransmit)
+ fsm *f;
+ int retransmit;
+{
+ u_char *outp;
+ int outlen, cilen;
+
+ if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+ /* Not currently negotiating - reset options */
+ if( f->callbacks->resetci )
+ (*f->callbacks->resetci)(f);
+ f->nakloops = 0;
+ }
+
+ if( !retransmit ){
+ /* New request - reset retransmission counter, use new ID */
+ f->retransmits = f->maxconfreqtransmits;
+ f->reqid = ++f->id;
+ }
+
+ f->seen_ack = 0;
+
+ /*
+ * Make up the request packet
+ */
+ outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
+ if( f->callbacks->cilen && f->callbacks->addci ){
+ cilen = (*f->callbacks->cilen)(f);
+ if( cilen > peer_mru[f->unit] - HEADERLEN )
+ cilen = peer_mru[f->unit] - HEADERLEN;
+ if (f->callbacks->addci)
+ (*f->callbacks->addci)(f, outp, &cilen);
+ } else
+ cilen = 0;
+
+ /* send the request to our peer */
+ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+ /* start the retransmit timer */
+ --f->retransmits;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+
+ FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
+ PROTO_NAME(f), f->reqid));
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void
+fsm_sdata(f, code, id, data, datalen)
+ fsm *f;
+ u_char code, id;
+ u_char *data;
+ int datalen;
+{
+ u_char *outp;
+ int outlen;
+
+ /* Adjust length to be smaller than MTU */
+ outp = outpacket_buf;
+ if (datalen > peer_mru[f->unit] - HEADERLEN)
+ datalen = peer_mru[f->unit] - HEADERLEN;
+ if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+ BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+ outlen = datalen + HEADERLEN;
+ MAKEHEADER(outp, f->protocol);
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
+ PROTO_NAME(f), code, id));
+}
diff --git a/usr.sbin/pppd/fsm.h b/usr.sbin/pppd/fsm.h
new file mode 100644
index 00000000000..fc3a5dcc179
--- /dev/null
+++ b/usr.sbin/pppd/fsm.h
@@ -0,0 +1,128 @@
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.h,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ * CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ 1 /* Configuration Request */
+#define CONFACK 2 /* Configuration Ack */
+#define CONFNAK 3 /* Configuration Nak */
+#define CONFREJ 4 /* Configuration Reject */
+#define TERMREQ 5 /* Termination Request */
+#define TERMACK 6 /* Termination Ack */
+#define CODEREJ 7 /* Code Reject */
+
+
+/*
+ * Each FSM is described by a fsm_callbacks and a fsm structure.
+ */
+typedef struct fsm_callbacks {
+ void (*resetci)(); /* Reset our Configuration Information */
+ int (*cilen)(); /* Length of our Configuration Information */
+ void (*addci)(); /* Add our Configuration Information */
+ int (*ackci)(); /* ACK our Configuration Information */
+ int (*nakci)(); /* NAK our Configuration Information */
+ int (*rejci)(); /* Reject our Configuration Information */
+ int (*reqci)(); /* Request peer's Configuration Information */
+ void (*up)(); /* Called when fsm reaches OPENED state */
+ void (*down)(); /* Called when fsm leaves OPENED state */
+ void (*starting)(); /* Called when we want the lower layer */
+ void (*finished)(); /* Called when we don't want the lower layer */
+ void (*protreject)(); /* Called when Protocol-Reject received */
+ void (*retransmit)(); /* Retransmission is necessary */
+ int (*extcode)(); /* Called when unknown code received */
+ char *proto_name; /* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+typedef struct fsm {
+ int unit; /* Interface unit number */
+ int protocol; /* Data Link Layer Protocol field value */
+ int state; /* State */
+ int flags; /* Contains option bits */
+ u_char id; /* Current id */
+ u_char reqid; /* Current request id */
+ u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */
+ int timeouttime; /* Timeout time in milliseconds */
+ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
+ int retransmits; /* Number of retransmissions left */
+ int maxtermtransmits; /* Maximum Terminate-Request transmissions */
+ int nakloops; /* Number of nak loops since last ack */
+ int maxnakloops; /* Maximum number of nak loops tolerated */
+ fsm_callbacks *callbacks; /* Callback routines */
+} fsm;
+
+
+/*
+ * Link states.
+ */
+#define INITIAL 0 /* Down, hasn't been opened */
+#define STARTING 1 /* Down, been opened */
+#define CLOSED 2 /* Up, hasn't been opened */
+#define STOPPED 3 /* Open, waiting for down event */
+#define CLOSING 4 /* Terminating the connection, not open */
+#define STOPPING 5 /* Terminating, but open */
+#define REQSENT 6 /* We've sent a Config Request */
+#define ACKRCVD 7 /* We've received a Config Ack */
+#define ACKSENT 8 /* We've sent a Config Ack */
+#define OPENED 9 /* Connection available */
+
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT 4 /* Wait for peer to speak first */
+
+
+/*
+ * Timeouts.
+ */
+#define DEFTIMEOUT 3 /* Timeout time in seconds */
+#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
+#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init __P((fsm *));
+void fsm_lowerup __P((fsm *));
+void fsm_lowerdown __P((fsm *));
+void fsm_open __P((fsm *));
+void fsm_close __P((fsm *));
+void fsm_input __P((fsm *, u_char *, int));
+void fsm_protreject __P((fsm *));
+void fsm_sdata __P((fsm *, int, int, u_char *, int));
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
diff --git a/usr.sbin/pppd/ipcp.c b/usr.sbin/pppd/ipcp.c
new file mode 100644
index 00000000000..1aacdecf3e2
--- /dev/null
+++ b/usr.sbin/pppd/ipcp.c
@@ -0,0 +1,1213 @@
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ipcp.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+/* local vars */
+static int cis_received[NUM_PPP]; /* # Conf-Reqs received */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipcp_resetci __P((fsm *)); /* Reset our CI */
+static int ipcp_cilen __P((fsm *)); /* Return length of our CI */
+static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipcp_up __P((fsm *)); /* We're UP */
+static void ipcp_down __P((fsm *)); /* We're DOWN */
+static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */
+
+fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+ ipcp_resetci, /* Reset our Configuration Information */
+ ipcp_cilen, /* Length of our Configuration Information */
+ ipcp_addci, /* Add our Configuration Information */
+ ipcp_ackci, /* ACK our Configuration Information */
+ ipcp_nakci, /* NAK our Configuration Information */
+ ipcp_rejci, /* Reject our Configuration Information */
+ ipcp_reqci, /* Request peer's Configuration Information */
+ ipcp_up, /* Called when fsm reaches OPENED state */
+ ipcp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ NULL, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPCP" /* String name of protocol */
+};
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
+#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR 6 /* new-style single address option */
+#define CILEN_ADDRS 10 /* old-style dual address option */
+
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * Make a string representation of a network IP address.
+ */
+char *
+ip_ntoa(ipaddr)
+u_int32_t ipaddr;
+{
+ static char b[64];
+
+ ipaddr = ntohl(ipaddr);
+
+ sprintf(b, "%d.%d.%d.%d",
+ (u_char)(ipaddr >> 24),
+ (u_char)(ipaddr >> 16),
+ (u_char)(ipaddr >> 8),
+ (u_char)(ipaddr));
+ return b;
+}
+
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+void
+ipcp_init(unit)
+ int unit;
+{
+ fsm *f = &ipcp_fsm[unit];
+ ipcp_options *wo = &ipcp_wantoptions[unit];
+ ipcp_options *ao = &ipcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPCP;
+ f->callbacks = &ipcp_callbacks;
+ fsm_init(&ipcp_fsm[unit]);
+
+ wo->neg_addr = 1;
+ wo->old_addrs = 0;
+ wo->ouraddr = 0;
+ wo->hisaddr = 0;
+
+ wo->neg_vj = 1;
+ wo->old_vj = 0;
+ wo->vj_protocol = IPCP_VJ_COMP;
+ wo->maxslotindex = MAX_STATES - 1; /* really max index */
+ wo->cflag = 1;
+
+ /* max slots and slot-id compression are currently hardwired in */
+ /* ppp_if.c to 16 and 1, this needs to be changed (among other */
+ /* things) gmc */
+
+ ao->neg_addr = 1;
+ ao->neg_vj = 1;
+ ao->maxslotindex = MAX_STATES - 1;
+ ao->cflag = 1;
+
+ /*
+ * XXX These control whether the user may use the proxyarp
+ * and defaultroute options.
+ */
+ ao->proxy_arp = 1;
+ ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+void
+ipcp_open(unit)
+ int unit;
+{
+ fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+void
+ipcp_close(unit)
+ int unit;
+{
+ fsm_close(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+void
+ipcp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+void
+ipcp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+void
+ipcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+void
+ipcp_protrej(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ */
+static void
+ipcp_resetci(f)
+ fsm *f;
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+ if (wo->ouraddr == 0)
+ wo->accept_local = 1;
+ if (wo->hisaddr == 0)
+ wo->accept_remote = 1;
+ ipcp_gotoptions[f->unit] = *wo;
+ cis_received[f->unit] = 0;
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ */
+static int
+ipcp_cilen(f)
+ fsm *f;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+
+#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+
+ return (LENCIADDR(go->neg_addr, go->old_addrs) +
+ LENCIVJ(go->neg_vj, go->old_vj));
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ if (!old) { \
+ PUTCHAR(maxslotindex, ucp); \
+ PUTCHAR(cflag, ucp); \
+ } \
+ len -= vjlen; \
+ } else \
+ neg = 0; \
+ }
+
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ if (len >= addrlen) { \
+ u_int32_t l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(addrlen, ucp); \
+ l = ntohl(val1); \
+ PUTLONG(l, ucp); \
+ if (old) { \
+ l = ntohl(val2); \
+ PUTLONG(l, ucp); \
+ } \
+ len -= addrlen; \
+ } else \
+ neg = 0; \
+ }
+
+ /*
+ * First see if we want to change our options to the old
+ * forms because we have received old forms from the peer.
+ */
+ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+ /* use the old style of address negotiation */
+ go->neg_addr = 1;
+ go->old_addrs = 1;
+ }
+ if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+ /* try an older style of VJ negotiation */
+ if (cis_received[f->unit] == 0) {
+ /* keep trying the new style until we see some CI from the peer */
+ go->neg_vj = 1;
+ } else {
+ /* use the old style only if the peer did */
+ if (ho->neg_vj && ho->old_vj) {
+ go->neg_vj = 1;
+ go->old_vj = 1;
+ go->vj_protocol = ho->vj_protocol;
+ }
+ }
+ }
+
+ ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_short cilen, citype, cishort;
+ u_int32_t cilong;
+ u_char cimaxslotindex, cicflag;
+
+ /*
+ * CIs must be in exactly the same order that we sent...
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if ((len -= vjlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != vjlen || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslotindex) \
+ goto bad; \
+ GETCHAR(cicflag, p); \
+ if (cicflag != cflag) \
+ goto bad; \
+ } \
+ }
+
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ u_int32_t l; \
+ if ((len -= addrlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != addrlen || \
+ citype != opt) \
+ goto bad; \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val1 != cilong) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val2 != cilong) \
+ goto bad; \
+ } \
+ }
+
+ ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ return (1);
+
+bad:
+ IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
+ return (0);
+}
+
+/*
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+ipcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
+ u_short cishort;
+ u_int32_t ciaddr1, ciaddr2, l;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIADDR(opt, neg, old, code) \
+ if (go->neg && \
+ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ ciaddr1 = htonl(l); \
+ if (old) { \
+ GETLONG(l, p); \
+ ciaddr2 = htonl(l); \
+ no.old_addrs = 1; \
+ } else \
+ ciaddr2 = 0; \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
+ */
+ NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+ if (go->accept_local && ciaddr1) { /* Do we know our address? */
+ try.ouraddr = ciaddr1;
+ IPCPDEBUG((LOG_INFO, "local IP address %s",
+ ip_ntoa(ciaddr1)));
+ }
+ if (go->accept_remote && ciaddr2) { /* Does he know his? */
+ try.hisaddr = ciaddr2;
+ IPCPDEBUG((LOG_INFO, "remote IP address %s",
+ ip_ntoa(ciaddr2)));
+ }
+ );
+
+ /*
+ * Accept the peer's value of maxslotindex provided that it
+ * is less than what we asked for. Turn off slot-ID compression
+ * if the peer wants. Send old-style compress-type option if
+ * the peer wants.
+ */
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ if (cilen == CILEN_VJ) {
+ GETCHAR(cimaxslotindex, p);
+ GETCHAR(cicflag, p);
+ if (cishort == IPCP_VJ_COMP) {
+ try.old_vj = 0;
+ if (cimaxslotindex < go->maxslotindex)
+ try.maxslotindex = cimaxslotindex;
+ if (!cicflag)
+ try.cflag = 0;
+ } else {
+ try.neg_vj = 0;
+ }
+ } else {
+ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+ try.old_vj = 1;
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about IP addresses, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+ goto bad;
+ no.neg_vj = 1;
+ break;
+ case CI_ADDRS:
+ if (go->neg_addr && go->old_addrs || no.old_addrs
+ || cilen != CILEN_ADDRS)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 1;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ GETLONG(l, p);
+ ciaddr2 = htonl(l);
+ if (ciaddr2 && go->accept_remote)
+ try.hisaddr = ciaddr2;
+ no.old_addrs = 1;
+ break;
+ case CI_ADDR:
+ if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+ goto bad;
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ if (try.ouraddr != 0)
+ try.neg_addr = 1;
+ no.neg_addr = 1;
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
+bad:
+ IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ */
+static int
+ipcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, ciflag, cilen;
+ u_short cishort;
+ u_int32_t cilong;
+ ipcp_options try; /* options to request next time */
+
+ try = *go;
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+ if (go->neg && \
+ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ u_int32_t l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val1) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val2) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+ if (go->neg && \
+ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+ len >= p[1] && \
+ p[0] == opt) { \
+ len -= p[1]; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) \
+ goto bad; \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslot) \
+ goto bad; \
+ GETCHAR(ciflag, p); \
+ if (ciflag != cflag) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+ REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
+bad:
+ IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
+ return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *ao = &ipcp_allowoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort; /* Parsed short value */
+ u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+ u_char maxslotindex, cflag;
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_ADDRS:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDRS) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * If neither we nor he knows his address, reject the option.
+ */
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ /*
+ * If he doesn't know our address, or if we both have our address
+ * but disagree about it, then NAK it with our idea.
+ */
+ GETLONG(tl, p); /* Parse desination address (ours) */
+ ciaddr2 = htonl(tl);
+ IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
+ if (ciaddr2 != wo->ouraddr) {
+ if (ciaddr2 == 0 || !wo->accept_local) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->ouraddr);
+ PUTLONG(tl, p);
+ }
+ } else {
+ go->ouraddr = ciaddr2; /* accept peer's idea */
+ }
+ }
+
+ ho->neg_addr = 1;
+ ho->old_addrs = 1;
+ ho->hisaddr = ciaddr1;
+ ho->ouraddr = ciaddr2;
+ break;
+
+ case CI_ADDR:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
+
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * Don't ACK an address of 0.0.0.0 - reject it instead.
+ */
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ ho->neg_addr = 1;
+ ho->hisaddr = ciaddr1;
+ break;
+
+ case CI_COMPRESSTYPE:
+ IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
+ if (!ao->neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+ IPCPDEBUG((LOG_INFO, "(%d)", cishort));
+
+ if (!(cishort == IPCP_VJ_COMP ||
+ (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ if (cilen == CILEN_VJ) {
+ GETCHAR(maxslotindex, p);
+ if (maxslotindex > ao->maxslotindex) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(ao->maxslotindex, p);
+ }
+ }
+ GETCHAR(cflag, p);
+ if (cflag && !ao->cflag) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(wo->cflag, p);
+ }
+ }
+ ho->maxslotindex = maxslotindex;
+ ho->cflag = cflag;
+ } else {
+ ho->old_vj = 1;
+ ho->maxslotindex = MAX_STATES - 1;
+ ho->cflag = 1;
+ }
+ break;
+
+ default:
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
+
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip)
+ BCOPY(cip, ucp, cilen); /* Move it */
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a CI_ADDR option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+ if (rc != CONFREJ && !ho->neg_addr &&
+ wo->req_addr && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_addr = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_ADDR, ucp);
+ PUTCHAR(CILEN_ADDR, ucp);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, ucp);
+ }
+
+ *len = ucp - inp; /* Compute output length */
+ IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+ipcp_up(f)
+ fsm *f;
+{
+ u_int32_t mask;
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+
+ IPCPDEBUG((LOG_INFO, "ipcp: up"));
+ go->default_route = 0;
+ go->proxy_arp = 0;
+
+ /*
+ * We must have a non-zero IP address for both ends of the link.
+ */
+ if (!ho->neg_addr)
+ ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+
+ if (ho->hisaddr == 0) {
+ syslog(LOG_ERR, "Could not determine remote IP address");
+ ipcp_close(f->unit);
+ return;
+ }
+ if (go->ouraddr == 0) {
+ syslog(LOG_ERR, "Could not determine local IP address");
+ ipcp_close(f->unit);
+ return;
+ }
+
+ /*
+ * Check that the peer is allowed to use the IP address it wants.
+ */
+ if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+ syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
+ ip_ntoa(ho->hisaddr));
+ ipcp_close(f->unit);
+ return;
+ }
+
+ syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
+ syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit);
+ return;
+ }
+
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ IPCPDEBUG((LOG_WARNING, "sifup failed"));
+ ipcp_close(f->unit);
+ return;
+ }
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, ho->hisaddr))
+ go->default_route = 1;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ go->proxy_arp = 1;
+
+ /*
+ * Execute the ip-up script, like this:
+ * /etc/ppp/ip-up interface tty speed local-IP remote-IP
+ */
+ ipcp_script(f, _PATH_IPUP);
+
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipcp_down(f)
+ fsm *f;
+{
+ u_int32_t ouraddr, hisaddr;
+
+ IPCPDEBUG((LOG_INFO, "ipcp: down"));
+
+ ouraddr = ipcp_gotoptions[f->unit].ouraddr;
+ hisaddr = ipcp_hisoptions[f->unit].hisaddr;
+ if (ipcp_gotoptions[f->unit].proxy_arp)
+ cifproxyarp(f->unit, hisaddr);
+ if (ipcp_gotoptions[f->unit].default_route)
+ cifdefaultroute(f->unit, hisaddr);
+ sifdown(f->unit);
+ cifaddr(f->unit, ouraddr, hisaddr);
+
+ /* Execute the ip-down script */
+ ipcp_script(f, _PATH_IPDOWN);
+}
+
+
+/*
+ * ipcp_script - Execute a script with arguments
+ * interface-name tty-name speed local-IP remote-IP.
+ */
+static void
+ipcp_script(f, script)
+ fsm *f;
+ char *script;
+{
+ char strspeed[32], strlocal[32], strremote[32];
+ char *argv[8];
+
+ sprintf(strspeed, "%d", baud_rate);
+ strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr));
+ strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr));
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = devnam;
+ argv[3] = strspeed;
+ argv[4] = strlocal;
+ argv[5] = strremote;
+ argv[6] = ipparam;
+ argv[7] = NULL;
+ run_program(script, argv, 0);
+}
+
+/*
+ * ipcp_printpkt - print the contents of an IPCP packet.
+ */
+char *ipcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej"
+};
+
+int
+ipcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer)();
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
+ printer(arg, " %s", ipcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_ADDRS:
+ if (olen == CILEN_ADDRS) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "addrs %s", ip_ntoa(htonl(cilong)));
+ GETLONG(cilong, p);
+ printer(arg, " %s", ip_ntoa(htonl(cilong)));
+ }
+ break;
+ case CI_COMPRESSTYPE:
+ if (olen >= CILEN_COMPRESS) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "compress ");
+ switch (cishort) {
+ case IPCP_VJ_COMP:
+ printer(arg, "VJ");
+ break;
+ case IPCP_VJ_COMP_OLD:
+ printer(arg, "old-VJ");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_ADDR:
+ if (olen == CILEN_ADDR) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "addr %s", ip_ntoa(htonl(cilong)));
+ }
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
diff --git a/usr.sbin/pppd/ipcp.h b/usr.sbin/pppd/ipcp.h
new file mode 100644
index 00000000000..706d3f5a124
--- /dev/null
+++ b/usr.sbin/pppd/ipcp.h
@@ -0,0 +1,68 @@
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $
+ */
+
+/*
+ * Options.
+ */
+#define CI_ADDRS 1 /* IP Addresses */
+#define CI_COMPRESSTYPE 2 /* Compression Type */
+#define CI_ADDR 3
+
+#define MAX_STATES 16 /* from slcompress.h */
+
+#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
+ /* maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
+#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
+ /* compression option*/
+
+typedef struct ipcp_options {
+ int neg_addr : 1; /* Negotiate IP Address? */
+ int old_addrs : 1; /* Use old (IP-Addresses) option? */
+ int req_addr : 1; /* Ask peer to send IP address? */
+ int default_route : 1; /* Assign default route through interface? */
+ int proxy_arp : 1; /* Make proxy ARP entry for peer? */
+ int neg_vj : 1; /* Van Jacobson Compression? */
+ int old_vj : 1; /* use old (short) form of VJ option? */
+ int accept_local : 1; /* accept peer's value for ouraddr */
+ int accept_remote : 1; /* accept peer's value for hisaddr */
+ u_short vj_protocol; /* protocol value to use in VJ option */
+ u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */
+ u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+} ipcp_options;
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+void ipcp_init __P((int));
+void ipcp_open __P((int));
+void ipcp_close __P((int));
+void ipcp_lowerup __P((int));
+void ipcp_lowerdown __P((int));
+void ipcp_input __P((int, u_char *, int));
+void ipcp_protrej __P((int));
+int ipcp_printpkt __P((u_char *, int, void (*)(), void *));
diff --git a/usr.sbin/pppd/lcp.c b/usr.sbin/pppd/lcp.c
new file mode 100644
index 00000000000..97c53df775f
--- /dev/null
+++ b/usr.sbin/pppd/lcp.c
@@ -0,0 +1,1822 @@
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: lcp.c,v 1.1.1.1 1995/10/18 08:47:58 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "magic.h"
+#include "chap.h"
+#include "upap.h"
+#include "ipcp.h"
+
+#ifdef _linux_ /* Needs ppp ioctls */
+#include <net/if.h>
+#include <linux/if_ppp.h>
+#endif
+
+/* global vars */
+fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */
+
+static u_int32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */
+static u_int32_t lcp_echo_number = 0; /* ID number of next echo frame */
+static u_int32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */
+
+static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */
+
+#ifdef _linux_
+u_int32_t idle_timer_running = 0;
+extern int idle_time_limit;
+#endif
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __P((fsm *)); /* Reset our CI */
+static int lcp_cilen __P((fsm *)); /* Return length of our CI */
+static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __P((fsm *)); /* We're UP */
+static void lcp_down __P((fsm *)); /* We're DOWN */
+static void lcp_starting __P((fsm *)); /* We need lower layer up */
+static void lcp_finished __P((fsm *)); /* We need lower layer down */
+static int lcp_extcode __P((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __P((fsm *, u_char *, int));
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup __P((int));
+static void lcp_echo_lowerdown __P((int));
+static void LcpEchoTimeout __P((caddr_t));
+static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
+static void LcpSendEchoRequest __P((fsm *));
+static void LcpLinkFailure __P((fsm *));
+
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
+ lcp_resetci, /* Reset our Configuration Information */
+ lcp_cilen, /* Length of our Configuration Information */
+ lcp_addci, /* Add our Configuration Information */
+ lcp_ackci, /* ACK our Configuration Information */
+ lcp_nakci, /* NAK our Configuration Information */
+ lcp_rejci, /* Reject our Configuration Information */
+ lcp_reqci, /* Request peer's Configuration Information */
+ lcp_up, /* Called when fsm reaches OPENED state */
+ lcp_down, /* Called when fsm leaves OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+void
+lcp_init(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_LCP;
+ f->callbacks = &lcp_callbacks;
+
+ fsm_init(f);
+
+ wo->passive = 0;
+ wo->silent = 0;
+ wo->restart = 0; /* Set to 1 in kernels or multi-line
+ implementations */
+ wo->neg_mru = 1;
+ wo->mru = DEFMRU;
+ wo->neg_asyncmap = 0;
+ wo->asyncmap = 0;
+ wo->neg_chap = 0; /* Set to 1 on server */
+ wo->neg_upap = 0; /* Set to 1 on server */
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+ wo->neg_lqr = 0; /* no LQR implementation yet */
+
+ ao->neg_mru = 1;
+ ao->mru = MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->asyncmap = 0;
+ ao->neg_chap = 1;
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = 1;
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+ ao->neg_lqr = 0; /* no LQR implementation yet */
+
+ memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+ xmit_accm[unit][3] = 0x60000000;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags = 0;
+ if (wo->passive)
+ f->flags |= OPT_PASSIVE;
+ if (wo->silent)
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+ /*
+ * This action is not strictly according to the FSM in RFC1548,
+ * but it does mean that the program terminates if you do a
+ * lcp_close(0) in passive/silent mode when a connection hasn't
+ * been established.
+ */
+ f->state = CLOSED;
+ lcp_finished(f);
+
+ } else
+ fsm_close(&lcp_fsm[unit]);
+}
+
+#ifdef _linux_
+static void IdleTimeCheck __P((caddr_t));
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+RestartIdleTimer (f)
+ fsm *f;
+{
+ u_long delta;
+ struct ppp_idle ddinfo;
+/*
+ * Read the time since the last packet was received.
+ */
+ if (ioctl (fd, PPPIOCGIDLE, &ddinfo) < 0) {
+ syslog (LOG_ERR, "ioctl(PPPIOCGIDLE): %m");
+ die (1);
+ }
+/*
+ * Compute the time since the last packet was received. If the timer
+ * has expired then disconnect the line.
+ */
+ delta = idle_time_limit - (u_long) ddinfo.recv_idle;
+ if (((int) delta <= 0L) && (f->state == OPENED)) {
+ syslog (LOG_NOTICE, "No IP frames received within idle time limit");
+ lcp_close(f->unit); /* Reset connection */
+ phase = PHASE_TERMINATE; /* Mark it down */
+ } else {
+ if ((int) delta <= 0L)
+ delta = (u_long) idle_time_limit;
+ assert (idle_timer_running==0);
+ TIMEOUT (IdleTimeCheck, (caddr_t) f, delta);
+ idle_timer_running = 1;
+ }
+}
+
+/*
+ * IdleTimeCheck - Timer expired on the IDLE detection for IP frames
+ */
+
+static void
+IdleTimeCheck (arg)
+ caddr_t arg;
+{
+ if (idle_timer_running != 0) {
+ idle_timer_running = 0;
+ RestartIdleTimer ((fsm *) arg);
+ }
+}
+#endif
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(unit)
+ int unit;
+{
+ sifdown(unit);
+ ppp_set_xaccm(unit, xmit_accm[unit]);
+ ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, PPP_MRU, 0x00000000, 0, 0);
+ peer_mru[unit] = PPP_MRU;
+ lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
+
+ fsm_lowerup(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void
+lcp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_input - Input LCP packet.
+ */
+void
+lcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ int oldstate;
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+ oldstate = f->state;
+ fsm_input(f, p, len);
+ if (oldstate == REQSENT && f->state == ACKSENT) {
+ /*
+ * The peer will probably send us an ack soon and then
+ * immediately start sending packets with the negotiated
+ * options. So as to be ready when that happens, we set
+ * our receive side to accept packets as negotiated now.
+ */
+ ppp_recv_config(f->unit, PPP_MRU,
+ go->neg_asyncmap? go->asyncmap: 0x00000000,
+ go->neg_pcompression, go->neg_accompression);
+ }
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ u_char *magp;
+
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if (f->state != OPENED)
+ break;
+ LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ magp = inp;
+ PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ lcp_received_echo_reply(f, id, inp, len);
+ break;
+
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_short prot;
+
+ LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
+
+ if (len < sizeof (u_short)) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!",
+ prot));
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != OPENED ){
+ LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d",
+ f->state));
+ return;
+ }
+
+ DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+/*ARGSUSED*/
+void
+lcp_protrej(unit)
+ int unit;
+{
+ /*
+ * Can't reject LCP!
+ */
+ LCPDEBUG((LOG_WARNING,
+ "lcp_protrej: Received Protocol-Reject for LCP!"));
+ fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void
+lcp_sprotrej(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the OPENED state.
+ */
+ p += 2;
+ len -= 2;
+
+ fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
+ p, len);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void
+ lcp_resetci(f)
+fsm *f;
+{
+ lcp_wantoptions[f->unit].magicnumber = magic();
+ lcp_wantoptions[f->unit].numloops = 0;
+ lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+ peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(f)
+ fsm *f;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg) (neg ? CILEN_VOID : 0)
+#define LENCICHAP(neg) (neg ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) (neg ? CILEN_SHORT : 0)
+#define LENCILONG(neg) (neg ? CILEN_LONG : 0)
+#define LENCILQR(neg) (neg ? CILEN_LQR: 0)
+ /*
+ * NB: we only ask for one of CHAP and UPAP, even if we will
+ * accept either.
+ */
+ return (LENCISHORT(go->neg_mru) +
+ LENCILONG(go->neg_asyncmap) +
+ LENCICHAP(go->neg_chap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
+ LENCILONG(go->neg_magicnumber) +
+ LENCIVOID(go->neg_pcompression) +
+ LENCIVOID(go->neg_accompression));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void
+lcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
+
+#define ADDCIVOID(opt, neg) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
+ }
+#define ADDCISHORT(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
+ PUTSHORT(val, ucp); \
+ }
+#define ADDCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
+ PUTSHORT(val, ucp); \
+ PUTCHAR(digest, ucp); \
+ }
+#define ADDCILONG(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(PPP_LQR, ucp); \
+ PUTLONG(val, ucp); \
+ }
+
+ ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
+ }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+lcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cilen, citype, cichar;
+ u_short cishort;
+ u_int32_t cilong;
+
+ /*
+ * CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define ACKCIVOID(opt, neg) \
+ if (neg) { \
+ if ((len -= CILEN_VOID) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || \
+ citype != opt) \
+ goto bad; \
+ }
+#define ACKCISHORT(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_SHORT) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_SHORT || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ }
+#define ACKCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ if ((len -= CILEN_CHAP) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAP || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != digest) \
+ goto bad; \
+ }
+#define ACKCILONG(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LONG) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LONG || \
+ citype != opt) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != PPP_LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+
+ ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ return (1);
+bad:
+ LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"));
+ return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+lcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char citype, cichar, *next;
+ u_short cishort;
+ u_int32_t cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+ int cilen;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIVOID(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCISHORT(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILONG(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * We don't care if they want to send us smaller packets than
+ * we want. Therefore, accept any MRU less than what we asked for,
+ * but then ignore the new value when setting the MRU in the kernel.
+ * If they send us a bigger MRU than what we asked, accept it, up to
+ * the limit of the default MRU we'd get if we didn't negotiate.
+ */
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort < DEFMRU)
+ try.mru = cishort;
+ );
+
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+
+ /*
+ * If they've nak'd our authentication-protocol, check whether
+ * they are proposing a different protocol, or a different
+ * hash algorithm for CHAP.
+ */
+ if ((go->neg_chap || go->neg_upap)
+ && len >= CILEN_SHORT
+ && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT) {
+ cilen = p[1];
+ INCPTR(2, p);
+ GETSHORT(cishort, p);
+ if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+ /*
+ * If they are asking for PAP, then they don't want to do CHAP.
+ * If we weren't asking for CHAP, then we were asking for PAP,
+ * in which case this Nak is bad.
+ */
+ if (!go->neg_chap)
+ goto bad;
+ go->neg_chap = 0;
+
+ } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+ GETCHAR(cichar, p);
+ if (go->neg_chap) {
+ /*
+ * We were asking for CHAP/MD5; they must want a different
+ * algorithm. If they can't do MD5, we'll have to stop
+ * asking for CHAP.
+ */
+ if (cichar != go->chap_mdtype)
+ go->neg_chap = 0;
+ } else {
+ /*
+ * Stop asking for PAP if we were asking for it.
+ */
+ go->neg_upap = 0;
+ }
+
+ } else {
+ /*
+ * We don't recognize what they're suggesting.
+ * Stop asking for what we were asking for.
+ */
+ if (go->neg_chap)
+ go->neg_chap = 0;
+ else
+ go->neg_upap = 0;
+ p += cilen - CILEN_SHORT;
+ }
+ }
+
+ /*
+ * Peer shouldn't send Nak for protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
+ if (!go->neg_chap ){
+ NAKCISHORT(CI_AUTHTYPE, neg_upap,
+ try.neg_upap = 0;
+ );
+ }
+
+ /*
+ * If they can't cope with our link quality protocol, we'll have
+ * to stop asking for LQR. We haven't got any other protocol.
+ * If they Nak the reporting period, take their value XXX ?
+ */
+ NAKCILQR(CI_QUALITY, neg_lqr,
+ if (cishort != PPP_LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+
+ /*
+ * Check for a looped-back line.
+ */
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ looped_back = 1;
+ );
+
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+ try.neg_pcompression = 0;
+ );
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+ try.neg_accompression = 0;
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
+ * An option we don't recognize represents the peer asking to
+ * negotiate some option we don't support, so ignore it.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if ((len -= cilen) < 0)
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT)
+ goto bad;
+ break;
+ case CI_ASYNCMAP:
+ if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+ goto bad;
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+ goto bad;
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED) {
+ if (looped_back) {
+ if (++try.numloops >= lcp_loopbackfail) {
+ syslog(LOG_NOTICE, "Serial line is looped back.");
+ lcp_close(f->unit);
+ }
+ } else
+ try.numloops = 0;
+ *go = try;
+ }
+
+ return 1;
+
+bad:
+ LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
+ */
+static int
+lcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
+ u_short cishort;
+ u_int32_t cilong;
+ u_char *start = p;
+ int plen = len;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIVOID(opt, neg) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \
+ }
+#define REJCISHORT(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \
+ }
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cishort != val || cichar != digest) \
+ goto bad; \
+ try.neg = 0; \
+ try.neg_upap = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \
+ }
+#define REJCILONG(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cilong != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != PPP_LQR || cilong != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
+ }
+
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
+bad:
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"));
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d",
+ plen, len, p - start));
+ return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *lenp; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_char cilen, citype, cichar;/* Parsed len, type, char value */
+ u_short cishort; /* Parsed short value */
+ u_int32_t cilong; /* Parse long value */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *rejp; /* Pointer to next char in reject frame */
+ u_char *nakp; /* Pointer to next char in Nak frame */
+ int l = *lenp; /* Length left */
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ nakp = nak_buffer;
+ rejp = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_MRU:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"));
+ if (!ao->neg_mru || /* Allow option? */
+ cilen != CILEN_SHORT) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETSHORT(cishort, p); /* Parse MRU */
+ LCPDEBUG((LOG_INFO, "(%d)", cishort));
+
+ /*
+ * He must be able to receive at least our minimum.
+ * No need to check a maximum. If he sends a large number,
+ * we'll just ignore it.
+ */
+ if (cishort < MINMRU) {
+ orc = CONFNAK; /* Nak CI */
+ PUTCHAR(CI_MRU, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(MINMRU, nakp); /* Give him a hint */
+ break;
+ }
+ ho->neg_mru = 1; /* Remember he sent MRU */
+ ho->mru = cishort; /* And remember value */
+ break;
+
+ case CI_ASYNCMAP:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"));
+ if (!ao->neg_asyncmap ||
+ cilen != CILEN_LONG) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong));
+
+ /*
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
+ */
+ if ((ao->asyncmap & ~cilong) != 0) {
+ orc = CONFNAK;
+ PUTCHAR(CI_ASYNCMAP, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(ao->asyncmap | cilong, nakp);
+ break;
+ }
+ ho->neg_asyncmap = 1;
+ ho->asyncmap = cilong;
+ break;
+
+ case CI_AUTHTYPE:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE"));
+ if (cilen < CILEN_SHORT ||
+ !(ao->neg_upap || ao->neg_chap)) {
+ /*
+ * Reject the option if we're not willing to authenticate.
+ */
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+ LCPDEBUG((LOG_INFO, "(%x)", cishort));
+
+ /*
+ * Authtype must be UPAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
+ */
+
+ if (cishort == PPP_PAP) {
+ if (ho->neg_chap || /* we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG((LOG_WARNING,
+ "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_upap) { /* we don't want to do PAP */
+ orc = CONFNAK; /* NAK it and suggest CHAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ break;
+ }
+ ho->neg_upap = 1;
+ break;
+ }
+ if (cishort == PPP_CHAP) {
+ if (ho->neg_upap || /* we've already accepted PAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_chap) { /* we don't want to do CHAP */
+ orc = CONFNAK; /* NAK it and suggest PAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != ao->chap_mdtype) {
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
+ break;
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Nak it with something we're willing to do.
+ * (At this point we know ao->neg_upap || ao->neg_chap.)
+ */
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ if (ao->neg_chap) {
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ } else {
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ }
+ break;
+
+ case CI_QUALITY:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY"));
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
+ break;
+ }
+
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x %x)", cishort, (unsigned int) cilong));
+
+ /*
+ * Check the protocol and the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ if (cishort != PPP_LQR) {
+ orc = CONFNAK;
+ PUTCHAR(CI_QUALITY, nakp);
+ PUTCHAR(CILEN_LQR, nakp);
+ PUTSHORT(PPP_LQR, nakp);
+ PUTLONG(ao->lqr_period, nakp);
+ break;
+ }
+ break;
+
+ case CI_MAGICNUMBER:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"));
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong));
+
+ /*
+ * He must have a different magic number.
+ */
+ if (go->neg_magicnumber &&
+ cilong == go->magicnumber) {
+ cilong = magic(); /* Don't put magic() inside macro! */
+ orc = CONFNAK;
+ PUTCHAR(CI_MAGICNUMBER, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(cilong, nakp);
+ break;
+ }
+ ho->neg_magicnumber = 1;
+ ho->magicnumber = cilong;
+ break;
+
+
+ case CI_PCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"));
+ if (!ao->neg_pcompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_pcompression = 1;
+ break;
+
+ case CI_ACCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"));
+ if (!ao->neg_accompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_accompression = 1;
+ break;
+
+ default:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d",
+ citype));
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc)));
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree /* Getting fed up with sending NAKs? */
+ && citype != CI_MAGICNUMBER) {
+ orc = CONFREJ; /* Get tough if so */
+ } else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ rc = CONFNAK;
+ }
+ }
+ if (orc == CONFREJ) { /* Reject this CI */
+ rc = CONFREJ;
+ if (cip != rejp) /* Need to move rejected CI? */
+ BCOPY(cip, rejp, cilen); /* Move it */
+ INCPTR(cilen, rejp); /* Update output pointer */
+ }
+ }
+
+ /*
+ * If we wanted to send additional NAKs (for unsent CIs), the
+ * code would go here. The extra NAKs would go at *nakp.
+ * At present there are no cases where we want to ask the
+ * peer to negotiate an option.
+ */
+
+ switch (rc) {
+ case CONFACK:
+ *lenp = next - inp;
+ break;
+ case CONFNAK:
+ /*
+ * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+ */
+ *lenp = nakp - nak_buffer;
+ BCOPY(nak_buffer, inp, *lenp);
+ break;
+ case CONFREJ:
+ *lenp = rejp - inp;
+ break;
+ }
+
+ LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ *
+ * Start UPAP, IPCP, etc.
+ */
+static void
+lcp_up(f)
+ fsm *f;
+{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ if (!go->neg_magicnumber)
+ go->magicnumber = 0;
+ if (!ho->neg_magicnumber)
+ ho->magicnumber = 0;
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ */
+ ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ ho->neg_pcompression, ho->neg_accompression);
+ /*
+ * If the asyncmap hasn't been negotiated, we really should
+ * set the receive asyncmap to ffffffff, but we set it to 0
+ * for backwards contemptibility.
+ */
+ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
+ (go->neg_asyncmap? go->asyncmap: 0x00000000),
+ go->neg_pcompression, go->neg_accompression);
+
+ if (ho->neg_mru)
+ peer_mru[f->unit] = ho->mru;
+
+ ChapLowerUp(f->unit); /* Enable CHAP */
+ upap_lowerup(f->unit); /* Enable UPAP */
+ ipcp_lowerup(f->unit); /* Enable IPCP */
+ ccp_lowerup(f->unit); /* Enable CCP */
+ lcp_echo_lowerup(f->unit); /* Enable echo messages */
+
+ link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(f)
+ fsm *f;
+{
+ lcp_echo_lowerdown(f->unit);
+ ccp_lowerdown(f->unit);
+ ipcp_lowerdown(f->unit);
+ ChapLowerDown(f->unit);
+ upap_lowerdown(f->unit);
+
+ sifdown(f->unit);
+ ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, PPP_MRU, 0x00000000, 0, 0);
+ peer_mru[f->unit] = PPP_MRU;
+
+ link_down(f->unit);
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(f)
+ fsm *f;
+{
+ link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+ fsm *f;
+{
+ link_terminated(f->unit);
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+char *lcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej", "ProtRej",
+ "EchoReq", "EchoRep", "DiscReq"
+};
+
+int
+lcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+ printer(arg, " %s", lcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_MRU:
+ if (olen == CILEN_SHORT) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "mru %d", cishort);
+ }
+ break;
+ case CI_ASYNCMAP:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "asyncmap 0x%x", cilong);
+ }
+ break;
+ case CI_AUTHTYPE:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "auth ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_PAP:
+ printer(arg, "upap");
+ break;
+ case PPP_CHAP:
+ printer(arg, "chap");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_QUALITY:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "quality ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_LQR:
+ printer(arg, "lqr");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_MAGICNUMBER:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "magic 0x%x", cilong);
+ }
+ break;
+ case CI_PCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "pcomp");
+ }
+ break;
+ case CI_ACCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "accomp");
+ }
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+
+static
+void LcpLinkFailure (f)
+ fsm *f;
+{
+ if (f->state == OPENED) {
+ syslog (LOG_NOTICE, "Excessive lack of response to LCP echo frames.");
+ lcp_close(f->unit); /* Reset connection */
+ }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (f)
+ fsm *f;
+{
+ long int delta;
+#ifdef __linux__
+ struct ppp_idle ddinfo;
+/*
+ * Read the time since the last packet was received.
+ */
+ if (ioctl (fd, PPPIOCGIDLE, &ddinfo) < 0) {
+ syslog (LOG_ERR, "ioctl(PPPIOCGIDLE): %m");
+ die (1);
+ }
+/*
+ * Compute the time since the last packet was received. If the timer
+ * has expired then send the echo request and reset the timer to maximum.
+ */
+ delta = (long int) lcp_echo_interval - (long int) ddinfo.recv_idle;
+ if (delta < 0L) {
+ LcpSendEchoRequest (f);
+ delta = (int) lcp_echo_interval;
+ }
+
+#else /* Other implementations do not have ability to find delta */
+ LcpSendEchoRequest (f);
+ delta = (int) lcp_echo_interval;
+#endif
+
+/*
+ * Start the timer for the next interval.
+ */
+ assert (lcp_echo_timer_running==0);
+ TIMEOUT (LcpEchoTimeout, (caddr_t) f, (u_int32_t) delta);
+ lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+
+static void
+LcpEchoTimeout (arg)
+ caddr_t arg;
+{
+ if (lcp_echo_timer_running != 0) {
+ lcp_echo_timer_running = 0;
+ LcpEchoCheck ((fsm *) arg);
+ }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+
+static void
+lcp_received_echo_reply (f, id, inp, len)
+ fsm *f;
+ int id; u_char *inp; int len;
+{
+ u_int32_t magic;
+
+ /* Check the magic number - don't count replies from ourselves. */
+ if (len < 4) {
+ syslog(LOG_DEBUG, "lcp: received short Echo-Reply, length %d", len);
+ return;
+ }
+ GETLONG(magic, inp);
+ if (lcp_gotoptions[f->unit].neg_magicnumber
+ && magic == lcp_gotoptions[f->unit].magicnumber) {
+ syslog(LOG_WARNING, "appear to have received our own echo-reply!");
+ return;
+ }
+
+ /* Reset the number of outstanding echo frames */
+ lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+
+static void
+LcpSendEchoRequest (f)
+ fsm *f;
+{
+ u_int32_t lcp_magic;
+ u_char pkt[4], *pktp;
+
+/*
+ * Detect the failure of the peer at this point.
+ */
+ if (lcp_echo_fails != 0) {
+ if (lcp_echos_pending++ >= lcp_echo_fails) {
+ LcpLinkFailure(f);
+ lcp_echos_pending = 0;
+ }
+ }
+/*
+ * Make and send the echo request frame.
+ */
+ if (f->state == OPENED) {
+ lcp_magic = lcp_gotoptions[f->unit].neg_magicnumber
+ ? lcp_gotoptions[f->unit].magicnumber
+ : 0L;
+ pktp = pkt;
+ PUTLONG(lcp_magic, pktp);
+
+ fsm_sdata(f, ECHOREQ,
+ lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+ }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerup (unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ /* Clear the parameters for generating echo frames */
+ lcp_echos_pending = 0;
+ lcp_echo_number = 0;
+ lcp_echo_timer_running = 0;
+
+ /* If a timeout interval is specified then start the timer */
+ if (lcp_echo_interval != 0)
+ LcpEchoCheck (f);
+#ifdef _linux_
+ /* If a idle time limit is given then start it */
+ if (idle_time_limit != 0)
+ RestartIdleTimer (f);
+#endif
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerdown (unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (lcp_echo_timer_running != 0) {
+ UNTIMEOUT (LcpEchoTimeout, (caddr_t) f);
+ lcp_echo_timer_running = 0;
+ }
+#ifdef _linux_
+ /* If a idle time limit is running then stop it */
+ if (idle_timer_running != 0) {
+ UNTIMEOUT (IdleTimeCheck, (caddr_t) f);
+ idle_timer_running = 0;
+ }
+#endif
+}
diff --git a/usr.sbin/pppd/lcp.h b/usr.sbin/pppd/lcp.h
new file mode 100644
index 00000000000..b7a4936aeec
--- /dev/null
+++ b/usr.sbin/pppd/lcp.h
@@ -0,0 +1,88 @@
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.h,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $
+ */
+
+/*
+ * Options.
+ */
+#define CI_MRU 1 /* Maximum Receive Unit */
+#define CI_ASYNCMAP 2 /* Async Control Character Map */
+#define CI_AUTHTYPE 3 /* Authentication Type */
+#define CI_QUALITY 4 /* Quality Protocol */
+#define CI_MAGICNUMBER 5 /* Magic Number */
+#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
+
+/*
+ * LCP-specific packet types.
+ */
+#define PROTREJ 8 /* Protocol Reject */
+#define ECHOREQ 9 /* Echo Request */
+#define ECHOREP 10 /* Echo Reply */
+#define DISCREQ 11 /* Discard Request */
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+ int passive : 1; /* Don't die if we don't get a response */
+ int silent : 1; /* Wait for the other end to start first */
+ int restart : 1; /* Restart vs. exit after close */
+ int neg_mru : 1; /* Negotiate the MRU? */
+ int neg_asyncmap : 1; /* Negotiate the async map? */
+ int neg_upap : 1; /* Ask for UPAP authentication? */
+ int neg_chap : 1; /* Ask for CHAP authentication? */
+ int neg_magicnumber : 1; /* Ask for magic number? */
+ int neg_pcompression : 1; /* HDLC Protocol Field Compression? */
+ int neg_accompression : 1; /* HDLC Address/Control Field Compression? */
+ int neg_lqr : 1; /* Negotiate use of Link Quality Reports */
+ u_short mru; /* Value of MRU */
+ u_char chap_mdtype; /* which MD type (hashing algorithm) */
+ u_int32_t asyncmap; /* Value of async map */
+ u_int32_t magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u_int32_t lqr_period; /* Reporting period for LQR 1/100ths second */
+} lcp_options;
+
+extern fsm lcp_fsm[];
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+extern u_int32_t xmit_accm[][8];
+
+#define DEFMRU 1500 /* Try for this */
+#define MINMRU 128 /* No MRUs below this */
+#define MAXMRU 16384 /* Normally limit MRU to this */
+
+void lcp_init __P((int));
+void lcp_open __P((int));
+void lcp_close __P((int));
+void lcp_lowerup __P((int));
+void lcp_lowerdown __P((int));
+void lcp_input __P((int, u_char *, int));
+void lcp_protrej __P((int));
+void lcp_sprotrej __P((int, u_char *, int));
+int lcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+/* Default number of times we receive our magic number from the peer
+ before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL 5
diff --git a/usr.sbin/pppd/magic.c b/usr.sbin/pppd/magic.c
new file mode 100644
index 00000000000..c44c10b1477
--- /dev/null
+++ b/usr.sbin/pppd/magic.c
@@ -0,0 +1,90 @@
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: magic.c,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "magic.h"
+
+static u_int32_t next; /* Next value to return */
+
+extern int gethostid __P((void));
+extern long mrand48 __P((void));
+extern void srand48 __P((long));
+
+
+/*
+ * magic_init - Initialize the magic number generator.
+ *
+ * Attempts to compute a random number seed which will not repeat.
+ * The current method uses the current hostid, current process ID
+ * and current time, currently.
+ */
+void
+magic_init()
+{
+ long seed;
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid();
+ srand48(seed);
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+u_int32_t
+magic()
+{
+ return (u_int32_t) mrand48();
+}
+
+#ifdef NO_DRAND48
+/*
+ * Substitute procedures for those systems which don't have
+ * drand48 et al.
+ */
+
+double
+drand48()
+{
+ return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
+}
+
+long
+mrand48()
+{
+ return random();
+}
+
+void
+srand48(seedval)
+long seedval;
+{
+ srandom((int)seedval);
+}
+
+#endif
diff --git a/usr.sbin/pppd/magic.h b/usr.sbin/pppd/magic.h
new file mode 100644
index 00000000000..eb88f27b056
--- /dev/null
+++ b/usr.sbin/pppd/magic.h
@@ -0,0 +1,23 @@
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: magic.h,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $
+ */
+
+void magic_init __P((void)); /* Initialize the magic number generator */
+u_int32_t magic __P((void)); /* Returns the next magic number */
diff --git a/usr.sbin/pppd/main.c b/usr.sbin/pppd/main.c
new file mode 100644
index 00000000000..493c586b98b
--- /dev/null
+++ b/usr.sbin/pppd/main.c
@@ -0,0 +1,1087 @@
+/*
+ * main.c - Point-to-Point Protocol main module
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "pppd.h"
+#include "magic.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+
+/*
+ * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
+ * /etc/ppp/options exists.
+ */
+#ifndef REQ_SYSOPTIONS
+#define REQ_SYSOPTIONS 1
+#endif
+
+/* interface vars */
+char ifname[IFNAMSIZ]; /* Interface name */
+int ifunit; /* Interface unit number */
+
+char *progname; /* Name of this program */
+char hostname[MAXNAMELEN]; /* Our hostname */
+static char pidfilename[MAXPATHLEN]; /* name of pid file */
+static char default_devnam[MAXPATHLEN]; /* name of default device */
+static pid_t pid; /* Our pid */
+static pid_t pgrpid; /* Process Group ID */
+static uid_t uid; /* Our real user-id */
+
+int fd = -1; /* Device file descriptor */
+
+int phase; /* where the link is at */
+int kill_link;
+int open_ccp_flag;
+
+static int initfdflags = -1; /* Initial file descriptor flags */
+
+u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
+static u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+
+int hungup; /* terminal has been hung up */
+static int n_children; /* # child processes still running */
+
+int baud_rate;
+
+char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
+
+/* prototypes */
+static void hup __P((int));
+static void term __P((int));
+static void chld __P((int));
+static void toggle_debug __P((int));
+static void open_ccp __P((int));
+static void bad_signal __P((int));
+
+static void get_input __P((void));
+void establish_ppp __P((void));
+void calltimeout __P((void));
+struct timeval *timeleft __P((struct timeval *));
+void reap_kids __P((void));
+void cleanup __P((int, caddr_t));
+void close_fd __P((void));
+void die __P((int));
+void novm __P((char *));
+
+void log_packet __P((u_char *, int, char *));
+void format_packet __P((u_char *, int,
+ void (*) (void *, char *, ...), void *));
+void pr_log __P((void *, char *, ...));
+
+extern char *ttyname __P((int));
+extern char *getlogin __P((void));
+
+#ifdef ultrix
+#undef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ */
+static struct protent {
+ u_short protocol;
+ void (*init)();
+ void (*input)();
+ void (*protrej)();
+ int (*printpkt)();
+ void (*datainput)();
+ char *name;
+} prottbl[] = {
+ { PPP_LCP, lcp_init, lcp_input, lcp_protrej,
+ lcp_printpkt, NULL, "LCP" },
+ { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej,
+ ipcp_printpkt, NULL, "IPCP" },
+ { PPP_PAP, upap_init, upap_input, upap_protrej,
+ upap_printpkt, NULL, "PAP" },
+ { PPP_CHAP, ChapInit, ChapInput, ChapProtocolReject,
+ ChapPrintPkt, NULL, "CHAP" },
+ { PPP_CCP, ccp_init, ccp_input, ccp_protrej,
+ ccp_printpkt, ccp_datainput, "CCP" },
+};
+
+#define N_PROTO (sizeof(prottbl) / sizeof(prottbl[0]))
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i, nonblock;
+ struct sigaction sa;
+ struct cmd *cmdp;
+ FILE *pidfile;
+ char *p;
+ struct passwd *pw;
+ struct timeval timo;
+ sigset_t mask;
+
+ p = ttyname(0);
+ if (p)
+ strcpy(devnam, p);
+ strcpy(default_devnam, devnam);
+
+ if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+ perror("couldn't get hostname");
+ die(1);
+ }
+ hostname[MAXNAMELEN-1] = 0;
+
+ uid = getuid();
+
+ if (!ppp_available()) {
+ fprintf(stderr, no_ppp_msg);
+ exit(1);
+ }
+
+ /*
+ * Initialize to the standard option set, then parse, in order,
+ * the system options file, the user's options file, and the command
+ * line arguments.
+ */
+ for (i = 0; i < N_PROTO; i++)
+ (*prottbl[i].init)(0);
+
+ progname = *argv;
+
+ if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS, 0) ||
+ !options_from_user() ||
+ !parse_args(argc-1, argv+1) ||
+ !options_for_tty())
+ die(1);
+ check_auth_options();
+ setipdefault();
+
+ /*
+ * If the user has specified the default device name explicitly,
+ * pretend they hadn't.
+ */
+ if (!default_device && strcmp(devnam, default_devnam) == 0)
+ default_device = 1;
+
+ /*
+ * Initialize system-dependent stuff and magic number package.
+ */
+ sys_init();
+ magic_init();
+
+ /*
+ * Detach ourselves from the terminal, if required,
+ * and identify who is running us.
+ */
+ if (!default_device && !nodetach && daemon(0, 0) < 0) {
+ perror("Couldn't detach from controlling terminal");
+ exit(1);
+ }
+ pid = getpid();
+ p = getlogin();
+ if (p == NULL) {
+ pw = getpwuid(uid);
+ if (pw != NULL && pw->pw_name != NULL)
+ p = pw->pw_name;
+ else
+ p = "(unknown)";
+ }
+ syslog(LOG_NOTICE, "pppd %s.%d started by %s, uid %d",
+ VERSION, PATCHLEVEL, p, uid);
+
+ /*
+ * Compute mask of all interesting signals and install signal handlers
+ * for each. Only one signal handler may be active at a time. Therefore,
+ * all other signals should be masked when any handler is executing.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGCHLD);
+
+#define SIGNAL(s, handler) { \
+ sa.sa_handler = handler; \
+ if (sigaction(s, &sa, NULL) < 0) { \
+ syslog(LOG_ERR, "Couldn't establish signal handler (%d): %m", s); \
+ die(1); \
+ } \
+ }
+
+ sa.sa_mask = mask;
+ sa.sa_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, term); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGCHLD, chld);
+
+ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */
+ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */
+
+ /*
+ * Install a handler for other signals which would otherwise
+ * cause pppd to exit without cleaning up.
+ */
+ SIGNAL(SIGABRT, bad_signal);
+ SIGNAL(SIGALRM, bad_signal);
+ SIGNAL(SIGFPE, bad_signal);
+ SIGNAL(SIGILL, bad_signal);
+ SIGNAL(SIGPIPE, bad_signal);
+ SIGNAL(SIGQUIT, bad_signal);
+ SIGNAL(SIGSEGV, bad_signal);
+#ifdef SIGBUS
+ SIGNAL(SIGBUS, bad_signal);
+#endif
+#ifdef SIGEMT
+ SIGNAL(SIGEMT, bad_signal);
+#endif
+#ifdef SIGPOLL
+ SIGNAL(SIGPOLL, bad_signal);
+#endif
+#ifdef SIGPROF
+ SIGNAL(SIGPROF, bad_signal);
+#endif
+#ifdef SIGSYS
+ SIGNAL(SIGSYS, bad_signal);
+#endif
+#ifdef SIGTRAP
+ SIGNAL(SIGTRAP, bad_signal);
+#endif
+#ifdef SIGVTALRM
+ SIGNAL(SIGVTALRM, bad_signal);
+#endif
+#ifdef SIGXCPU
+ SIGNAL(SIGXCPU, bad_signal);
+#endif
+#ifdef SIGXFSZ
+ SIGNAL(SIGXFSZ, bad_signal);
+#endif
+
+ /*
+ * Lock the device if we've been asked to.
+ */
+ if (lockflag && !default_device)
+ if (lock(devnam) < 0)
+ die(1);
+
+ do {
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ * If we're dialling out, or we don't want to use the modem lines,
+ * we open it in non-blocking mode, but then we need to clear
+ * the non-blocking I/O bit.
+ */
+ nonblock = (connector || !modem)? O_NONBLOCK: 0;
+ if ((fd = open(devnam, nonblock | O_RDWR, 0)) < 0) {
+ syslog(LOG_ERR, "Failed to open %s: %m", devnam);
+ die(1);
+ }
+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
+ syslog(LOG_ERR, "Couldn't get device fd flags: %m");
+ die(1);
+ }
+ if (nonblock) {
+ initfdflags &= ~O_NONBLOCK;
+ fcntl(fd, F_SETFL, initfdflags);
+ }
+ hungup = 0;
+ kill_link = 0;
+
+ /* run connection script */
+ if (connector && connector[0]) {
+ MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector));
+
+ /* set line speed, flow control, etc.; set CLOCAL for now */
+ set_up_tty(fd, 1);
+
+ /* drop dtr to hang up in case modem is off hook */
+ if (!default_device && modem) {
+ setdtr(fd, FALSE);
+ sleep(1);
+ setdtr(fd, TRUE);
+ }
+
+ if (device_script(connector, fd, fd) < 0) {
+ syslog(LOG_ERR, "Connect script failed");
+ setdtr(fd, FALSE);
+ die(1);
+ }
+
+ syslog(LOG_INFO, "Serial connection established.");
+ sleep(1); /* give it time to set up its terminal */
+ }
+
+ /* set line speed, flow control, etc.; clear CLOCAL if modem option */
+ set_up_tty(fd, 0);
+
+ /* set up the serial device as a ppp interface */
+ establish_ppp();
+
+ syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+ (void) sprintf(ifname, "ppp%d", ifunit);
+
+ /* write pid to file */
+ (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ }
+
+ /*
+ * Set device for non-blocking reads.
+ */
+ if (fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+ syslog(LOG_ERR, "Couldn't set device to non-blocking mode: %m");
+ die(1);
+ }
+
+ /*
+ * Block all signals, start opening the connection, and wait for
+ * incoming events (reply, timeout, etc.).
+ */
+ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
+ lcp_lowerup(0);
+ lcp_open(0); /* Start protocol */
+ for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) {
+ wait_input(timeleft(&timo));
+ calltimeout();
+ get_input();
+ if (kill_link) {
+ lcp_close(0);
+ kill_link = 0;
+ }
+ if (open_ccp_flag) {
+ if (phase == PHASE_NETWORK) {
+ ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
+ ccp_open(0);
+ }
+ open_ccp_flag = 0;
+ }
+ reap_kids(); /* Don't leave dead kids lying around */
+ }
+
+ /*
+ * Run disconnector script, if requested.
+ * First we need to reset non-blocking mode.
+ * XXX we may not be able to do this if the line has hung up!
+ */
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) >= 0)
+ initfdflags = -1;
+ disestablish_ppp();
+ if (disconnector) {
+ set_up_tty(fd, 1);
+ if (device_script(disconnector, fd, fd) < 0) {
+ syslog(LOG_WARNING, "disconnect script failed");
+ } else {
+ syslog(LOG_INFO, "Serial link disconnected.");
+ }
+ }
+
+ close_fd();
+ if (unlink(pidfilename) < 0 && errno != ENOENT)
+ syslog(LOG_WARNING, "unable to delete pid file: %m");
+ pidfilename[0] = 0;
+
+ } while (persist);
+
+ die(0);
+}
+
+
+/*
+ * get_input - called when incoming data is available.
+ */
+static void
+get_input()
+{
+ int len, i;
+ u_char *p;
+ u_short protocol;
+
+ p = inpacket_buf; /* point to beginning of packet buffer */
+
+ len = read_packet(inpacket_buf);
+ if (len < 0)
+ return;
+
+ if (len == 0) {
+ syslog(LOG_NOTICE, "Modem hangup");
+ hungup = 1;
+ lcp_lowerdown(0); /* serial link is no longer available */
+ phase = PHASE_DEAD;
+ return;
+ }
+
+ if (debug /*&& (debugflags & DBG_INPACKET)*/)
+ log_packet(p, len, "rcvd ");
+
+ if (len < PPP_HDRLEN) {
+ MAINDEBUG((LOG_INFO, "io(): Received short packet."));
+ return;
+ }
+
+ p += 2; /* Skip address and control */
+ GETSHORT(protocol, p);
+ len -= PPP_HDRLEN;
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ */
+ if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
+ MAINDEBUG((LOG_INFO,
+ "io(): Received non-LCP packet when LCP not open."));
+ return;
+ }
+
+ /*
+ * Upcall the proper protocol input routine.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++) {
+ if (prottbl[i].protocol == protocol) {
+ (*prottbl[i].input)(0, p, len);
+ return;
+ }
+ if (protocol == (prottbl[i].protocol & ~0x8000)
+ && prottbl[i].datainput != NULL) {
+ (*prottbl[i].datainput)(0, p, len);
+ return;
+ }
+ }
+
+ if (debug)
+ syslog(LOG_WARNING, "Unknown protocol (0x%x) received", protocol);
+ lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
+}
+
+
+/*
+ * demuxprotrej - Demultiplex a Protocol-Reject.
+ */
+void
+demuxprotrej(unit, protocol)
+ int unit;
+ u_short protocol;
+{
+ int i;
+
+ /*
+ * Upcall the proper Protocol-Reject routine.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
+ if (prottbl[i].protocol == protocol) {
+ (*prottbl[i].protrej)(unit);
+ return;
+ }
+
+ syslog(LOG_WARNING,
+ "demuxprotrej: Unrecognized Protocol-Reject for protocol 0x%x",
+ protocol);
+}
+
+
+/*
+ * bad_signal - We've caught a fatal signal. Clean up state and exit.
+ */
+static void
+bad_signal(sig)
+ int sig;
+{
+ syslog(LOG_ERR, "Fatal signal %d", sig);
+ die(1);
+}
+
+/*
+ * quit - Clean up state and exit (with an error indication).
+ */
+void
+quit()
+{
+ die(1);
+}
+
+/*
+ * die - like quit, except we can specify an exit status.
+ */
+void
+die(status)
+ int status;
+{
+ cleanup(0, NULL);
+ syslog(LOG_INFO, "Exit.");
+ exit(status);
+}
+
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+void
+cleanup(status, arg)
+ int status;
+ caddr_t arg;
+{
+ if (fd >= 0)
+ close_fd();
+
+ if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
+ syslog(LOG_WARNING, "unable to delete pid file: %m");
+ pidfilename[0] = 0;
+
+ if (lockflag && !default_device)
+ unlock();
+}
+
+/*
+ * close_fd - restore the terminal device and close it.
+ */
+void
+close_fd()
+{
+ disestablish_ppp();
+
+ /* drop dtr to hang up */
+ if (modem)
+ setdtr(fd, FALSE);
+
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
+ initfdflags = -1;
+
+ restore_tty();
+
+ close(fd);
+ fd = -1;
+}
+
+
+struct callout {
+ struct timeval c_time; /* time at which to call routine */
+ caddr_t c_arg; /* argument to routine */
+ void (*c_func)(); /* routine */
+ struct callout *c_next;
+};
+
+static struct callout *callout = NULL; /* Callout list */
+static struct timeval timenow; /* Current time */
+
+/*
+ * timeout - Schedule a timeout.
+ *
+ * Note that this timeout takes the number of seconds, NOT hz (as in
+ * the kernel).
+ */
+void
+timeout(func, arg, time)
+ void (*func)();
+ caddr_t arg;
+ int time;
+{
+ struct callout *newp, *p, **pp;
+
+ MAINDEBUG((LOG_DEBUG, "Timeout %lx:%lx in %d seconds.",
+ (long) func, (long) arg, time));
+
+ /*
+ * Allocate timeout.
+ */
+ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
+ syslog(LOG_ERR, "Out of memory in timeout()!");
+ die(1);
+ }
+ newp->c_arg = arg;
+ newp->c_func = func;
+ gettimeofday(&timenow, NULL);
+ newp->c_time.tv_sec = timenow.tv_sec + time;
+ newp->c_time.tv_usec = timenow.tv_usec;
+
+ /*
+ * Find correct place and link it in.
+ */
+ for (pp = &callout; (p = *pp); pp = &p->c_next)
+ if (newp->c_time.tv_sec < p->c_time.tv_sec
+ || (newp->c_time.tv_sec == p->c_time.tv_sec
+ && newp->c_time.tv_usec < p->c_time.tv_sec))
+ break;
+ newp->c_next = p;
+ *pp = newp;
+}
+
+
+/*
+ * untimeout - Unschedule a timeout.
+ */
+void
+untimeout(func, arg)
+ void (*func)();
+ caddr_t arg;
+{
+ struct itimerval itv;
+ struct callout **copp, *freep;
+ int reschedule = 0;
+
+ MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg));
+
+ /*
+ * Find first matching timeout and remove it from the list.
+ */
+ for (copp = &callout; (freep = *copp); copp = &freep->c_next)
+ if (freep->c_func == func && freep->c_arg == arg) {
+ *copp = freep->c_next;
+ (void) free((char *) freep);
+ break;
+ }
+}
+
+
+/*
+ * calltimeout - Call any timeout routines which are now due.
+ */
+void
+calltimeout()
+{
+ struct callout *p;
+
+ while (callout != NULL) {
+ p = callout;
+
+ if (gettimeofday(&timenow, NULL) < 0) {
+ syslog(LOG_ERR, "Failed to get time of day: %m");
+ die(1);
+ }
+ if (!(p->c_time.tv_sec < timenow.tv_sec
+ || (p->c_time.tv_sec == timenow.tv_sec
+ && p->c_time.tv_usec <= timenow.tv_usec)))
+ break; /* no, it's not time yet */
+
+ callout = p->c_next;
+ (*p->c_func)(p->c_arg);
+
+ free((char *) p);
+ }
+}
+
+
+/*
+ * timeleft - return the length of time until the next timeout is due.
+ */
+struct timeval *
+timeleft(tvp)
+ struct timeval *tvp;
+{
+ if (callout == NULL)
+ return NULL;
+
+ gettimeofday(&timenow, NULL);
+ tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
+ tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
+ if (tvp->tv_usec < 0) {
+ tvp->tv_usec += 1000000;
+ tvp->tv_sec -= 1;
+ }
+ if (tvp->tv_sec < 0)
+ tvp->tv_sec = tvp->tv_usec = 0;
+
+ return tvp;
+}
+
+
+/*
+ * hup - Catch SIGHUP signal.
+ *
+ * Indicates that the physical layer has been disconnected.
+ * We don't rely on this indication; if the user has sent this
+ * signal, we just take the link down.
+ */
+static void
+hup(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Hangup (SIGHUP)");
+ kill_link = 1;
+}
+
+
+/*
+ * term - Catch SIGTERM signal and SIGINT signal (^C/del).
+ *
+ * Indicates that we should initiate a graceful disconnect and exit.
+ */
+/*ARGSUSED*/
+static void
+term(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Terminating on signal %d.", sig);
+ persist = 0; /* don't try to restart */
+ kill_link = 1;
+}
+
+
+/*
+ * chld - Catch SIGCHLD signal.
+ * Calls reap_kids to get status for any dead kids.
+ */
+static void
+chld(sig)
+ int sig;
+{
+ reap_kids();
+}
+
+
+/*
+ * toggle_debug - Catch SIGUSR1 signal.
+ *
+ * Toggle debug flag.
+ */
+/*ARGSUSED*/
+static void
+toggle_debug(sig)
+ int sig;
+{
+ debug = !debug;
+ note_debug_level();
+}
+
+
+/*
+ * open_ccp - Catch SIGUSR2 signal.
+ *
+ * Try to (re)negotiate compression.
+ */
+/*ARGSUSED*/
+static void
+open_ccp(sig)
+ int sig;
+{
+ open_ccp_flag = 1;
+}
+
+
+/*
+ * device_script - run a program to connect or disconnect the
+ * serial device.
+ */
+int
+device_script(program, in, out)
+ char *program;
+ int in, out;
+{
+ int pid;
+ int status;
+ int errfd;
+
+ pid = fork();
+
+ if (pid < 0) {
+ syslog(LOG_ERR, "Failed to create child process: %m");
+ die(1);
+ }
+
+ if (pid == 0) {
+ dup2(in, 0);
+ dup2(out, 1);
+ errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ if (errfd >= 0)
+ dup2(errfd, 2);
+ setuid(getuid());
+ setgid(getgid());
+ execl("/bin/sh", "sh", "-c", program, (char *)0);
+ syslog(LOG_ERR, "could not exec /bin/sh: %m");
+ _exit(99);
+ /* NOTREACHED */
+ }
+
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "error waiting for (dis)connection process: %m");
+ die(1);
+ }
+
+ return (status == 0 ? 0 : -1);
+}
+
+
+/*
+ * run-program - execute a program with given arguments,
+ * but don't wait for it.
+ * If the program can't be executed, logs an error unless
+ * must_exist is 0 and the program file doesn't exist.
+ */
+int
+run_program(prog, args, must_exist)
+ char *prog;
+ char **args;
+ int must_exist;
+{
+ int pid;
+ char *nullenv[1];
+
+ pid = fork();
+ if (pid == -1) {
+ syslog(LOG_ERR, "Failed to create child process for %s: %m", prog);
+ return -1;
+ }
+ if (pid == 0) {
+ int new_fd;
+
+ /* Leave the current location */
+ (void) setsid(); /* No controlling tty. */
+ (void) umask (S_IRWXG|S_IRWXO);
+ (void) chdir ("/"); /* no current directory. */
+ setuid(geteuid());
+ setgid(getegid());
+
+ /* Ensure that nothing of our device environment is inherited. */
+ close (0);
+ close (1);
+ close (2);
+ close (fd); /* tty interface to the ppp device */
+ /* XXX should call sysdep cleanup procedure here */
+
+ /* Don't pass handles to the PPP device, even by accident. */
+ new_fd = open (_PATH_DEVNULL, O_RDWR);
+ if (new_fd >= 0) {
+ if (new_fd != 0) {
+ dup2 (new_fd, 0); /* stdin <- /dev/null */
+ close (new_fd);
+ }
+ dup2 (0, 1); /* stdout -> /dev/null */
+ dup2 (0, 2); /* stderr -> /dev/null */
+ }
+
+#ifdef BSD
+ /* Force the priority back to zero if pppd is running higher. */
+ if (setpriority (PRIO_PROCESS, 0, 0) < 0)
+ syslog (LOG_WARNING, "can't reset priority to 0: %m");
+#endif
+
+ /* SysV recommends a second fork at this point. */
+
+ /* run the program; give it a null environment */
+ nullenv[0] = NULL;
+ execve(prog, args, nullenv);
+ if (must_exist || errno != ENOENT)
+ syslog(LOG_WARNING, "Can't execute %s: %m", prog);
+ _exit(-1);
+ }
+ MAINDEBUG((LOG_DEBUG, "Script %s started; pid = %d", prog, pid));
+ ++n_children;
+ return 0;
+}
+
+
+/*
+ * reap_kids - get status from any dead child processes,
+ * and log a message for abnormal terminations.
+ */
+void
+reap_kids()
+{
+ int pid, status;
+
+ if (n_children == 0)
+ return;
+ if ((pid = waitpid(-1, &status, WNOHANG)) == -1) {
+ if (errno != ECHILD)
+ syslog(LOG_ERR, "Error waiting for child process: %m");
+ return;
+ }
+ if (pid > 0) {
+ --n_children;
+ if (WIFSIGNALED(status)) {
+ syslog(LOG_WARNING, "Child process %d terminated with signal %d",
+ pid, WTERMSIG(status));
+ }
+ }
+}
+
+
+/*
+ * log_packet - format a packet and log it.
+ */
+
+char line[256]; /* line to be logged accumulated here */
+char *linep;
+
+void
+log_packet(p, len, prefix)
+ u_char *p;
+ int len;
+ char *prefix;
+{
+ strcpy(line, prefix);
+ linep = line + strlen(line);
+ format_packet(p, len, pr_log, NULL);
+ if (linep != line)
+ syslog(LOG_DEBUG, "%s", line);
+}
+
+/*
+ * format_packet - make a readable representation of a packet,
+ * calling `printer(arg, format, ...)' to output it.
+ */
+void
+format_packet(p, len, printer, arg)
+ u_char *p;
+ int len;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int i, n;
+ u_short proto;
+ u_char x;
+
+ if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+ p += 2;
+ GETSHORT(proto, p);
+ len -= PPP_HDRLEN;
+ for (i = 0; i < N_PROTO; ++i)
+ if (proto == prottbl[i].protocol)
+ break;
+ if (i < N_PROTO) {
+ printer(arg, "[%s", prottbl[i].name);
+ n = (*prottbl[i].printpkt)(p, len, printer, arg);
+ printer(arg, "]");
+ p += n;
+ len -= n;
+ } else {
+ printer(arg, "[proto=0x%x]", proto);
+ }
+ }
+
+ for (; len > 0; --len) {
+ GETCHAR(x, p);
+ printer(arg, " %.2x", x);
+ }
+}
+
+#ifdef __STDC__
+#include <stdarg.h>
+
+void
+pr_log(void *arg, char *fmt, ...)
+{
+ int n;
+ va_list pvar;
+ char buf[256];
+
+ va_start(pvar, fmt);
+ vsprintf(buf, fmt, pvar);
+ va_end(pvar);
+
+ n = strlen(buf);
+ if (linep + n + 1 > line + sizeof(line)) {
+ syslog(LOG_DEBUG, "%s", line);
+ linep = line;
+ }
+ strcpy(linep, buf);
+ linep += n;
+}
+
+#else /* __STDC__ */
+#include <varargs.h>
+
+void
+pr_log(arg, fmt, va_alist)
+void *arg;
+char *fmt;
+va_dcl
+{
+ int n;
+ va_list pvar;
+ char buf[256];
+
+ va_start(pvar);
+ vsprintf(buf, fmt, pvar);
+ va_end(pvar);
+
+ n = strlen(buf);
+ if (linep + n + 1 > line + sizeof(line)) {
+ syslog(LOG_DEBUG, "%s", line);
+ linep = line;
+ }
+ strcpy(linep, buf);
+ linep += n;
+}
+#endif
+
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+void
+print_string(p, len, printer, arg)
+ char *p;
+ int len;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int c;
+
+ printer(arg, "\"");
+ for (; len > 0; --len) {
+ c = *p++;
+ if (' ' <= c && c <= '~')
+ printer(arg, "%c", c);
+ else
+ printer(arg, "\\%.3o", c);
+ }
+ printer(arg, "\"");
+}
+
+/*
+ * novm - log an error message saying we ran out of memory, and die.
+ */
+void
+novm(msg)
+ char *msg;
+{
+ syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg);
+ die(1);
+}
diff --git a/usr.sbin/pppd/md5.c b/usr.sbin/pppd/md5.c
new file mode 100644
index 00000000000..480c860c0aa
--- /dev/null
+++ b/usr.sbin/pppd/md5.c
@@ -0,0 +1,304 @@
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5Final (mdContext)
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/usr.sbin/pppd/md5.h b/usr.sbin/pppd/md5.h
new file mode 100644
index 00000000000..7492b2228e2
--- /dev/null
+++ b/usr.sbin/pppd/md5.h
@@ -0,0 +1,58 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+typedef unsigned int UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init ();
+void MD5Update ();
+void MD5Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/usr.sbin/pppd/options.c b/usr.sbin/pppd/options.c
new file mode 100644
index 00000000000..86389dd5f9a
--- /dev/null
+++ b/usr.sbin/pppd/options.c
@@ -0,0 +1,1740 @@
+/*
+ * options.c - handles option processing for PPP.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: options.c,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <syslog.h>
+#include <string.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+
+#include <net/ppp-comp.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#if defined(ultrix) || defined(NeXT)
+char *strdup __P((char *));
+#endif
+
+#ifndef GIDSET_TYPE
+#define GIDSET_TYPE gid_t
+#endif
+
+/*
+ * Option variables and default values.
+ */
+int debug = 0; /* Debug flag */
+int kdebugflag = 0; /* Tell kernel to print debug messages */
+int default_device = 1; /* Using /dev/tty or equivalent */
+char devnam[MAXPATHLEN] = "/dev/tty"; /* Device name */
+int crtscts = 0; /* Use hardware flow control */
+int modem = 1; /* Use modem control lines */
+int inspeed = 0; /* Input/Output speed requested */
+u_int32_t netmask = 0; /* IP netmask to set on interface */
+int lockflag = 0; /* Create lock file to lock the serial dev */
+int nodetach = 0; /* Don't detach from controlling tty */
+char *connector = NULL; /* Script to establish physical link */
+char *disconnector = NULL; /* Script to disestablish physical link */
+char user[MAXNAMELEN]; /* Username for PAP */
+char passwd[MAXSECRETLEN]; /* Password for PAP */
+int auth_required = 0; /* Peer is required to authenticate */
+int defaultroute = 0; /* assign default route through interface */
+int proxyarp = 0; /* Set up proxy ARP entry for peer */
+int persist = 0; /* Reopen link after it goes down */
+int uselogin = 0; /* Use /etc/passwd for checking PAP */
+int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
+int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
+char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
+char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+int usehostname = 0; /* Use hostname for our_name */
+int disable_defaultip = 0; /* Don't use hostname for default IP adrs */
+char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
+int cryptpap; /* Passwords in pap-secrets are encrypted */
+
+#ifdef _linux_
+int idle_time_limit = 0;
+static int setidle __P((char **));
+#endif
+
+/*
+ * Prototypes
+ */
+static int setdebug __P((void));
+static int setkdebug __P((char **));
+static int setpassive __P((void));
+static int setsilent __P((void));
+static int noopt __P((void));
+static int setnovj __P((void));
+static int setnovjccomp __P((void));
+static int setvjslots __P((char **));
+static int reqpap __P((void));
+static int nopap __P((void));
+static int setupapfile __P((char **));
+static int nochap __P((void));
+static int reqchap __P((void));
+static int setspeed __P((char *));
+static int noaccomp __P((void));
+static int noasyncmap __P((void));
+static int noipaddr __P((void));
+static int nomagicnumber __P((void));
+static int setasyncmap __P((char **));
+static int setescape __P((char **));
+static int setmru __P((char **));
+static int setmtu __P((char **));
+static int nomru __P((void));
+static int nopcomp __P((void));
+static int setconnector __P((char **));
+static int setdisconnector __P((char **));
+static int setdomain __P((char **));
+static int setnetmask __P((char **));
+static int setcrtscts __P((void));
+static int setnocrtscts __P((void));
+static int setxonxoff __P((void));
+static int setnodetach __P((void));
+static int setmodem __P((void));
+static int setlocal __P((void));
+static int setlock __P((void));
+static int setname __P((char **));
+static int setuser __P((char **));
+static int setremote __P((char **));
+static int setauth __P((void));
+static int readfile __P((char **));
+static int setdefaultroute __P((void));
+static int setnodefaultroute __P((void));
+static int setproxyarp __P((void));
+static int setnoproxyarp __P((void));
+static int setpersist __P((void));
+static int setdologin __P((void));
+static int setusehostname __P((void));
+static int setnoipdflt __P((void));
+static int setlcptimeout __P((char **));
+static int setlcpterm __P((char **));
+static int setlcpconf __P((char **));
+static int setlcpfails __P((char **));
+static int setipcptimeout __P((char **));
+static int setipcpterm __P((char **));
+static int setipcpconf __P((char **));
+static int setipcpfails __P((char **));
+static int setpaptimeout __P((char **));
+static int setpapreqs __P((char **));
+static int setpapreqtime __P((char **));
+static int setchaptimeout __P((char **));
+static int setchapchal __P((char **));
+static int setchapintv __P((char **));
+static int setipcpaccl __P((void));
+static int setipcpaccr __P((void));
+static int setlcpechointv __P((char **));
+static int setlcpechofails __P((char **));
+static int setbsdcomp __P((char **));
+static int setnobsdcomp __P((void));
+static int setipparam __P((char **));
+static int setpapcrypt __P((void));
+
+static int number_option __P((char *, u_int32_t *, int));
+static int readable __P((int fd));
+
+void usage();
+
+/*
+ * Valid arguments.
+ */
+static struct cmd {
+ char *cmd_name;
+ int num_args;
+ int (*cmd_func)();
+} cmds[] = {
+ {"-all", 0, noopt}, /* Don't request/allow any options */
+ {"-ac", 0, noaccomp}, /* Disable Address/Control compress */
+ {"-am", 0, noasyncmap}, /* Disable asyncmap negotiation */
+ {"-as", 1, setasyncmap}, /* set the desired async map */
+ {"-d", 0, setdebug}, /* Increase debugging level */
+ {"-detach", 0, setnodetach}, /* don't fork */
+ {"-ip", 0, noipaddr}, /* Disable IP address negotiation */
+ {"-mn", 0, nomagicnumber}, /* Disable magic number negotiation */
+ {"-mru", 0, nomru}, /* Disable mru negotiation */
+ {"-p", 0, setpassive}, /* Set passive mode */
+ {"-pc", 0, nopcomp}, /* Disable protocol field compress */
+ {"+ua", 1, setupapfile}, /* Get PAP user and password from file */
+ {"+pap", 0, reqpap}, /* Require PAP auth from peer */
+ {"-pap", 0, nopap}, /* Don't allow UPAP authentication with peer */
+ {"+chap", 0, reqchap}, /* Require CHAP authentication from peer */
+ {"-chap", 0, nochap}, /* Don't allow CHAP authentication with peer */
+ {"-vj", 0, setnovj}, /* disable VJ compression */
+ {"-vjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
+ {"vj-max-slots", 1, setvjslots}, /* Set maximum VJ header slots */
+ {"asyncmap", 1, setasyncmap}, /* set the desired async map */
+ {"escape", 1, setescape}, /* set chars to escape on transmission */
+ {"connect", 1, setconnector}, /* A program to set up a connection */
+ {"disconnect", 1, setdisconnector}, /* program to disconnect serial dev. */
+ {"crtscts", 0, setcrtscts}, /* set h/w flow control */
+ {"-crtscts", 0, setnocrtscts}, /* clear h/w flow control */
+ {"xonxoff", 0, setxonxoff}, /* set s/w flow control */
+ {"debug", 0, setdebug}, /* Increase debugging level */
+ {"kdebug", 1, setkdebug}, /* Enable kernel-level debugging */
+ {"domain", 1, setdomain}, /* Add given domain name to hostname*/
+ {"mru", 1, setmru}, /* Set MRU value for negotiation */
+ {"mtu", 1, setmtu}, /* Set our MTU */
+ {"netmask", 1, setnetmask}, /* set netmask */
+ {"passive", 0, setpassive}, /* Set passive mode */
+ {"silent", 0, setsilent}, /* Set silent mode */
+ {"modem", 0, setmodem}, /* Use modem control lines */
+ {"local", 0, setlocal}, /* Don't use modem control lines */
+ {"lock", 0, setlock}, /* Lock serial device (with lock file) */
+ {"name", 1, setname}, /* Set local name for authentication */
+ {"user", 1, setuser}, /* Set username for PAP auth with peer */
+ {"usehostname", 0, setusehostname}, /* Must use hostname for auth. */
+ {"remotename", 1, setremote}, /* Set remote name for authentication */
+ {"auth", 0, setauth}, /* Require authentication from peer */
+ {"file", 1, readfile}, /* Take options from a file */
+ {"defaultroute", 0, setdefaultroute}, /* Add default route */
+ {"-defaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
+ {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
+ {"-proxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
+ {"persist", 0, setpersist}, /* Keep on reopening connection after close */
+ {"login", 0, setdologin}, /* Use system password database for UPAP */
+ {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
+ {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
+ {"lcp-echo-interval", 1, setlcpechointv}, /* time for lcp echo events */
+ {"lcp-restart", 1, setlcptimeout}, /* Set timeout for LCP */
+ {"lcp-max-terminate", 1, setlcpterm}, /* Set max #xmits for term-reqs */
+ {"lcp-max-configure", 1, setlcpconf}, /* Set max #xmits for conf-reqs */
+ {"lcp-max-failure", 1, setlcpfails}, /* Set max #conf-naks for LCP */
+ {"ipcp-restart", 1, setipcptimeout}, /* Set timeout for IPCP */
+ {"ipcp-max-terminate", 1, setipcpterm}, /* Set max #xmits for term-reqs */
+ {"ipcp-max-configure", 1, setipcpconf}, /* Set max #xmits for conf-reqs */
+ {"ipcp-max-failure", 1, setipcpfails}, /* Set max #conf-naks for IPCP */
+ {"pap-restart", 1, setpaptimeout}, /* Set retransmit timeout for PAP */
+ {"pap-max-authreq", 1, setpapreqs}, /* Set max #xmits for auth-reqs */
+ {"pap-timeout", 1, setpapreqtime}, /* Set time limit for peer PAP auth. */
+ {"chap-restart", 1, setchaptimeout}, /* Set timeout for CHAP */
+ {"chap-max-challenge", 1, setchapchal}, /* Set max #xmits for challenge */
+ {"chap-interval", 1, setchapintv}, /* Set interval for rechallenge */
+ {"ipcp-accept-local", 0, setipcpaccl}, /* Accept peer's address for us */
+ {"ipcp-accept-remote", 0, setipcpaccr}, /* Accept peer's address for it */
+ {"bsdcomp", 1, setbsdcomp}, /* request BSD-Compress */
+ {"-bsdcomp", 0, setnobsdcomp}, /* don't allow BSD-Compress */
+ {"ipparam", 1, setipparam}, /* set ip script parameter */
+ {"papcrypt", 0, setpapcrypt}, /* PAP passwords encrypted */
+#ifdef _linux_
+ {"idle-disconnect", 1, setidle}, /* seconds for disconnect of idle IP */
+#endif
+ {NULL, 0, NULL}
+};
+
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION ""
+#endif
+
+static char *usage_string = "\
+pppd version %s patch level %d%s\n\
+Usage: %s [ arguments ], where arguments are:\n\
+ <device> Communicate over the named device\n\
+ <speed> Set the baud rate to <speed>\n\
+ <loc>:<rem> Set the local and/or remote interface IP\n\
+ addresses. Either one may be omitted.\n\
+ asyncmap <n> Set the desired async map to hex <n>\n\
+ auth Require authentication from peer\n\
+ connect <p> Invoke shell command <p> to set up the serial line\n\
+ crtscts Use hardware RTS/CTS flow control\n\
+ defaultroute Add default route through interface\n\
+ file <f> Take options from file <f>\n\
+ modem Use modem control lines\n\
+ mru <n> Set MRU value to <n> for negotiation\n\
+ netmask <n> Set interface netmask to <n>\n\
+See pppd(8) for more options.\n\
+";
+
+
+/*
+ * parse_args - parse a string of arguments, from the command
+ * line or from a file.
+ */
+int
+parse_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg, *val;
+ struct cmd *cmdp;
+ int ret;
+
+ while (argc > 0) {
+ arg = *argv++;
+ --argc;
+
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(arg, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ if (argc < cmdp->num_args) {
+ fprintf(stderr, "Too few parameters for command %s\n", arg);
+ return 0;
+ }
+ if (!(*cmdp->cmd_func)(argv))
+ return 0;
+ argc -= cmdp->num_args;
+ argv += cmdp->num_args;
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if ((ret = setdevname(arg)) == 0
+ && (ret = setspeed(arg)) == 0
+ && (ret = setipaddr(arg)) == 0) {
+ fprintf(stderr, "%s: unrecognized command\n", arg);
+ usage();
+ return 0;
+ }
+ if (ret < 0) /* error */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * usage - print out a message telling how to use the program.
+ */
+void
+usage()
+{
+ fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
+ progname);
+}
+
+/*
+ * options_from_file - Read a string of options from a file,
+ * and interpret them.
+ */
+int
+options_from_file(filename, must_exist, check_prot)
+ char *filename;
+ int must_exist;
+ int check_prot;
+{
+ FILE *f;
+ int i, newline, ret;
+ struct cmd *cmdp;
+ char *argv[MAXARGS];
+ char args[MAXARGS][MAXWORDLEN];
+ char cmd[MAXWORDLEN];
+
+ if ((f = fopen(filename, "r")) == NULL) {
+ if (!must_exist && errno == ENOENT)
+ return 1;
+ perror(filename);
+ return 0;
+ }
+ if (check_prot && !readable(fileno(f))) {
+ fprintf(stderr, "%s: access denied\n", filename);
+ fclose(f);
+ return 0;
+ }
+
+ while (getword(f, cmd, &newline, filename)) {
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(cmd, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ for (i = 0; i < cmdp->num_args; ++i) {
+ if (!getword(f, args[i], &newline, filename)) {
+ fprintf(stderr,
+ "In file %s: too few parameters for command %s\n",
+ filename, cmd);
+ fclose(f);
+ return 0;
+ }
+ argv[i] = args[i];
+ }
+ if (!(*cmdp->cmd_func)(argv)) {
+ fclose(f);
+ return 0;
+ }
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if ((ret = setdevname(cmd)) == 0
+ && (ret = setspeed(cmd)) == 0
+ && (ret = setipaddr(cmd)) == 0) {
+ fprintf(stderr, "In file %s: unrecognized command %s\n",
+ filename, cmd);
+ fclose(f);
+ return 0;
+ }
+ if (ret < 0) /* error */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * options_from_user - See if the use has a ~/.ppprc file,
+ * and if so, interpret options from it.
+ */
+int
+options_from_user()
+{
+ char *user, *path, *file;
+ int ret;
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
+ return 1;
+ file = _PATH_USEROPT;
+ path = malloc(strlen(user) + strlen(file) + 2);
+ if (path == NULL)
+ novm("init file name");
+ strcpy(path, user);
+ strcat(path, "/");
+ strcat(path, file);
+ ret = options_from_file(path, 0, 1);
+ free(path);
+ return ret;
+}
+
+/*
+ * options_for_tty - See if an options file exists for the serial
+ * device, and if so, interpret options from it.
+ */
+int
+options_for_tty()
+{
+ char *dev, *path;
+ int ret;
+
+ dev = strrchr(devnam, '/');
+ if (dev == NULL)
+ dev = devnam;
+ else
+ ++dev;
+ if (strcmp(dev, "tty") == 0)
+ return 1; /* don't look for /etc/ppp/options.tty */
+ path = malloc(strlen(_PATH_TTYOPT) + strlen(dev) + 1);
+ if (path == NULL)
+ novm("tty init file name");
+ strcpy(path, _PATH_TTYOPT);
+ strcat(path, dev);
+ ret = options_from_file(path, 0, 0);
+ free(path);
+ return ret;
+}
+
+/*
+ * readable - check if a file is readable by the real user.
+ */
+static int
+readable(fd)
+ int fd;
+{
+ uid_t uid;
+ int ngroups, i;
+ struct stat sbuf;
+ GIDSET_TYPE groups[NGROUPS_MAX];
+
+ uid = getuid();
+ if (uid == 0)
+ return 1;
+ if (fstat(fd, &sbuf) != 0)
+ return 0;
+ if (sbuf.st_uid == uid)
+ return sbuf.st_mode & S_IRUSR;
+ if (sbuf.st_gid == getgid())
+ return sbuf.st_mode & S_IRGRP;
+ ngroups = getgroups(NGROUPS_MAX, groups);
+ for (i = 0; i < ngroups; ++i)
+ if (sbuf.st_gid == groups[i])
+ return sbuf.st_mode & S_IRGRP;
+ return sbuf.st_mode & S_IROTH;
+}
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (" or ').
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> is ignored.
+ */
+
+int
+getword(f, word, newlinep, filename)
+ FILE *f;
+ char *word;
+ int *newlinep;
+ char *filename;
+{
+ int c, len, escape;
+ int quoted, comment;
+ int value, digit, got, n;
+
+#define isoctal(c) ((c) >= '0' && (c) < '8')
+
+ *newlinep = 0;
+ len = 0;
+ escape = 0;
+ comment = 0;
+
+ /*
+ * First skip white-space and comments.
+ */
+ for (;;) {
+ c = getc(f);
+ if (c == EOF)
+ break;
+
+ /*
+ * A newline means the end of a comment; backslash-newline
+ * is ignored. Note that we cannot have escape && comment.
+ */
+ if (c == '\n') {
+ if (!escape) {
+ *newlinep = 1;
+ comment = 0;
+ } else
+ escape = 0;
+ continue;
+ }
+
+ /*
+ * Ignore characters other than newline in a comment.
+ */
+ if (comment)
+ continue;
+
+ /*
+ * If this character is escaped, we have a word start.
+ */
+ if (escape)
+ break;
+
+ /*
+ * If this is the escape character, look at the next character.
+ */
+ if (c == '\\') {
+ escape = 1;
+ continue;
+ }
+
+ /*
+ * If this is the start of a comment, ignore the rest of the line.
+ */
+ if (c == '#') {
+ comment = 1;
+ continue;
+ }
+
+ /*
+ * A non-whitespace character is the start of a word.
+ */
+ if (!isspace(c))
+ break;
+ }
+
+ /*
+ * Save the delimiter for quoted strings.
+ */
+ if (!escape && (c == '"' || c == '\'')) {
+ quoted = c;
+ c = getc(f);
+ } else
+ quoted = 0;
+
+ /*
+ * Process characters until the end of the word.
+ */
+ while (c != EOF) {
+ if (escape) {
+ /*
+ * This character is escaped: backslash-newline is ignored,
+ * various other characters indicate particular values
+ * as for C backslash-escapes.
+ */
+ escape = 0;
+ if (c == '\n') {
+ c = getc(f);
+ continue;
+ }
+
+ got = 0;
+ switch (c) {
+ case 'a':
+ value = '\a';
+ break;
+ case 'b':
+ value = '\b';
+ break;
+ case 'f':
+ value = '\f';
+ break;
+ case 'n':
+ value = '\n';
+ break;
+ case 'r':
+ value = '\r';
+ break;
+ case 's':
+ value = ' ';
+ break;
+ case 't':
+ value = '\t';
+ break;
+
+ default:
+ if (isoctal(c)) {
+ /*
+ * \ddd octal sequence
+ */
+ value = 0;
+ for (n = 0; n < 3 && isoctal(c); ++n) {
+ value = (value << 3) + (c & 07);
+ c = getc(f);
+ }
+ got = 1;
+ break;
+ }
+
+ if (c == 'x') {
+ /*
+ * \x<hex_string> sequence
+ */
+ value = 0;
+ c = getc(f);
+ for (n = 0; n < 2 && isxdigit(c); ++n) {
+ digit = toupper(c) - '0';
+ if (digit > 10)
+ digit += '0' + 10 - 'A';
+ value = (value << 4) + digit;
+ c = getc (f);
+ }
+ got = 1;
+ break;
+ }
+
+ /*
+ * Otherwise the character stands for itself.
+ */
+ value = c;
+ break;
+ }
+
+ /*
+ * Store the resulting character for the escape sequence.
+ */
+ if (len < MAXWORDLEN-1)
+ word[len] = value;
+ ++len;
+
+ if (!got)
+ c = getc(f);
+ continue;
+
+ }
+
+ /*
+ * Not escaped: see if we've reached the end of the word.
+ */
+ if (quoted) {
+ if (c == quoted)
+ break;
+ } else {
+ if (isspace(c) || c == '#') {
+ ungetc (c, f);
+ break;
+ }
+ }
+
+ /*
+ * Backslash starts an escape sequence.
+ */
+ if (c == '\\') {
+ escape = 1;
+ c = getc(f);
+ continue;
+ }
+
+ /*
+ * An ordinary character: store it in the word and get another.
+ */
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+
+ c = getc(f);
+ }
+
+ /*
+ * End of the word: check for errors.
+ */
+ if (c == EOF) {
+ if (ferror(f)) {
+ if (errno == 0)
+ errno = EIO;
+ perror(filename);
+ die(1);
+ }
+ /*
+ * If len is zero, then we didn't find a word before the
+ * end of the file.
+ */
+ if (len == 0)
+ return 0;
+ }
+
+ /*
+ * Warn if the word was too long, and append a terminating null.
+ */
+ if (len >= MAXWORDLEN) {
+ fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
+ progname, filename, word);
+ len = MAXWORDLEN - 1;
+ }
+ word[len] = 0;
+
+ return 1;
+
+#undef isoctal
+
+}
+
+/*
+ * number_option - parse an unsigned numeric parameter for an option.
+ */
+static int
+number_option(str, valp, base)
+ char *str;
+ u_int32_t *valp;
+ int base;
+{
+ char *ptr;
+
+ *valp = strtoul(str, &ptr, base);
+ if (ptr == str) {
+ fprintf(stderr, "%s: invalid number: %s\n", progname, str);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * int_option - like number_option, but valp is int *,
+ * the base is assumed to be 0, and *valp is not changed
+ * if there is an error.
+ */
+static int
+int_option(str, valp)
+ char *str;
+ int *valp;
+{
+ u_int32_t v;
+
+ if (!number_option(str, &v, 0))
+ return 0;
+ *valp = (int) v;
+ return 1;
+}
+
+
+/*
+ * The following procedures execute commands.
+ */
+
+/*
+ * readfile - take commands from a file.
+ */
+static int
+readfile(argv)
+ char **argv;
+{
+ return options_from_file(*argv, 1, 1);
+}
+
+/*
+ * setdebug - Set debug (command line argument).
+ */
+static int
+setdebug()
+{
+ debug++;
+ return (1);
+}
+
+/*
+ * setkdebug - Set kernel debugging level.
+ */
+static int
+setkdebug(argv)
+ char **argv;
+{
+ return int_option(*argv, &kdebugflag);
+}
+
+/*
+ * noopt - Disable all options.
+ */
+static int
+noopt()
+{
+ BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
+ BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
+ return (1);
+}
+
+/*
+ * noaccomp - Disable Address/Control field compression negotiation.
+ */
+static int
+noaccomp()
+{
+ lcp_wantoptions[0].neg_accompression = 0;
+ lcp_allowoptions[0].neg_accompression = 0;
+ return (1);
+}
+
+
+/*
+ * noasyncmap - Disable async map negotiation.
+ */
+static int
+noasyncmap()
+{
+ lcp_wantoptions[0].neg_asyncmap = 0;
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ return (1);
+}
+
+
+/*
+ * noipaddr - Disable IP address negotiation.
+ */
+static int
+noipaddr()
+{
+ ipcp_wantoptions[0].neg_addr = 0;
+ ipcp_allowoptions[0].neg_addr = 0;
+ return (1);
+}
+
+
+/*
+ * nomagicnumber - Disable magic number negotiation.
+ */
+static int
+nomagicnumber()
+{
+ lcp_wantoptions[0].neg_magicnumber = 0;
+ lcp_allowoptions[0].neg_magicnumber = 0;
+ return (1);
+}
+
+
+/*
+ * nomru - Disable mru negotiation.
+ */
+static int
+nomru()
+{
+ lcp_wantoptions[0].neg_mru = 0;
+ lcp_allowoptions[0].neg_mru = 0;
+ return (1);
+}
+
+
+/*
+ * setmru - Set MRU for negotiation.
+ */
+static int
+setmru(argv)
+ char **argv;
+{
+ u_int32_t mru;
+
+ if (!number_option(*argv, &mru, 0))
+ return 0;
+ lcp_wantoptions[0].mru = mru;
+ lcp_wantoptions[0].neg_mru = 1;
+ return (1);
+}
+
+
+/*
+ * setmru - Set the largest MTU we'll use.
+ */
+static int
+setmtu(argv)
+ char **argv;
+{
+ u_int32_t mtu;
+
+ if (!number_option(*argv, &mtu, 0))
+ return 0;
+ if (mtu < MINMRU || mtu > MAXMRU) {
+ fprintf(stderr, "mtu option value of %ld is too %s\n", mtu,
+ (mtu < MINMRU? "small": "large"));
+ return 0;
+ }
+ lcp_allowoptions[0].mru = mtu;
+ return (1);
+}
+
+
+/*
+ * nopcomp - Disable Protocol field compression negotiation.
+ */
+static int
+nopcomp()
+{
+ lcp_wantoptions[0].neg_pcompression = 0;
+ lcp_allowoptions[0].neg_pcompression = 0;
+ return (1);
+}
+
+
+/*
+ * setpassive - Set passive mode (don't give up if we time out sending
+ * LCP configure-requests).
+ */
+static int
+setpassive()
+{
+ lcp_wantoptions[0].passive = 1;
+ return (1);
+}
+
+
+/*
+ * setsilent - Set silent mode (don't start sending LCP configure-requests
+ * until we get one from the peer).
+ */
+static int
+setsilent()
+{
+ lcp_wantoptions[0].silent = 1;
+ return 1;
+}
+
+
+/*
+ * nopap - Disable PAP authentication with peer.
+ */
+static int
+nopap()
+{
+ lcp_allowoptions[0].neg_upap = 0;
+ return (1);
+}
+
+
+/*
+ * reqpap - Require PAP authentication from peer.
+ */
+static int
+reqpap()
+{
+ lcp_wantoptions[0].neg_upap = 1;
+ auth_required = 1;
+ return 1;
+}
+
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+ char **argv;
+{
+ FILE * ufile;
+ int l;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ if ((ufile = fopen(*argv, "r")) == NULL) {
+ fprintf(stderr, "unable to open user login data file %s\n", *argv);
+ return 0;
+ }
+ if (!readable(fileno(ufile))) {
+ fprintf(stderr, "%s: access denied\n", *argv);
+ return 0;
+ }
+ check_access(ufile, *argv);
+
+ /* get username */
+ if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
+ || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
+ fprintf(stderr, "Unable to read user login data file %s.\n", *argv);
+ return 0;
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(user);
+ if (l > 0 && user[l-1] == '\n')
+ user[l-1] = 0;
+ l = strlen(passwd);
+ if (l > 0 && passwd[l-1] == '\n')
+ passwd[l-1] = 0;
+
+ return (1);
+}
+
+
+/*
+ * nochap - Disable CHAP authentication with peer.
+ */
+static int
+nochap()
+{
+ lcp_allowoptions[0].neg_chap = 0;
+ return (1);
+}
+
+
+/*
+ * reqchap - Require CHAP authentication from peer.
+ */
+static int
+reqchap()
+{
+ lcp_wantoptions[0].neg_chap = 1;
+ auth_required = 1;
+ return (1);
+}
+
+
+/*
+ * setnovj - disable vj compression
+ */
+static int
+setnovj()
+{
+ ipcp_wantoptions[0].neg_vj = 0;
+ ipcp_allowoptions[0].neg_vj = 0;
+ return (1);
+}
+
+
+/*
+ * setnovjccomp - disable VJ connection-ID compression
+ */
+static int
+setnovjccomp()
+{
+ ipcp_wantoptions[0].cflag = 0;
+ ipcp_allowoptions[0].cflag = 0;
+ return 1;
+}
+
+
+/*
+ * setvjslots - set maximum number of connection slots for VJ compression
+ */
+static int
+setvjslots(argv)
+ char **argv;
+{
+ int value;
+
+ if (!int_option(*argv, &value))
+ return 0;
+ if (value < 2 || value > 16) {
+ fprintf(stderr, "pppd: vj-max-slots value must be between 2 and 16\n");
+ return 0;
+ }
+ ipcp_wantoptions [0].maxslotindex =
+ ipcp_allowoptions[0].maxslotindex = value - 1;
+ return 1;
+}
+
+
+/*
+ * setconnector - Set a program to connect to a serial line
+ */
+static int
+setconnector(argv)
+ char **argv;
+{
+ connector = strdup(*argv);
+ if (connector == NULL)
+ novm("connector string");
+
+ return (1);
+}
+
+/*
+ * setdisconnector - Set a program to disconnect from the serial line
+ */
+static int
+setdisconnector(argv)
+ char **argv;
+{
+ disconnector = strdup(*argv);
+ if (disconnector == NULL)
+ novm("disconnector string");
+
+ return (1);
+}
+
+
+/*
+ * setdomain - Set domain name to append to hostname
+ */
+static int
+setdomain(argv)
+ char **argv;
+{
+ gethostname(hostname, MAXNAMELEN);
+ if (**argv != 0) {
+ if (**argv != '.')
+ strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
+ strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
+ }
+ hostname[MAXNAMELEN-1] = 0;
+ return (1);
+}
+
+
+/*
+ * setasyncmap - add bits to asyncmap (what we request peer to escape).
+ */
+static int
+setasyncmap(argv)
+ char **argv;
+{
+ u_int32_t asyncmap;
+
+ if (!number_option(*argv, &asyncmap, 16))
+ return 0;
+ lcp_wantoptions[0].asyncmap |= asyncmap;
+ lcp_wantoptions[0].neg_asyncmap = 1;
+ return(1);
+}
+
+
+/*
+ * setescape - add chars to the set we escape on transmission.
+ */
+static int
+setescape(argv)
+ char **argv;
+{
+ int n, ret;
+ char *p, *endp;
+
+ p = *argv;
+ ret = 1;
+ while (*p) {
+ n = strtol(p, &endp, 16);
+ if (p == endp) {
+ fprintf(stderr, "%s: invalid hex number: %s\n", progname, p);
+ return 0;
+ }
+ p = endp;
+ if (n < 0 || 0x20 <= n && n <= 0x3F || n == 0x5E || n > 0xFF) {
+ fprintf(stderr, "%s: can't escape character 0x%x\n", progname, n);
+ ret = 0;
+ } else
+ xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
+ while (*p == ',' || *p == ' ')
+ ++p;
+ }
+ return ret;
+}
+
+
+/*
+ * setspeed - Set the speed.
+ */
+static int
+setspeed(arg)
+ char *arg;
+{
+ char *ptr;
+ int spd;
+
+ spd = strtol(arg, &ptr, 0);
+ if (ptr == arg || *ptr != 0 || spd == 0)
+ return 0;
+ inspeed = spd;
+ return 1;
+}
+
+
+/*
+ * setdevname - Set the device name.
+ */
+int
+setdevname(cp)
+ char *cp;
+{
+ struct stat statbuf;
+ char *tty, *ttyname();
+ char dev[MAXPATHLEN];
+
+ if (strncmp("/dev/", cp, 5) != 0) {
+ strcpy(dev, "/dev/");
+ strncat(dev, cp, MAXPATHLEN - 5);
+ dev[MAXPATHLEN-1] = 0;
+ cp = dev;
+ }
+
+ /*
+ * Check if there is a device by this name.
+ */
+ if (stat(cp, &statbuf) < 0) {
+ if (errno == ENOENT)
+ return 0;
+ syslog(LOG_ERR, cp);
+ return -1;
+ }
+
+ (void) strncpy(devnam, cp, MAXPATHLEN);
+ devnam[MAXPATHLEN-1] = 0;
+ default_device = FALSE;
+
+ return 1;
+}
+
+
+/*
+ * setipaddr - Set the IP address
+ */
+int
+setipaddr(arg)
+ char *arg;
+{
+ struct hostent *hp;
+ char *colon;
+ u_int32_t local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = strchr(arg, ':')) == NULL)
+ return 0;
+
+ /*
+ * If colon first character, then no local addr.
+ */
+ if (colon != arg) {
+ *colon = '\0';
+ if ((local = inet_addr(arg)) == -1) {
+ if ((hp = gethostbyname(arg)) == NULL) {
+ fprintf(stderr, "unknown host: %s\n", arg);
+ return -1;
+ } else {
+ local = *(u_int32_t *)hp->h_addr;
+ if (our_name[0] == 0) {
+ strncpy(our_name, arg, MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (bad_ip_adrs(local)) {
+ fprintf(stderr, "bad local IP address %s\n", ip_ntoa(local));
+ return -1;
+ }
+ if (local != 0)
+ wo->ouraddr = local;
+ *colon = ':';
+ }
+
+ /*
+ * If colon last character, then no remote addr.
+ */
+ if (*++colon != '\0') {
+ if ((remote = inet_addr(colon)) == -1) {
+ if ((hp = gethostbyname(colon)) == NULL) {
+ fprintf(stderr, "unknown host: %s\n", colon);
+ return -1;
+ } else {
+ remote = *(u_int32_t *)hp->h_addr;
+ if (remote_name[0] == 0) {
+ strncpy(remote_name, colon, MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (bad_ip_adrs(remote)) {
+ fprintf(stderr, "bad remote IP address %s\n", ip_ntoa(remote));
+ return -1;
+ }
+ if (remote != 0)
+ wo->hisaddr = remote;
+ }
+
+ return 1;
+}
+
+
+/*
+ * setnoipdflt - disable setipdefault()
+ */
+static int
+setnoipdflt()
+{
+ disable_defaultip = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccl - accept peer's idea of our address
+ */
+static int
+setipcpaccl()
+{
+ ipcp_wantoptions[0].accept_local = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccr - accept peer's idea of its address
+ */
+static int
+setipcpaccr()
+{
+ ipcp_wantoptions[0].accept_remote = 1;
+ return 1;
+}
+
+
+/*
+ * setipdefault - default our local IP address based on our hostname.
+ */
+void
+setipdefault()
+{
+ struct hostent *hp;
+ u_int32_t local;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * If local IP address already given, don't bother.
+ */
+ if (wo->ouraddr != 0 || disable_defaultip)
+ return;
+
+ /*
+ * Look up our hostname (possibly with domain name appended)
+ * and take the first IP address as our local IP address.
+ * If there isn't an IP address for our hostname, too bad.
+ */
+ wo->accept_local = 1; /* don't insist on this default value */
+ if ((hp = gethostbyname(hostname)) == NULL)
+ return;
+ local = *(u_int32_t *)hp->h_addr;
+ if (local != 0 && !bad_ip_adrs(local))
+ wo->ouraddr = local;
+}
+
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(argv)
+ char **argv;
+{
+ u_int32_t mask;
+
+ if ((mask = inet_addr(*argv)) == -1 || (netmask & ~mask) != 0) {
+ fprintf(stderr, "Invalid netmask %s\n", *argv);
+ return 0;
+ }
+
+ netmask = mask;
+ return (1);
+}
+
+static int
+setcrtscts()
+{
+ crtscts = 1;
+ return (1);
+}
+
+static int
+setnocrtscts()
+{
+ crtscts = -1;
+ return (1);
+}
+
+static int
+setxonxoff()
+{
+ lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
+ lcp_wantoptions[0].neg_asyncmap = 1;
+
+ crtscts = 2;
+ return (1);
+}
+
+static int
+setnodetach()
+{
+ nodetach = 1;
+ return (1);
+}
+
+static int
+setmodem()
+{
+ modem = 1;
+ return 1;
+}
+
+static int
+setlocal()
+{
+ modem = 0;
+ return 1;
+}
+
+static int
+setlock()
+{
+ lockflag = 1;
+ return 1;
+}
+
+static int
+setusehostname()
+{
+ usehostname = 1;
+ return 1;
+}
+
+static int
+setname(argv)
+ char **argv;
+{
+ if (our_name[0] == 0) {
+ strncpy(our_name, argv[0], MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ return 1;
+}
+
+static int
+setuser(argv)
+ char **argv;
+{
+ strncpy(user, argv[0], MAXNAMELEN);
+ user[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setremote(argv)
+ char **argv;
+{
+ strncpy(remote_name, argv[0], MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setauth()
+{
+ auth_required = 1;
+ return 1;
+}
+
+static int
+setdefaultroute()
+{
+ if (!ipcp_allowoptions[0].default_route) {
+ fprintf(stderr, "%s: defaultroute option is disabled\n", progname);
+ return 0;
+ }
+ ipcp_wantoptions[0].default_route = 1;
+ return 1;
+}
+
+static int
+setnodefaultroute()
+{
+ ipcp_allowoptions[0].default_route = 0;
+ ipcp_wantoptions[0].default_route = 0;
+ return 1;
+}
+
+static int
+setproxyarp()
+{
+ if (!ipcp_allowoptions[0].proxy_arp) {
+ fprintf(stderr, "%s: proxyarp option is disabled\n", progname);
+ return 0;
+ }
+ ipcp_wantoptions[0].proxy_arp = 1;
+ return 1;
+}
+
+static int
+setnoproxyarp()
+{
+ ipcp_wantoptions[0].proxy_arp = 0;
+ ipcp_allowoptions[0].proxy_arp = 0;
+ return 1;
+}
+
+static int
+setpersist()
+{
+ persist = 1;
+ return 1;
+}
+
+static int
+setdologin()
+{
+ uselogin = 1;
+ return 1;
+}
+
+/*
+ * Functions to set the echo interval for modem-less monitors
+ */
+
+static int
+setlcpechointv(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_echo_interval);
+}
+
+static int
+setlcpechofails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_echo_fails);
+}
+
+/*
+ * Functions to set timeouts, max transmits, etc.
+ */
+static int
+setlcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].timeouttime);
+}
+
+static int
+setlcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxtermtransmits);
+}
+
+static int
+setlcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxconfreqtransmits);
+}
+
+static int
+setlcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops);
+}
+
+static int
+setipcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].timeouttime);
+}
+
+static int
+setipcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxtermtransmits);
+}
+
+static int
+setipcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxconfreqtransmits);
+}
+
+static int
+setipcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops);
+}
+
+static int
+setpaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_timeouttime);
+}
+
+static int
+setpapreqtime(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_reqtimeout);
+}
+
+static int
+setpapreqs(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_maxtransmits);
+}
+
+static int
+setchaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].timeouttime);
+}
+
+static int
+setchapchal(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].max_transmits);
+}
+
+static int
+setchapintv(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].chal_interval);
+}
+
+static int
+setbsdcomp(argv)
+ char **argv;
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ fprintf(stderr, "%s: invalid argument format for bsdcomp option\n",
+ progname);
+ return 0;
+ }
+ if (rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)
+ || abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS)) {
+ fprintf(stderr, "%s: bsdcomp option values must be 0 or %d .. %d\n",
+ progname, BSD_MIN_BITS, BSD_MAX_BITS);
+ return 0;
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = rbits;
+ } else
+ ccp_wantoptions[0].bsd_compress = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].bsd_compress = 1;
+ ccp_allowoptions[0].bsd_bits = abits;
+ } else
+ ccp_allowoptions[0].bsd_compress = 0;
+ return 1;
+}
+
+static int
+setnobsdcomp()
+{
+ ccp_wantoptions[0].bsd_compress = 0;
+ ccp_allowoptions[0].bsd_compress = 0;
+ return 1;
+}
+
+static int
+setipparam(argv)
+ char **argv;
+{
+ ipparam = strdup(*argv);
+ if (ipparam == NULL)
+ novm("ipparam string");
+
+ return 1;
+}
+
+static int
+setpapcrypt()
+{
+ cryptpap = 1;
+ return 1;
+}
+
+#ifdef _linux_
+static int setidle (argv)
+ char **argv;
+{
+ return int_option(*argv, &idle_time_limit);
+}
+#endif
diff --git a/usr.sbin/pppd/patchlevel.h b/usr.sbin/pppd/patchlevel.h
new file mode 100644
index 00000000000..8c33cd91a78
--- /dev/null
+++ b/usr.sbin/pppd/patchlevel.h
@@ -0,0 +1,6 @@
+/* $Id: patchlevel.h,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $ */
+#define PATCHLEVEL 0
+
+#define VERSION "2.2"
+#define IMPLEMENTATION ""
+#define DATE "17 August 95"
diff --git a/usr.sbin/pppd/pathnames.h b/usr.sbin/pppd/pathnames.h
new file mode 100644
index 00000000000..fb0a2ede371
--- /dev/null
+++ b/usr.sbin/pppd/pathnames.h
@@ -0,0 +1,22 @@
+/*
+ * define path names
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $
+ */
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+
+#else
+#define _PATH_VARRUN "/etc/ppp/"
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+#define _PATH_UPAPFILE "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS "/etc/ppp/options"
+#define _PATH_IPUP "/etc/ppp/ip-up"
+#define _PATH_IPDOWN "/etc/ppp/ip-down"
+#define _PATH_TTYOPT "/etc/ppp/options."
+#define _PATH_CONNERRS "/etc/ppp/connect-errors"
+#define _PATH_USEROPT ".ppprc"
diff --git a/usr.sbin/pppd/pppd.8 b/usr.sbin/pppd/pppd.8
new file mode 100644
index 00000000000..169d644ab7b
--- /dev/null
+++ b/usr.sbin/pppd/pppd.8
@@ -0,0 +1,795 @@
+.\" manual page [] for pppd 2.0
+.\" $Id: pppd.8,v 1.1.1.1 1995/10/18 08:47:59 deraadt Exp $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH PPPD 8
+.SH NAME
+pppd \- Point to Point Protocol daemon
+.SH SYNOPSIS
+.B pppd
+[
+.I tty_name
+] [
+.I speed
+] [
+.I options
+]
+.SH DESCRIPTION
+.LP
+The Point-to-Point Protocol (PPP) provides a method for transmitting
+datagrams over serial point-to-point links. PPP
+is composed of three parts: a method for encapsulating datagrams over
+serial links, an extensible Link Control Protocol (LCP), and
+a family of Network Control Protocols (NCP) for establishing
+and configuring different network-layer protocols.
+.LP
+The encapsulation scheme is provided by driver code in the kernel.
+.B pppd
+provides the basic LCP, authentication support, and an
+NCP for establishing and configuring the Internet Protocol (IP)
+(called the IP Control Protocol, IPCP).
+.SH FREQUENTLY USED OPTIONS
+.TP
+.I <tty_name>
+Communicate over the named device. The string "/dev/"
+is prepended if necessary. If no device name is given,
+or if the name of the controlling terminal is given,
+.I pppd
+will use the controlling terminal, and will not fork to put itself in
+the background.
+.TP
+.I <speed>
+Set the baud rate to <speed> (a decimal number). On systems such as
+4.4BSD and NetBSD, any speed can be specified. Other systems
+(e.g. SunOS) allow only a limited set of speeds.
+.TP
+.B asyncmap \fI<map>
+Set the async character map to <map>.
+This map describes which control characters cannot be successfully
+received over the serial line.
+.I pppd
+will ask the peer to send these characters as a 2-byte escape sequence.
+The argument is a 32 bit hex number
+with each bit representing a character to escape.
+Bit 0 (00000001) represents the character 0x00;
+bit 31 (80000000) represents the character 0x1f or ^_.
+If multiple \fBasyncmap\fR options are
+given, the values are ORed together.
+If no \fBasyncmap\fR option is given, no async character map will be
+negotiated for the receive direction; the peer should then escape
+\fIall\fR control characters.
+.TP
+.B auth
+Require the peer to authenticate itself before allowing network
+packets to be sent or received.
+.TP
+.B connect \fI<p>
+Use the executable or shell command specified by \fI<p>\fR to set up the
+serial line. This script would typically use the chat(8) program to
+dial the modem and start the remote ppp session.
+.TP
+.B crtscts
+Use hardware flow control (i.e. RTS/CTS) to control the flow of data
+on the serial port. If neither the \fBcrtscts\fR nor the
+\fB\-crtscts\fR option is given, the hardware flow control setting for
+the serial port is left unchanged.
+.TP
+.B defaultroute
+Add a default route to the system routing tables, using the peer as
+the gateway, when IPCP negotiation is successfully completed.
+This entry is removed when the PPP connection is broken.
+.TP
+.B disconnect \fI<p>
+Run the executable or shell command specified by \fI<p>\fR after
+\fIpppd\fR has terminated the link. This script could, for example,
+issue commands to the modem to cause it to hang up if hardware modem
+control signals were not available.
+.TP
+.B escape \fIxx,yy,...
+Specifies that certain characters should be escaped on transmission
+(regardless of whether the peer requests them to be escaped with its
+async control character map). The characters to be escaped are
+specified as a list of hex numbers separated by commas. Note that
+almost any character can be specified for the \fBescape\fR option,
+unlike the \fBasyncmap\fR option which only allows control characters
+to be specified. The characters which may not be escaped are those
+with hex values 0x20 - 0x3f or 0x5e.
+.TP
+.B file \fI<f>
+Read options from file <f> (the format is described below).
+.TP
+.B lock
+Specifies that \fIpppd\fR should create a UUCP-style lock file for the
+serial device to ensure exclusive access to the device.
+.TP
+.B mru \fI<n>
+Set the MRU [Maximum Receive Unit] value to <n> for negotiation.
+.I pppd
+will ask the peer to send packets of no more than <n> bytes. The
+minimum MRU value is 128. The default MRU value is 1500. A value of
+296 is recommended for slow links (40 bytes for TCP/IP header + 256
+bytes of data).
+.TP
+.B mtu \fI<n>
+Set the MTU [Maximum Transmit Unit] value to \fI<n>\fR. Unless the
+peer requests a smaller value via MRU negotiation, \fIpppd\fR will
+request that the kernel networking code send data packets of no more
+than \fIn\fR bytes through the PPP network interface.
+.TP
+.B netmask \fI<n>
+Set the interface netmask to <n>, a 32 bit netmask in "decimal dot"
+notation (e.g. 255.255.255.0). If this option is given, the value
+specified is ORed with the default netmask. The default netmask is
+chosen based on the negotiated remote IP address; it is the
+appropriate network mask for the class of the remote IP address, ORed
+with the netmasks for any non point-to-point network interfaces in the
+system which are on the same network.
+.TP
+.B passive
+Enables the "passive" option in the LCP. With this option,
+.I pppd
+will attempt to initiate a connection; if no reply is received from
+the peer,
+.I pppd
+will then just wait passively for a valid LCP packet from the peer
+(instead of exiting, as it does without this option).
+.TP
+.B silent
+With this option,
+.I pppd
+will not transmit LCP packets to initiate a connection until a valid
+LCP packet is received from the peer (as for the `passive' option with
+ancient versions of \fIpppd\fR).
+.SH OPTIONS
+.TP
+.I <local_IP_address>\fB:\fI<remote_IP_address>
+Set the local and/or remote interface IP addresses. Either one may be
+omitted. The IP addresses can be specified with a host name or in
+decimal dot notation (e.g. 150.234.56.78). The default local
+address is the (first) IP address of the system (unless the
+.B noipdefault
+option is given). The remote address will be obtained from the peer
+if not specified in any option. Thus, in simple cases, this option is
+not required. If a local and/or remote IP address is specified with
+this option,
+.I pppd
+will not accept a different value from the peer in the IPCP
+negotiation, unless the
+.B ipcp-accept-local
+and/or
+.B ipcp-accept-remote
+options are given, respectively.
+.TP
+.B -ac
+Disable Address/Control compression negotiation (use default, i.e.
+address/control field compression disabled).
+.TP
+.B -all
+Don't request or allow negotiation of any options for LCP and IPCP (use
+default values).
+.TP
+.B -am
+Disable asyncmap negotiation (use the default asyncmap, i.e. escape
+all control characters).
+.TP
+.B -as \fI<n>
+Same as
+.B asyncmap \fI<n>
+.TP
+.B bsdcomp \fInr,nt
+Request that the peer compress packets that it sends, using the
+BSD-Compress scheme, with a maximum code size of \fInr\fR bits, and
+agree to compress packets sent to the peer with a maximum code size of
+\fInt\fR bits. If \fInt\fR is not specified, it defaults to the value
+given for \fInr\fR. Values in the range 9 to 15 may be used for
+\fInr\fR and \fInt\fR; larger values give better compression but
+consume more kernel memory for compression dictionaries.
+Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
+compression in the corresponding direction.
+.TP
+.B \-bsdcomp
+Disables compression; \fBpppd\fR will not request or agree to compress
+packets using the BSD-Compress scheme.
+.TP
+.B +chap
+Require the peer to authenticate itself using CHAP [Cryptographic
+Handshake Authentication Protocol] authentication.
+.TP
+.B -chap
+Don't agree to authenticate using CHAP.
+.TP
+.B chap-interval \fI<n>
+If this option is given,
+.I pppd
+will rechallenge the peer every <n> seconds.
+.TP
+.B chap-max-challenge \fI<n>
+Set the maximum number of CHAP challenge transmissions to <n> (default
+10).
+.TP
+.B chap-restart \fI<n>
+Set the CHAP restart interval (retransmission timeout for challenges)
+to <n> seconds (default 3).
+.TP
+.B -crtscts
+Disable hardware flow control (i.e. RTS/CTS) on the serial port. If
+neither the \fBcrtscts\fR nor the \fB\-crtscts\fR option is given,
+the hardware flow control setting for the serial port is left
+unchanged.
+.TP
+.B -d
+Increase debugging level (same as the \fBdebug\fR option).
+.TP
+.B debug
+Increase debugging level (same as \fB\-d\fR).
+If this
+option is given, \fIpppd\fR will log the contents of all control
+packets sent or received in a readable form. The packets are logged
+through syslog with facility \fIdaemon\fR and level \fIdebug\fR. This
+information can be directed to a file by setting up /etc/syslog.conf
+appropriately (see syslog.conf(5)).
+.TP
+.B \-defaultroute
+Disable the \fBdefaultroute\fR option. The system administrator who
+wishes to prevent users from creating default routes with \fIpppd\fR
+can do so by placing this option in the /etc/ppp/options file.
+.TP
+.B -detach
+Don't fork to become a background process (otherwise
+.I pppd
+will do so if a serial device other than its controlling terminal is
+specified).
+.TP
+.B domain \fI<d>
+Append the domain name <d> to the local host name for authentication
+purposes. For example, if gethostname() returns the name porsche, but the
+fully qualified domain name is porsche.Quotron.COM, you would use the
+domain option to set the domain name to Quotron.COM.
+.TP
+.B -ip
+Disable IP address negotiation. If this option is used, the remote IP
+address must be specified with an option on the command line or in an
+options file.
+.TP
+.B ipcp-accept-local
+With this option,
+.I pppd
+will accept the peer's idea of our local IP address, even if the
+local IP address was specified in an option.
+.TP
+.B ipcp-accept-remote
+With this option,
+.I pppd
+will accept the peer's idea of its (remote) IP address, even if the
+remote IP address was specified in an option.
+.TP
+.B ipcp-max-configure \fI<n>
+Set the maximum number of IPCP configure-request transmissions to <n>
+(default 10).
+.TP
+.B ipcp-max-failure \fI<n>
+Set the maximum number of IPCP configure-NAKs returned before starting
+to send configure-Rejects instead to <n> (default 10).
+.TP
+.B ipcp-max-terminate \fI<n>
+Set the maximum number of IPCP terminate-request transmissions to <n>
+(default 3).
+.TP
+.B ipcp-restart \fI<n>
+Set the IPCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B ipparam \fIstring
+Provides an extra parameter to the ip-up and ip-down scripts. If this
+option is given, the \fIstring\fR supplied is given as the 6th
+parameter to those scripts.
+.TP
+.B kdebug \fIn
+Enable debugging code in the kernel-level PPP driver. The argument
+\fIn\fR is a number which is the sum of the following values: 1 to
+enable general debug messages, 2 to request that the contents of
+received packets be printed, and 4 to request that the contents of
+transmitted packets be printed.
+.TP
+.B lcp-echo-failure \fI<n>
+If this option is given, \fIpppd\fR will presume the peer to be dead
+if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
+echo-reply. If this happens, \fIpppd\fR will terminate the
+connection. Use of this option requires a non-zero value for the
+\fIlcp-echo-interval\fR parameter. This option can be used to enable
+\fIpppd\fR to terminate after the physical connection has been broken
+(e.g., the modem has hung up) in situations where no hardware modem
+control lines are available.
+.TP
+.B lcp-echo-interval \fI<n>
+If this option is given, \fIpppd\fR will send an LCP echo-request
+frame to the peer every \fIn\fR seconds. Under Linux, the
+echo-request is sent when no packets have been received from the peer
+for \fIn\fR seconds. Normally the peer should respond to the
+echo-request by sending an echo-reply. This option can be used with
+the \fIlcp-echo-failure\fR option to detect that the peer is no longer
+connected.
+.TP
+.B lcp-max-configure \fI<n>
+Set the maximum number of LCP configure-request transmissions to <n>
+(default 10).
+.TP
+.B lcp-max-failure \fI<n>
+Set the maximum number of LCP configure-NAKs returned before starting
+to send configure-Rejects instead to <n> (default 10).
+.TP
+.B lcp-max-terminate \fI<n>
+Set the maximum number of LCP terminate-request transmissions to <n>
+(default 3).
+.TP
+.B lcp-restart \fI<n>
+Set the LCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B local
+Don't use the modem control lines. With this option,
+.B pppd
+will ignore the state of the CD (Carrier Detect) signal from the modem and
+will not change the state of the DTR (Data Terminal Ready) signal.
+.TP
+.B login
+Use the system password database for authenticating the peer using
+PAP, and record the user in the system wtmp file.
+.TP
+.B modem
+Use the modem control lines. This option is the default. With this
+option,
+.B pppd
+will wait for the CD (Carrier Detect) signal from the modem to be asserted
+when opening the serial device
+(unless a connect script is specified), and it will drop the DTR (Data
+Terminal Ready) signal briefly when the connection is terminated and before
+executing the connect script.
+On Ultrix, this option implies hardware
+flow control, as for the \fBcrtscts\fR option.
+.TP
+.B -mn
+Disable magic number negotiation. With this option,
+.I pppd
+cannot detect a looped-back line.
+.TP
+.B -mru
+Disable MRU [Maximum Receive Unit] negotiation. With this option,
+\fIpppd\fR will use the default MRU value of 1500 bytes.
+.TP
+.B name \fI<n>
+Set the name of the local system for authentication purposes to <n>.
+.TP
+.B noipdefault
+Disables the default behaviour when no local IP address is specified,
+which is to determine (if possible) the local IP address from the
+hostname. With this option, the peer will have to supply the local IP
+address during IPCP negotiation (unless it specified explicitly on the
+command line or in an options file).
+.TP
+.B -p
+Same as the
+.B passive
+option.
+.TP
+.B +pap
+Require the peer to authenticate itself using PAP.
+.TP
+.B -pap
+Don't agree to authenticate using PAP.
+.TP
+.B papcrypt
+Indicates that all secrets in the /etc/ppp/pap-secrets file which
+are used for checking the identity of the peer are encrypted, and thus
+pppd should not accept a password which (before encryption) is
+identical to the secret from the /etc/ppp/pap-secrets file.
+.TP
+.B pap-max-authreq \fI<n>
+Set the maximum number of PAP authenticate-request transmissions to
+<n> (default 10).
+.TP
+.B pap-restart \fI<n>
+Set the PAP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B pap-timeout \fI<n>
+Set the maximum time that
+.I pppd
+will wait for the peer to authenticate itself with PAP to
+<n> seconds (0 means no limit).
+.TP
+.B -pc
+Disable protocol field compression negotiation (use default, i.e.
+protocol field compression disabled).
+.TP
+.B persist
+Do not exit after a connection is terminated; instead try to reopen
+the connection.
+.TP
+.B proxyarp
+Add an entry to this system's ARP [Address Resolution Protocol] table
+with the IP address of the peer and the Ethernet address of this
+system.
+.TP
+.B \-proxyarp
+Disable the \fBproxyarp\fR option. The system administrator who
+wishes to prevent users from creating proxy ARP entries with
+\fIpppd\fR can do so by placing this option in the /etc/ppp/options
+file.
+.TP
+.B remotename \fI<n>
+Set the assumed name of the remote system for authentication purposes
+to <n>.
+.TP
+.B +ua \fI<p>
+Agree to authenticate using PAP [Password Authentication Protocol] if
+requested by the peer, and
+use the data in file <p> for the user and password to send to the
+peer. The file contains the remote user name, followed by a newline,
+followed by the remote password, followed by a newline. This option
+is obsolescent.
+.TP
+.B usehostname
+Enforce the use of the hostname as the name of the local system for
+authentication purposes (overrides the
+.B name
+option).
+.TP
+.B user \fI<u>
+Set the user name to use for authenticating this machine with the peer
+using PAP to <u>.
+.TP
+.B -vj
+Disable negotiation of Van Jacobson style TCP/IP header compression (use
+default, i.e. no compression).
+.TP
+.B -vjccomp
+Disable the connection-ID compression option in Van Jacobson style
+TCP/IP header compression. With this option, \fIpppd\fR will not omit
+the connection-ID byte from Van Jacobson compressed TCP/IP headers,
+nor ask the peer to do so.
+.TP
+.B vj-max-slots \fIn
+Sets the number of connection slots to be used by the Van Jacobson
+TCP/IP header compression and decompression code to \fIn\fR, which
+must be between 2 and 16 (inclusive).
+.TP
+.B xonxoff
+Use software flow control (i.e. XON/XOFF) to control the flow of data on
+the serial port. This option is only implemented on Linux systems
+at present.
+.SH OPTIONS FILES
+Options can be taken from files as well as the command line.
+.I pppd
+reads options from the files /etc/ppp/options and ~/.ppprc before
+looking at the command line. An options file is parsed into a series
+of words, delimited by whitespace. Whitespace can be included in a
+word by enclosing the word in quotes ("). A backslash (\\) quotes the
+following character. A hash (#) starts a comment, which continues
+until the end of the line.
+.SH AUTHENTICATION
+.I pppd
+provides system administrators with sufficient access control that PPP
+access to a server machine can be provided to legitimate users without
+fear of compromising the security of the server or the network it's
+on. In part this is provided by the /etc/ppp/options file, where the
+administrator can place options to require authentication whenever
+.I pppd
+is run, and in part by the PAP and CHAP secrets files, where the
+administrator can restrict the set of IP addresses which individual
+users may use.
+.LP
+The default behaviour of
+.I pppd
+is to agree to authenticate if requested, and to not
+require authentication from the peer. However,
+.I pppd
+will not agree to
+authenticate itself with a particular protocol if it has no secrets
+which could be used to do so.
+.LP
+Authentication is based on secrets, which are selected from secrets
+files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
+Both secrets files have the same format, and both can store secrets
+for several combinations of server (authenticating peer) and client
+(peer being authenticated). Note that
+.I pppd
+can be both a server
+and client, and that different protocols can be used in the two
+directions if desired.
+.LP
+A secrets file is parsed into words as for a options file. A secret
+is specified by a line containing at least 3 words, in the order
+client name, server name, secret. Any following words on the same line are
+taken to be a list of acceptable IP addresses for that client. If
+there are only 3 words on the line, it is assumed that any IP address
+is OK; to disallow all IP addresses, use "-". If the secret starts
+with an `@', what follows is assumed to be the name of a file from
+which to read the secret. A "*" as the client or server name matches
+any name. When selecting a secret, \fIpppd\fR takes the best match, i.e.
+the match with the fewest wildcards.
+.LP
+Thus a secrets file contains both secrets for use in authenticating
+other hosts, plus secrets which we use for authenticating ourselves to
+others. Which secret to use is chosen based on the names of the host
+(the `local name') and its peer (the `remote name'). The local name
+is set as follows:
+.TP 3
+if the \fBusehostname\fR option is given,
+then the local name is the hostname of this machine
+(with the domain appended, if given)
+.TP 3
+else if the \fBname\fR option is given,
+then use the argument of the first \fBname\fR option seen
+.TP 3
+else if the local IP address is specified with a hostname,
+then use that name
+.TP 3
+else use the hostname of this machine (with the domain appended, if given)
+.LP
+When authenticating ourselves using PAP, there is also a `username'
+which is the local name by default, but can be set with the \fBuser\fR
+option or the \fB+ua\fR option.
+.LP
+The remote name is set as follows:
+.TP 3
+if the \fBremotename\fR option is given,
+then use the argument of the last \fBremotename\fR option seen
+.TP 3
+else if the remote IP address is specified with a hostname,
+then use that host name
+.TP 3
+else the remote name is the null string "".
+.LP
+Secrets are selected from the PAP secrets file as follows:
+.TP 2
+*
+For authenticating the peer, look for a secret with client ==
+username specified in the PAP authenticate-request, and server ==
+local name.
+.TP 2
+*
+For authenticating ourselves to the peer, look for a secret with
+client == our username, server == remote name.
+.LP
+When authenticating the peer with PAP, a secret of "" matches any
+password supplied by the peer. If the password doesn't match the
+secret, the password is encrypted using crypt() and checked against
+the secret again; thus secrets for authenticating the peer can be
+stored in encrypted form. If the \fBpapcrypt\fR option is given, the
+first (unencrypted) comparison is omitted, for better security.
+.LP
+If the \fBlogin\fR option was specified, the
+username and password are also checked against the system password
+database. Thus, the system administrator can set up the pap-secrets
+file to allow PPP access only to certain users, and to restrict the
+set of IP addresses that each user can use. Typically, when using the
+\fBlogin\fR option, the secret in /etc/ppp/pap-secrets would be "", to
+avoid the need to have the same secret in two places.
+.LP
+Secrets are selected from the CHAP secrets file as follows:
+.TP 2
+*
+For authenticating the peer, look for a secret with client == name
+specified in the CHAP-Response message, and server == local name.
+.TP 2
+*
+For authenticating ourselves to the peer, look for a secret with
+client == local name, and server == name specified in the
+CHAP-Challenge message.
+.LP
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If authentication
+fails, \fIpppd\fR will terminated the link (by closing LCP). If IPCP
+negotiates an unacceptable IP address for the remote host, IPCP will
+be closed. IP packets can only be sent or received when IPCP is open.
+.LP
+In some cases it is desirable to allow some hosts which can't
+authenticate themselves to connect and use one of a restricted set of
+IP addresses, even when the local host generally requires
+authentication. If the peer refuses to authenticate itself when
+requested, \fIpppd\fR takes that as equivalent to authenticating with
+PAP using the empty string for the username and password. Thus, by
+adding a line to the pap-secrets file which specifies the empty string
+for the client and password, it is possible to allow restricted access
+to hosts which refuse to authenticate themselves.
+.SH ROUTING
+.LP
+When IPCP negotiation is completed successfully,
+.I pppd
+will inform the kernel of the local and remote IP addresses for the
+ppp interface. This is sufficient to create a
+host route to the remote end of the link, which will enable the peers
+to exchange IP packets. Communication with other machines generally
+requires further modification to routing tables and/or ARP (Address
+Resolution Protocol) tables. In some cases this will be done
+automatically through the actions of the \fIrouted\fR or \fIgated\fR
+daemons, but in most cases some further intervention is required.
+.LP
+Sometimes it is desirable
+to add a default route through the remote host, as in the case of a
+machine whose only connection to the Internet is through the ppp
+interface. The \fBdefaultroute\fR option causes \fIpppd\fR to create such a
+default route when IPCP comes up, and delete it when the link is
+terminated.
+.LP
+In some cases it is desirable to use proxy ARP, for example on a
+server machine connected to a LAN, in order to allow other hosts to
+communicate with the remote host. The \fBproxyarp\fR option causes \fIpppd\fR
+to look for a network interface on the same subnet as the remote host
+(an interface supporting broadcast and ARP, which is up and not a
+point-to-point or loopback interface). If found, \fIpppd\fR creates a
+permanent, published ARP entry with the IP address of the remote host
+and the hardware address of the network interface found.
+.SH EXAMPLES
+.LP
+In the simplest case, you can connect the serial ports of two machines
+and issue a command like
+.IP
+pppd /dev/ttya 9600 passive
+.LP
+to each machine, assuming there is no \fIgetty\fR running on the
+serial ports. If one machine has a \fIgetty\fR running, you can use
+\fIkermit\fR or \fItip\fR on the other machine to log in to the first
+machine and issue a command like
+.IP
+pppd passive
+.LP
+Then exit from the communications program (making sure the connection
+isn't dropped), and issue a command like
+.IP
+pppd /dev/ttya 9600
+.LP
+The process of logging in to the other machine and starting \fIpppd\fR
+can be automated by using the \fBconnect\fR option to run \fIchat\fR,
+for example:
+.IP
+pppd /dev/ttya 38400 connect 'chat "" "" "login:" "username"
+"Password:" "password" "% " "exec pppd passive"'
+.LP
+(Note however that running chat like this will leave the password
+visible in the parameter list of pppd and chat.)
+.LP
+If your serial connection is any more complicated than a piece of
+wire, you may need to arrange for some control characters to be
+escaped. In particular, it is often useful to escape XON (^Q) and
+XOFF (^S), using \fBasyncmap a0000\fR. If the path includes a telnet,
+you probably should escape ^] as well (\fBasyncmap 200a0000\fR).
+If the path includes an rlogin, you will need to use the \fBescape
+ff\fR option on the end which is running the rlogin client, since many
+rlogin implementations are not
+transparent; they will remove the sequence [0xff, 0xff, 0x73, 0x73,
+followed by any 8 bytes] from the stream.
+.SH DIAGNOSTICS
+.LP
+Messages are sent to the syslog daemon using facility LOG_DAEMON.
+(This can be overriden by recompiling \fIpppd\fR with the macro
+LOG_PPP defined as the desired facility.) In order to see the error
+and debug messages, you will need to edit your /etc/syslog.conf file
+to direct the messages to the desired output device or file.
+.LP
+The \fBdebug\fR option causes the contents of all control packets sent
+or received to be logged, that is, all LCP, PAP, CHAP or IPCP packets.
+This can be useful if the PPP negotiation does not succeed.
+If debugging is enabled at compile time, the \fBdebug\fR option also
+causes other debugging messages to be logged.
+.LP
+Debugging can also be enabled or disabled by sending a
+SIGUSR1 to the
+.I pppd
+process. This signal acts as a toggle.
+.SH FILES
+.TP
+.B /var/run/ppp\fIn\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp\fIn\fB.pid \fR(others)
+Process-ID for \fIpppd\fR process on ppp interface unit \fIn\fR.
+.TP
+.B /etc/ppp/ip-up
+A program or script which is executed when the link is available for
+sending and receiving IP packets (that is, IPCP has come up). It is
+executed with the parameters
+.IP
+\fIinterface-name tty-device speed local-IP-address
+remote-IP-address\fR
+.IP
+and with its standard input,
+output and error streams redirected to \fB/dev/null\fR.
+.IP
+This program or script is executed with the same real and effective
+user-ID as \fIpppd\fR, that is, at least the effective user-ID and
+possibly the real user-ID will be \fBroot\fR. This is so that it can
+be used to manipulate routes, run privileged daemons (e.g.
+\fBsendmail\fR), etc. Be careful that the contents of the
+/etc/ppp/ip-up and /etc/ppp/ip-down scripts do not compromise your
+system's security.
+.TP
+.B /etc/ppp/ip-down
+A program or script which is executed when the link is no longer
+available for sending and receiving IP packets. This script can be
+used for undoing the effects of the /etc/ppp/ip-up script. It is
+invoked with the same parameters as the ip-up script, and the same
+security considerations apply, since it is executed with the same
+effective and real user-IDs as \fIpppd\fR.
+.TP
+.B /etc/ppp/pap-secrets
+Usernames, passwords and IP addresses for PAP authentication.
+.TP
+.B /etc/ppp/chap-secrets
+Names, secrets and IP addresses for CHAP authentication.
+.TP
+.B /etc/ppp/options
+System default options for
+.I pppd,
+read before user default options or command-line options.
+.TP
+.B ~/.ppprc
+User default options, read before command-line options.
+.TP
+.B /etc/ppp/options.\fIttyname
+System default options for the serial port being used, read after
+command-line options.
+.SH SEE ALSO
+.TP
+.B RFC1144
+Jacobson, V.
+.I Compressing TCP/IP headers for low-speed serial links.
+1990 February.
+.TP
+.B RFC1321
+Rivest, R.
+.I The MD5 Message-Digest Algorithm.
+1992 April.
+.TP
+.B RFC1332
+McGregor, G.
+.I PPP Internet Protocol Control Protocol (IPCP).
+1992 May.
+.TP
+.B RFC1334
+Lloyd, B.; Simpson, W.A.
+.I PPP authentication protocols.
+1992 October.
+.TP
+.B RFC1548
+Simpson, W.A.
+.I The Point\-to\-Point Protocol (PPP).
+1993 December.
+.TP
+.B RFC1549
+Simpson, W.A.
+.I PPP in HDLC Framing.
+1993 December
+.SH NOTES
+The following signals have the specified effect when sent to the
+.I pppd
+process.
+.TP
+.B SIGINT, SIGTERM
+These signals cause \fBpppd\fR to terminate the link (by closing LCP),
+restore the serial device settings, and exit.
+.TP
+.B SIGHUP
+This signal causes \fBpppd\fR to terminate the link, restore the
+serial device settings, and close the serial device. If the
+\fBpersist\fR option has been specified, \fBpppd\fR will try to reopen
+the serial device and start another connection. Otherwise \fBpppd\fR
+will exit.
+.TP
+.B SIGUSR2
+This signal causes
+.B pppd
+to renegotiate compression. This can be useful to re-enable
+compression after it has been disabled as a result of a fatal
+decompression error. With the BSD Compress scheme, fatal
+decompression errors generally indicate a bug in one or other
+implementation.
+
+.SH AUTHORS
+Drew Perkins,
+Brad Clements,
+Karl Fox,
+Greg Christy,
+Brad Parker,
+Paul Mackerras (paulus@cs.anu.edu.au).
diff --git a/usr.sbin/pppd/pppd.h b/usr.sbin/pppd/pppd.h
new file mode 100644
index 00000000000..403262fa085
--- /dev/null
+++ b/usr.sbin/pppd/pppd.h
@@ -0,0 +1,255 @@
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pppd.h,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $
+ */
+
+/*
+ * TODO:
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h> /* for u_int32_t, if defined */
+#include <net/ppp_defs.h>
+
+#define NUM_PPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Limits.
+ */
+
+#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
+#define MAXARGS 1 /* max # args to a command */
+#define MAXNAMELEN 256 /* max length of hostname or name for auth */
+#define MAXSECRETLEN 256 /* max length of password or secret */
+
+/*
+ * Global variables.
+ */
+
+extern int hungup; /* Physical layer has disconnected */
+extern int ifunit; /* Interface unit number */
+extern char ifname[]; /* Interface name */
+extern int fd; /* Serial device file descriptor */
+extern char hostname[]; /* Our hostname */
+extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
+extern int phase; /* Current state of link - see values below */
+extern int baud_rate; /* Current link speed in bits/sec */
+extern char *progname; /* Name of this program */
+
+/*
+ * Variables set by command-line options.
+ */
+
+extern int debug; /* Debug flag */
+extern int kdebugflag; /* Tell kernel to print debug messages */
+extern int default_device; /* Using /dev/tty or equivalent */
+extern char devnam[]; /* Device name */
+extern int crtscts; /* Use hardware flow control */
+extern int modem; /* Use modem control lines */
+extern int inspeed; /* Input/Output speed requested */
+extern u_int32_t netmask; /* IP netmask to set on interface */
+extern int lockflag; /* Create lock file to lock the serial dev */
+extern int nodetach; /* Don't detach from controlling tty */
+extern char *connector; /* Script to establish physical link */
+extern char *disconnector; /* Script to disestablish physical link */
+extern char user[]; /* Username for PAP */
+extern char passwd[]; /* Password for PAP */
+extern int auth_required; /* Peer is required to authenticate */
+extern int proxyarp; /* Set up proxy ARP entry for peer */
+extern int persist; /* Reopen link after it goes down */
+extern int uselogin; /* Use /etc/passwd for checking PAP */
+extern int lcp_echo_interval; /* Interval between LCP echo-requests */
+extern int lcp_echo_fails; /* Tolerance to unanswered echo-requests */
+extern char our_name[]; /* Our name for authentication purposes */
+extern char remote_name[]; /* Peer's name for authentication */
+extern int usehostname; /* Use hostname for our_name */
+extern int disable_defaultip; /* Don't use hostname for default IP adrs */
+extern char *ipparam; /* Extra parameter for ip up/down scripts */
+extern int cryptpap; /* Others' PAP passwords are encrypted */
+
+/*
+ * Values for phase.
+ */
+#define PHASE_DEAD 0
+#define PHASE_ESTABLISH 1
+#define PHASE_AUTHENTICATE 2
+#define PHASE_NETWORK 3
+#define PHASE_TERMINATE 4
+
+/*
+ * Prototypes.
+ */
+void quit __P((void)); /* Cleanup and exit */
+void timeout __P((void (*)(), caddr_t, int));
+ /* Look-alike of kernel's timeout() */
+void untimeout __P((void (*)(), caddr_t));
+ /* Look-alike of kernel's untimeout() */
+void output __P((int, u_char *, int));
+ /* Output a PPP packet */
+void demuxprotrej __P((int, int));
+ /* Demultiplex a Protocol-Reject */
+int check_passwd __P((int, char *, int, char *, int, char **, int *));
+ /* Check peer-supplied username/password */
+int get_secret __P((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
+u_int32_t GetMask __P((u_int32_t)); /* get netmask for address */
+void die __P((int));
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+ (c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+ *(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+ (s) = *(cp)++ << 8; \
+ (s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+ *(cp)++ = (u_char) ((s) >> 8); \
+ *(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+ (l) = *(cp)++ << 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+ *(cp)++ = (u_char) ((l) >> 24); \
+ *(cp)++ = (u_char) ((l) >> 16); \
+ *(cp)++ = (u_char) ((l) >> 8); \
+ *(cp)++ = (u_char) (l); \
+}
+
+#define INCPTR(n, cp) ((cp) += (n))
+#define DECPTR(n, cp) ((cp) -= (n))
+
+#undef FALSE
+#define FALSE 0
+#undef TRUE
+#define TRUE 1
+
+/*
+ * System dependent definitions for user-level 4.3BSD UNIX implementation.
+ */
+
+#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
+
+#define TIMEOUT(r, f, t) timeout((r), (f), (t))
+#define UNTIMEOUT(r, f) untimeout((r), (f))
+
+#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BZERO(s, n) memset(s, 0, n)
+#define EXIT(u) quit()
+
+#define PRINTMSG(m, l) { m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); }
+
+/*
+ * MAKEHEADER - Add Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+ PUTCHAR(PPP_ALLSTATIONS, p); \
+ PUTCHAR(PPP_UI, p); \
+ PUTSHORT(t, p); }
+
+
+#ifdef DEBUGALL
+#define DEBUGMAIN 1
+#define DEBUGFSM 1
+#define DEBUGLCP 1
+#define DEBUGIPCP 1
+#define DEBUGUPAP 1
+#define DEBUGCHAP 1
+#endif
+
+#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
+ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
+ || defined(DEBUGCHAP)
+#define LOG_PPP LOG_LOCAL2
+#else
+#define LOG_PPP LOG_DAEMON
+#endif
+#endif /* LOG_PPP */
+
+#ifdef DEBUGMAIN
+#define MAINDEBUG(x) if (debug) syslog x
+#else
+#define MAINDEBUG(x)
+#endif
+
+#ifdef DEBUGFSM
+#define FSMDEBUG(x) if (debug) syslog x
+#else
+#define FSMDEBUG(x)
+#endif
+
+#ifdef DEBUGLCP
+#define LCPDEBUG(x) if (debug) syslog x
+#else
+#define LCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPCP
+#define IPCPDEBUG(x) if (debug) syslog x
+#else
+#define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGUPAP
+#define UPAPDEBUG(x) if (debug) syslog x
+#else
+#define UPAPDEBUG(x)
+#endif
+
+#ifdef DEBUGCHAP
+#define CHAPDEBUG(x) if (debug) syslog x
+#else
+#define CHAPDEBUG(x)
+#endif
+
+#ifndef SIGTYPE
+#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
+#define SIGTYPE void
+#else
+#define SIGTYPE int
+#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
+#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#endif
+
+#endif /* __PPP_H__ */
diff --git a/usr.sbin/pppd/pppstats/Makefile b/usr.sbin/pppd/pppstats/Makefile
new file mode 100644
index 00000000000..2593ca6b521
--- /dev/null
+++ b/usr.sbin/pppd/pppstats/Makefile
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $
+
+PROG= pppstats
+SRCS= pppstats.c
+MAN= pppstats.8
+MLINKS= pppstats.8 slstats.8
+BINDIR= /usr/sbin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pppd/pppstats/pppstats.8 b/usr.sbin/pppd/pppstats/pppstats.8
new file mode 100644
index 00000000000..d599994c8c3
--- /dev/null
+++ b/usr.sbin/pppd/pppstats/pppstats.8
@@ -0,0 +1,179 @@
+.\" @(#) $Header: /home/cvs/src/usr.sbin/pppd/pppstats/pppstats.8,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $ (LBL)
+.Dd November 15, 1994
+.Dt PPPSTATS 8
+.Sh NAME
+.Nm pppstats
+.Nd report statistics for the specified PPP interface
+.Sh SYNOPSIS
+.Nm pppstats
+.Op Fl v
+.Op Fl r
+.Op Fl z
+.Op Fl c Ar count
+.Op Fl w Ar wait
+.Op Ar interface
+.Sh DESCRIPTION
+.Pp
+The
+.Nm pppstats
+utility reports PPP-related statistics at regular intervals for the
+specified PPP
+.Ar interface .
+If the
+.Ar interface
+is unspecified, it will default to ppp0.
+The display is split horizontally
+into input and output sections containing columns of statistics
+describing the properties and volume of packets received and
+transmitted by the interface.
+.Pp
+The first report will consist of a snapshot of the interface's
+statistics. Further output, if any, will describe activity between
+report intervals.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar count
+Repeat the display
+.Ar count
+times. The first display is for the time since a reboot and each
+subsequent report is for the time period since the last display.
+If this option is not specified, the default repeat
+.Ar count
+is 1 if the
+.Fl w
+option is not specified, otherwise infinity.
+.It Fl r
+Display additional statistics summarizing the compression ratio
+achieved by the packet compression algorithm in use.
+.It Fl v
+Display additional statistics demonstrating the efficacy of VJ header
+compression and providing more explicit information on the operation
+of the algorithm.
+.It Fl w Ar wait
+Pause
+.Ar wait
+seconds between each display. If no
+.Ar wait
+interval is specified, the default is 5 seconds.
+.It Fl z
+Instead of the standard display, show statistics indicating the
+performance of the packet compression algorithm in use.
+.El
+.Pp
+The following fields are printed on the input side when the
+.Fl z
+option is not used:
+.Bl -tag -width search
+.It Li IN
+The total number of bytes received by this interface.
+.It Li PACK
+The total number of packets received by this interface.
+.It Li VJCOMP
+The number of compressed TCP packets received by this interface.
+.It Li VJUNC
+The number of uncompressed TCP packets received by this interface.
+.It Li VJERR
+The number of corrupted or bogus packets received by this interface.
+.It Li VJTOSS
+The number of VJ header-compressed TCP packets dropped on reception by
+this interface. Only reported when the
+.Fl v
+option is specified.
+.It Li NON-VJ
+The total number of non-TCP packets received by this interface. Only
+reported when the
+.Fl v
+option is specified.
+.It Li RATIO
+The overall compression ratio achieved for received packets by the
+packet compression scheme in use, as a number between 0.0 and 1.0,
+representing the average proportionate reduction in the size of the
+packets achieved by the use of packet compression (thus 0.0 indicates
+that the data is incompressible). Only reported when the
+.Fl r
+option is specified.
+.It Li UBYTE
+The total number of bytes received, after decompression of compressed
+packets. Only reported when the
+.Fl r
+option is specified.
+.El
+.Pp
+The following fields are printed on the output side:
+.Bl -tag -width search
+.It Li OUT
+The total number of bytes transmitted from this interface.
+.It Li PACK
+The total number of packets transmitted from this interface.
+.It Li VJCOMP
+The number of TCP packets transmitted from this interface with
+VJ-compressed TCP headers.
+.It Li VJUNC
+The number of TCP packets transmitted from this interface with
+VJ-uncompressed TCP headers.
+.It Li NON-VJ
+The total number of non-TCP packets transmitted from this interface.
+.It Li VJSRCH
+The number of searches for the cached header entry for a VJ header
+compressed TCP packet. Only reported when the
+.Fl v
+option is specified.
+.It Li VJMISS
+The number of failed searches for the cached header entry for a
+VJ header compressed TCP packet. Only reported when the
+.Fl v
+option is specified.
+.It Li RATIO
+The overall compression ratio achieved for transmitted packets by the
+packet compression scheme in use, as a number between 0.0 and 1.0.
+Only reported when the
+.Fl r
+option is specified.
+.It Li UBYTE
+The total number of bytes to be transmitted, before packet compression
+is applied. Only reported when the
+.Fl v
+option is specified.
+.El
+.Pp
+When the
+.Fl z
+option is specified,
+.Nm pppstats
+instead displays the following fields, relating to the packet
+compression algorithm currently in use. If packet compression is not
+in use, these fields will all display zeroes. The fields displayed on
+the input side are:
+.Bl -tag -width search
+.It Li COMPRESSED BYTE
+The number of bytes of compressed packets received.
+.It Li COMPRESSED PACK
+The number of compressed packets received.
+.It Li INCOMPRESSIBLE BYTE
+The number of bytes of incompressible packets (that is, those which
+were transmitted in uncompressed form) received.
+.It Li INCOMPRESSIBLE PACK
+The number of incompressible packets received.
+.It Li COMP RATIO
+The recent compression ratio for incoming packets, as a number between
+0.0 and 1.0.
+.El
+.Pp
+The fields displayed on the output side are:
+.Bl -tag -width search
+.It Li COMPRESSED BYTE
+The number of bytes of compressed packets transmitted.
+.It Li COMPRESSED PACK
+The number of compressed packets transmitted.
+.It Li INCOMPRESSIBLE BYTE
+The number of bytes of incompressible packets transmitted (that is,
+those which were transmitted in uncompressed form).
+.It Li INCOMPRESSIBLE PACK
+The number of incompressible packets transmitted.
+.It Li COMP RATIO
+The recent compression ratio for outgoing packets, as a number between
+0.0 and 1.0.
+.El
+.Sh SEE ALSO
+.Xr pppd 8
diff --git a/usr.sbin/pppd/pppstats/pppstats.c b/usr.sbin/pppd/pppstats/pppstats.c
new file mode 100644
index 00000000000..a2e43db580b
--- /dev/null
+++ b/usr.sbin/pppd/pppstats/pppstats.c
@@ -0,0 +1,310 @@
+/*
+ * print PPP statistics:
+ * pppstats [-v] [-r] [-z] [-c count] [-w wait] [interface]
+ *
+ * -v Verbose mode for default display
+ * -r Show compression ratio in default display
+ * -z Show compression statistics instead of default display
+ *
+ * from the original "slstats" by Van Jacobson
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: pppstats.c,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ppp_defs.h>
+#include <net/if.h>
+#include <net/if_ppp.h>
+
+int vflag, rflag, zflag; /* select type of display */
+int interval, count;
+int infinite;
+int unit;
+int s; /* socket file descriptor */
+int signalled; /* set if alarm goes off "early" */
+char *progname;
+char interface[IFNAMSIZ];
+
+void
+usage()
+{
+ fprintf(stderr, "Usage: %s [-v|-r|-z] [-c count] [-w wait] [interface]\n",
+ progname);
+ exit(1);
+}
+
+/*
+ * Called if an interval expires before intpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+void
+catchalarm(arg)
+ int arg;
+{
+ signalled = 1;
+}
+
+void
+get_ppp_stats(curp)
+ struct ppp_stats *curp;
+{
+ struct ifpppstatsreq req;
+
+ strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
+ if (ioctl(s, SIOCGPPPSTATS, &req) == 0) {
+ *curp = req.stats;
+ return;
+ }
+ fprintf(stderr, "%s: ", progname);
+ if (errno == ENOTTY)
+ errx(1, "kernel support missing");
+ else
+ err(1, "couldn't get PPP statistics");
+}
+
+get_ppp_cstats(csp)
+ struct ppp_comp_stats *csp;
+{
+ struct ifpppcstatsreq creq;
+
+ strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
+ if (ioctl(s, SIOCGPPPCSTATS, &creq) == 0) {
+ *csp = creq.stats;
+ return;
+ }
+ if (errno == ENOTTY) {
+ if (zflag)
+ errx(1, "no kernel compression support\n");
+ warnx("no kernel compression support\n");
+ rflag = 0;
+ } else
+ err(1, "couldn't get PPP compression stats");
+}
+
+
+#define V(offset) (cur.offset - old.offset)
+#define W(offset) (ccs.offset - ocs.offset)
+
+#define CRATE(x) ((x).unc_bytes == 0? 0.0: \
+ 1.0 - ((double)((x).comp_bytes + (x).inc_bytes) \
+ / (x).unc_bytes))
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed is cumulative.
+ */
+void
+intpr()
+{
+ register int line = 0;
+ sigset_t oldmask, mask;
+ struct ppp_stats cur, old;
+ struct ppp_comp_stats ccs, ocs;
+
+ memset(&old, 0, sizeof(old));
+ memset(&ocs, 0, sizeof(ocs));
+
+ while (1) {
+ get_ppp_stats(&cur);
+ if (zflag || rflag)
+ get_ppp_cstats(&ccs);
+
+ (void)signal(SIGALRM, catchalarm);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if ((line % 20) == 0) {
+ if (zflag) {
+ printf("IN: COMPRESSED INCOMPRESSIBLE COMP | ");
+ printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n");
+ printf(" BYTE PACK BYTE PACK RATIO | ");
+ printf(" BYTE PACK BYTE PACK RATIO");
+ } else {
+ printf("%8.8s %6.6s %6.6s %6.6s %6.6s",
+ "IN", "PACK", "VJCOMP", "VJUNC", "VJERR");
+ if (vflag)
+ printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
+ if (rflag)
+ printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+ printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s",
+ "OUT", "PACK", "VJCOMP", "VJUNC", "NON-VJ");
+ if (vflag)
+ printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
+ if(rflag)
+ printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+ }
+ putchar('\n');
+ }
+
+ if (zflag) {
+ printf("%8u %6u %8u %6u %6.2f",
+ W(d.comp_bytes),
+ W(d.comp_packets),
+ W(d.inc_bytes),
+ W(d.inc_packets),
+ ccs.d.ratio == 0? 0.0:
+ 1 - 1.0 / ccs.d.ratio * 256.0);
+
+ printf(" | %8u %6u %8u %6u %6.2f",
+ W(c.comp_bytes),
+ W(c.comp_packets),
+ W(c.inc_bytes),
+ W(c.inc_packets),
+ ccs.c.ratio == 0? 0.0:
+ 1 - 1.0 / ccs.c.ratio * 256.0);
+
+ } else {
+
+ printf("%8u %6u %6u %6u %6u",
+ V(p.ppp_ibytes),
+ V(p.ppp_ipackets),
+ V(vj.vjs_compressedin),
+ V(vj.vjs_uncompressedin),
+ V(vj.vjs_errorin));
+ if (vflag)
+ printf(" %6u %6u",
+ V(vj.vjs_tossed),
+ V(p.ppp_ipackets) -
+ V(vj.vjs_compressedin) -
+ V(vj.vjs_uncompressedin) -
+ V(vj.vjs_errorin));
+ if (rflag)
+ printf(" %6.2f %6u",
+ CRATE(ccs.d),
+ W(d.unc_bytes));
+ printf(" | %8u %6u %6u %6u %6u",
+ V(p.ppp_obytes),
+ V(p.ppp_opackets),
+ V(vj.vjs_compressed),
+ V(vj.vjs_packets) - V(vj.vjs_compressed),
+ V(p.ppp_opackets) - V(vj.vjs_packets));
+ if (vflag)
+ printf(" %6u %6u",
+ V(vj.vjs_searches),
+ V(vj.vjs_misses));
+
+ if (rflag)
+ printf(" %6.2f %6u",
+ CRATE(ccs.c),
+ W(c.unc_bytes));
+
+ }
+
+ putchar('\n');
+ fflush(stdout);
+ line++;
+
+ count--;
+ if (!infinite && !count)
+ break;
+
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (signalled == 0)
+ sigpause(0);
+ sigsetmask(oldmask);
+ signalled = 0;
+ (void)alarm(interval);
+ old = cur;
+ ocs = ccs;
+ }
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ struct ifreq ifr;
+
+ strcpy(interface, "ppp0");
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ while ((c = getopt(argc, argv, "vrzc:w:")) != -1) {
+ switch (c) {
+ case 'v':
+ ++vflag;
+ break;
+ case 'r':
+ ++rflag;
+ break;
+ case 'z':
+ ++zflag;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ if (count <= 0)
+ usage();
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ if (interval <= 0)
+ usage();
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!interval && count)
+ interval = 5;
+ if (interval && !count)
+ infinite = 1;
+ if (!interval && !count)
+ count = 1;
+
+ if (argc > 1)
+ usage();
+ if (argc > 0)
+ strncpy(interface, argv[0], sizeof(interface));
+
+ if (sscanf(interface, "ppp%d", &unit) != 1)
+ errx(1, "invalid interface '%s' specified\n", interface);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(1, "couldn't create IP socket");
+ strcpy(ifr.ifr_name, interface);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
+ errx(1, "nonexistent interface '%s' specified\n", interface);
+
+ intpr();
+ exit(0);
+}
diff --git a/usr.sbin/pppd/sys-bsd.c b/usr.sbin/pppd/sys-bsd.c
new file mode 100644
index 00000000000..8ff8e7cd5b9
--- /dev/null
+++ b/usr.sbin/pppd/sys-bsd.c
@@ -0,0 +1,1135 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: sys-bsd.c,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#if RTM_VERSION >= 3
+#include <netinet/if_ether.h>
+#endif
+
+#include "pppd.h"
+
+static int initdisc = -1; /* Initial TTY discipline */
+static int rtm_seq;
+
+static int restore_term; /* 1 => we've munged the terminal */
+static struct termios inittermios; /* Initial TTY termios */
+static struct winsize wsinfo; /* Initial window size info */
+
+static char *lock_file; /* name of lock file created */
+
+int sockfd; /* socket for doing interface ioctls */
+
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init()
+{
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+
+ /* Get an internet socket for doing socket ioctl's on. */
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "Couldn't create IP socket: %m");
+ die(1);
+ }
+}
+
+/*
+ * note_debug_level - note a change in the debug level.
+ */
+void
+note_debug_level()
+{
+ if (debug) {
+ syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ } else {
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ }
+}
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+int
+ppp_available()
+{
+ int s, ok;
+ struct ifreq ifr;
+ extern char *no_ppp_msg;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ no_ppp_msg = "\
+This system lacks kernel support for PPP. To include PPP support\n\
+in the kernel, please follow the steps detailed in the README.bsd\n\
+file in the ppp-2.2 distribution.\n";
+ return ok;
+}
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ int pppdisc = PPPDISC;
+ int x;
+
+ if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
+ die(1);
+ }
+ if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+
+ /*
+ * Enable debug in the driver if requested.
+ */
+ if (kdebugflag) {
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
+ } else {
+ x |= (kdebugflag & 0xFF) * SC_DEBUG;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+ syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
+ }
+ }
+}
+
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ int x;
+ char *s;
+
+ if (initdisc >= 0) {
+ /*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+ s = NULL;
+ switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+ case SC_RCV_B7_0:
+ s = "bit 7 set to 1";
+ break;
+ case SC_RCV_B7_1:
+ s = "bit 7 set to 0";
+ break;
+ case SC_RCV_EVNP:
+ s = "odd parity";
+ break;
+ case SC_RCV_ODDP:
+ s = "even parity";
+ break;
+ }
+ if (s != NULL) {
+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
+ syslog(LOG_WARNING, "All received characters had %s", s);
+ }
+ }
+ if (ioctl(fd, TIOCSETD, &initdisc) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ }
+}
+
+
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ *
+ * For *BSD, we assume that speed_t values numerically equal bits/second.
+ */
+set_up_tty(fd, local)
+ int fd, local;
+{
+ struct termios tios;
+
+ if (tcgetattr(fd, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ die(1);
+ }
+
+ if (!restore_term) {
+ inittermios = tios;
+ ioctl(fd, TIOCGWINSZ, &wsinfo);
+ }
+
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+ if (crtscts > 0)
+ tios.c_cflag |= CRTSCTS;
+ else if (crtscts < 0)
+ tios.c_cflag &= ~CRTSCTS;
+
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (local || !modem)
+ tios.c_cflag |= CLOCAL;
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ if (crtscts == 2) {
+ tios.c_iflag |= IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ }
+
+ if (inspeed) {
+ cfsetospeed(&tios, inspeed);
+ cfsetispeed(&tios, inspeed);
+ } else {
+ inspeed = cfgetospeed(&tios);
+ /*
+ * We can't proceed if the serial port speed is 0,
+ * since that implies that the serial port is disabled.
+ */
+ if (inspeed == 0) {
+ syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
+ devnam);
+ die(1);
+ }
+ }
+ baud_rate = inspeed;
+
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ die(1);
+ }
+
+ restore_term = 1;
+}
+
+/*
+ * restore_tty - restore the terminal to the saved settings.
+ */
+void
+restore_tty()
+{
+ if (restore_term) {
+ if (!default_device) {
+ /*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+ }
+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ if (errno != ENXIO)
+ syslog(LOG_WARNING, "tcsetattr: %m");
+ ioctl(fd, TIOCSWINSZ, &wsinfo);
+ restore_term = 0;
+ }
+}
+
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+setdtr(fd, on)
+int fd, on;
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+ if (debug)
+ log_packet(p, len, "sent ");
+
+ if (write(fd, p, len) < 0) {
+ syslog(LOG_ERR, "write: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * wait_input - wait until there is data available on fd,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+wait_input(timo)
+ struct timeval *timo;
+{
+ fd_set ready;
+ int n;
+
+ FD_ZERO(&ready);
+ FD_SET(fd, &ready);
+ n = select(fd+1, &ready, NULL, &ready, timo);
+ if (n < 0 && errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ return -1;
+ syslog(LOG_ERR, "read(fd): %m");
+ die(1);
+ }
+ return len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ u_int x;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
+ x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+ppp_set_xaccm(unit, accm)
+ int unit;
+ ext_accm accm;
+{
+ if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
+ syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
+}
+
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ int x;
+
+ if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
+ quit();
+ }
+ if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
+ quit();
+ }
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.
+ */
+ccp_test(unit, opt_ptr, opt_len, for_transmit)
+ int unit, opt_len, for_transmit;
+ u_char *opt_ptr;
+{
+ struct ppp_option_data data;
+
+ data.ptr = opt_ptr;
+ data.length = opt_len;
+ data.transmit = for_transmit;
+ return ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0;
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(unit, isopen, isup)
+ int unit, isopen, isup;
+{
+ int x;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ return;
+ }
+ x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
+ x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+}
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(unit)
+ int unit;
+{
+ int x;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
+ return 0;
+ }
+ return x & SC_DC_FERROR;
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp, maxcid)
+ int u, vjcomp, cidcomp, maxcid;
+{
+ u_int x;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ return 0;
+ }
+ x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
+ x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+#ifndef SC_ENABLE_IP
+#define SC_ENABLE_IP 0x100 /* compat for old versions of kernel code */
+#endif
+
+int
+sifup(u)
+ int u;
+{
+ struct ifreq ifr;
+ u_int x;
+ struct npioctl npi;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ npi.protocol = PPP_IP;
+ npi.mode = NPMODE_PASS;
+ if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
+ if (errno != ENOTTY) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
+ return 0;
+ }
+ /* for backwards compatibility */
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ return 0;
+ }
+ x |= SC_ENABLE_IP;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(u)
+ int u;
+{
+ struct ifreq ifr;
+ u_int x;
+ int rv;
+ struct npioctl npi;
+
+ rv = 1;
+ npi.protocol = PPP_IP;
+ npi.mode = NPMODE_ERROR;
+ if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
+ if (errno != ENOTTY) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
+ rv = 0;
+ } else {
+ /* backwards compatibility */
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ rv = 0;
+ } else {
+ x &= ~SC_ENABLE_IP;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ rv = 0;
+ }
+ }
+ }
+ }
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ rv = 0;
+ } else {
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ rv = 0;
+ }
+ }
+ return rv;
+}
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family); \
+ addr.sa_len = sizeof(addr);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+ int u;
+ u_int32_t o, h, m;
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ if (m != 0) {
+ SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+ } else
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+ if (errno != EEXIST) {
+ syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ return 0;
+ }
+ syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+ int u;
+ u_int32_t o, h;
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+ int u;
+ u_int32_t g;
+{
+ return dodefaultroute(g, 's');
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+ int u;
+ u_int32_t g;
+{
+ return dodefaultroute(g, 'c');
+}
+
+/*
+ * dodefaultroute - talk to a routing socket to add/delete a default route.
+ */
+int
+dodefaultroute(g, cmd)
+ u_int32_t g;
+ int cmd;
+{
+ int routes;
+ struct {
+ struct rt_msghdr hdr;
+ struct sockaddr_in dst;
+ struct sockaddr_in gway;
+ struct sockaddr_in mask;
+ } rtmsg;
+
+ if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ syslog(LOG_ERR, "%cifdefaultroute: opening routing socket: %m", cmd);
+ return 0;
+ }
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+ rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
+ rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
+ rtmsg.hdr.rtm_version = RTM_VERSION;
+ rtmsg.hdr.rtm_seq = ++rtm_seq;
+ rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ rtmsg.dst.sin_len = sizeof(rtmsg.dst);
+ rtmsg.dst.sin_family = AF_INET;
+ rtmsg.gway.sin_len = sizeof(rtmsg.gway);
+ rtmsg.gway.sin_family = AF_INET;
+ rtmsg.gway.sin_addr.s_addr = g;
+ rtmsg.mask.sin_len = sizeof(rtmsg.dst);
+ rtmsg.mask.sin_family = AF_INET;
+
+ rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
+ if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
+ syslog(LOG_ERR, "%s default route: %m", cmd=='s'? "add": "delete");
+ close(routes);
+ return 0;
+ }
+
+ close(routes);
+ return 1;
+}
+
+#if RTM_VERSION >= 3
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+static struct {
+ struct rt_msghdr hdr;
+ struct sockaddr_inarp dst;
+ struct sockaddr_dl hwa;
+ char extra[128];
+} arpmsg;
+
+static int arpmsg_valid;
+
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ int routes;
+ int l;
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ memset(&arpmsg, 0, sizeof(arpmsg));
+ if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
+ return 0;
+ }
+
+ arpmsg.hdr.rtm_type = RTM_ADD;
+ arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
+ arpmsg.hdr.rtm_version = RTM_VERSION;
+ arpmsg.hdr.rtm_seq = ++rtm_seq;
+ arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ arpmsg.hdr.rtm_inits = RTV_EXPIRE;
+ arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
+ arpmsg.dst.sin_family = AF_INET;
+ arpmsg.dst.sin_addr.s_addr = hisaddr;
+ arpmsg.dst.sin_other = SIN_PROXY;
+
+ arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+ + arpmsg.hwa.sdl_len;
+ if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+ syslog(LOG_ERR, "add proxy arp entry: %m");
+ close(routes);
+ return 0;
+ }
+
+ close(routes);
+ arpmsg_valid = 1;
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ int routes;
+
+ if (!arpmsg_valid)
+ return 0;
+ arpmsg_valid = 0;
+
+ arpmsg.hdr.rtm_type = RTM_DELETE;
+ arpmsg.hdr.rtm_seq = ++rtm_seq;
+
+ if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
+ return 0;
+ }
+
+ if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+ syslog(LOG_ERR, "delete proxy arp entry: %m");
+ close(routes);
+ return 0;
+ }
+
+ close(routes);
+ return 1;
+}
+
+#else /* RTM_VERSION */
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+ struct {
+ struct sockaddr_dl sdl;
+ char space[128];
+ } dls;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &dls.sdl)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
+ arpreq.arp_ha.sa_family = AF_UNSPEC;
+ BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+#endif /* RTM_VERSION */
+
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_int32_t ipaddr;
+ struct sockaddr_dl *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_int32_t ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+ ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ /*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+ && ifr->ifr_addr.sa_family == AF_LINK) {
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *) &ifr->ifr_addr;
+ BCOPY(dla, hwaddr, dla->sdl_len);
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ return 0;
+}
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u_int32_t
+GetMask(addr)
+ u_int32_t addr;
+{
+ u_int32_t mask, nmask, ina;
+ struct ifreq *ifr, *ifend, ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ addr = ntohl(addr);
+ if (IN_CLASSA(addr)) /* determine network mask for address class */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+
+ /*
+ * Scan through the system's network interfaces.
+ */
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
+ return mask;
+ }
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+ ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
+ /*
+ * Check the interface's internet address.
+ */
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ntohl(ina) & nmask) != (addr & nmask))
+ continue;
+ /*
+ * Check that the interface is up, and not point-to-point or loopback.
+ */
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+ != IFF_UP)
+ continue;
+ /*
+ * Get its netmask and OR it into our mask.
+ */
+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
+ }
+
+ return mask;
+}
+
+/*
+ * lock - create a lock file for the named lock device
+ */
+#define LOCK_PREFIX "/var/spool/lock/LCK.."
+
+int
+lock(dev)
+ char *dev;
+{
+ char hdb_lock_buffer[12];
+ int fd, pid, n;
+ char *p;
+
+ if ((p = strrchr(dev, '/')) != NULL)
+ dev = p + 1;
+ lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
+ if (lock_file == NULL)
+ novm("lock file name");
+ strcat(strcpy(lock_file, LOCK_PREFIX), dev);
+
+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+ if (errno == EEXIST
+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
+ /* Read the lock file to find out who has the device locked */
+ n = read(fd, hdb_lock_buffer, 11);
+ if (n > 0) {
+ hdb_lock_buffer[n] = 0;
+ pid = atoi(hdb_lock_buffer);
+ }
+ if (n <= 0) {
+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
+ close(fd);
+ } else {
+ if (kill(pid, 0) == -1 && errno == ESRCH) {
+ /* pid no longer exists - remove the lock file */
+ if (unlink(lock_file) == 0) {
+ close(fd);
+ syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
+ dev, pid);
+ continue;
+ } else
+ syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
+ dev);
+ } else
+ syslog(LOG_NOTICE, "Device %s is locked by pid %d",
+ dev, pid);
+ }
+ close(fd);
+ } else
+ syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ return -1;
+ }
+
+ sprintf(hdb_lock_buffer, "%10d\n", getpid());
+ write(fd, hdb_lock_buffer, 11);
+
+ close(fd);
+ return 0;
+}
+
+/*
+ * unlock - remove our lockfile
+ */
+unlock()
+{
+ if (lock_file) {
+ unlink(lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ }
+}
diff --git a/usr.sbin/pppd/upap.c b/usr.sbin/pppd/upap.c
new file mode 100644
index 00000000000..6d4e0658076
--- /dev/null
+++ b/usr.sbin/pppd/upap.c
@@ -0,0 +1,590 @@
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: upap.c,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "upap.h"
+
+
+upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
+
+
+static void upap_timeout __P((caddr_t));
+static void upap_reqtimeout __P((caddr_t));
+static void upap_rauthreq __P((upap_state *, u_char *, int, int));
+static void upap_rauthack __P((upap_state *, u_char *, int, int));
+static void upap_rauthnak __P((upap_state *, u_char *, int, int));
+static void upap_sauthreq __P((upap_state *));
+static void upap_sresp __P((upap_state *, int, int, char *, int));
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+void
+upap_init(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ u->us_unit = unit;
+ u->us_user = NULL;
+ u->us_userlen = 0;
+ u->us_passwd = NULL;
+ u->us_passwdlen = 0;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+ u->us_id = 0;
+ u->us_timeouttime = UPAP_DEFTIMEOUT;
+ u->us_maxtransmits = 10;
+ u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void
+upap_authwithpeer(unit, user, password)
+ int unit;
+ char *user, *password;
+{
+ upap_state *u = &upap[unit];
+
+ /* Save the username and password we're given */
+ u->us_user = user;
+ u->us_userlen = strlen(user);
+ u->us_passwd = password;
+ u->us_passwdlen = strlen(password);
+ u->us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (u->us_clientstate == UPAPCS_INITIAL ||
+ u->us_clientstate == UPAPCS_PENDING) {
+ u->us_clientstate = UPAPCS_PENDING;
+ return;
+ }
+
+ upap_sauthreq(u); /* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void
+upap_authpeer(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ /* Lower layer up yet? */
+ if (u->us_serverstate == UPAPSS_INITIAL ||
+ u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_PENDING;
+ return;
+ }
+
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0)
+ TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout);
+}
+
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void
+upap_timeout(arg)
+ caddr_t arg;
+{
+ upap_state *u = (upap_state *) arg;
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ)
+ return;
+
+ if (u->us_transmits >= u->us_maxtransmits) {
+ /* give up in disgust */
+ syslog(LOG_ERR, "No response to PAP authenticate-requests");
+ u->us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+ return;
+ }
+
+ upap_sauthreq(u); /* Send Authenticate-Request */
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void
+upap_reqtimeout(arg)
+ caddr_t arg;
+{
+ upap_state *u = (upap_state *) arg;
+
+ if (u->us_serverstate != UPAPSS_LISTEN)
+ return; /* huh?? */
+
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+void
+upap_lowerup(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_INITIAL)
+ u->us_clientstate = UPAPCS_CLOSED;
+ else if (u->us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(u); /* send an auth-request */
+ }
+
+ if (u->us_serverstate == UPAPSS_INITIAL)
+ u->us_serverstate = UPAPSS_CLOSED;
+ else if (u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0)
+ TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout);
+ }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+void
+upap_lowerdown(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
+ UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
+ if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+ UNTIMEOUT(upap_reqtimeout, (caddr_t) u);
+
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen. In any case, pretend lower layer went down.
+ */
+void
+upap_protrej(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) {
+ syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
+ auth_withpeer_fail(unit, PPP_PAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(unit, PPP_PAP);
+ }
+ upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+void
+upap_input(unit, inpacket, l)
+ int unit;
+ u_char *inpacket;
+ int l;
+{
+ upap_state *u = &upap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < UPAP_HEADERLEN) {
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < UPAP_HEADERLEN) {
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."));
+ return;
+ }
+ if (len > l) {
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
+ return;
+ }
+ len -= UPAP_HEADERLEN;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case UPAP_AUTHREQ:
+ upap_rauthreq(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHACK:
+ upap_rauthack(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHNAK:
+ upap_rauthnak(u, inp, id, len);
+ break;
+
+ default: /* XXX Need code reject */
+ break;
+ }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void
+upap_rauthreq(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char ruserlen, rpasswdlen;
+ char *ruser, *rpasswd;
+ int retcode;
+ char *msg;
+ int msglen;
+
+ UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
+
+ if (u->us_serverstate < UPAPSS_LISTEN)
+ return;
+
+ /*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (u->us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (u->us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
+ * Parse user/passwd.
+ */
+ if (len < sizeof (u_char)) {
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ return;
+ }
+ GETCHAR(ruserlen, inp);
+ len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+ if (len < 0) {
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ return;
+ }
+ ruser = (char *) inp;
+ INCPTR(ruserlen, inp);
+ GETCHAR(rpasswdlen, inp);
+ if (len < rpasswdlen) {
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ return;
+ }
+ rpasswd = (char *) inp;
+
+ /*
+ * Check the username and password given.
+ */
+ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+ rpasswdlen, &msg, &msglen);
+
+ upap_sresp(u, retcode, id, msg, msglen);
+
+ if (retcode == UPAP_AUTHACK) {
+ u->us_serverstate = UPAPSS_OPEN;
+ auth_peer_success(u->us_unit, PPP_PAP);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ }
+
+ if (u->us_reqtimeout > 0)
+ UNTIMEOUT(upap_reqtimeout, (caddr_t) u);
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void
+upap_rauthack(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char msglen;
+ char *msg;
+
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < sizeof (u_char)) {
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
+ return;
+ }
+ GETCHAR(msglen, inp);
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+
+ u->us_clientstate = UPAPCS_OPEN;
+
+ auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nakk.
+ */
+static void
+upap_rauthnak(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char msglen;
+ char *msg;
+
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < sizeof (u_char)) {
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
+ return;
+ }
+ GETCHAR(msglen, inp);
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+
+ u->us_clientstate = UPAPCS_BADAUTH;
+
+ syslog(LOG_ERR, "PAP authentication failed");
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void
+upap_sauthreq(u)
+ upap_state *u;
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
+ u->us_userlen + u->us_passwdlen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(UPAP_AUTHREQ, outp);
+ PUTCHAR(++u->us_id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(u->us_userlen, outp);
+ BCOPY(u->us_user, outp, u->us_userlen);
+ INCPTR(u->us_userlen, outp);
+ PUTCHAR(u->us_passwdlen, outp);
+ BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+ output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
+
+ TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
+ ++u->us_transmits;
+ u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void
+upap_sresp(u, code, id, msg, msglen)
+ upap_state *u;
+ u_char code, id;
+ char *msg;
+ int msglen;
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+ outp = outpacket_buf;
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(msglen, outp);
+ BCOPY(msg, outp, msglen);
+ output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
+}
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+char *upap_codenames[] = {
+ "AuthReq", "AuthAck", "AuthNak"
+};
+
+int
+upap_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len;
+ int mlen, ulen, wlen;
+ char *user, *pwd, *msg;
+ u_char *pstart;
+
+ if (plen < UPAP_HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < UPAP_HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
+ printer(arg, " %s", upap_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= UPAP_HEADERLEN;
+ switch (code) {
+ case UPAP_AUTHREQ:
+ if (len < 1)
+ break;
+ ulen = p[0];
+ if (len < ulen + 2)
+ break;
+ wlen = p[ulen + 1];
+ if (len < ulen + wlen + 2)
+ break;
+ user = (char *) (p + 1);
+ pwd = (char *) (p + ulen + 2);
+ p += ulen + wlen + 2;
+ len -= ulen + wlen + 2;
+ printer(arg, " user=");
+ print_string(user, ulen, printer, arg);
+ printer(arg, " password=");
+ print_string(pwd, wlen, printer, arg);
+ break;
+ case UPAP_AUTHACK:
+ case UPAP_AUTHNAK:
+ if (len < 1)
+ break;
+ mlen = p[0];
+ if (len < mlen + 1)
+ break;
+ msg = (char *) (p + 1);
+ p += mlen + 1;
+ len -= mlen + 1;
+ printer(arg, "msg=");
+ print_string(msg, mlen, printer, arg);
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
diff --git a/usr.sbin/pppd/upap.h b/usr.sbin/pppd/upap.h
new file mode 100644
index 00000000000..c0eb75070f5
--- /dev/null
+++ b/usr.sbin/pppd/upap.h
@@ -0,0 +1,93 @@
+/*
+ * upap.h - User/Password Authentication Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: upap.h,v 1.1.1.1 1995/10/18 08:48:00 deraadt Exp $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ * UPAP codes.
+ */
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
+
+
+/*
+ * Each interface is described by upap structure.
+ */
+typedef struct upap_state {
+ int us_unit; /* Interface unit number */
+ char *us_user; /* User */
+ int us_userlen; /* User length */
+ char *us_passwd; /* Password */
+ int us_passwdlen; /* Password length */
+ int us_clientstate; /* Client state */
+ int us_serverstate; /* Server state */
+ u_char us_id; /* Current id */
+ int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
+ int us_reqtimeout; /* Time to wait for auth-req from peer */
+} upap_state;
+
+
+/*
+ * Client states.
+ */
+#define UPAPCS_INITIAL 0 /* Connection down */
+#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN 4 /* We've received an Ack */
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */
+
+/*
+ * Server states.
+ */
+#define UPAPSS_INITIAL 0 /* Connection down */
+#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
+#define UPAPSS_OPEN 4 /* We've sent an Ack */
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
+
+
+/*
+ * Timeouts.
+ */
+#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */
+#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
+
+
+extern upap_state upap[];
+
+void upap_init __P((int));
+void upap_authwithpeer __P((int, char *, char *));
+void upap_authpeer __P((int));
+void upap_lowerup __P((int));
+void upap_lowerdown __P((int));
+void upap_input __P((int, u_char *, int));
+void upap_protrej __P((int));
+int upap_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
diff --git a/usr.sbin/pstat/Makefile b/usr.sbin/pstat/Makefile
new file mode 100644
index 00000000000..72736830aae
--- /dev/null
+++ b/usr.sbin/pstat/Makefile
@@ -0,0 +1,14 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $
+
+PROG= pstat
+MAN= pstat.8
+BINGRP= kmem
+BINMODE=2555
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+.if (${MACHINE_ARCH} == "m68k")
+CFLAGS+=-D${MACHINE}
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pstat/pstat.8 b/usr.sbin/pstat/pstat.8
new file mode 100644
index 00000000000..fd63f690d4f
--- /dev/null
+++ b/usr.sbin/pstat/pstat.8
@@ -0,0 +1,331 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 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.
+.\"
+.\" from: @(#)pstat.8 8.4 (Berkeley) 4/19/94
+.\" $Id: pstat.8,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $
+.\"
+.Dd April 19, 1994
+.Dt PSTAT 8
+.Os BSD 4
+.Sh NAME
+.Nm pstat
+.Nd display system data structures
+.Sh SYNOPSIS
+.Nm pstat
+.Op Fl Tfknstv
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Sh DESCRIPTION
+.Nm Pstat
+displays open file entry, swap space utilization,
+terminal state, and vnode data structures.
+If
+.Ar corefile
+is given, the information is sought there, otherwise
+in
+.Pa /dev/kmem .
+The required namelist is taken from
+.Pa /netbsd
+unless
+.Ar system
+is specified.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl T
+Prints the number of used and free slots in the several system tables
+and is useful for checking to see how large system tables have become
+if the system is under heavy load.
+.It Fl f
+Print the open file table with these headings:
+.Bl -tag -width indent
+.It LOC
+The core location of this table entry.
+.It TYPE
+The type of object the file table entry points to.
+.It FLG
+Miscellaneous state variables encoded thus:
+.Bl -tag -width indent
+.It R
+open for reading
+.It W
+open for writing
+.It A
+open for appending
+.It S
+shared lock present
+.It X
+exclusive lock present
+.It I
+signal pgrp when data ready
+.El
+.It CNT
+Number of processes that know this open file.
+.It MSG
+Number of messages outstanding for this file.
+.It DATA
+The location of the vnode table entry or socket structure for this file.
+.It OFFSET
+The file offset (see
+.Xr lseek 2 ) .
+.El
+.It Fl k
+Use 1K-byte blocks.
+.It Fl n
+Print devices by major/minor number rather than by name.
+.It Fl s
+Print information about swap space usage on all the
+swap areas compiled into the kernel.
+The first column is the device name of the partition. The next column is
+the total space available in the partition. The
+.Ar Used
+column indicates the total blocks used so far; the
+.Ar Available
+column indicates how much space is remaining on each partition.
+The
+.Ar Capacity
+reports the percentage of space used.
+.Pp
+If more than one partition is configured into the system, totals for all
+of the statistics will be reported in the final line of the report.
+.It Fl t
+Print table for terminals
+with these headings:
+.Bl -tag -width indent
+.It RAW
+Number of characters in raw input queue.
+.It CAN
+Number of characters in canonicalized input queue.
+.It OUT
+Number of characters in putput queue.
+.It MODE
+See
+.Xr tty 4 .
+.It ADDR
+Physical device address.
+.It DEL
+Number of delimiters (newlines) in canonicalized input queue.
+.It COL
+Calculated column position of terminal.
+.It STATE
+Miscellaneous state variables encoded thus:
+.Bl -tag -width indent
+.It T
+delay timeout in progress
+.It W
+waiting for open to complete
+.It O
+open
+.It F
+outq has been flushed during DMA
+.It C
+carrier is on
+.It B
+busy doing output
+.It A
+process is awaiting output
+.It X
+open for exclusive use
+.It S
+output stopped
+.It H
+hangup on close
+.El
+.It PGRP
+Process group for which this is controlling terminal.
+.It DISC
+Line discipline; blank is old tty
+OTTYDISC
+or
+.Ql new tty
+for
+NTTYDISC
+or
+.Ql net
+for
+NETLDISC
+(see
+.Xr bk 4 ) .
+.El
+.It Fl v
+Print the active vnodes. Each group of vnodes corresponding
+to a particular filesystem is preceded by a two line header. The
+first line consists of the following:
+.Pp
+.Df I
+.No *** MOUNT Em fstype from
+on
+.Em on fsflags
+.De
+.Pp
+where
+.Em fstype
+is one of
+.Em ufs , nfs , mfs , or pc ;
+.Em from
+is the filesystem is mounted from;
+.Em on
+is the directory
+the filesystem is mounted on; and
+.Em fsflags
+is a list
+of optional flags applied to the mount (see
+.Xr mount 8 ) .
+.The second line is a header for the individual fields ,
+the first part of which are fixed, and the second part are filesystem
+type specific. The headers common to all vnodes are:
+.Bl -tag -width indent
+.It ADDR
+Location of this vnode.
+.It TYP
+File type.
+.It VFLAG
+.Pp
+A list of letters representing vnode flags:
+.Bl -tag -width indent
+.It R
+\- VROOT
+.It T
+\- VTEXT
+.It L
+\- VXLOCK
+.It W
+\- VXWANT
+.It E
+\- VEXLOCK
+.It S
+\- VSHLOCK
+.It T
+\- VLWAIT
+.It A
+\- VALIASED
+.It B
+\- VBWAIT
+.El
+.Pp
+.It USE
+The number of references to this vnode.
+.It HOLD
+The number of I/O buffers held by this vnode.
+.It FILEID
+The vnode fileid.
+In the case of
+.Em ufs
+this is the inode number.
+.It IFLAG
+Miscellaneous filesystem specific state variables encoded thus:
+.Bl -tag -width indent
+.It "For ufs:"
+.Pp
+.Bl -tag -width indent
+.It L
+locked
+.It U
+update time
+.Pq Xr fs 5
+must be corrected
+.It A
+access time must be corrected
+.It W
+wanted by another process (L flag is on)
+.It C
+changed time must be corrected
+.It S
+shared lock applied
+.It E
+exclusive lock applied
+.It Z
+someone waiting for a lock
+.It M
+contains modifications
+.It R
+has a rename in progress
+.El
+.It "For nfs:"
+.Bl -tag -width indent
+.It W
+waiting for I/O buffer flush to complete
+.It P
+I/O buffers being flushed
+.It M
+locally modified data exists
+.It E
+an earlier write failed
+.It X
+non-cacheable lease (nqnfs)
+.It O
+write lease (nqnfs)
+.It G
+lease was evicted (nqnfs)
+.El
+.El
+.It SIZ/RDEV
+Number of bytes in an ordinary file, or
+major and minor device of special file.
+.El
+.El
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environmental variable
+.Ev BLOCKSIZE
+is set, and the
+.Fl k
+option is not specified, the block counts will be displayed in units of that
+size block.
+.El
+.Sh FILES
+.Bl -tag -width /dev/kmemxxx -compact
+.It Pa /netbsd
+namelist
+.It Pa /dev/kmem
+default source of tables
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr systat 1 ,
+.Xr stat 2 ,
+.Xr fs 5 ,
+.Xr iostat 8 ,
+.Xr vmstat 8
+.Rs
+.Rt Tn UNIX Rt Implementation ,
+.Ra K. Thompson
+.Re
+.Sh BUGS
+Swap statistics are reported for all swap partitions compiled into the kernel,
+regardless of whether those partitions are being used.
+.Pp
+Does not understand NFS swap servers.
+.Sh HISTORY
+The
+.Nm pstat
+command appeared in 4.0BSD.
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
new file mode 100644
index 00000000000..ada59d7a2ce
--- /dev/null
+++ b/usr.sbin/pstat/pstat.c
@@ -0,0 +1,1159 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/* from: static char sccsid[] = "@(#)pstat.c 8.9 (Berkeley) 2/16/94"; */
+static char *rcsid = "$Id: pstat.c,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/map.h>
+#include <sys/ucred.h>
+#define _KERNEL
+#include <sys/file.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#define NFS
+#include <sys/mount.h>
+#undef NFS
+#undef _KERNEL
+#include <sys/stat.h>
+#include <nfs/nfsnode.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct nlist nl[] = {
+#define VM_SWAPMAP 0
+ { "_swapmap" }, /* list of free swap areas */
+#define VM_NSWAPMAP 1
+ { "_nswapmap" },/* size of the swap map */
+#define VM_SWDEVT 2
+ { "_swdevt" }, /* list of swap devices and sizes */
+#define VM_NSWAP 3
+ { "_nswap" }, /* size of largest swap device */
+#define VM_NSWDEV 4
+ { "_nswdev" }, /* number of swap devices */
+#define VM_DMMAX 5
+ { "_dmmax" }, /* maximum size of a swap block */
+#define V_MOUNTLIST 6
+ { "_mountlist" }, /* address of head of mount list. */
+#define V_NUMV 7
+ { "_numvnodes" },
+#define FNL_NFILE 8
+ {"_nfiles"},
+#define FNL_MAXFILE 9
+ {"_maxfiles"},
+#define NLMANDATORY FNL_MAXFILE /* names up to here are mandatory */
+#define VM_NISWAP NLMANDATORY + 1
+ { "_niswap" },
+#define VM_NISWDEV NLMANDATORY + 2
+ { "_niswdev" },
+#define SCONS NLMANDATORY + 3
+ { "_constty" },
+#define SPTY NLMANDATORY + 4
+ { "_pt_tty" },
+#define SNPTY NLMANDATORY + 5
+ { "_npty" },
+
+#ifdef sparc
+#define SZS (SNPTY+1)
+ { "_zs_tty" },
+#define SCZS (SNPTY+2)
+ { "_zscd" },
+#endif
+
+#ifdef hp300
+#define SDCA (SNPTY+1)
+ { "_dca_tty" },
+#define SNDCA (SNPTY+2)
+ { "_ndca" },
+#define SDCM (SNPTY+3)
+ { "_dcm_tty" },
+#define SNDCM (SNPTY+4)
+ { "_ndcm" },
+#define SDCL (SNPTY+5)
+ { "_dcl_tty" },
+#define SNDCL (SNPTY+6)
+ { "_ndcl" },
+#define SITE (SNPTY+7)
+ { "_ite_tty" },
+#define SNITE (SNPTY+8)
+ { "_nite" },
+#endif
+
+#ifdef mips
+#define SDC (SNPTY+1)
+ { "_dc_tty" },
+#define SNDC (SNPTY+2)
+ { "_dc_cnt" },
+#endif
+
+#ifdef i386
+#define SPC (SNPTY+1)
+ { "_pc_tty" },
+#define SCPC (SNPTY+2)
+ { "_pccd" },
+#define SCOM (SNPTY+3)
+ { "_com_tty" },
+#define SCCOM (SNPTY+4)
+ { "_comcd" },
+#endif
+#ifdef amiga
+#define SSER (SNPTY + 1)
+ { "_ser_tty" },
+#define SCSER (SNPTY + 2)
+ { "_sercd" },
+#define SITE (SNPTY + 3)
+ { "_ite_tty" },
+#define SCITE (SNPTY + 4)
+ { "_itecd" },
+#define SMFCS (SNPTY + 5)
+ { "_mfcs_tty" },
+#define SCMFCS (SNPTY + 6)
+ { "_mfcscd" },
+#endif
+
+ { "" }
+};
+
+int usenumflag;
+int totalflag;
+int kflag;
+char *nlistf = NULL;
+char *memf = NULL;
+kvm_t *kd;
+
+#define SVAR(var) __STRING(var) /* to force expansion */
+#define KGET(idx, var) \
+ KGET1(idx, &var, sizeof(var), SVAR(var))
+#define KGET1(idx, p, s, msg) \
+ KGET2(nl[idx].n_value, p, s, msg)
+#define KGET2(addr, p, s, msg) \
+ if (kvm_read(kd, (u_long)(addr), p, s) != s) \
+ warnx("cannot read %s: %s", msg, kvm_geterr(kd))
+#define KGETRET(addr, p, s, msg) \
+ if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
+ warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
+ return (0); \
+ }
+
+void filemode __P((void));
+int getfiles __P((char **, int *));
+struct mount *
+ getmnt __P((struct mount *));
+struct e_vnode *
+ kinfo_vnodes __P((int *));
+struct e_vnode *
+ loadvnodes __P((int *));
+void mount_print __P((struct mount *));
+void nfs_header __P((void));
+int nfs_print __P((struct vnode *));
+void swapmode __P((void));
+void ttymode __P((void));
+void ttyprt __P((struct tty *, int));
+void ttytype __P((char *, int, int));
+void ttytype_newcf __P((char *, int, int));
+void ttytype_oldcf __P((char *, int, int));
+void ufs_header __P((void));
+int ufs_print __P((struct vnode *));
+void usage __P((void));
+void vnode_header __P((void));
+void vnode_print __P((struct vnode *, struct vnode *));
+void vnodemode __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, i, quit, ret;
+ int fileflag, swapflag, ttyflag, vnodeflag;
+ char buf[_POSIX2_LINE_MAX];
+
+ fileflag = swapflag = ttyflag = vnodeflag = 0;
+ while ((ch = getopt(argc, argv, "TM:N:fiknstv")) != -1)
+ switch (ch) {
+ case 'f':
+ fileflag = 1;
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'n':
+ usenumflag = 1;
+ break;
+ case 's':
+ swapflag = 1;
+ break;
+ case 'T':
+ totalflag = 1;
+ break;
+ case 't':
+ ttyflag = 1;
+ break;
+ case 'k':
+ kflag = 1;
+ break;
+ case 'v':
+ case 'i': /* Backward compatibility. */
+ vnodeflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ (void)setgid(getgid());
+
+ if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
+ errx(1, "kvm_openfiles: %s", buf);
+ if ((ret = kvm_nlist(kd, nl)) != 0) {
+ if (ret == -1)
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+ for (i = quit = 0; i <= NLMANDATORY; i++)
+ if (!nl[i].n_value) {
+ quit = 1;
+ warnx("undefined symbol: %s\n", nl[i].n_name);
+ }
+ if (quit)
+ exit(1);
+ }
+ if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
+ usage();
+ if (fileflag || totalflag)
+ filemode();
+ if (vnodeflag || totalflag)
+ vnodemode();
+ if (ttyflag)
+ ttymode();
+ if (swapflag || totalflag)
+ swapmode();
+ exit (0);
+}
+
+struct e_vnode {
+ struct vnode *avnode;
+ struct vnode vnode;
+};
+
+void
+vnodemode()
+{
+ register struct e_vnode *e_vnodebase, *endvnode, *evp;
+ register struct vnode *vp;
+ register struct mount *maddr, *mp;
+ int numvnodes;
+
+ e_vnodebase = loadvnodes(&numvnodes);
+ if (totalflag) {
+ (void)printf("%7d vnodes\n", numvnodes);
+ return;
+ }
+ endvnode = e_vnodebase + numvnodes;
+ (void)printf("%d active vnodes\n", numvnodes);
+
+
+#define ST mp->mnt_stat
+ maddr = NULL;
+ for (evp = e_vnodebase; evp < endvnode; evp++) {
+ vp = &evp->vnode;
+ if (vp->v_mount != maddr) {
+ /*
+ * New filesystem
+ */
+ if ((mp = getmnt(vp->v_mount)) == NULL)
+ continue;
+ maddr = vp->v_mount;
+ mount_print(mp);
+ vnode_header();
+ if (!strncmp(ST.f_fstypename, MOUNT_UFS, MFSNAMELEN) ||
+ !strncmp(ST.f_fstypename, MOUNT_MFS, MFSNAMELEN)) {
+ ufs_header();
+ } else if (!strncmp(ST.f_fstypename, MOUNT_NFS,
+ MFSNAMELEN)) {
+ nfs_header();
+ }
+ (void)printf("\n");
+ }
+ vnode_print(evp->avnode, vp);
+ if (!strncmp(ST.f_fstypename, MOUNT_UFS, MFSNAMELEN) ||
+ !strncmp(ST.f_fstypename, MOUNT_MFS, MFSNAMELEN)) {
+ ufs_print(vp);
+ } else if (!strncmp(ST.f_fstypename, MOUNT_NFS, MFSNAMELEN)) {
+ nfs_print(vp);
+ }
+ (void)printf("\n");
+ }
+ free(e_vnodebase);
+}
+
+void
+vnode_header()
+{
+ (void)printf("ADDR TYP VFLAG USE HOLD");
+}
+
+void
+vnode_print(avnode, vp)
+ struct vnode *avnode;
+ struct vnode *vp;
+{
+ char *type, flags[16];
+ char *fp = flags;
+ register int flag;
+
+ /*
+ * set type
+ */
+ switch(vp->v_type) {
+ case VNON:
+ type = "non"; break;
+ case VREG:
+ type = "reg"; break;
+ case VDIR:
+ type = "dir"; break;
+ case VBLK:
+ type = "blk"; break;
+ case VCHR:
+ type = "chr"; break;
+ case VLNK:
+ type = "lnk"; break;
+ case VSOCK:
+ type = "soc"; break;
+ case VFIFO:
+ type = "fif"; break;
+ case VBAD:
+ type = "bad"; break;
+ default:
+ type = "unk"; break;
+ }
+ /*
+ * gather flags
+ */
+ flag = vp->v_flag;
+ if (flag & VROOT)
+ *fp++ = 'R';
+ if (flag & VTEXT)
+ *fp++ = 'T';
+ if (flag & VSYSTEM)
+ *fp++ = 'S';
+ if (flag & VXLOCK)
+ *fp++ = 'L';
+ if (flag & VXWANT)
+ *fp++ = 'W';
+ if (flag & VBWAIT)
+ *fp++ = 'B';
+ if (flag & VALIASED)
+ *fp++ = 'A';
+ if (flag == 0)
+ *fp++ = '-';
+ *fp = '\0';
+ (void)printf("%8x %s %5s %4d %4d",
+ avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
+}
+
+void
+ufs_header()
+{
+ (void)printf(" FILEID IFLAG RDEV|SZ");
+}
+
+int
+ufs_print(vp)
+ struct vnode *vp;
+{
+ register int flag;
+ struct inode inode, *ip = &inode;
+ char flagbuf[16], *flags = flagbuf;
+ char *name;
+ mode_t type;
+
+ KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
+ flag = ip->i_flag;
+ if (flag & IN_LOCKED)
+ *flags++ = 'L';
+ if (flag & IN_WANTED)
+ *flags++ = 'W';
+ if (flag & IN_RENAME)
+ *flags++ = 'R';
+ if (flag & IN_UPDATE)
+ *flags++ = 'U';
+ if (flag & IN_ACCESS)
+ *flags++ = 'A';
+ if (flag & IN_CHANGE)
+ *flags++ = 'C';
+ if (flag & IN_MODIFIED)
+ *flags++ = 'M';
+ if (flag & IN_SHLOCK)
+ *flags++ = 'S';
+ if (flag & IN_EXLOCK)
+ *flags++ = 'E';
+ if (flag & IN_LWAIT)
+ *flags++ = 'Z';
+ if (flag == 0)
+ *flags++ = '-';
+ *flags = '\0';
+
+ (void)printf(" %6d %5s", ip->i_number, flagbuf);
+ type = ip->i_mode & S_IFMT;
+ if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+ if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL))
+ (void)printf(" %2d,%-2d",
+ major(ip->i_rdev), minor(ip->i_rdev));
+ else
+ (void)printf(" %7s", name);
+ else
+ (void)printf(" %7qd", ip->i_size);
+ return (0);
+}
+
+void
+nfs_header()
+{
+ (void)printf(" FILEID NFLAG RDEV|SZ");
+}
+
+int
+nfs_print(vp)
+ struct vnode *vp;
+{
+ struct nfsnode nfsnode, *np = &nfsnode;
+ char flagbuf[16], *flags = flagbuf;
+ register int flag;
+ char *name;
+ mode_t type;
+
+ KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
+ flag = np->n_flag;
+ if (flag & NFLUSHWANT)
+ *flags++ = 'W';
+ if (flag & NFLUSHINPROG)
+ *flags++ = 'P';
+ if (flag & NMODIFIED)
+ *flags++ = 'M';
+ if (flag & NWRITEERR)
+ *flags++ = 'E';
+ if (flag & NQNFSNONCACHE)
+ *flags++ = 'X';
+ if (flag & NQNFSWRITE)
+ *flags++ = 'O';
+ if (flag & NQNFSEVICTED)
+ *flags++ = 'G';
+ if (flag == 0)
+ *flags++ = '-';
+ *flags = '\0';
+
+#define VT np->n_vattr
+ (void)printf(" %6d %5s", VT.va_fileid, flagbuf);
+ type = VT.va_mode & S_IFMT;
+ if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
+ if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
+ (void)printf(" %2d,%-2d",
+ major(VT.va_rdev), minor(VT.va_rdev));
+ else
+ (void)printf(" %7s", name);
+ else
+ (void)printf(" %7qd", np->n_size);
+ return (0);
+}
+
+/*
+ * Given a pointer to a mount structure in kernel space,
+ * read it in and return a usable pointer to it.
+ */
+struct mount *
+getmnt(maddr)
+ struct mount *maddr;
+{
+ static struct mtab {
+ struct mtab *next;
+ struct mount *maddr;
+ struct mount mount;
+ } *mhead = NULL;
+ register struct mtab *mt;
+
+ for (mt = mhead; mt != NULL; mt = mt->next)
+ if (maddr == mt->maddr)
+ return (&mt->mount);
+ if ((mt = malloc(sizeof(struct mtab))) == NULL)
+ err(1, NULL);
+ KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
+ mt->maddr = maddr;
+ mt->next = mhead;
+ mhead = mt;
+ return (&mt->mount);
+}
+
+void
+mount_print(mp)
+ struct mount *mp;
+{
+ register int flags;
+ char *type;
+
+#define ST mp->mnt_stat
+ (void)printf("*** MOUNT ");
+ (void)printf("%.*s %s on %s", MFSNAMELEN, ST.f_fstypename,
+ ST.f_mntfromname, ST.f_mntonname);
+ if (flags = mp->mnt_flag) {
+ char *comma = "(";
+
+ putchar(' ');
+ /* user visable flags */
+ if (flags & MNT_RDONLY) {
+ (void)printf("%srdonly", comma);
+ flags &= ~MNT_RDONLY;
+ comma = ",";
+ }
+ if (flags & MNT_SYNCHRONOUS) {
+ (void)printf("%ssynchronous", comma);
+ flags &= ~MNT_SYNCHRONOUS;
+ comma = ",";
+ }
+ if (flags & MNT_NOEXEC) {
+ (void)printf("%snoexec", comma);
+ flags &= ~MNT_NOEXEC;
+ comma = ",";
+ }
+ if (flags & MNT_NOSUID) {
+ (void)printf("%snosuid", comma);
+ flags &= ~MNT_NOSUID;
+ comma = ",";
+ }
+ if (flags & MNT_NODEV) {
+ (void)printf("%snodev", comma);
+ flags &= ~MNT_NODEV;
+ comma = ",";
+ }
+ if (flags & MNT_EXPORTED) {
+ (void)printf("%sexport", comma);
+ flags &= ~MNT_EXPORTED;
+ comma = ",";
+ }
+ if (flags & MNT_EXRDONLY) {
+ (void)printf("%sexrdonly", comma);
+ flags &= ~MNT_EXRDONLY;
+ comma = ",";
+ }
+ if (flags & MNT_LOCAL) {
+ (void)printf("%slocal", comma);
+ flags &= ~MNT_LOCAL;
+ comma = ",";
+ }
+ if (flags & MNT_QUOTA) {
+ (void)printf("%squota", comma);
+ flags &= ~MNT_QUOTA;
+ comma = ",";
+ }
+ /* filesystem control flags */
+ if (flags & MNT_UPDATE) {
+ (void)printf("%supdate", comma);
+ flags &= ~MNT_UPDATE;
+ comma = ",";
+ }
+ if (flags & MNT_MLOCK) {
+ (void)printf("%slock", comma);
+ flags &= ~MNT_MLOCK;
+ comma = ",";
+ }
+ if (flags & MNT_MWAIT) {
+ (void)printf("%swait", comma);
+ flags &= ~MNT_MWAIT;
+ comma = ",";
+ }
+ if (flags & MNT_MPBUSY) {
+ (void)printf("%sbusy", comma);
+ flags &= ~MNT_MPBUSY;
+ comma = ",";
+ }
+ if (flags & MNT_MPWANT) {
+ (void)printf("%swant", comma);
+ flags &= ~MNT_MPWANT;
+ comma = ",";
+ }
+ if (flags & MNT_UNMOUNT) {
+ (void)printf("%sunmount", comma);
+ flags &= ~MNT_UNMOUNT;
+ comma = ",";
+ }
+ if (flags)
+ (void)printf("%sunknown_flags:%x", comma, flags);
+ (void)printf(")");
+ }
+ (void)printf("\n");
+#undef ST
+}
+
+struct e_vnode *
+loadvnodes(avnodes)
+ int *avnodes;
+{
+ int mib[2];
+ size_t copysize;
+ struct e_vnode *vnodebase;
+
+ if (memf != NULL) {
+ /*
+ * do it by hand
+ */
+ return (kinfo_vnodes(avnodes));
+ }
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_VNODE;
+ if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
+ err(1, "sysctl: KERN_VNODE");
+ if ((vnodebase = malloc(copysize)) == NULL)
+ err(1, NULL);
+ if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
+ err(1, "sysctl: KERN_VNODE");
+ if (copysize % sizeof(struct e_vnode))
+ errx(1, "vnode size mismatch");
+ *avnodes = copysize / sizeof(struct e_vnode);
+
+ return (vnodebase);
+}
+
+/*
+ * simulate what a running kernel does in in kinfo_vnode
+ */
+struct e_vnode *
+kinfo_vnodes(avnodes)
+ int *avnodes;
+{
+ struct mntlist mountlist;
+ struct mount *mp, mount;
+ struct vnode *vp, vnode;
+ char *vbuf, *evbuf, *bp;
+ int num, numvnodes;
+
+#define VPTRSZ sizeof(struct vnode *)
+#define VNODESZ sizeof(struct vnode)
+
+ KGET(V_NUMV, numvnodes);
+ if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
+ err(1, NULL);
+ bp = vbuf;
+ evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
+ KGET(V_MOUNTLIST, mountlist);
+ for (num = 0, mp = mountlist.cqh_first; ; mp = mp->mnt_list.cqe_next) {
+ KGET2(mp, &mount, sizeof(mount), "mount entry");
+ for (vp = mount.mnt_vnodelist.lh_first;
+ vp != NULL; vp = vp->v_mntvnodes.le_next) {
+ KGET2(vp, &vnode, sizeof(vnode), "vnode");
+ if ((bp + VPTRSZ + VNODESZ) > evbuf)
+ /* XXX - should realloc */
+ errx(1, "no more room for vnodes");
+ memmove(bp, &vp, VPTRSZ);
+ bp += VPTRSZ;
+ memmove(bp, &vnode, VNODESZ);
+ bp += VNODESZ;
+ num++;
+ }
+ if (mp == mountlist.cqh_last)
+ break;
+ }
+ *avnodes = num;
+ return ((struct e_vnode *)vbuf);
+}
+
+char hdr[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n";
+
+void
+ttymode()
+{
+
+#ifdef sparc
+ ttytype("console", SCONS, 1);
+ ttytype_newcf("zs", SZS, SCZS);
+#endif
+
+#ifdef vax
+ /* May fill in this later */
+#endif
+#ifdef tahoe
+ if (nl[SNVX].n_type != 0)
+ ttytype_oldcf("vx", SVX, SNVX);
+ if (nl[SNMP].n_type != 0)
+ ttytype_oldcf("mp", SMP, SNMP);
+#endif
+#ifdef hp300
+ if (nl[SNITE].n_type != 0)
+ ttytype_oldcf("ite", SITE, SNITE);
+ if (nl[SNDCA].n_type != 0)
+ ttytype_oldcf("dca", SDCA, SNDCA);
+ if (nl[SNDCM].n_type != 0)
+ ttytype_oldcf("dcm", SDCM, SNDCM);
+ if (nl[SNDCL].n_type != 0)
+ ttytype_oldcf("dcl", SDCL, SNDCL);
+#endif
+#ifdef mips
+ if (nl[SNDC].n_type != 0)
+ ttytype_oldcf("dc", SDC, SNDC);
+#endif
+#ifdef i386
+ if (nl[SCPC].n_type != 0)
+ ttytype_newcf("pc", SPC, SCPC);
+ if (nl[SCCOM].n_type != 0)
+ ttytype_newcf("com", SCOM, SCCOM);
+#endif
+#ifdef amiga
+ if (nl[SCSER].n_type != 0)
+ ttytype_newcf("ser", SSER, SCSER);
+ if (nl[SCITE].n_type != 0)
+ ttytype_newcf("ite", SITE, SCITE);
+ if (nl[SCMFCS].n_type != 0)
+ ttytype_newcf("mfcs", SMFCS, SCMFCS);
+#endif
+ if (nl[SNPTY].n_type != 0)
+ ttytype_oldcf("pty", SPTY, SNPTY);
+}
+
+void
+ttytype_oldcf(name, type, number)
+ char *name;
+ int type, number;
+{
+ int ntty;
+
+ KGET(number, ntty);
+ ttytype(name, type, ntty);
+}
+
+void
+ttytype_newcf(name, type, config)
+ char *name;
+ int type, config;
+{
+ struct cfdriver cf;
+ void **cd;
+ int i;
+
+ KGET(config, cf);
+ cd = malloc(cf.cd_ndevs * sizeof(void *));
+ if (!cd)
+ return;
+ KGET2(cf.cd_devs, cd, cf.cd_ndevs * sizeof(void *), "cfdevicep");
+ for (i = cf.cd_ndevs - 1; i >= 0; --i)
+ if (cd[i])
+ break;
+ free(cd);
+ ttytype(name, type, i + 1);
+}
+
+void
+ttytype(name, type, number)
+ char *name;
+ int type, number;
+{
+ static struct tty **ttyp;
+ static int nttyp;
+ static struct tty tty;
+ int ntty = number, i;
+
+ (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
+ if (ntty > nttyp) {
+ nttyp = ntty;
+ if ((ttyp = realloc(ttyp, nttyp * sizeof(*ttyp))) == 0)
+ err(1, NULL);
+ }
+ KGET1(type, ttyp, nttyp * sizeof(*ttyp), "tty pointers");
+ (void)printf(hdr);
+ for (i = 0; i < ntty; i++) {
+ if (ttyp[i] == NULL)
+ continue;
+ KGET2(ttyp[i], &tty, sizeof(struct tty), "tty struct");
+ ttyprt(&tty, i);
+ }
+}
+
+struct {
+ int flag;
+ char val;
+} ttystates[] = {
+ { TS_WOPEN, 'W'},
+ { TS_ISOPEN, 'O'},
+ { TS_CARR_ON, 'C'},
+ { TS_TIMEOUT, 'T'},
+ { TS_FLUSH, 'F'},
+ { TS_BUSY, 'B'},
+ { TS_ASLEEP, 'A'},
+ { TS_XCLUDE, 'X'},
+ { TS_TTSTOP, 'S'},
+ { TS_TBLOCK, 'K'},
+ { TS_ASYNC, 'Y'},
+ { TS_BKSL, 'D'},
+ { TS_ERASE, 'E'},
+ { TS_LNCH, 'L'},
+ { TS_TYPEN, 'P'},
+ { TS_CNTTB, 'N'},
+ { 0, '\0'},
+};
+
+void
+ttyprt(tp, line)
+ register struct tty *tp;
+ int line;
+{
+ register int i, j;
+ pid_t pgid;
+ char *name, state[20];
+
+ if (usenumflag || tp->t_dev == 0 ||
+ (name = devname(tp->t_dev, S_IFCHR)) == NULL)
+ (void)printf("%7d ", line);
+ else
+ (void)printf("%-7s ", name);
+ (void)printf("%3d %4d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
+ (void)printf("%4d %4d %3d %6d ", tp->t_outq.c_cc,
+ tp->t_hiwat, tp->t_lowat, tp->t_column);
+ for (i = j = 0; ttystates[i].flag; i++)
+ if (tp->t_state&ttystates[i].flag)
+ state[j++] = ttystates[i].val;
+ if (j == 0)
+ state[j++] = '-';
+ state[j] = '\0';
+ (void)printf("%-6s %6x", state, (u_long)tp->t_session & ~KERNBASE);
+ pgid = 0;
+ if (tp->t_pgrp != NULL)
+ KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
+ (void)printf("%6d ", pgid);
+ switch (tp->t_line) {
+ case TTYDISC:
+ (void)printf("term\n");
+ break;
+ case TABLDISC:
+ (void)printf("tab\n");
+ break;
+ case SLIPDISC:
+ (void)printf("slip\n");
+ break;
+ case PPPDISC:
+ (void)printf("ppp\n");
+ break;
+ default:
+ (void)printf("%d\n", tp->t_line);
+ break;
+ }
+}
+
+void
+filemode()
+{
+ register struct file *fp;
+ struct file *addr;
+ char *buf, flagbuf[16], *fbp;
+ int len, maxfile, nfile;
+ static char *dtypes[] = { "???", "inode", "socket" };
+
+ KGET(FNL_MAXFILE, maxfile);
+ if (totalflag) {
+ KGET(FNL_NFILE, nfile);
+ (void)printf("%3d/%3d files\n", nfile, maxfile);
+ return;
+ }
+ if (getfiles(&buf, &len) == -1)
+ return;
+ /*
+ * Getfiles returns in malloc'd memory a pointer to the first file
+ * structure, and then an array of file structs (whose addresses are
+ * derivable from the previous entry).
+ */
+ addr = ((struct filelist *)buf)->lh_first;
+ fp = (struct file *)(buf + sizeof(struct filelist));
+ nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
+
+ (void)printf("%d/%d open files\n", nfile, maxfile);
+ (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n");
+ for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) {
+ if ((unsigned)fp->f_type > DTYPE_SOCKET)
+ continue;
+ (void)printf("%x ", addr);
+ (void)printf("%-8.8s", dtypes[fp->f_type]);
+ fbp = flagbuf;
+ if (fp->f_flag & FREAD)
+ *fbp++ = 'R';
+ if (fp->f_flag & FWRITE)
+ *fbp++ = 'W';
+ if (fp->f_flag & FAPPEND)
+ *fbp++ = 'A';
+#ifdef FSHLOCK /* currently gone */
+ if (fp->f_flag & FSHLOCK)
+ *fbp++ = 'S';
+ if (fp->f_flag & FEXLOCK)
+ *fbp++ = 'X';
+#endif
+ if (fp->f_flag & FASYNC)
+ *fbp++ = 'I';
+ *fbp = '\0';
+ (void)printf("%6s %3d", flagbuf, fp->f_count);
+ (void)printf(" %3d", fp->f_msgcount);
+ (void)printf(" %8.1x", fp->f_data);
+ if (fp->f_offset < 0)
+ (void)printf(" %qx\n", fp->f_offset);
+ else
+ (void)printf(" %qd\n", fp->f_offset);
+ }
+ free(buf);
+}
+
+int
+getfiles(abuf, alen)
+ char **abuf;
+ int *alen;
+{
+ size_t len;
+ int mib[2];
+ char *buf;
+
+ /*
+ * XXX
+ * Add emulation of KINFO_FILE here.
+ */
+ if (memf != NULL)
+ errx(1, "files on dead kernel, not implemented\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_FILE;
+ if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
+ warn("sysctl: KERN_FILE");
+ return (-1);
+ }
+ if ((buf = malloc(len)) == NULL)
+ err(1, NULL);
+ if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
+ warn("sysctl: KERN_FILE");
+ return (-1);
+ }
+ *abuf = buf;
+ *alen = len;
+ return (0);
+}
+
+/*
+ * swapmode is based on a program called swapinfo written
+ * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+void
+swapmode()
+{
+ char *header;
+ int hlen, nswap, nswdev, dmmax, nswapmap, niswap, niswdev;
+ int s, e, div, i, l, avail, nfree, npfree, used;
+ struct swdevt *sw;
+ long blocksize, *perdev;
+ struct map *swapmap, *kswapmap;
+ struct mapent *mp;
+
+ KGET(VM_NSWAP, nswap);
+ KGET(VM_NSWDEV, nswdev);
+ KGET(VM_DMMAX, dmmax);
+ KGET(VM_NSWAPMAP, nswapmap);
+ KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */
+ if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
+ (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
+ (mp = malloc(nswapmap * sizeof(*mp))) == NULL)
+ err(1, "malloc");
+ KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
+ KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap");
+
+ /* Supports sequential swap */
+ if (nl[VM_NISWAP].n_value != 0) {
+ KGET(VM_NISWAP, niswap);
+ KGET(VM_NISWDEV, niswdev);
+ } else {
+ niswap = nswap;
+ niswdev = nswdev;
+ }
+
+ /* First entry in map is `struct map'; rest are mapent's. */
+ swapmap = (struct map *)mp;
+ if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
+ errx(1, "panic: nswapmap goof");
+
+ /* Count up swap space. */
+ nfree = 0;
+ memset(perdev, 0, nswdev * sizeof(*perdev));
+ for (mp++; mp->m_addr != 0; mp++) {
+ s = mp->m_addr; /* start of swap region */
+ e = mp->m_addr + mp->m_size; /* end of region */
+ nfree += mp->m_size;
+
+ /*
+ * Swap space is split up among the configured disks.
+ *
+ * For interleaved swap devices, the first dmmax blocks
+ * of swap space some from the first disk, the next dmmax
+ * blocks from the next, and so on up to niswap blocks.
+ *
+ * Sequential swap devices follow the interleaved devices
+ * (i.e. blocks starting at niswap) in the order in which
+ * they appear in the swdev table. The size of each device
+ * will be a multiple of dmmax.
+ *
+ * The list of free space joins adjacent free blocks,
+ * ignoring device boundries. If we want to keep track
+ * of this information per device, we'll just have to
+ * extract it ourselves. We know that dmmax-sized chunks
+ * cannot span device boundaries (interleaved or sequential)
+ * so we loop over such chunks assigning them to devices.
+ */
+ i = -1;
+ while (s < e) { /* XXX this is inefficient */
+ int bound = roundup(s+1, dmmax);
+
+ if (bound > e)
+ bound = e;
+ if (bound <= niswap) {
+ /* Interleaved swap chunk. */
+ if (i == -1)
+ i = (s / dmmax) % niswdev;
+ perdev[i] += bound - s;
+ if (++i >= niswdev)
+ i = 0;
+ } else {
+ /* Sequential swap chunk. */
+ if (i < niswdev) {
+ i = niswdev;
+ l = niswap + sw[i].sw_nblks;
+ }
+ while (s >= l) {
+ /* XXX don't die on bogus blocks */
+ if (i == nswdev-1)
+ break;
+ l += sw[++i].sw_nblks;
+ }
+ perdev[i] += bound - s;
+ }
+ s = bound;
+ }
+ }
+
+ if (kflag) {
+ header = "1K-blocks";
+ blocksize = 1024;
+ hlen = strlen(header);
+ } else
+ header = getbsize(&hlen, &blocksize);
+ if (!totalflag)
+ (void)printf("%-11s %*s %8s %8s %8s %s\n",
+ "Device", hlen, header,
+ "Used", "Avail", "Capacity", "Type");
+ div = blocksize / 512;
+ avail = npfree = 0;
+ for (i = 0; i < nswdev; i++) {
+ int xsize, xfree;
+
+ if (!totalflag)
+ (void)printf("/dev/%-6s %*d ",
+ devname(sw[i].sw_dev, S_IFBLK),
+ hlen, sw[i].sw_nblks / div);
+
+ /*
+ * Don't report statistics for partitions which have not
+ * yet been activated via swapon(8).
+ */
+ if (!(sw[i].sw_flags & SW_FREED)) {
+ if (totalflag)
+ continue;
+ (void)printf(" *** not available for swapping ***\n");
+ continue;
+ }
+ xsize = sw[i].sw_nblks;
+ xfree = perdev[i];
+ used = xsize - xfree;
+ npfree++;
+ avail += xsize;
+ if (totalflag)
+ continue;
+ (void)printf("%8d %8d %5.0f%% %s\n",
+ used / div, xfree / div,
+ (double)used / (double)xsize * 100.0,
+ (sw[i].sw_flags & SW_SEQUENTIAL) ?
+ "Sequential" : "Interleaved");
+ }
+
+ /*
+ * If only one partition has been set up via swapon(8), we don't
+ * need to bother with totals.
+ */
+ used = avail - nfree;
+ if (totalflag) {
+ (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048);
+ return;
+ }
+ if (npfree > 1) {
+ (void)printf("%-11s %*d %8d %8d %5.0f%%\n",
+ "Total", hlen, avail / div, used / div, nfree / div,
+ (double)used / (double)avail * 100.0);
+ }
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: pstat [-Tfknstv] [-M core] [-N system]\n");
+ exit(1);
+}
diff --git a/usr.sbin/pwd_mkdb/Makefile b/usr.sbin/pwd_mkdb/Makefile
new file mode 100644
index 00000000000..4110a97b72f
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/Makefile
@@ -0,0 +1,13 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $
+
+PROG= pwd_mkdb
+SRCS= pw_scan.c pwd_mkdb.c getpwent.c
+MAN= pwd_mkdb.8
+
+.PATH: ${.CURDIR}/../../lib/libc/gen
+
+.include <bsd.prog.mk>
+
+getpwent.o: getpwent.c
+ ${CC} ${CFLAGS} ${CPPFLAGS} -UYP -c ${.IMPSRC}
diff --git a/usr.sbin/pwd_mkdb/pw_scan.c b/usr.sbin/pwd_mkdb/pw_scan.c
new file mode 100644
index 00000000000..00fd45cdf64
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pw_scan.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright(C) 1995, Jason Downs. 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[] = "from: @(#)pw_scan.c 8.3 (Berkeley) 4/2/94";*/
+static char *rcsid = "$Id: pw_scan.c,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $";
+#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, flags)
+ char *bp;
+ struct passwd *pw;
+ int *flags;
+{
+ long id;
+ int root;
+ char *p, *sh;
+
+ if (flags != (int *)NULL)
+ *flags = 0;
+
+ 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 == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOUID;
+
+ 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;
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOGID;
+
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ pw->pw_change = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOCHG;
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ pw->pw_expire = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOEXP;
+ 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/usr.sbin/pwd_mkdb/pw_scan.h b/usr.sbin/pwd_mkdb/pw_scan.h
new file mode 100644
index 00000000000..f1ff78c1f64
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/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 *, int *));
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8
new file mode 100644
index 00000000000..fb11ea1cf58
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8
@@ -0,0 +1,129 @@
+.\" Copyright (c) 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.
+.\"
+.\" from: @(#)pwd_mkdb.8 8.1 (Berkeley) 6/6/93
+.\" $Id: pwd_mkdb.8,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt PWD_MKDB 8
+.Os
+.Sh NAME
+.Nm pwd_mkdb
+.Nd "generate the password databases"
+.Sh SYNOPSIS
+.Nm pwd_mkdb
+.Op Fl p
+.Ar file
+.Sh DESCRIPTION
+.Nm Pwd_mkdb
+creates
+.Xr db 3
+style secure and insecure databases for the specified file.
+These databases are then installed into
+.Dq Pa /etc/spwd.db
+and
+.Dq Pa /etc/pwd.db
+respectively.
+The file is installed into
+.Dq Pa /etc/master.passwd .
+The file must be in the correct format (see
+.Xr passwd 5 ) .
+It is important to note that the format used in this system is
+different from the historic Version 7 style format.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl p
+Create a Version 7 style password file and install it into
+.Dq Pa /etc/passwd .
+.El
+.Pp
+The two databases differ in that the secure version contains the user's
+encrypted password and the insecure version has an asterisk (``*'')
+.Pp
+The databases are used by the C library password routines (see
+.Xr getpwent 3 ) .
+.Pp
+.Nm Pwd_mkdb
+exits zero on success, non-zero on failure.
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/master.passwd
+The current password file.
+.It Pa /etc/passwd
+A Version 7 format password file.
+.It Pa /etc/pwd.db
+The insecure password database file.
+.It Pa /etc/pwd.db.tmp
+A temporary file.
+.It Pa /etc/spwd.db
+The secure password database file.
+.It Pa /etc/spwd.db.tmp
+A temporary file.
+.El
+.Sh BUGS
+Because of the necessity for atomic update of the password files,
+.Nm pwd_mkdb
+uses
+.Xr rename 2
+to install them.
+This, however, requires that the file specified on the command line live
+on the same file system as the
+.Dq Pa /etc
+directory.
+.Pp
+There are the obvious races with multiple people running
+.Nm pwd_mkdb
+on different password files at the same time.
+The front-ends to
+.Nm pwd_mkdb ,
+.Xr chpass 1 ,
+.Xr passwd 1
+and
+.Xr vipw 8 ,
+handle the locking necessary to avoid this problem.
+.Sh COMPATIBILITY
+Previous versions of the system had a program similar to
+.Nm pwd_mkdb ,
+.Xr mkpasswd 8 ,
+which built
+.Xr dbm 3
+style databases for the password file but depended on the calling programs
+to install them.
+The program was renamed in order that previous users of the program
+not be surprised by the changes in functionality.
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr db 3 ,
+.Xr getpwent 3 ,
+.Xr passwd 5 ,
+.Xr vipw 8
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
new file mode 100644
index 00000000000..86cbcf7d565
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -0,0 +1,431 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright(C) 1994, Jason Downs. 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) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94";*/
+static char *rcsid = "$Id: pwd_mkdb.c,v 1.1.1.1 1995/10/18 08:48:01 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_scan.h"
+
+#define INSECURE 1
+#define SECURE 2
+#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+/* pull this out of the C library. */
+extern const char __yp_token[];
+
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
+static struct passwd pwd; /* password structure */
+static char *pname; /* password file name */
+
+void cleanup __P((void));
+void error __P((char *));
+void mv __P((char *, char *));
+int scan __P((FILE *, struct passwd *, int *));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ DB *dp, *edp;
+ DBT data, key;
+ FILE *fp, *oldfp;
+ sigset_t set;
+ int ch, cnt, len, makeold, tfd, flags;
+ char *p, *t;
+ char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
+ int hasyp = 0;
+ DBT ypdata, ypkey;
+
+ makeold = 0;
+ while ((ch = getopt(argc, argv, "pv")) != EOF)
+ switch(ch) {
+ case 'p': /* create V7 "file.orig" */
+ makeold = 1;
+ break;
+ case 'v': /* backward compatible */
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ /*
+ * This could be changed to allow the user to interrupt.
+ * Probably not worth the effort.
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTSTP);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
+
+ /* We don't care what the user wants. */
+ (void)umask(0);
+
+ pname = *argv;
+ /* Open the original password file */
+ if (!(fp = fopen(pname, "r")))
+ error(pname);
+
+ /* Open the temporary insecure password database. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
+ dp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+ if (dp == NULL)
+ error(buf);
+ clean = FILE_INSECURE;
+
+ /*
+ * Open file for old password file. Minor trickiness -- don't want to
+ * chance the file already existing, since someone (stupidly) might
+ * still be using this for permission checking. So, open it first and
+ * fdopen the resulting fd. The resulting file should be readable by
+ * everyone.
+ */
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ if ((tfd = open(buf,
+ O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
+ error(buf);
+ if ((oldfp = fdopen(tfd, "w")) == NULL)
+ error(buf);
+ clean = FILE_ORIG;
+ }
+
+ /*
+ * The databases actually contain three copies of the original data.
+ * Each password file entry is converted into a rough approximation
+ * of a ``struct passwd'', with the strings placed inline. This
+ * object is then stored as the data for three separate keys. The
+ * first key * is the pw_name field prepended by the _PW_KEYBYNAME
+ * character. The second key is the pw_uid field prepended by the
+ * _PW_KEYBYUID character. The third key is the line number in the
+ * original file prepended by the _PW_KEYBYNUM character. (The special
+ * characters are prepended to ensure that the keys do not collide.)
+ *
+ * If we see something go by that looks like YP, we save a special
+ * pointer record, which if YP is enabled in the C lib, will speed
+ * things up.
+ */
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+ for (cnt = 1; scan(fp, &pwd, &flags); ++cnt) {
+#define COMPACT(e) t = e; while (*p++ = *t++);
+
+ /* look like YP? */
+ if((pwd.pw_name[0] == '+') || (pwd.pw_name[0] == '-'))
+ hasyp++;
+
+ /* Create insecure data. */
+ p = buf;
+ COMPACT(pwd.pw_name);
+ COMPACT("*");
+ memmove(p, &pwd.pw_uid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_gid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ memmove(p, &pwd.pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Store insecure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ memmove(tbuf + 1, pwd.pw_name, len);
+ key.size = len + 1;
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ /* Store insecure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ /* Store insecure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ /* Create original format password file entry */
+ if (makeold)
+ (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
+ pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
+ pwd.pw_dir, pwd.pw_shell);
+ }
+
+ /* Store YP token, if needed. */
+ if(hasyp) {
+ ypkey.data = (u_char *)__yp_token;
+ ypkey.size = strlen(__yp_token);
+ ypdata.data = (u_char *)NULL;
+ ypdata.size = 0;
+
+ if ((dp->put)(dp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
+ error("put");
+ }
+
+ (void)(dp->close)(dp);
+ if (makeold) {
+ (void)fflush(oldfp);
+ (void)fclose(oldfp);
+ }
+
+ /* Open the temporary encrypted password database. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ if (!edp)
+ error(buf);
+ clean = FILE_SECURE;
+
+ rewind(fp);
+ for (cnt = 1; scan(fp, &pwd, &flags); ++cnt) {
+
+ /* Create secure data. */
+ p = buf;
+ COMPACT(pwd.pw_name);
+ COMPACT(pwd.pw_passwd);
+ memmove(p, &pwd.pw_uid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_gid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ memmove(p, &pwd.pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Store secure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ memmove(tbuf + 1, pwd.pw_name, len);
+ key.size = len + 1;
+ if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ /* Store secure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ /* Store secure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+ if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+ }
+
+ /* Store YP token, if needed. */
+ if(hasyp) {
+ ypkey.data = (u_char *)__yp_token;
+ ypkey.size = strlen(__yp_token);
+ ypdata.data = (u_char *)NULL;
+ ypdata.size = 0;
+
+ if((dp->put)(edp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
+ error("put");
+ }
+
+ (void)(edp->close)(edp);
+
+ /* Set master.passwd permissions, in case caller forgot. */
+ (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
+ (void)fclose(fp);
+
+ /* Install as the real password files. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
+ mv(buf, _PATH_MP_DB);
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
+ mv(buf, _PATH_SMP_DB);
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ mv(buf, _PATH_PASSWD);
+ }
+ /*
+ * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
+ * all use flock(2) on it to block other incarnations of themselves.
+ * The rename means that everything is unlocked, as the original file
+ * can no longer be accessed.
+ */
+ mv(pname, _PATH_MASTERPASSWD);
+ exit(0);
+}
+
+int
+scan(fp, pw, flags)
+ FILE *fp;
+ struct passwd *pw;
+ int *flags;
+{
+ static int lcnt;
+ static char line[LINE_MAX];
+ char *p;
+
+ if (!fgets(line, sizeof(line), fp))
+ return (0);
+ ++lcnt;
+ /*
+ * ``... if I swallow anything evil, put your fingers down my
+ * throat...''
+ * -- The Who
+ */
+ if (!(p = strchr(line, '\n'))) {
+ warnx("line too long");
+ goto fmt;
+
+ }
+ *p = '\0';
+ if (!pw_scan(line, pw, flags)) {
+ warnx("at line #%d", lcnt);
+fmt: errno = EFTYPE; /* XXX */
+ error(pname);
+ }
+
+ return (1);
+}
+
+void
+mv(from, to)
+ char *from, *to;
+{
+ char buf[MAXPATHLEN];
+
+ if (rename(from, to)) {
+ int sverrno = errno;
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+void
+error(name)
+ char *name;
+{
+
+ warn(name);
+ cleanup();
+ exit(1);
+}
+
+void
+cleanup()
+{
+ char buf[MAXPATHLEN];
+
+ switch(clean) {
+ case FILE_ORIG:
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ (void)unlink(buf);
+ /* FALLTHROUGH */
+ case FILE_SECURE:
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
+ (void)unlink(buf);
+ /* FALLTHROUGH */
+ case FILE_INSECURE:
+ (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
+ (void)unlink(buf);
+ }
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
+ exit(1);
+}
diff --git a/usr.sbin/quot/Makefile b/usr.sbin/quot/Makefile
new file mode 100644
index 00000000000..12e48c3368f
--- /dev/null
+++ b/usr.sbin/quot/Makefile
@@ -0,0 +1,6 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+
+PROG= quot
+MAN= quot.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/quot/quot.8 b/usr.sbin/quot/quot.8
new file mode 100644
index 00000000000..c5c86f802b1
--- /dev/null
+++ b/usr.sbin/quot/quot.8
@@ -0,0 +1,96 @@
+.\" Copyright (C) 1994 Wolfgang Solfrank.
+.\" Copyright (C) 1994 TooLs GmbH.
+.\" 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 TooLs GmbH.
+.\" 4. The name of TooLs GmbH may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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: quot.8,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+.\"
+.Dd February 8, 1994
+.Dt QUOT 8
+.Os BSD 4
+.Sh NAME
+.Nm quot
+.Nd display disk space occupied by each user
+.Sh SYNOPSIS
+.Nm quot
+.Op Fl acfhknv
+.Op Ar filesystem ...
+.Sh DESCRIPTION
+.Nm Quot
+is used to gather statistics about the disk usage for each local user.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Include statistics for all mounted filesystems.
+.It Fl c
+Display three columns containing number of blocks per file,
+number of files in this category, and aggregate total of
+blocks in files with this or lower size.
+.It Fl f
+For each user, display count of files and space occupied.
+.It Fl h
+Estimate the number of blocks in each file based on its size.
+Despite that this doesn't give the correct resuls (it doesn't
+account for the holes in files), this option isn't any faster
+and thus is discouraged.
+.It Fl k
+By default, all sizes are reported in 512-byte block counts.
+The
+.Fl k
+options causes the numbers to be reported in kilobyte counts.
+.It Fl n
+Given a list of inodes (plus some optional data on each line)
+in the standard input, for each file print out the owner (plus
+the remainder of the input line). This is traditionally used
+in the pipe:
+.Bd -literal -offset indent
+ncheck filesystem | sort +0n | quot -n filesystem
+.Ed
+.Pp
+to get a report of files and their owners.
+.It Fl v
+In addition to the default output, display the number of files
+not accessed within 30, 60 and 90 days.
+.El
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environmental variable
+.Ev BLOCKSIZE
+is set, and the
+.Gl k
+option is not specified, the block counts will be displayed in units of that
+size block.
+.El
+.\".Sh BUGS
+.Sh SEE ALSO
+.Xr df 1 ,
+.Xr quota 1 ,
+.Xr getmntinfo 3 ,
+.Xr fstab 5 ,
+.Xr mount 8 ,
diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c
new file mode 100644
index 00000000000..7ad626d9ffa
--- /dev/null
+++ b/usr.sbin/quot/quot.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 1991, 1994 Wolfgang Solfrank.
+ * Copyright (C) 1991, 1994 TooLs GmbH.
+ * 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 TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 rcsid[] = "$Id: quot.c,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <ufs/ffs/fs.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+
+/* some flags of what to do: */
+static char estimate;
+static char count;
+static char unused;
+static int (*func)();
+static long blocksize;
+static char *header;
+static int headerlen;
+
+/*
+ * Original BSD quot doesn't round to number of frags/blocks,
+ * doesn't account for indirection blocks and gets it totally
+ * wrong if the size is a multiple of the blocksize.
+ * The new code always counts the number of 512 byte blocks
+ * instead of the number of kilobytes and converts them to
+ * kByte when done (on request).
+ */
+#ifdef COMPAT
+#define SIZE(n) (n)
+#else
+#define SIZE(n) (((n) * 512 + blocksize - 1)/blocksize)
+#endif
+
+#define INOCNT(fs) ((fs)->fs_ipg)
+#define INOSZ(fs) (sizeof(struct dinode) * INOCNT(fs))
+
+static struct dinode *get_inode(fd,super,ino)
+ struct fs *super;
+ ino_t ino;
+{
+ static struct dinode *ip;
+ static ino_t last;
+
+ if (fd < 0) { /* flush cache */
+ if (ip) {
+ free(ip);
+ ip = 0;
+ }
+ return 0;
+ }
+
+ if (!ip || ino < last || ino >= last + INOCNT(super)) {
+ if (!ip
+ && !(ip = (struct dinode *)malloc(INOSZ(super)))) {
+ perror("allocate inodes");
+ exit(1);
+ }
+ last = (ino / INOCNT(super)) * INOCNT(super);
+ if (lseek(fd,ino_to_fsba(super,last) << super->fs_fshift,0) < 0
+ || read(fd,ip,INOSZ(super)) != INOSZ(super)) {
+ perror("read inodes");
+ exit(1);
+ }
+ }
+
+ return ip + ino % INOCNT(super);
+}
+
+#ifdef COMPAT
+#define actualblocks(super,ip) ((ip)->di_blocks/2)
+#else
+#define actualblocks(super,ip) ((ip)->di_blocks)
+#endif
+
+static virtualblocks(super,ip)
+ struct fs *super;
+ struct dinode *ip;
+{
+ register off_t nblk, sz;
+
+ sz = ip->di_size;
+#ifdef COMPAT
+ if (lblkno(super,sz) >= NDADDR) {
+ nblk = blkroundup(super,sz);
+ if (sz == nblk)
+ nblk += super->fs_bsize;
+ }
+
+ return sz / 1024;
+
+#else /* COMPAT */
+
+ if (lblkno(super,sz) >= NDADDR) {
+ nblk = blkroundup(super,sz);
+ sz = lblkno(super,nblk);
+ sz = (sz - NDADDR + NINDIR(super) - 1) / NINDIR(super);
+ while (sz > 0) {
+ nblk += sz * super->fs_bsize;
+ /* sz - 1 rounded up */
+ sz = (sz - 1 + NINDIR(super) - 1) / NINDIR(super);
+ }
+ } else
+ nblk = fragroundup(super,sz);
+
+ return nblk / 512;
+#endif /* COMPAT */
+}
+
+static isfree(ip)
+ struct dinode *ip;
+{
+#ifdef COMPAT
+ return (ip->di_mode&IFMT) == 0;
+#else /* COMPAT */
+
+ switch (ip->di_mode&IFMT) {
+ case IFIFO:
+ case IFLNK: /* should check FASTSYMLINK? */
+ case IFDIR:
+ case IFREG:
+ return 0;
+ default:
+ return 1;
+ }
+#endif
+}
+
+static struct user {
+ uid_t uid;
+ char *name;
+ daddr_t space;
+ long count;
+ daddr_t spc30;
+ daddr_t spc60;
+ daddr_t spc90;
+} *users;
+static int nusers;
+
+static inituser()
+{
+ register i;
+ register struct user *usr;
+
+ if (!nusers) {
+ nusers = 8;
+ if (!(users =
+ (struct user *)calloc(nusers,sizeof(struct user)))) {
+ perror("allocate users");
+ exit(1);
+ }
+ } else {
+ for (usr = users, i = nusers; --i >= 0; usr++) {
+ usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0;
+ usr->count = 0;
+ }
+ }
+}
+
+static usrrehash()
+{
+ register i;
+ register struct user *usr, *usrn;
+ struct user *svusr;
+
+ svusr = users;
+ nusers <<= 1;
+ if (!(users = (struct user *)calloc(nusers,sizeof(struct user)))) {
+ perror("allocate users");
+ exit(1);
+ }
+ for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) {
+ for (usrn = users + (usr->uid&(nusers - 1)); usrn->name;
+ usrn--) {
+ if (usrn <= users)
+ usrn = users + nusers;
+ }
+ *usrn = *usr;
+ }
+}
+
+static struct user *user(uid)
+ uid_t uid;
+{
+ register struct user *usr;
+ register i;
+ struct passwd *pwd;
+
+ while (1) {
+ for (usr = users + (uid&(nusers - 1)), i = nusers; --i >= 0;
+ usr--) {
+ if (!usr->name) {
+ usr->uid = uid;
+
+ if (!(pwd = getpwuid(uid))) {
+ if (usr->name = (char *)malloc(7))
+ sprintf(usr->name,"#%d",uid);
+ } else {
+ if (usr->name = (char *)
+ malloc(strlen(pwd->pw_name) + 1))
+ strcpy(usr->name,pwd->pw_name);
+ }
+ if (!usr->name) {
+ perror("allocate users");
+ exit(1);
+ }
+
+ return usr;
+
+ } else if (usr->uid == uid)
+ return usr;
+
+ if (usr <= users)
+ usr = users + nusers;
+ }
+ usrrehash();
+ }
+}
+
+static cmpusers(u1,u2)
+ struct user *u1, *u2;
+{
+ return u2->space - u1->space;
+}
+
+#define sortusers(users) (qsort((users),nusers,sizeof(struct user), \
+ cmpusers))
+
+static uses(uid,blks,act)
+ uid_t uid;
+ daddr_t blks;
+ time_t act;
+{
+ static time_t today;
+ register struct user *usr;
+
+ if (!today)
+ time(&today);
+
+ usr = user(uid);
+ usr->count++;
+ usr->space += blks;
+
+ if (today - act > 90L * 24L * 60L * 60L)
+ usr->spc90 += blks;
+ if (today - act > 60L * 24L * 60L * 60L)
+ usr->spc60 += blks;
+ if (today - act > 30L * 24L * 60L * 60L)
+ usr->spc30 += blks;
+}
+
+#ifdef COMPAT
+#define FSZCNT 500
+#else
+#define FSZCNT 512
+#endif
+struct fsizes {
+ struct fsizes *fsz_next;
+ daddr_t fsz_first, fsz_last;
+ ino_t fsz_count[FSZCNT];
+ daddr_t fsz_sz[FSZCNT];
+} *fsizes;
+
+static initfsizes()
+{
+ register struct fsizes *fp;
+ register i;
+
+ for (fp = fsizes; fp; fp = fp->fsz_next) {
+ for (i = FSZCNT; --i >= 0;) {
+ fp->fsz_count[i] = 0;
+ fp->fsz_sz[i] = 0;
+ }
+ }
+}
+
+static dofsizes(fd,super,name)
+ struct fs *super;
+ char *name;
+{
+ ino_t inode, maxino;
+ struct dinode *ip;
+ daddr_t sz, ksz;
+ struct fsizes *fp, **fsp;
+ register i;
+
+ maxino = super->fs_ncg * super->fs_ipg - 1;
+#ifdef COMPAT
+ if (!(fsizes = (struct fsizes *)malloc(sizeof(struct fsizes)))) {
+ perror("alloc fsize structure");
+ exit(1);
+ }
+#endif /* COMPAT */
+ for (inode = 0; inode < maxino; inode++) {
+ errno = 0;
+ if ((ip = get_inode(fd,super,inode))
+#ifdef COMPAT
+ && ((ip->di_mode&IFMT) == IFREG
+ || (ip->di_mode&IFMT) == IFDIR)
+#else /* COMPAT */
+ && !isfree(ip)
+#endif /* COMPAT */
+ ) {
+ sz = estimate ? virtualblocks(super,ip) :
+ actualblocks(super,ip);
+#ifdef COMPAT
+ if (sz >= FSZCNT) {
+ fsizes->fsz_count[FSZCNT-1]++;
+ fsizes->fsz_sz[FSZCNT-1] += sz;
+ } else {
+ fsizes->fsz_count[sz]++;
+ fsizes->fsz_sz[sz] += sz;
+ }
+#else /* COMPAT */
+ ksz = SIZE(sz);
+ for (fsp = &fsizes; fp = *fsp; fsp = &fp->fsz_next) {
+ if (ksz < fp->fsz_last)
+ break;
+ }
+ if (!fp || ksz < fp->fsz_first) {
+ if (!(fp = (struct fsizes *)
+ malloc(sizeof(struct fsizes)))) {
+ perror("alloc fsize structure");
+ exit(1);
+ }
+ fp->fsz_next = *fsp;
+ *fsp = fp;
+ fp->fsz_first = (ksz / FSZCNT) * FSZCNT;
+ fp->fsz_last = fp->fsz_first + FSZCNT;
+ for (i = FSZCNT; --i >= 0;) {
+ fp->fsz_count[i] = 0;
+ fp->fsz_sz[i] = 0;
+ }
+ }
+ fp->fsz_count[ksz % FSZCNT]++;
+ fp->fsz_sz[ksz % FSZCNT] += sz;
+#endif /* COMPAT */
+ } else if (errno) {
+ perror(name);
+ exit(1);
+ }
+ }
+ sz = 0;
+ for (fp = fsizes; fp; fp = fp->fsz_next) {
+ for (i = 0; i < FSZCNT; i++) {
+ if (fp->fsz_count[i])
+ printf("%d\t%d\t%d\n",fp->fsz_first + i,
+ fp->fsz_count[i],
+ SIZE(sz += fp->fsz_sz[i]));
+ }
+ }
+}
+
+static douser(fd,super,name)
+ struct fs *super;
+ char *name;
+{
+ ino_t inode, maxino;
+ struct user *usr, *usrs;
+ struct dinode *ip;
+ register n;
+
+ maxino = super->fs_ncg * super->fs_ipg - 1;
+ for (inode = 0; inode < maxino; inode++) {
+ errno = 0;
+ if ((ip = get_inode(fd,super,inode))
+ && !isfree(ip))
+ uses(ip->di_uid,
+ estimate ? virtualblocks(super,ip) :
+ actualblocks(super,ip),
+ ip->di_atime);
+ else if (errno) {
+ perror(name);
+ exit(1);
+ }
+ }
+ if (!(usrs = (struct user *)malloc(nusers * sizeof(struct user)))) {
+ perror("allocate users");
+ exit(1);
+ }
+ bcopy(users,usrs,nusers * sizeof(struct user));
+ sortusers(usrs);
+ for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) {
+ printf("%5d",SIZE(usr->space));
+ if (count)
+ printf("\t%5d",usr->count);
+ printf("\t%-8s",usr->name);
+ if (unused)
+ printf("\t%5d\t%5d\t%5d",
+ SIZE(usr->spc30),
+ SIZE(usr->spc60),
+ SIZE(usr->spc90));
+ printf("\n");
+ }
+ free(usrs);
+}
+
+static donames(fd,super,name)
+ struct fs *super;
+ char *name;
+{
+ int c;
+ ino_t inode, inode1;
+ ino_t maxino;
+ struct dinode *ip;
+
+ maxino = super->fs_ncg * super->fs_ipg - 1;
+ /* first skip the name of the filesystem */
+ while ((c = getchar()) != EOF && (c < '0' || c > '9'))
+ while ((c = getchar()) != EOF && c != '\n');
+ ungetc(c,stdin);
+ inode1 = -1;
+ while (scanf("%d",&inode) == 1) {
+ if (inode < 0 || inode > maxino) {
+ fprintf(stderr,"illegal inode %d\n",inode);
+ return;
+ }
+ errno = 0;
+ if ((ip = get_inode(fd,super,inode))
+ && !isfree(ip)) {
+ printf("%s\t",user(ip->di_uid)->name);
+ /* now skip whitespace */
+ while ((c = getchar()) == ' ' || c == '\t');
+ /* and print out the remainder of the input line */
+ while (c != EOF && c != '\n') {
+ putchar(c);
+ c = getchar();
+ }
+ putchar('\n');
+ inode1 = inode;
+ } else {
+ if (errno) {
+ perror(name);
+ exit(1);
+ }
+ /* skip this line */
+ while ((c = getchar()) != EOF && c != '\n');
+ }
+ if (c == EOF)
+ break;
+ }
+}
+
+static usage()
+{
+#ifdef COMPAT
+ fprintf(stderr,"Usage: quot [-nfcvha] [filesystem ...]\n");
+#else /* COMPAT */
+ fprintf(stderr,"Usage: quot [ -acfhknv ] [ filesystem ... ]\n");
+#endif /* COMPAT */
+ exit(1);
+}
+
+static char superblock[SBSIZE];
+
+quot(name,mp)
+ char *name, *mp;
+{
+ int fd;
+
+ get_inode(-1); /* flush cache */
+ inituser();
+ initfsizes();
+ if ((fd = open(name,0)) < 0
+ || lseek(fd,SBOFF,0) != SBOFF
+ || read(fd,superblock,SBSIZE) != SBSIZE) {
+ perror(name);
+ close(fd);
+ return;
+ }
+ if (((struct fs *)superblock)->fs_magic != FS_MAGIC) {
+ fprintf(stderr,"%s: not a BSD filesystem\n",name);
+ close(fd);
+ return;
+ }
+ printf("%s:",name);
+ if (mp)
+ printf(" (%s)",mp);
+ putchar('\n');
+ (*func)(fd,superblock,name);
+ close(fd);
+}
+
+int main(argc,argv)
+ char **argv;
+{
+ int fd;
+ char all = 0;
+ FILE *fp;
+ struct statfs *mp;
+ char dev[MNAMELEN + 1];
+ char *nm;
+ int cnt;
+
+ func = douser;
+#ifndef COMPAT
+ header = getbsize(&headerlen,&blocksize);
+#endif
+ while (--argc > 0 && **++argv == '-') {
+ while (*++*argv) {
+ switch (**argv) {
+ case 'n':
+ func = donames;
+ break;
+ case 'c':
+ func = dofsizes;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ case 'f':
+ count = 1;
+ break;
+ case 'h':
+ estimate = 1;
+ break;
+#ifndef COMPAT
+ case 'k':
+ blocksize = 1024;
+ break;
+#endif /* COMPAT */
+ case 'v':
+ unused = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ }
+ if (all) {
+ cnt = getmntinfo(&mp,MNT_NOWAIT);
+ for (; --cnt >= 0; mp++) {
+ if (!strncmp(mp->f_fstypename, MOUNT_UFS, MFSNAMELEN)) {
+ if (nm = strrchr(mp->f_mntfromname,'/')) {
+ sprintf(dev,"/dev/r%s",nm + 1);
+ nm = dev;
+ } else
+ nm = mp->f_mntfromname;
+ quot(nm,mp->f_mntonname);
+ }
+ }
+ }
+ while (--argc >= 0)
+ quot(*argv++,0);
+ return 0;
+}
diff --git a/usr.sbin/quotaon/Makefile b/usr.sbin/quotaon/Makefile
new file mode 100644
index 00000000000..71d874d23c5
--- /dev/null
+++ b/usr.sbin/quotaon/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+
+PROG= quotaon
+MAN= quotaon.8
+MLINKS= quotaon.8 quotaoff.8
+LINKS= ${BINDIR}/quotaon ${BINDIR}/quotaoff
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/quotaon/quotaon.8 b/usr.sbin/quotaon/quotaon.8
new file mode 100644
index 00000000000..9d209902045
--- /dev/null
+++ b/usr.sbin/quotaon/quotaon.8
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\" 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.
+.\"
+.\" from: @(#)quotaon.8 8.2 (Berkeley) 12/11/93
+.\" $Id: quotaon.8,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+.\"
+.Dd December 11, 1993
+.Dt QUOTAON 8
+.Os BSD 4.2
+.Sh NAME
+.Nm quotaon ,
+.Nm quotaoff
+.Nd turn filesystem quotas on and off
+.Sh SYNOPSIS
+.Nm quotaon
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm quotaon
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Nm quotaoff
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm quotaoff
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Sh DESCRIPTION
+.Nm Quotaon
+announces to the system that disk quotas should be enabled on one or more
+filesystems.
+.Nm Quotaoff
+announces to the system that the specified
+filesystems should have any disk quotas
+diskquotas turned off.
+The filesystems specified must have entries in
+.Pa /etc/fstab
+and be mounted.
+.Nm Quotaon
+expects each filesystem to have quota files named
+.Pa quota.user
+and
+.Pa quota.group
+which are located at the root of the associated file system.
+These defaults may be overridden in
+.Pa /etc/fstab .
+By default both user and group quotas are enabled.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+If the
+.Fl a
+flag is supplied in place of any filesystem names,
+.Nm quotaon Ns / Ns Nm quotaoff
+will enable/disable all the filesystems indicated in
+.Pa /etc/fstab
+to be read-write with disk quotas.
+By default only the types of quotas listed in
+.Pa /etc/fstab
+are enabled.
+.It Fl g
+Only group quotas listed in
+.Pa /etc/fstab
+should be enabled/disabled.
+.It Fl u
+Only user quotas listed in
+.Pa /etc/fstab
+should be enabled/disabled.
+.It Fl v
+Causes
+.Nm quotaon
+and
+.Nm quotaoff
+to print a message for each filesystem where quotas are turned on or off.
+.El
+.Pp
+Specifying both
+.Fl g
+and
+.Fl u
+is equivalent to the default.
+.Sh FILES
+.Bl -tag -width quota.group -compact
+.It Pa quota.user
+at the filesystem root with user quotas
+.It Pa quota.group
+at the filesystem root with group quotas
+.It Pa /etc/fstab
+filesystem table
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr fstab 5 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr repquota 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/quotaon/quotaon.c b/usr.sbin/quotaon/quotaon.c
new file mode 100644
index 00000000000..e719634108c
--- /dev/null
+++ b/usr.sbin/quotaon/quotaon.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)quotaon.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: quotaon.c,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Turn quota on/off for a filesystem.
+ */
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <ufs/ufs/quota.h>
+#include <stdio.h>
+#include <string.h>
+#include <fstab.h>
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+
+int aflag; /* all file systems */
+int gflag; /* operate on group quotas */
+int uflag; /* operate on user quotas */
+int vflag; /* verbose */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register struct fstab *fs;
+ char ch, *qfnp, *whoami, *rindex();
+ long argnum, done = 0;
+ int i, offmode = 0, errs = 0;
+ extern char *optarg;
+ extern int optind;
+
+ whoami = rindex(*argv, '/') + 1;
+ if (whoami == (char *)1)
+ whoami = *argv;
+ if (strcmp(whoami, "quotaoff") == 0)
+ offmode++;
+ else if (strcmp(whoami, "quotaon") != 0) {
+ fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
+ whoami);
+ exit(1);
+ }
+ while ((ch = getopt(argc, argv, "avug")) != EOF) {
+ switch(ch) {
+ case 'a':
+ aflag++;
+ break;
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage(whoami);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc <= 0 && !aflag)
+ usage(whoami);
+ if (!gflag && !uflag) {
+ gflag++;
+ uflag++;
+ }
+ setfsent();
+ while ((fs = getfsent()) != NULL) {
+ if (strcmp(fs->fs_vfstype, "ufs") ||
+ strcmp(fs->fs_type, FSTAB_RW))
+ continue;
+ if (aflag) {
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
+ (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
+ }
+ }
+ endfsent();
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not found in fstab\n",
+ argv[i]);
+ exit(errs);
+}
+
+usage(whoami)
+ char *whoami;
+{
+
+ fprintf(stderr, "Usage:\n\t%s [-g] [-u] [-v] -a\n", whoami);
+ fprintf(stderr, "\t%s [-g] [-u] [-v] filesys ...\n", whoami);
+ exit(1);
+}
+
+quotaonoff(fs, offmode, type, qfpathname)
+ register struct fstab *fs;
+ int offmode, type;
+ char *qfpathname;
+{
+
+ if (strcmp(fs->fs_file, "/") && readonly(fs))
+ return (1);
+ if (offmode) {
+ if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
+ fprintf(stderr, "quotaoff: ");
+ perror(fs->fs_file);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: quotas turned off\n", fs->fs_file);
+ return (0);
+ }
+ if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
+ fprintf(stderr, "quotaon: using %s on", qfpathname);
+ perror(fs->fs_file);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: %s quotas turned on\n", fs->fs_file,
+ qfextension[type]);
+ return (0);
+}
+
+/*
+ * Check to see if target appears in list of size cnt.
+ */
+oneof(target, list, cnt)
+ register char *target, *list[];
+ int cnt;
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ if (strcmp(target, list[i]) == 0)
+ return (i);
+ return (-1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
+ sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strcpy(buf, fs->fs_mntops);
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+
+/*
+ * Verify file system is mounted and not readonly.
+ */
+readonly(fs)
+ register struct fstab *fs;
+{
+ struct statfs fsbuf;
+
+ if (statfs(fs->fs_file, &fsbuf) < 0 ||
+ strcmp(fsbuf.f_mntonname, fs->fs_file) ||
+ strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
+ printf("%s: not mounted\n", fs->fs_file);
+ return (1);
+ }
+ if (fsbuf.f_flags & MNT_RDONLY) {
+ printf("%s: mounted read-only\n", fs->fs_file);
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/rarpd/Makefile b/usr.sbin/rarpd/Makefile
new file mode 100644
index 00000000000..ba41f15ba71
--- /dev/null
+++ b/usr.sbin/rarpd/Makefile
@@ -0,0 +1,14 @@
+# @(#) $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+
+PROG= rarpd
+SRCS= rarpd.c
+
+CFLAGS+=-I${.CURDIR}
+
+# Uncomment the following to require a boot file in TFTP_DIR
+# to exist for a rarp reply to be sent.
+# CFLAGS+=-DREQUIRE_TFTPBOOT -DTFTP_DIR=\"/tftpboot\"
+
+MAN= rarpd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rarpd/rarpd.8 b/usr.sbin/rarpd/rarpd.8
new file mode 100644
index 00000000000..27ec0127113
--- /dev/null
+++ b/usr.sbin/rarpd/rarpd.8
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 1988-1990 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: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\" @(#) $Id: rarpd.8,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $
+.\"
+.Dd October 26, 1990
+.Dt RARPD 8
+.Sh NAME
+.Nm rarpd
+.Nd Reverse ARP Daemon
+.Sh SYNOPSIS
+.Nm rarpd
+.Op Fl adf
+.Op Ar interface
+.Sh DESCRIPTION
+.Nm Rarpd
+services Reverse ARP requests on the Ethernet connected to
+.Ar interface.
+Upon receiving a request,
+.Nm rarpd
+maps the target hardware address to an IP address via its name, which
+must be present in both the
+.Xr ethers 5
+and
+.Xr hosts 5
+databases.
+If a host does not exist in both databases, the translation cannot
+proceed and a reply will not be sent.
+.\" .Pp
+.\" Additionally, a request is honored only if the server
+.\" (i.e., the host that rarpd is running on)
+.\" can "boot" the target; that is, if the directory
+.\" .Pa /tftpboot/ Ns Em ipaddr
+.\" exists, where
+.\" .Rm ipaddr
+.\" is the target IP address.
+.Pp
+In normal operation,
+.Nm rarpd
+forks a copy of itself and runs in
+the background. Anomalies and errors are reported via
+.Xr syslog 3 .
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Listen on all the Ethernets attached to the system.
+If
+.Sq Fl a
+is omitted, an interface must be specified.
+.It Fl d
+Run in debug mode, with all the output to stderr.
+This option implies the
+.Fl f
+option.
+.It Fl f
+Run in the foreground.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/ethers
+.It Pa /etc/hosts
+.\" .It Pa /tftpboot
+.El
+.Sh SEE ALSO
+.Xr bpf 4 ,
+.Rs
+.%R A Reverse Address Resolution Protocol
+.%N RFC 903
+.%A Finlayson, R.
+.%A Mann, T.
+.%A Mogul, J.C.
+.%A Theimer, M.
+.Re
+.Sh AUTHORS
+Craig Leres (leres@ee.lbl.gov) and Steven McCanne (mccanne@ee.lbl.gov).
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
diff --git a/usr.sbin/rarpd/rarpd.c b/usr.sbin/rarpd/rarpd.c
new file mode 100644
index 00000000000..0e897586d23
--- /dev/null
+++ b/usr.sbin/rarpd/rarpd.c
@@ -0,0 +1,818 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] =
+"@(#) $Id: rarpd.c,v 1.1.1.1 1995/10/18 08:48:02 deraadt Exp $";
+#endif
+
+
+/*
+ * rarpd - Reverse ARP Daemon
+ *
+ * Usage: rarpd -a [ -d -f ]
+ * rarpd [ -d -f ] interface
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+
+#define FATAL 1 /* fatal error occurred */
+#define NONFATAL 0 /* non fatal error occurred */
+
+/*
+ * The structure for each interface.
+ */
+struct if_info {
+ int ii_fd; /* BPF file descriptor */
+ u_char ii_eaddr[6]; /* Ethernet address of this interface */
+ u_long ii_ipaddr; /* IP address of this interface */
+ u_long ii_netmask; /* subnet or net mask */
+ struct if_info *ii_next;
+};
+/*
+ * The list of all interfaces that are being listened to. rarp_loop()
+ * "selects" on the descriptors in this list.
+ */
+struct if_info *iflist;
+
+int rarp_open __P((char *));
+void init_one __P((char *));
+void init_all __P((void));
+void rarp_loop __P((void));
+void lookup_eaddr __P((char *, u_char *));
+void lookup_ipaddr __P((char *, u_long *, u_long *));
+void usage __P((void));
+void rarp_process __P((struct if_info *, u_char *));
+void rarp_reply __P((struct if_info *, struct ether_header *, u_long));
+void update_arptab __P((u_char *, u_long));
+void err __P((int, const char *,...));
+void debug __P((const char *,...));
+u_long ipaddrtonetmask __P((u_long));
+
+#ifdef REQUIRE_TFTPBOOT
+int rarp_bootable __P((u_long));
+#endif
+
+int aflag = 0; /* listen on "all" interfaces */
+int dflag = 0; /* print debugging messages */
+int fflag = 0; /* don't fork */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int op, pid, devnull, f;
+ char *ifname, *hostname, *name;
+
+ extern char *optarg;
+ extern int optind, opterr;
+
+ if (name = strrchr(argv[0], '/'))
+ ++name;
+ else
+ name = argv[0];
+ if (*name == '-')
+ ++name;
+
+ /* All error reporting is done through syslogs. */
+ openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON);
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "adf")) != EOF) {
+ switch (op) {
+ case 'a':
+ ++aflag;
+ break;
+
+ case 'd':
+ ++dflag;
+ break;
+
+ case 'f':
+ ++fflag;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ ifname = argv[optind++];
+ hostname = ifname ? argv[optind] : 0;
+ if ((aflag && ifname) || (!aflag && ifname == 0))
+ usage();
+
+ if (aflag)
+ init_all();
+ else
+ init_one(ifname);
+
+ if ((!fflag) && (!dflag)) {
+ pid = fork();
+ if (pid > 0)
+ /* Parent exits, leaving child in background. */
+ exit(0);
+ else
+ if (pid == -1) {
+ err(FATAL, "cannot fork");
+ /* NOTREACHED */
+ }
+ /* Fade into the background */
+ f = open("/dev/tty", O_RDWR);
+ if (f >= 0) {
+ if (ioctl(f, TIOCNOTTY, 0) < 0) {
+ err(FATAL, "TIOCNOTTY: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) close(f);
+ }
+ (void) chdir("/");
+ (void) setpgrp(0, getpid());
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull >= 0) {
+ (void) dup2(devnull, 0);
+ (void) dup2(devnull, 1);
+ (void) dup2(devnull, 2);
+ if (devnull > 2)
+ (void) close(devnull);
+ }
+ }
+ rarp_loop();
+}
+/*
+ * Add 'ifname' to the interface list. Lookup its IP address and network
+ * mask and Ethernet address, and open a BPF file for it.
+ */
+void
+init_one(ifname)
+ char *ifname;
+{
+ struct if_info *p;
+
+ p = (struct if_info *)malloc(sizeof(*p));
+ if (p == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ p->ii_next = iflist;
+ iflist = p;
+
+ p->ii_fd = rarp_open(ifname);
+ lookup_eaddr(ifname, p->ii_eaddr);
+ lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask);
+}
+/*
+ * Initialize all "candidate" interfaces that are in the system
+ * configuration list. A "candidate" is up, not loopback and not
+ * point to point.
+ */
+void
+init_all()
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int fd;
+ int i, len;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "init_all: SIOCGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
+ err(FATAL, "init_all: SIOCGIFFLAGS: %s",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ if ((ifr->ifr_flags &
+ (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
+ continue;
+ init_one(ifr->ifr_name);
+ }
+ (void) close(fd);
+}
+
+void
+usage()
+{
+ (void) fprintf(stderr, "usage: rarpd -a [ -d -f ]\n");
+ (void) fprintf(stderr, " rarpd [ -d -f ] interface\n");
+ exit(1);
+}
+
+static int
+bpf_open()
+{
+ int fd;
+ int n = 0;
+ char device[sizeof "/dev/bpf000"];
+
+ /* Go through all the minors and find one that isn't in use. */
+ do {
+ (void) sprintf(device, "/dev/bpf%d", n++);
+ fd = open(device, O_RDWR);
+ } while (fd < 0 && errno == EBUSY);
+
+ if (fd < 0) {
+ err(FATAL, "%s: %s", device, strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Open a BPF file and attach it to the interface named 'device'.
+ * Set immediate mode, and set a filter that accepts only RARP requests.
+ */
+int
+rarp_open(device)
+ char *device;
+{
+ int fd;
+ struct ifreq ifr;
+ u_int dlt;
+ int immediate;
+
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_REVARP, 0, 3),
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARPOP_REVREQUEST, 0, 1),
+ BPF_STMT(BPF_RET | BPF_K, sizeof(struct ether_arp) +
+ sizeof(struct ether_header)),
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ };
+ static struct bpf_program filter = {
+ sizeof insns / sizeof(insns[0]),
+ insns
+ };
+
+ fd = bpf_open();
+
+ /* Set immediate mode so packets are processed as they arrive. */
+ immediate = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
+ err(FATAL, "BIOCIMMEDIATE: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+ if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
+ err(FATAL, "BIOCSETIF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Check that the data link layer is an Ethernet; this code won't work
+ * with anything else. */
+ if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) {
+ err(FATAL, "BIOCGDLT: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ if (dlt != DLT_EN10MB) {
+ err(FATAL, "%s is not an ethernet", device);
+ /* NOTREACHED */
+ }
+ /* Set filter program. */
+ if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
+ err(FATAL, "BIOCSETF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Perform various sanity checks on the RARP request packet. Return
+ * false on failure and log the reason.
+ */
+static int
+rarp_check(p, len)
+ u_char *p;
+ int len;
+{
+ struct ether_header *ep = (struct ether_header *) p;
+ struct ether_arp *ap = (struct ether_arp *) (p + sizeof(*ep));
+
+ (void) debug("got a packet");
+
+ if (len < sizeof(*ep) + sizeof(*ap)) {
+ err(NONFATAL, "truncated request");
+ return 0;
+ }
+ /* XXX This test might be better off broken out... */
+ if (ntohs (ep->ether_type) != ETHERTYPE_REVARP ||
+ ntohs (ap->arp_hrd) != ARPHRD_ETHER ||
+ ntohs (ap->arp_op) != ARPOP_REVREQUEST ||
+ ntohs (ap->arp_pro) != ETHERTYPE_IP ||
+ ap->arp_hln != 6 || ap->arp_pln != 4) {
+ err(NONFATAL, "request fails sanity check");
+ return 0;
+ }
+ if (bcmp((char *) &ep->ether_shost, (char *) &ap->arp_sha, 6) != 0) {
+ err(NONFATAL, "ether/arp sender address mismatch");
+ return 0;
+ }
+ if (bcmp((char *) &ap->arp_sha, (char *) &ap->arp_tha, 6) != 0) {
+ err(NONFATAL, "ether/arp target address mismatch");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Loop indefinitely listening for RARP requests on the
+ * interfaces in 'iflist'.
+ */
+void
+rarp_loop()
+{
+ u_char *buf, *bp, *ep;
+ int cc, fd;
+ fd_set fds, listeners;
+ int bufsize, maxfd = 0;
+ struct if_info *ii;
+
+ if (iflist == 0) {
+ err(FATAL, "no interfaces");
+ /* NOTREACHED */
+ }
+ if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t) & bufsize) < 0) {
+ err(FATAL, "BIOCGBLEN: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ buf = (u_char *) malloc((unsigned) bufsize);
+ if (buf == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /*
+ * Find the highest numbered file descriptor for select().
+ * Initialize the set of descriptors to listen to.
+ */
+ FD_ZERO(&fds);
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ FD_SET(ii->ii_fd, &fds);
+ if (ii->ii_fd > maxfd)
+ maxfd = ii->ii_fd;
+ }
+ while (1) {
+ listeners = fds;
+ if (select(maxfd + 1, &listeners, (struct fd_set *) 0,
+ (struct fd_set *) 0, (struct timeval *) 0) < 0) {
+ err(FATAL, "select: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ fd = ii->ii_fd;
+ if (!FD_ISSET(fd, &listeners))
+ continue;
+ again:
+ cc = read(fd, (char *) buf, bufsize);
+ /* Don't choke when we get ptraced */
+ if (cc < 0 && errno == EINTR)
+ goto again;
+ /* Due to a SunOS bug, after 2^31 bytes, the file
+ * offset overflows and read fails with EINVAL. The
+ * lseek() to 0 will fix things. */
+ if (cc < 0) {
+ if (errno == EINVAL &&
+ (lseek(fd, 0, SEEK_CUR) + bufsize) < 0) {
+ (void) lseek(fd, 0, 0);
+ goto again;
+ }
+ err(FATAL, "read: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Loop through the packet(s) */
+#define bhp ((struct bpf_hdr *)bp)
+ bp = buf;
+ ep = bp + cc;
+ while (bp < ep) {
+ register int caplen, hdrlen;
+
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+ if (rarp_check(bp + hdrlen, caplen))
+ rarp_process(ii, bp + hdrlen);
+ bp += BPF_WORDALIGN(hdrlen + caplen);
+ }
+ }
+ }
+}
+
+#ifdef REQUIRE_TFTPBOOT
+
+#ifndef TFTP_DIR
+#define TFTP_DIR "/tftpboot"
+#endif
+
+/*
+ * True if this server can boot the host whose IP address is 'addr'.
+ * This check is made by looking in the tftp directory for the
+ * configuration file.
+ */
+int
+rarp_bootable(addr)
+ u_long addr;
+{
+ register struct dirent *dent;
+ register DIR *d;
+ char ipname[9];
+ static DIR *dd = 0;
+
+ (void) sprintf(ipname, "%08X", addr);
+ /* If directory is already open, rewind it. Otherwise, open it. */
+ if (d = dd)
+ rewinddir(d);
+ else {
+ if (chdir(TFTP_DIR) == -1) {
+ err(FATAL, "chdir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ d = opendir(".");
+ if (d == 0) {
+ err(FATAL, "opendir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ dd = d;
+ }
+ while (dent = readdir(d))
+ if (strncmp(dent->d_name, ipname, 8) == 0)
+ return 1;
+ return 0;
+}
+#endif /* REQUIRE_TFTPBOOT */
+
+/*
+ * Given a list of IP addresses, 'alist', return the first address that
+ * is on network 'net'; 'netmask' is a mask indicating the network portion
+ * of the address.
+ */
+u_long
+choose_ipaddr(alist, net, netmask)
+ u_long **alist;
+ u_long net;
+ u_long netmask;
+{
+ for (; *alist; ++alist) {
+ if ((**alist & netmask) == net)
+ return **alist;
+ }
+ return 0;
+}
+/*
+ * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has
+ * already been checked for validity. The reply is overlaid on the request.
+ */
+void
+rarp_process(ii, pkt)
+ struct if_info *ii;
+ u_char *pkt;
+{
+ struct ether_header *ep;
+ struct hostent *hp;
+ u_long target_ipaddr;
+ char ename[256];
+ struct in_addr in;
+
+ ep = (struct ether_header *) pkt;
+
+ if (ether_ntohost(ename, &ep->ether_shost) != 0 ||
+ (hp = gethostbyname(ename)) == 0)
+ return;
+
+ /* Choose correct address from list. */
+ if (hp->h_addrtype != AF_INET) {
+ err(FATAL, "cannot handle non IP addresses");
+ /* NOTREACHED */
+ }
+ target_ipaddr = choose_ipaddr((u_long **) hp->h_addr_list,
+ ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask);
+
+ if (target_ipaddr == 0) {
+ in.s_addr = ii->ii_ipaddr & ii->ii_netmask;
+ err(NONFATAL, "cannot find %s on net %s\n",
+ ename, inet_ntoa(in));
+ return;
+ }
+#ifdef REQUIRE_TFTPBOOT
+ if (rarp_bootable(htonl(target_ipaddr)))
+#endif
+ rarp_reply(ii, ep, target_ipaddr);
+}
+/*
+ * Lookup the ethernet address of the interface attached to the BPF
+ * file descriptor 'fd'; return it in 'eaddr'.
+ */
+void
+lookup_eaddr(ifname, eaddr)
+ char *ifname;
+ u_char *eaddr;
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr_dl *sdl;
+ int fd;
+ int i, len;
+
+ /* We cannot use SIOCGIFADDR on the BPF descriptor.
+ We must instead get all the interfaces with SIOCGIFCONF
+ and find the right one. */
+
+ /* Use datagram socket to get Ethernet address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
+ sdl->sdl_alen != 6)
+ continue;
+ if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) {
+ bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6);
+ if (dflag)
+ fprintf(stderr, "%s: %x:%x:%x:%x:%x:%x\n",
+ ifr->ifr_name, eaddr[0], eaddr[1],
+ eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
+ return;
+ }
+ }
+
+ err(FATAL, "lookup_eaddr: Never saw interface `%s'!", ifname);
+}
+/*
+ * Lookup the IP address and network mask of the interface named 'ifname'.
+ */
+void
+lookup_ipaddr(ifname, addrp, netmaskp)
+ char *ifname;
+ u_long *addrp;
+ u_long *netmaskp;
+{
+ int fd;
+ struct ifreq ifr;
+
+ /* Use datagram socket to get IP address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ if (ioctl(fd, SIOCGIFADDR, (char *) &ifr) < 0) {
+ err(FATAL, "SIOCGIFADDR: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ *addrp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ if (ioctl(fd, SIOCGIFNETMASK, (char *) &ifr) < 0) {
+ perror("SIOCGIFNETMASK");
+ exit(1);
+ }
+ *netmaskp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
+ * address class. */
+ if (*netmaskp == 0)
+ *netmaskp = ipaddrtonetmask(*addrp);
+
+ (void) close(fd);
+}
+/*
+ * Poke the kernel arp tables with the ethernet/ip address combinataion
+ * given. When processing a reply, we must do this so that the booting
+ * host (i.e. the guy running rarpd), won't try to ARP for the hardware
+ * address of the guy being booted (he cannot answer the ARP).
+ */
+void
+update_arptab(ep, ipaddr)
+ u_char *ep;
+ u_long ipaddr;
+{
+ int s;
+ struct arpreq request;
+ struct sockaddr_in *sin;
+
+ request.arp_flags = 0;
+ sin = (struct sockaddr_in *) & request.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ipaddr;
+ request.arp_ha.sa_family = AF_UNSPEC;
+ /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
+ because AF_UNSPEC is zero and the kernel assumes that a zero
+ sa_family means that the real sa_family value is in sa_len. */
+ request.arp_ha.sa_len = 16; /* XXX */
+ bcopy((char *) ep, (char *) request.arp_ha.sa_data, 6);
+
+#if 0
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ioctl(s, SIOCSARP, (caddr_t) & request) < 0) {
+ err(NONFATAL, "SIOCSARP: %s", strerror(errno));
+ }
+ (void) close(s);
+#endif
+}
+/*
+ * Build a reverse ARP packet and sent it out on the interface.
+ * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built
+ * on top of the request, then written to the network.
+ *
+ * RFC 903 defines the ether_arp fields as follows. The following comments
+ * are taken (more or less) straight from this document.
+ *
+ * ARPOP_REVREQUEST
+ *
+ * arp_sha is the hardware address of the sender of the packet.
+ * arp_spa is undefined.
+ * arp_tha is the 'target' hardware address.
+ * In the case where the sender wishes to determine his own
+ * protocol address, this, like arp_sha, will be the hardware
+ * address of the sender.
+ * arp_tpa is undefined.
+ *
+ * ARPOP_REVREPLY
+ *
+ * arp_sha is the hardware address of the responder (the sender of the
+ * reply packet).
+ * arp_spa is the protocol address of the responder (see the note below).
+ * arp_tha is the hardware address of the target, and should be the same as
+ * that which was given in the request.
+ * arp_tpa is the protocol address of the target, that is, the desired address.
+ *
+ * Note that the requirement that arp_spa be filled in with the responder's
+ * protocol is purely for convenience. For instance, if a system were to use
+ * both ARP and RARP, then the inclusion of the valid protocol-hardware
+ * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
+ * ARP request.
+ */
+void
+rarp_reply(ii, ep, ipaddr)
+ struct if_info *ii;
+ struct ether_header *ep;
+ u_long ipaddr;
+{
+ int n;
+ struct ether_arp *ap = (struct ether_arp *) (ep + 1);
+ int len;
+
+ update_arptab((u_char *) & ap->arp_sha, ipaddr);
+
+ /* Build the rarp reply by modifying the rarp request in place. */
+ ep->ether_type = htons(ETHERTYPE_REVARP);
+ ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+ ap->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+ ap->arp_op = htons(ARPOP_REVREPLY);
+
+ bcopy((char *) &ap->arp_sha, (char *) &ep->ether_dhost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ep->ether_shost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ap->arp_sha, 6);
+
+ bcopy((char *) &ipaddr, (char *) ap->arp_tpa, 4);
+ /* Target hardware is unchanged. */
+ bcopy((char *) &ii->ii_ipaddr, (char *) ap->arp_spa, 4);
+
+ len = sizeof(*ep) + sizeof(*ap);
+ n = write(ii->ii_fd, (char *) ep, len);
+ if (n != len) {
+ err(NONFATAL, "write: only %d of %d bytes written", n, len);
+ }
+}
+/*
+ * Get the netmask of an IP address. This routine is used if
+ * SIOCGIFNETMASK doesn't work.
+ */
+u_long
+ipaddrtonetmask(addr)
+ u_long addr;
+{
+ if (IN_CLASSA(addr))
+ return IN_CLASSA_NET;
+ if (IN_CLASSB(addr))
+ return IN_CLASSB_NET;
+ if (IN_CLASSC(addr))
+ return IN_CLASSC_NET;
+ err(FATAL, "unknown IP address class: %08X", addr);
+ /* NOTREACHED */
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(int fatal, const char *fmt,...)
+#else
+err(fmt, va_alist)
+ int fatal;
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ if (dflag) {
+ if (fatal)
+ (void) fprintf(stderr, "rarpd: error: ");
+ else
+ (void) fprintf(stderr, "rarpd: warning: ");
+ (void) vfprintf(stderr, fmt, ap);
+ (void) fprintf(stderr, "\n");
+ }
+ vsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ if (fatal)
+ exit(1);
+ /* NOTREACHED */
+}
+
+void
+#if __STDC__
+debug(const char *fmt,...)
+#else
+debug(fmt, va_alist)
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+
+ if (dflag) {
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) fprintf(stderr, "rarpd: ");
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+}
diff --git a/usr.sbin/rbootd/Makefile b/usr.sbin/rbootd/Makefile
new file mode 100644
index 00000000000..59d3137bb79
--- /dev/null
+++ b/usr.sbin/rbootd/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $NetBSD: Makefile,v 1.4 1995/08/21 17:05:08 thorpej Exp $
+
+PROG= rbootd
+SRCS= bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c
+MAN= rbootd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rbootd/bpf.c b/usr.sbin/rbootd/bpf.c
new file mode 100644
index 00000000000..fcb06445bc9
--- /dev/null
+++ b/usr.sbin/rbootd/bpf.c
@@ -0,0 +1,425 @@
+/* $NetBSD: bpf.c,v 1.5 1995/10/06 05:12:12 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)bpf.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: bpf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: bpf.c,v 1.5 1995/10/06 05:12:12 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+#include "pathnames.h"
+
+static int BpfFd = -1;
+static unsigned BpfLen = 0;
+static u_int8_t *BpfPkt = NULL;
+
+/*
+** BpfOpen -- Open and initialize a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** File descriptor of opened BPF device (for select() etc).
+**
+** Side Effects:
+** If an error is encountered, the program terminates here.
+*/
+int
+BpfOpen()
+{
+ struct ifreq ifr;
+ char bpfdev[32];
+ int n = 0;
+
+ /*
+ * Open the first available BPF device.
+ */
+ do {
+ (void) sprintf(bpfdev, _PATH_BPF, n++);
+ BpfFd = open(bpfdev, O_RDWR);
+ } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
+
+ if (BpfFd < 0) {
+ syslog(LOG_ERR, "bpf: no available devices: %m");
+ Exit(0);
+ }
+
+ /*
+ * Set interface name for bpf device, get data link layer
+ * type and make sure it's type Ethernet.
+ */
+ (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
+ if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
+ Exit(0);
+ }
+
+ /*
+ * Make sure we are dealing with an Ethernet device.
+ */
+ if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
+ Exit(0);
+ }
+ if (n != DLT_EN10MB) {
+ syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
+ IntfName, n);
+ Exit(0);
+ }
+
+ /*
+ * On read(), return packets immediately (do not buffer them).
+ */
+ n = 1;
+ if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
+ Exit(0);
+ }
+
+ /*
+ * Try to enable the chip/driver's multicast address filter to
+ * grab our RMP address. If this fails, try promiscuous mode.
+ * If this fails, there's no way we are going to get any RMP
+ * packets so just exit here.
+ */
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
+ syslog(LOG_WARNING,
+ "bpf: can't add mcast addr (%m), setting promiscuous mode");
+
+ if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
+ syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
+ Exit(0);
+ }
+ }
+
+ /*
+ * Ask BPF how much buffer space it requires and allocate one.
+ */
+ if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
+ Exit(0);
+ }
+ if (BpfPkt == NULL)
+ BpfPkt = (u_int8_t *)malloc(BpfLen);
+
+ if (BpfPkt == NULL) {
+ syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
+ BpfLen);
+ Exit(0);
+ }
+
+ /*
+ * Write a little program to snarf RMP Boot packets and stuff
+ * it down BPF's throat (i.e. set up the packet filter).
+ */
+ {
+#define RMP ((struct rmp_packet *)0)
+ static struct bpf_insn bpf_insn[] = {
+ { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
+ { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
+ { BPF_RET|BPF_K, 0, 0, 0x0 }
+ };
+#undef RMP
+ static struct bpf_program bpf_pgm = {
+ sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
+ };
+
+ if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
+ Exit(0);
+ }
+ }
+
+ return(BpfFd);
+}
+
+/*
+** BPF GetIntfName -- Return the name of a network interface attached to
+** the system, or 0 if none can be found. The interface
+** must be configured up; the lowest unit number is
+** preferred; loopback is ignored.
+**
+** Parameters:
+** errmsg - if no network interface found, *errmsg explains why.
+**
+** Returns:
+** A (static) pointer to interface name, or NULL on error.
+**
+** Side Effects:
+** None.
+*/
+char *
+BpfGetIntfName(errmsg)
+ char **errmsg;
+{
+ struct ifreq ibuf[8], *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ int fd;
+ int minunit, n;
+ char *cp;
+ static char device[sizeof(ifrp->ifr_name)];
+ static char errbuf[128] = "No Error!";
+
+ if (errmsg != NULL)
+ *errmsg = errbuf;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (void) strcpy(errbuf, "bpf: socket: %m");
+ return(NULL);
+ }
+ ifc.ifc_len = sizeof ibuf;
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+#ifdef OSIOCGIFCONF
+ if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
+ return(NULL);
+ }
+#else
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
+ return(NULL);
+ }
+#endif
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ mp = 0;
+ minunit = 666;
+ for (; ifrp < ifend; ++ifrp) {
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
+ return(NULL);
+ }
+
+ /*
+ * If interface is down or this is the loopback interface,
+ * ignore it.
+ */
+ if ((ifrp->ifr_flags & IFF_UP) == 0 ||
+#ifdef IFF_LOOPBACK
+ (ifrp->ifr_flags & IFF_LOOPBACK))
+#else
+ (strcmp(ifrp->ifr_name, "lo0") == 0))
+#endif
+ continue;
+
+ for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+ ;
+ n = atoi(cp);
+ if (n < minunit) {
+ minunit = n;
+ mp = ifrp;
+ }
+ }
+
+ (void) close(fd);
+ if (mp == 0) {
+ (void) strcpy(errbuf, "bpf: no interfaces found");
+ return(NULL);
+ }
+
+ (void) strcpy(device, mp->ifr_name);
+ return(device);
+}
+
+/*
+** BpfRead -- Read packets from a BPF device and fill in `rconn'.
+**
+** Parameters:
+** rconn - filled in with next packet.
+** doread - is True if we can issue a read() syscall.
+**
+** Returns:
+** True if `rconn' contains a new packet, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfRead(rconn, doread)
+ RMPCONN *rconn;
+ int doread;
+{
+ register int datlen, caplen, hdrlen;
+ static u_int8_t *bp = NULL, *ep = NULL;
+ int cc;
+
+ /*
+ * The read() may block, or it may return one or more packets.
+ * We let the caller decide whether or not we can issue a read().
+ */
+ if (doread) {
+ if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
+ syslog(LOG_ERR, "bpf: read: %m");
+ return(0);
+ } else {
+ bp = BpfPkt;
+ ep = BpfPkt + cc;
+ }
+ }
+
+#define bhp ((struct bpf_hdr *)bp)
+ /*
+ * If there is a new packet in the buffer, stuff it into `rconn'
+ * and return a success indication.
+ */
+ if (bp < ep) {
+ datlen = bhp->bh_datalen;
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+
+ if (caplen != datlen)
+ syslog(LOG_ERR,
+ "bpf: short packet dropped (%d of %d bytes)",
+ caplen, datlen);
+ else if (caplen > sizeof(struct rmp_packet))
+ syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
+ caplen);
+ else {
+ rconn->rmplen = htons(caplen);
+ bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp,
+ sizeof(struct timeval));
+ bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen);
+ }
+ bp += BPF_WORDALIGN(caplen + hdrlen);
+ return(1);
+ }
+#undef bhp
+
+ return(0);
+}
+
+/*
+** BpfWrite -- Write packet to BPF device.
+**
+** Parameters:
+** rconn - packet to send.
+**
+** Returns:
+** True if write succeeded, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfWrite(rconn)
+ RMPCONN *rconn;
+{
+ if (write(BpfFd, (char *)&rconn->rmp, ntohs(rconn->rmplen)) < 0) {
+ syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
+ return(0);
+ }
+
+ return(1);
+}
+
+/*
+** BpfClose -- Close a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+BpfClose()
+{
+ struct ifreq ifr;
+
+ if (BpfPkt != NULL) {
+ free((char *)BpfPkt);
+ BpfPkt = NULL;
+ }
+
+ if (BpfFd == -1)
+ return;
+
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
+ (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
+
+ (void) close(BpfFd);
+ BpfFd = -1;
+}
diff --git a/usr.sbin/rbootd/conf.c b/usr.sbin/rbootd/conf.c
new file mode 100644
index 00000000000..51ad23bac5c
--- /dev/null
+++ b/usr.sbin/rbootd/conf.c
@@ -0,0 +1,92 @@
+/* $NetBSD: conf.c,v 1.5 1995/10/06 05:12:13 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)conf.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: conf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)conf.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: conf.c,v 1.5 1995/10/06 05:12:13 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include "defs.h"
+#include "pathnames.h"
+
+/*
+** Define (and possibly initialize) global variables here.
+**
+** Caveat:
+** The maximum number of bootable files (`char *BootFiles[]') is
+** limited to C_MAXFILE (i.e. the maximum number of files that
+** can be spec'd in the configuration file). This was done to
+** simplify the boot file search code.
+*/
+
+char MyHost[MAXHOSTNAMELEN+1]; /* host name */
+pid_t MyPid; /* process id */
+int DebugFlg = 0; /* set true if debugging */
+int BootAny = 0; /* set true if we boot anyone */
+
+char *ConfigFile = NULL; /* configuration file */
+char *DfltConfig = _PATH_RBOOTDCONF; /* default configuration file */
+char *PidFile = _PATH_RBOOTDPID; /* file w/pid of server */
+char *BootDir = _PATH_RBOOTDLIB; /* directory w/boot files */
+char *DbgFile = _PATH_RBOOTDDBG; /* debug output file */
+
+FILE *DbgFp = NULL; /* debug file pointer */
+char *IntfName = NULL; /* intf we are attached to */
+
+u_int16_t SessionID = 0; /* generated session ID */
+
+char *BootFiles[C_MAXFILE]; /* list of boot files */
+
+CLIENT *Clients = NULL; /* list of addrs we'll accept */
+RMPCONN *RmpConns = NULL; /* list of active connections */
+
+u_int8_t RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */
diff --git a/usr.sbin/rbootd/defs.h b/usr.sbin/rbootd/defs.h
new file mode 100644
index 00000000000..9ff814e2c30
--- /dev/null
+++ b/usr.sbin/rbootd/defs.h
@@ -0,0 +1,186 @@
+/* $NetBSD: defs.h,v 1.5 1995/10/06 05:12:14 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)defs.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: defs.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#include "rmp.h"
+#include "rmp_var.h"
+
+/*
+** Common #define's and external variables. All other files should
+** include this.
+*/
+
+/*
+ * This may be defined in <sys/param.h>, if not, it's defined here.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/*
+ * SIGUSR1 and SIGUSR2 are defined in <signal.h> for 4.3BSD systems.
+ */
+#ifndef SIGUSR1
+#define SIGUSR1 SIGEMT
+#endif
+#ifndef SIGUSR2
+#define SIGUSR2 SIGFPE
+#endif
+
+/*
+ * These can be faster & more efficient than strcmp()/strncmp()...
+ */
+#define STREQN(s1,s2) ((*s1 == *s2) && (strcmp(s1,s2) == 0))
+#define STRNEQN(s1,s2,n) ((*s1 == *s2) && (strncmp(s1,s2,n) == 0))
+
+/*
+ * Configuration file limitations.
+ */
+#define C_MAXFILE 10 /* max number of boot-able files */
+#define C_LINELEN 1024 /* max length of line */
+
+/*
+ * Direction of packet (used as argument to DispPkt).
+ */
+#define DIR_RCVD 0
+#define DIR_SENT 1
+#define DIR_NONE 2
+
+/*
+ * These need not be functions, so...
+ */
+#define FreeStr(str) free(str)
+#define FreeClient(cli) free(cli)
+#define GenSessID() (++SessionID ? SessionID: ++SessionID)
+
+/*
+ * Converting an Ethernet address to a string is done in many routines.
+ * Using `rmp.hp_hdr.saddr' works because this field is *never* changed;
+ * it will *always* contain the source address of the packet.
+ */
+#define EnetStr(rptr) GetEtherAddr(&(rptr)->rmp.hp_hdr.saddr[0])
+
+/*
+ * Every machine we can boot will have one of these allocated for it
+ * (unless there are no restrictions on who we can boot).
+ */
+typedef struct client_s {
+ u_int8_t addr[RMP_ADDRLEN]; /* addr of machine */
+ char *files[C_MAXFILE]; /* boot-able files */
+ struct client_s *next; /* ptr to next */
+} CLIENT;
+
+/*
+ * Every active connection has one of these allocated for it.
+ */
+typedef struct rmpconn_s {
+ struct rmp_packet rmp; /* RMP packet */
+ int rmplen; /* length of packet */
+ struct timeval tstamp; /* last time active */
+ int bootfd; /* open boot file */
+ struct rmpconn_s *next; /* ptr to next */
+} RMPCONN;
+
+/*
+ * All these variables are defined in "conf.c".
+ */
+extern char MyHost[]; /* this hosts' name */
+extern pid_t MyPid; /* this processes' ID */
+extern int DebugFlg; /* set true if debugging */
+extern int BootAny; /* set true if we can boot anyone */
+
+extern char *ConfigFile; /* configuration file */
+extern char *DfltConfig; /* default configuration file */
+extern char *DbgFile; /* debug output file */
+extern char *PidFile; /* file containing pid of server */
+extern char *BootDir; /* directory w/boot files */
+
+extern FILE *DbgFp; /* debug file pointer */
+extern char *IntfName; /* interface we are attached to */
+
+extern u_int16_t SessionID; /* generated session ID */
+
+extern char *BootFiles[]; /* list of boot files */
+
+extern CLIENT *Clients; /* list of addrs we'll accept */
+extern RMPCONN *RmpConns; /* list of active connections */
+
+extern u_int8_t RmpMcastAddr[]; /* RMP multicast address */
+
+void AddConn __P((RMPCONN *));
+int BootDone __P((RMPCONN *));
+void BpfClose __P((void));
+char *BpfGetIntfName __P((char **));
+int BpfOpen __P((void));
+int BpfRead __P((RMPCONN *, int));
+int BpfWrite __P((RMPCONN *));
+void DebugOff __P((int));
+void DebugOn __P((int));
+void DispPkt __P((RMPCONN *, int));
+void DoTimeout __P((void));
+void DspFlnm __P((u_int, char *));
+void Exit __P((int));
+CLIENT *FindClient __P((RMPCONN *));
+RMPCONN *FindConn __P((RMPCONN *));
+void FreeClients __P((void));
+void FreeConn __P((RMPCONN *));
+void FreeConns __P((void));
+int GetBootFiles __P((void));
+char *GetEtherAddr __P((u_int8_t *));
+CLIENT *NewClient __P((u_int8_t *));
+RMPCONN *NewConn __P((RMPCONN *));
+char *NewStr __P((char *));
+u_int8_t *ParseAddr __P((char *));
+int ParseConfig __P((void));
+void ProcessPacket __P((RMPCONN *, CLIENT *));
+void ReConfig __P((int));
+void RemoveConn __P((RMPCONN *));
+int SendBootRepl __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendFileNo __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendPacket __P((RMPCONN *));
+int SendReadRepl __P((RMPCONN *));
+int SendServerID __P((RMPCONN *));
diff --git a/usr.sbin/rbootd/parseconf.c b/usr.sbin/rbootd/parseconf.c
new file mode 100644
index 00000000000..e96e9275d73
--- /dev/null
+++ b/usr.sbin/rbootd/parseconf.c
@@ -0,0 +1,361 @@
+/* $NetBSD: parseconf.c,v 1.4 1995/10/06 05:12:16 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)parseconf.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: parseconf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: parseconf.c,v 1.4 1995/10/06 05:12:16 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "defs.h"
+
+/*
+** ParseConfig -- parse the config file into linked list of clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** 1 on success, 0 otherwise.
+**
+** Side Effects:
+** - Linked list of clients will be (re)allocated.
+**
+** Warnings:
+** - GetBootFiles() must be called before this routine
+** to create a linked list of default boot files.
+*/
+int
+ParseConfig()
+{
+ FILE *fp;
+ CLIENT *client;
+ u_int8_t *addr;
+ char line[C_LINELEN];
+ register char *cp, *bcp;
+ register int i, j;
+ int omask, linecnt = 0;
+
+ if (BootAny) /* ignore config file */
+ return(1);
+
+ FreeClients(); /* delete old list of clients */
+
+ if ((fp = fopen(ConfigFile, "r")) == NULL) {
+ syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",
+ ConfigFile);
+ return(0);
+ }
+
+ /*
+ * We've got to block SIGHUP to prevent reconfiguration while
+ * dealing with the linked list of Clients. This can be done
+ * when actually linking the new client into the list, but
+ * this could have unexpected results if the server was HUP'd
+ * whilst reconfiguring. Hence, it is done here.
+ */
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * GETSTR positions `bcp' at the start of the current token,
+ * and null terminates it. `cp' is positioned at the start
+ * of the next token. spaces & commas are separators.
+ */
+#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \
+ bcp = cp; \
+ while (*cp && *cp!=',' && !isspace(*cp)) cp++; \
+ if (*cp) *cp++ = '\0'
+
+ /*
+ * For each line, parse it into a new CLIENT struct.
+ */
+ while (fgets(line, C_LINELEN, fp) != NULL) {
+ linecnt++; /* line counter */
+
+ if (*line == '\0' || *line == '#') /* ignore comment */
+ continue;
+
+ if ((cp = index(line,'#')) != NULL) /* trash comments */
+ *cp = '\0';
+
+ cp = line; /* init `cp' */
+ GETSTR; /* get RMP addr */
+ if (bcp == cp) /* all delimiters */
+ continue;
+
+ /*
+ * Get an RMP address from a string. Abort on failure.
+ */
+ if ((addr = ParseAddr(bcp)) == NULL) {
+ syslog(LOG_ERR,
+ "ParseConfig: line %d: cant parse <%s>",
+ linecnt, bcp);
+ continue;
+ }
+
+ if ((client = NewClient(addr)) == NULL) /* alloc new client */
+ continue;
+
+ GETSTR; /* get first file */
+
+ /*
+ * If no boot files are spec'd, use the default list.
+ * Otherwise, validate each file (`bcp') against the
+ * list of boot-able files.
+ */
+ i = 0;
+ if (bcp == cp) /* no files spec'd */
+ for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)
+ client->files[i] = BootFiles[i];
+ else {
+ do {
+ /*
+ * For each boot file spec'd, make sure it's
+ * in our list. If so, include a pointer to
+ * it in the CLIENT's list of boot files.
+ */
+ for (j = 0; ; j++) {
+ if (j==C_MAXFILE||BootFiles[j]==NULL) {
+ syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",
+ linecnt, bcp);
+ break;
+ }
+ if (STREQN(BootFiles[j], bcp)) {
+ if (i < C_MAXFILE)
+ client->files[i++] =
+ BootFiles[j];
+ else
+ syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",
+ linecnt, bcp);
+ break;
+ }
+ }
+ GETSTR; /* get next file */
+ } while (bcp != cp);
+
+ /*
+ * Restricted list of boot files were spec'd,
+ * however, none of them were found. Since we
+ * apparently cant let them boot "just anything",
+ * the entire record is invalidated.
+ */
+ if (i == 0) {
+ FreeClient(client);
+ continue;
+ }
+ }
+
+ /*
+ * Link this client into the linked list of clients.
+ * SIGHUP has already been blocked.
+ */
+ if (Clients)
+ client->next = Clients;
+ Clients = client;
+ }
+
+ (void) fclose(fp); /* close config file */
+
+ (void) sigsetmask(omask); /* reset signal mask */
+
+ return(1); /* return success */
+}
+
+/*
+** ParseAddr -- Parse a string containing an RMP address.
+**
+** This routine is fairly liberal at parsing an RMP address. The
+** address must contain 6 octets consisting of between 0 and 2 hex
+** chars (upper/lower case) separated by colons. If two colons are
+** together (e.g. "::", the octet between them is recorded as being
+** zero. Hence, the following addrs are all valid and parse to the
+** same thing:
+**
+** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD
+**
+** For clarity, an RMP address is really an Ethernet address, but
+** since the HP boot code uses IEEE 802.3, it's really an IEEE
+** 802.3 address. Of course, all of these are identical.
+**
+** Parameters:
+** str - string representation of an RMP address.
+**
+** Returns:
+** pointer to a static array of RMP_ADDRLEN bytes.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+*/
+u_int8_t *
+ParseAddr(str)
+ char *str;
+{
+ static u_int8_t addr[RMP_ADDRLEN];
+ register char *cp;
+ register unsigned i;
+ register int part, subpart;
+
+ bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */
+
+ part = subpart = 0;
+ for (cp = str; *cp; cp++) {
+ /*
+ * A colon (`:') must be used to delimit each octet.
+ */
+ if (*cp == ':') {
+ if (++part == RMP_ADDRLEN) /* too many parts */
+ return(NULL);
+ subpart = 0;
+ continue;
+ }
+
+ /*
+ * Convert hex character to an integer.
+ */
+ if (isdigit(*cp))
+ i = *cp - '0';
+ else {
+ i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;
+ if (i < 10 || i > 15) /* not a hex char */
+ return(NULL);
+ }
+
+ if (subpart++) {
+ if (subpart > 2) /* too many hex chars */
+ return(NULL);
+ addr[part] <<= 4;
+ }
+ addr[part] |= i;
+ }
+
+ if (part != (RMP_ADDRLEN-1)) /* too few parts */
+ return(NULL);
+
+ return(&addr[0]);
+}
+
+/*
+** GetBootFiles -- record list of files in current (boot) directory.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Number of boot files on success, 0 on failure.
+**
+** Side Effects:
+** Strings in `BootFiles' are freed/allocated.
+**
+** Warnings:
+** - After this routine is called, ParseConfig() must be
+** called to re-order it's list of boot file pointers.
+*/
+int
+GetBootFiles()
+{
+ DIR *dfd;
+ struct stat statb;
+ register struct dirent *dp;
+ register int i;
+
+ /*
+ * Free the current list of boot files.
+ */
+ for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {
+ FreeStr(BootFiles[i]);
+ BootFiles[i] = NULL;
+ }
+
+ /*
+ * Open current directory to read boot file names.
+ */
+ if ((dfd = opendir(".")) == NULL) { /* open BootDir */
+ syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",
+ BootDir);
+ return(0);
+ }
+
+ /*
+ * Read each boot file name and allocate space for it in the
+ * list of boot files (BootFiles). All boot files read after
+ * C_MAXFILE will be ignored.
+ */
+ i = 0;
+ for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {
+ if (stat(dp->d_name, &statb) < 0 ||
+ (statb.st_mode & S_IFMT) != S_IFREG)
+ continue;
+ if (i == C_MAXFILE)
+ syslog(LOG_ERR,
+ "GetBootFiles: too many boot files (%s ignored)",
+ dp->d_name);
+ else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)
+ i++;
+ }
+
+ (void) closedir(dfd); /* close BootDir */
+
+ if (i == 0) /* cant find any boot files */
+ syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);
+
+ return(i);
+}
diff --git a/usr.sbin/rbootd/pathnames.h b/usr.sbin/rbootd/pathnames.h
new file mode 100644
index 00000000000..381864abc45
--- /dev/null
+++ b/usr.sbin/rbootd/pathnames.h
@@ -0,0 +1,53 @@
+/* $NetBSD: pathnames.h,v 1.3 1995/08/21 17:05:15 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: pathnames.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#define _PATH_BPF "/dev/bpf%d"
+#define _PATH_RBOOTDCONF "/etc/rbootd.conf"
+#define _PATH_RBOOTDDBG "/tmp/rbootd.dbg"
+#define _PATH_RBOOTDLIB "/usr/mdec/rbootd"
+#define _PATH_RBOOTDPID "/var/run/rbootd.pid"
diff --git a/usr.sbin/rbootd/rbootd.8 b/usr.sbin/rbootd/rbootd.8
new file mode 100644
index 00000000000..f4f7eb02e4a
--- /dev/null
+++ b/usr.sbin/rbootd/rbootd.8
@@ -0,0 +1,158 @@
+.\" $NetBSD: rbootd.8,v 1.3 1995/08/21 17:05:16 thorpej Exp $
+.\"
+.\" Copyright (c) 1988, 1992 The University of Utah and the Center
+.\" for Software Science (CSS).
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Center for Software Science of the University of Utah Computer
+.\" Science Department. CSS requests users of this software to return
+.\" to css-dist@cs.utah.edu any improvements that they make and grant
+.\" CSS redistribution rights.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)rbootd.8 8.2 (Berkeley) 12/11/93
+.\"
+.\" Utah Hdr: rbootd.man 3.1 92/07/06
+.\" Author: Jeff Forys, University of Utah CSS
+.\"
+.Dd "December 11, 1993"
+.Dt RBOOTD 8
+.Os
+.Sh NAME
+.Nm rbootd
+.Nd HP remote boot server
+.Sh SYNOPSIS
+.Nm rbootd
+.Op Fl ad
+.Op Fl i Ar interface
+.Op config_file
+.Sh DESCRIPTION
+The
+.Nm rbootd
+utility services boot requests from Hewlett-Packard workstations over a
+local area network.
+All boot files must reside in the boot file directory; further, if a
+client supplies path information in its boot request, it will be silently
+stripped away before processing.
+By default,
+.Nm rbootd
+only responds to requests from machines listed in its configuration file.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl a
+Respond to boot requests from any machine.
+The configuration file is ignored if this option is specified.
+.It Fl d
+Run
+.Nm rbootd
+in debug mode.
+Packets sent and received are displayed to the terminal.
+.It Fl i Ar interface
+Service boot requests on specified interface.
+If unspecified,
+.Nm rbootd
+searches the system interface list for the lowest numbered, configured
+``up'' interface (excluding loopback).
+Ties are broken by choosing the earliest match.
+.El
+.Pp
+Specifying
+.Ar config_file
+on the command line causes
+.Nm rbootd
+to use a different configuration file from the default.
+.Pp
+The configuration file is a text file where each line describes a particular
+machine.
+A line must start with a machine's Ethernet address followed by an optional
+list of boot file names.
+An Ethernet address is specified in hexadecimal with each of its six octets
+separated by a colon.
+The boot file names come from the boot file directory.
+The ethernet address and boot file(s) must be separated by white-space
+and/or comma characters.
+A pound sign causes the remainder of a line to be ignored.
+.Pp
+Here is a sample configuration file:
+.Bl -column 08:00:09:0:66:ad SYSHPBSD,SYSHPUX "# vandy (anything)"
+.It #
+.It # ethernet addr boot file(s) comments
+.It #
+.It 08:00:09:0:66:ad SYSHPBSD # snake (4.3BSD)
+.It 08:00:09:0:59:5b # vandy (anything)
+.It 8::9:1:C6:75 SYSHPBSD,SYSHPUX # jaguar (either)
+.El
+.Pp
+.Nm Rbootd
+logs status and error messages via
+.Xr syslog 3 .
+A startup message is always logged, and in the case of fatal errors (or
+deadly signals) a message is logged announcing the server's termination.
+In general, a non-fatal error is handled by ignoring the event that caused
+it (e.g. an invalid Ethernet address in the config file causes that line
+to be invalidated).
+.Pp
+The following signals have the specified effect when sent to the server
+process using the
+.Xr kill 1
+command:
+.Bl -tag -width SIGUSR1 -offset -compact
+.It SIGHUP
+Drop all active connections and reconfigure.
+.It SIGUSR1
+Turn on debugging, do nothing if already on.
+.It SIGUSR2
+Turn off debugging, do nothing if already off.
+.El
+.Sh "FILES"
+.Bl -tag -width /usr/libexec/rbootd -compact
+.It /dev/bpf#
+packet-filter device
+.It /etc/rbootd.conf
+configuration file
+.It /tmp/rbootd.dbg
+debug output
+.It /usr/mdec/rbootd
+directory containing boot files
+.It /var/run/rbootd.pid
+process id
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr socket 2 ,
+.Xr signal 3 ,
+.Xr syslog 3 ,
+.Xr rmp 4
+.Sh BUGS
+If multiple servers are started on the same interface, each will receive
+and respond to the same boot packets.
diff --git a/usr.sbin/rbootd/rbootd.c b/usr.sbin/rbootd/rbootd.c
new file mode 100644
index 00000000000..11d5445911a
--- /dev/null
+++ b/usr.sbin/rbootd/rbootd.c
@@ -0,0 +1,449 @@
+/* $NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: rbootd.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+extern char *__progname; /* from crt0.o */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, fd, omask, maxfds;
+ fd_set rset;
+
+ /*
+ * Close any open file descriptors.
+ * Temporarily leave stdin & stdout open for `-d',
+ * and stderr open for any pre-syslog error messages.
+ */
+ {
+ int i, nfds = getdtablesize();
+
+ for (i = 0; i < nfds; i++)
+ if (i != fileno(stdin) && i != fileno(stdout) &&
+ i != fileno(stderr))
+ (void) close(i);
+ }
+
+ /*
+ * Parse any arguments.
+ */
+ while ((c = getopt(argc, argv, "adi:")) != EOF)
+ switch(c) {
+ case 'a':
+ BootAny++;
+ break;
+ case 'd':
+ DebugFlg++;
+ break;
+ case 'i':
+ IntfName = optarg;
+ break;
+ }
+ for (; optind < argc; optind++) {
+ if (ConfigFile == NULL)
+ ConfigFile = argv[optind];
+ else {
+ warnx("too many config files (`%s' ignored)\n",
+ argv[optind]);
+ }
+ }
+
+ if (ConfigFile == NULL) /* use default config file */
+ ConfigFile = DfltConfig;
+
+ if (DebugFlg) {
+ DbgFp = stdout; /* output to stdout */
+
+ (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */
+ (void) signal(SIGUSR2, SIG_IGN);
+ (void) fclose(stderr); /* finished with it */
+ } else {
+ if (daemon(0, 0))
+ err(1, "can't detach from terminal");
+
+ (void) signal(SIGUSR1, DebugOn);
+ (void) signal(SIGUSR2, DebugOff);
+ }
+
+ openlog(__progname, LOG_PID, LOG_DAEMON);
+
+ /*
+ * If no interface was specified, get one now.
+ *
+ * This is convoluted because we want to get the default interface
+ * name for the syslog("restarted") message. If BpfGetIntfName()
+ * runs into an error, it will return a syslog-able error message
+ * (in `errmsg') which will be displayed here.
+ */
+ if (IntfName == NULL) {
+ char *errmsg;
+
+ if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
+ syslog(LOG_NOTICE, "restarted (??)");
+ syslog(LOG_ERR, errmsg);
+ Exit(0);
+ }
+ }
+
+ syslog(LOG_NOTICE, "restarted (%s)", IntfName);
+
+ (void) signal(SIGHUP, ReConfig);
+ (void) signal(SIGINT, Exit);
+ (void) signal(SIGTERM, Exit);
+
+ /*
+ * Grab our host name and pid.
+ */
+ if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ Exit(0);
+ }
+ MyHost[MAXHOSTNAMELEN] = '\0';
+
+ MyPid = getpid();
+
+ /*
+ * Write proc's pid to a file.
+ */
+ {
+ FILE *fp;
+
+ if ((fp = fopen(PidFile, "w")) != NULL) {
+ (void) fprintf(fp, "%d\n", (int) MyPid);
+ (void) fclose(fp);
+ } else {
+ syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
+ }
+ }
+
+ /*
+ * All boot files are relative to the boot directory, we might
+ * as well chdir() there to make life easier.
+ */
+ if (chdir(BootDir) < 0) {
+ syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
+ Exit(0);
+ }
+
+ /*
+ * Initial configuration.
+ */
+ omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */
+ if (GetBootFiles() == 0) /* get list of boot files */
+ Exit(0);
+ if (ParseConfig() == 0) /* parse config file */
+ Exit(0);
+
+ /*
+ * Open and initialize a BPF device for the appropriate interface.
+ * If an error is encountered, a message is displayed and Exit()
+ * is called.
+ */
+ fd = BpfOpen();
+
+ (void) sigsetmask(omask); /* allow reconfig's */
+
+ /*
+ * Main loop: receive a packet, determine where it came from,
+ * and if we service this host, call routine to handle request.
+ */
+ maxfds = fd + 1;
+ FD_ZERO(&rset);
+ FD_SET(fd, &rset);
+ for (;;) {
+ struct timeval timeout;
+ fd_set r;
+ int nsel;
+
+ r = rset;
+
+ if (RmpConns == NULL) { /* timeout isnt necessary */
+ nsel = select(maxfds, &r, NULL, NULL, NULL);
+ } else {
+ timeout.tv_sec = RMP_TIMEOUT;
+ timeout.tv_usec = 0;
+ nsel = select(maxfds, &r, NULL, NULL, &timeout);
+ }
+
+ if (nsel < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ Exit(0);
+ } else if (nsel == 0) { /* timeout */
+ DoTimeout(); /* clear stale conns */
+ continue;
+ }
+
+ if (FD_ISSET(fd, &r)) {
+ RMPCONN rconn;
+ CLIENT *client, *FindClient();
+ int doread = 1;
+
+ while (BpfRead(&rconn, doread)) {
+ doread = 0;
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(&rconn,DIR_RCVD);
+
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * If we do not restrict service, set the
+ * client to NULL (ProcessPacket() handles
+ * this). Otherwise, check that we can
+ * service this host; if not, log a message
+ * and ignore the packet.
+ */
+ if (BootAny) {
+ client = NULL;
+ } else if ((client=FindClient(&rconn))==NULL) {
+ syslog(LOG_INFO,
+ "%s: boot packet ignored",
+ EnetStr(&rconn));
+ (void) sigsetmask(omask);
+ continue;
+ }
+
+ ProcessPacket(&rconn,client);
+
+ (void) sigsetmask(omask);
+ }
+ }
+ }
+}
+
+/*
+** DoTimeout -- Free any connections that have timed out.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Timed out connections in `RmpConns' will be freed.
+*/
+void
+DoTimeout()
+{
+ register RMPCONN *rtmp;
+ struct timeval now;
+
+ (void) gettimeofday(&now, (struct timezone *)0);
+
+ /*
+ * For each active connection, if RMP_TIMEOUT seconds have passed
+ * since the last packet was sent, delete the connection.
+ */
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
+ syslog(LOG_WARNING, "%s: connection timed out (%u)",
+ EnetStr(rtmp), rtmp->rmp.r_type);
+ RemoveConn(rtmp);
+ }
+}
+
+/*
+** FindClient -- Find client associated with a packet.
+**
+** Parameters:
+** rconn - the new packet.
+**
+** Returns:
+** Pointer to client info if found, NULL otherwise.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked since
+** a reconfigure can invalidate the information returned.
+*/
+
+CLIENT *
+FindClient(rconn)
+ register RMPCONN *rconn;
+{
+ register CLIENT *ctmp;
+
+ for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(ctmp);
+}
+
+/*
+** Exit -- Log an error message and exit.
+**
+** Parameters:
+** sig - caught signal (or zero if not dying on a signal).
+**
+** Returns:
+** Does not return.
+**
+** Side Effects:
+** - This process ceases to exist.
+*/
+void
+Exit(sig)
+ int sig;
+{
+ if (sig > 0)
+ syslog(LOG_ERR, "going down on signal %d", sig);
+ else
+ syslog(LOG_ERR, "going down with fatal error");
+ BpfClose();
+ exit(1);
+}
+
+/*
+** ReConfig -- Get new list of boot files and reread config files.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All active connections are dropped.
+** - List of boot-able files is changed.
+** - List of clients is changed.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+ReConfig(signo)
+ int signo;
+{
+ syslog(LOG_NOTICE, "reconfiguring boot server");
+
+ FreeConns();
+
+ if (GetBootFiles() == 0)
+ Exit(0);
+
+ if (ParseConfig() == 0)
+ Exit(0);
+}
+
+/*
+** DebugOff -- Turn off debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is closed.
+*/
+void
+DebugOff(signo)
+ int signo;
+{
+ if (DbgFp != NULL)
+ (void) fclose(DbgFp);
+
+ DbgFp = NULL;
+}
+
+/*
+** DebugOn -- Turn on debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is opened/truncated if not already opened,
+** otherwise do nothing.
+*/
+void
+DebugOn(signo)
+ int signo;
+{
+ if (DbgFp == NULL) {
+ if ((DbgFp = fopen(DbgFile, "w")) == NULL)
+ syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
+ }
+}
diff --git a/usr.sbin/rbootd/rmp.h b/usr.sbin/rbootd/rmp.h
new file mode 100644
index 00000000000..4a686ef2b45
--- /dev/null
+++ b/usr.sbin/rbootd/rmp.h
@@ -0,0 +1,97 @@
+/* $NetBSD: rmp.h,v 1.4 1995/10/06 05:12:18 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)rmp.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: rmp.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Define MIN/MAX sizes of RMP (ethernet) packet.
+ * For ease of computation, the 4 octet CRC field is not included.
+ *
+ * MCLBYTES is for bpfwrite(); it is adamant about using a cluster.
+ */
+
+#define RMP_MAX_PACKET MIN(1514,MCLBYTES)
+#define RMP_MIN_PACKET 60
+
+/*
+ * Define RMP/Ethernet Multicast address (9:0:9:0:0:4) and its length.
+ */
+#define RMP_ADDR { 0x9, 0x0, 0x9, 0x0, 0x0, 0x4 }
+#define RMP_ADDRLEN 6
+
+/*
+ * Define IEEE802.2 (Logical Link Control) information.
+ */
+#define IEEE_DSAP_HP 0xF8 /* Destination Service Access Point */
+#define IEEE_SSAP_HP 0xF8 /* Source Service Access Point */
+#define IEEE_CNTL_HP 0x0300 /* Type 1 / I format control information */
+
+#define HPEXT_DXSAP 0x608 /* HP Destination Service Access Point */
+#define HPEXT_SXSAP 0x609 /* HP Source Service Access Point */
+
+/*
+ * 802.3-style "Ethernet" header.
+ */
+
+struct hp_hdr {
+ u_int8_t daddr[RMP_ADDRLEN];
+ u_int8_t saddr[RMP_ADDRLEN];
+ u_int16_t len;
+};
+
+/*
+ * HP uses 802.2 LLC with their own local extensions. This struct makes
+ * sense out of this data (encapsulated in the above 802.3 packet).
+ */
+
+struct hp_llc {
+ u_int8_t dsap; /* 802.2 DSAP */
+ u_int8_t ssap; /* 802.2 SSAP */
+ u_int16_t cntrl; /* 802.2 control field */
+ u_int16_t filler; /* HP filler (must be zero) */
+ u_int16_t dxsap; /* HP extended DSAP */
+ u_int16_t sxsap; /* HP extended SSAP */
+};
diff --git a/usr.sbin/rbootd/rmp_var.h b/usr.sbin/rbootd/rmp_var.h
new file mode 100644
index 00000000000..f00d90583cc
--- /dev/null
+++ b/usr.sbin/rbootd/rmp_var.h
@@ -0,0 +1,246 @@
+/* $NetBSD: rmp_var.h,v 1.7 1995/10/06 05:12:19 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)rmp_var.h 8.1 (Berkeley) 6/4/93
+ *
+ * from: Utah Hdr: rmp_var.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Possible values for "rmp_type" fields.
+ */
+
+#define RMP_BOOT_REQ 1 /* boot request packet */
+#define RMP_BOOT_REPL 129 /* boot reply packet */
+#define RMP_READ_REQ 2 /* read request packet */
+#define RMP_READ_REPL 130 /* read reply packet */
+#define RMP_BOOT_DONE 3 /* boot complete packet */
+
+/*
+ * Useful constants.
+ */
+
+#define RMP_VERSION 2 /* protocol version */
+#define RMP_TIMEOUT 600 /* timeout connection after ten minutes */
+#define RMP_PROBESID 0xffff /* session ID for probes */
+#define RMP_HOSTLEN 13 /* max length of server's name */
+#define RMP_MACHLEN 20 /* length of machine type field */
+
+/*
+ * RMP error codes
+ */
+
+#define RMP_E_OKAY 0
+#define RMP_E_EOF 2 /* read reply: returned end of file */
+#define RMP_E_ABORT 3 /* abort operation */
+#define RMP_E_BUSY 4 /* boot reply: server busy */
+#define RMP_E_TIMEOUT 5 /* lengthen time out (not implemented) */
+#define RMP_E_NOFILE 16 /* boot reply: file does not exist */
+#define RMP_E_OPENFILE 17 /* boot reply: file open failed */
+#define RMP_E_NODFLT 18 /* boot reply: default file does not exist */
+#define RMP_E_OPENDFLT 19 /* boot reply: default file open failed */
+#define RMP_E_BADSID 25 /* read reply: bad session ID */
+#define RMP_E_BADPACKET 27 /* Bad packet detected */
+
+/*
+ * RMPDATALEN is the maximum number of data octets that can be stuffed
+ * into an RMP packet. This excludes the 802.2 LLC w/HP extensions.
+ */
+#define RMPDATALEN (RMP_MAX_PACKET - (sizeof(struct hp_hdr) + \
+ sizeof(struct hp_llc)))
+
+/*
+ * Define sizes of packets we send. Boot and Read replies are variable
+ * in length depending on the length of `s'.
+ *
+ * Also, define how much space `restofpkt' can take up for outgoing
+ * Boot and Read replies. Boot Request packets are effectively
+ * limited to 255 bytes due to the preceding 1-byte length field.
+ */
+
+#define RMPBOOTSIZE(s) htons(sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_repl) + s - sizeof(restofpkt))
+#define RMPREADSIZE(s) htons(sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_read_repl) + s - sizeof(restofpkt) \
+ - sizeof(u_int8_t))
+#define RMPDONESIZE htons(sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_done))
+#define RMPBOOTDATA 255
+#define RMPREADDATA (RMPDATALEN - \
+ (2*sizeof(u_int8_t)+sizeof(u_int16_t)+sizeof(u_word)))
+
+/*
+ * This protocol defines some field sizes as "rest of ethernet packet".
+ * There is no easy way to specify this in C, so we use a one character
+ * field to denote it, and index past it to the end of the packet.
+ */
+
+typedef char restofpkt;
+
+/*
+ * Due to the RMP packet layout, we'll run into alignment problems
+ * on machines that can't access (or don't, by default, align) words
+ * on half-word boundaries. If you know that your machine does not suffer
+ * from this problem, add it to the vax/tahoe/m68k #define below.
+ *
+ * The following macros are used to deal with this problem:
+ * WORDZE(w) Return True if u_word `w' is zero, False otherwise.
+ * ZEROWORD(w) Set u_word `w' to zero.
+ * COPYWORD(w1,w2) Copy u_word `w1' to `w2'.
+ * GETWORD(w,i) Copy u_word `w' into int `i'.
+ * PUTWORD(i,w) Copy int `i' into u_word `w'.
+ *
+ * N.B. Endianness is handled by use of ntohl/htonl
+ */
+#if defined(__vax__) || defined(__tahoe__) || defined(__m68k__)
+
+typedef u_int32_t u_word;
+
+#define WORDZE(w) ((w) == 0)
+#define ZEROWORD(w) (w) = 0
+#define COPYWORD(w1,w2) (w2) = (w1)
+#define GETWORD(w, i) (i) = ntohl(w)
+#define PUTWORD(i, w) (w) = htonl(i)
+
+#else
+
+#define _WORD_HIGHPART 0
+#define _WORD_LOWPART 1
+
+typedef struct _uword { u_int16_t val[2]; } u_word;
+
+#define WORDZE(w) \
+ ((w.val[_WORD_HIGHPART] == 0) && (w.val[_WORD_LOWPART] == 0))
+#define ZEROWORD(w) \
+ (w).val[_WORD_HIGHPART] = (w).val[_WORD_LOWPART] = 0
+#define COPYWORD(w1, w2) \
+ { (w2).val[_WORD_HIGHPART] = (w1).val[_WORD_HIGHPART]; \
+ (w2).val[_WORD_LOWPART] = (w1).val[_WORD_LOWPART]; \
+ }
+#define GETWORD(w, i) \
+ (i) = (((u_int32_t)ntohs((w).val[_WORD_HIGHPART])) << 16) | ntohs((w).val[_WORD_LOWPART])
+#define PUTWORD(i, w) \
+ { (w).val[_WORD_HIGHPART] = htons((u_int16_t) ((i >> 16) & 0xffff)); \
+ (w).val[_WORD_LOWPART] = htons((u_int16_t) (i & 0xffff)); \
+ }
+
+#endif
+
+/*
+ * Packet structures.
+ */
+
+struct rmp_raw { /* generic RMP packet */
+ u_int8_t rmp_type; /* packet type */
+ u_int8_t rmp_rawdata[RMPDATALEN-1];
+};
+
+struct rmp_boot_req { /* boot request */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_REQ) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_seqno; /* sequence number (real time clock) */
+ u_int16_t rmp_session; /* session id (normally 0) */
+ u_int16_t rmp_version; /* protocol version (RMP_VERSION) */
+ char rmp_machtype[RMP_MACHLEN]; /* machine type */
+ u_int8_t rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file to be read */
+};
+
+struct rmp_boot_repl { /* boot reply */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_REPL) */
+ u_int8_t rmp_retcode; /* return code (normally 0) */
+ u_word rmp_seqno; /* sequence number (from boot req) */
+ u_int16_t rmp_session; /* session id (generated) */
+ u_int16_t rmp_version; /* protocol version (RMP_VERSION) */
+ u_int8_t rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file (from boot req) */
+};
+
+struct rmp_read_req { /* read request */
+ u_int8_t rmp_type; /* packet type (RMP_READ_REQ) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_offset; /* file relative byte offset */
+ u_int16_t rmp_session; /* session id (from boot repl) */
+ u_int16_t rmp_size; /* max no of bytes to send */
+};
+
+struct rmp_read_repl { /* read reply */
+ u_int8_t rmp_type; /* packet type (RMP_READ_REPL) */
+ u_int8_t rmp_retcode; /* return code (normally 0) */
+ u_word rmp_offset; /* byte offset (from read req) */
+ u_int16_t rmp_session; /* session id (from read req) */
+ restofpkt rmp_data; /* data (max size from read req) */
+ u_int8_t rmp_unused; /* padding to 16-bit boundary */
+};
+
+struct rmp_boot_done { /* boot complete */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_DONE) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_unused; /* not used (0) */
+ u_int16_t rmp_session; /* session id (from read repl) */
+};
+
+struct rmp_packet {
+ struct hp_hdr hp_hdr;
+ struct hp_llc hp_llc;
+ union {
+ struct rmp_boot_req rmp_brq; /* boot request */
+ struct rmp_boot_repl rmp_brpl; /* boot reply */
+ struct rmp_read_req rmp_rrq; /* read request */
+ struct rmp_read_repl rmp_rrpl; /* read reply */
+ struct rmp_boot_done rmp_done; /* boot complete */
+ struct rmp_raw rmp_raw; /* raw data */
+ } rmp_proto;
+};
+
+/*
+ * Make life easier...
+ */
+
+#define r_type rmp_proto.rmp_raw.rmp_type
+#define r_data rmp_proto.rmp_raw.rmp_rawdata
+#define r_brq rmp_proto.rmp_brq
+#define r_brpl rmp_proto.rmp_brpl
+#define r_rrq rmp_proto.rmp_rrq
+#define r_rrpl rmp_proto.rmp_rrpl
+#define r_done rmp_proto.rmp_done
diff --git a/usr.sbin/rbootd/rmpproto.c b/usr.sbin/rbootd/rmpproto.c
new file mode 100644
index 00000000000..d752ac0e9aa
--- /dev/null
+++ b/usr.sbin/rbootd/rmpproto.c
@@ -0,0 +1,598 @@
+/* $NetBSD: rmpproto.c,v 1.5 1995/10/06 05:12:21 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: rmpproto.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)rmpproto.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: rmpproto.c,v 1.5 1995/10/06 05:12:21 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** ProcessPacket -- determine packet type and do what's required.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** rconn - the new connection
+** client - list of files available to this host
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If this is a valid boot request, it will be added to
+** the linked list of outstanding requests (RmpConns).
+** - If this is a valid boot complete, its associated
+** entry in RmpConns will be deleted.
+** - Also, unless we run out of memory, a reply will be
+** sent to the host that sent the packet.
+*/
+void
+ProcessPacket(rconn, client)
+ RMPCONN *rconn;
+ CLIENT *client;
+{
+ struct rmp_packet *rmp;
+ RMPCONN *rconnout;
+
+ rmp = &rconn->rmp; /* cache pointer to RMP packet */
+
+ switch(rmp->r_type) { /* do what we came here to do */
+ case RMP_BOOT_REQ: /* boot request */
+ if ((rconnout = NewConn(rconn)) == NULL)
+ return;
+
+ /*
+ * If the Session ID is 0xffff, this is a "probe"
+ * packet and we do not want to add the connection
+ * to the linked list of active connections. There
+ * are two types of probe packets, if the Sequence
+ * Number is 0 they want to know our host name, o/w
+ * they want the name of the file associated with
+ * the number spec'd by the Sequence Number.
+ *
+ * If this is an actual boot request, open the file
+ * and send a reply. If SendBootRepl() does not
+ * return 0, add the connection to the linked list
+ * of active connections, otherwise delete it since
+ * an error was encountered.
+ */
+ if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ (void) SendServerID(rconnout);
+ else
+ (void) SendFileNo(rmp, rconnout,
+ client? client->files:
+ BootFiles);
+ FreeConn(rconnout);
+ } else {
+ if (SendBootRepl(rmp, rconnout,
+ client? client->files: BootFiles))
+ AddConn(rconnout);
+ else
+ FreeConn(rconnout);
+ }
+ break;
+
+ case RMP_BOOT_REPL: /* boot reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a boot reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_READ_REQ: /* read request */
+ /*
+ * Send a portion of the boot file.
+ */
+ (void) SendReadRepl(rconn);
+ break;
+
+ case RMP_READ_REPL: /* read reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a read reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_BOOT_DONE: /* boot complete */
+ /*
+ * Remove the entry from the linked list of active
+ * connections.
+ */
+ (void) BootDone(rconn);
+ break;
+
+ default: /* unknown RMP packet type */
+ syslog(LOG_WARNING, "%s: unknown packet type (%u)",
+ EnetStr(rconn), rmp->r_type);
+ }
+}
+
+/*
+** SendServerID -- send our host name to who ever requested it.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendServerID(rconn)
+ RMPCONN *rconn;
+{
+ register struct rmp_packet *rpl;
+ register char *src, *dst;
+ register u_int8_t *size;
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ ZEROWORD(rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */
+
+ /*
+ * Copy our host name into the reply packet incrementing the
+ * length as we go. Stop at RMP_HOSTLEN or the first dot.
+ */
+ src = MyHost;
+ dst = (char *) &rpl->r_brpl.rmp_flnm;
+ for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
+ if (*src == '.' || *src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendFileNo -- send the name of a bootable file to the requester.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendFileNo(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ register struct rmp_packet *rpl;
+ register char *src, *dst;
+ register u_int8_t *size;
+ register int i;
+
+ GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ PUTWORD(i, rpl->r_brpl.rmp_seqno);
+ i--;
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */
+ *size = 0; /* init length to zero */
+
+ /*
+ * Copy the file name into the reply packet incrementing the
+ * length as we go. Stop at end of string or when RMPBOOTDATA
+ * characters have been copied. Also, set return code to
+ * indicate success or "no more files".
+ */
+ if (i < C_MAXFILE && filelist[i] != NULL) {
+ src = filelist[i];
+ dst = (char *)&rpl->r_brpl.rmp_flnm;
+ for (; *src && *size < RMPBOOTDATA; (*size)++) {
+ if (*src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ } else
+ rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendBootRepl -- open boot file and respond to boot request.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendBootRepl(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ int retval;
+ char *filename, filepath[RMPBOOTDATA+1];
+ RMPCONN *oldconn;
+ register struct rmp_packet *rpl;
+ register char *src, *dst1, *dst2;
+ register u_int8_t i;
+
+ /*
+ * If another connection already exists, delete it since we
+ * are obviously starting again.
+ */
+ if ((oldconn = FindConn(rconn)) != NULL) {
+ syslog(LOG_WARNING, "%s: dropping existing connection",
+ EnetStr(oldconn));
+ RemoveConn(oldconn);
+ }
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = htons(GenSessID());
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+ rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
+
+ /*
+ * Copy file name to `filepath' string, and into reply packet.
+ */
+ src = &req->r_brq.rmp_flnm;
+ dst1 = filepath;
+ dst2 = &rpl->r_brpl.rmp_flnm;
+ for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
+ *dst1++ = *dst2++ = *src++;
+ *dst1 = '\0';
+
+ /*
+ * If we are booting HP-UX machines, their secondary loader will
+ * ask for files like "/hp-ux". As a security measure, we do not
+ * allow boot files to lay outside the boot directory (unless they
+ * are purposely link'd out. So, make `filename' become the path-
+ * stripped file name and spoof the client into thinking that it
+ * really got what it wanted.
+ */
+ filename = (filename = rindex(filepath,'/'))? ++filename: filepath;
+
+ /*
+ * Check that this is a valid boot file name.
+ */
+ for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
+ if (STREQN(filename, filelist[i]))
+ goto match;
+
+ /*
+ * Invalid boot file name, set error and send reply packet.
+ */
+ rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
+ retval = 0;
+ goto sendpkt;
+
+match:
+ /*
+ * This is a valid boot file. Open the file and save the file
+ * descriptor associated with this connection and set success
+ * indication. If the file couldnt be opened, set error:
+ * "no such file or dir" - RMP_E_NOFILE
+ * "file table overflow" - RMP_E_BUSY
+ * "too many open files" - RMP_E_BUSY
+ * anything else - RMP_E_OPENFILE
+ */
+ if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
+ rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
+ (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
+ RMP_E_OPENFILE;
+ retval = 0;
+ } else {
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ retval = 1;
+ }
+
+sendpkt:
+ syslog(LOG_INFO, "%s: request to boot %s (%s)",
+ EnetStr(rconn), filename, retval? "granted": "denied");
+
+ rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
+
+ return (retval & SendPacket(rconn));
+}
+
+/*
+** SendReadRepl -- send a portion of the boot file to the requester.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendReadRepl(rconn)
+ RMPCONN *rconn;
+{
+ int retval = 0;
+ RMPCONN *oldconn;
+ register struct rmp_packet *rpl, *req;
+ register int size = 0;
+ int madeconn = 0;
+
+ /*
+ * Find the old connection. If one doesnt exist, create one only
+ * to return the error code.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ if ((oldconn = NewConn(rconn)) == NULL)
+ return(0);
+ syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
+ EnetStr(rconn));
+ madeconn++;
+ }
+
+ req = &rconn->rmp; /* cache ptr to request packet */
+ rpl = &oldconn->rmp; /* cache ptr to reply packet */
+
+ if (madeconn) { /* no active connection above; abort */
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (ntohs(req->r_rrq.rmp_session) !=
+ ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
+ ntohs(rpl->r_rrpl.rmp_session))) {
+ syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * If the requester asks for more data than we can fit,
+ * silently clamp the request size down to RMPREADDATA.
+ *
+ * N.B. I do not know if this is "legal", however it seems
+ * to work. This is necessary for bpfwrite() on machines
+ * with MCLBYTES less than 1514.
+ */
+ if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA)
+ req->r_rrq.rmp_size = htons(RMPREADDATA);
+
+ /*
+ * Position read head on file according to info in request packet.
+ */
+ GETWORD(req->r_rrq.rmp_offset, size);
+ if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) {
+ syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Read data directly into reply packet.
+ */
+ if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
+ (int) ntohs(req->r_rrq.rmp_size))) <= 0) {
+ if (size < 0) {
+ syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ } else {
+ rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
+ }
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Set success indication.
+ */
+ rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
+
+sendpkt:
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_rrpl.rmp_type = RMP_READ_REPL;
+ COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
+ rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
+
+ oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */
+
+ retval &= SendPacket(oldconn); /* send packet */
+
+ if (madeconn) /* clean up after ourself */
+ FreeConn(oldconn);
+
+ return (retval);
+}
+
+/*
+** BootDone -- free up memory allocated for a connection.
+**
+** Parameters:
+** rconn - incoming boot complete packet.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+BootDone(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *oldconn;
+ struct rmp_packet *rpl;
+
+ /*
+ * If we cant find the connection, ignore the request.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ syslog(LOG_ERR, "BootDone: no existing connection (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ rpl = &oldconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (ntohs(rconn->rmp.r_rrq.rmp_session) !=
+ ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
+ ntohs(rpl->r_rrpl.rmp_session))) {
+ syslog(LOG_ERR, "BootDone: bad session id (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ RemoveConn(oldconn); /* remove connection */
+
+ syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
+
+ return(1);
+}
+
+/*
+** SendPacket -- send an RMP packet to a remote host.
+**
+** Parameters:
+** rconn - packet to be sent.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendPacket(rconn)
+ register RMPCONN *rconn;
+{
+ /*
+ * Set Ethernet Destination address to Source (BPF and the enet
+ * driver will take care of getting our source address set).
+ */
+ bcopy((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&rconn->rmp.hp_hdr.daddr[0], RMP_ADDRLEN);
+ rconn->rmp.hp_hdr.len = htons(ntohs(rconn->rmplen)
+ - sizeof(struct hp_hdr));
+
+ /*
+ * Reverse 802.2/HP Extended Source & Destination Access Pts.
+ */
+ rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP);
+ rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP);
+
+ /*
+ * Last time this connection was active.
+ */
+ (void) gettimeofday(&rconn->tstamp, (struct timezone *)0);
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(rconn,DIR_SENT);
+
+ /*
+ * Send RMP packet to remote host.
+ */
+ return(BpfWrite(rconn));
+}
diff --git a/usr.sbin/rbootd/utils.c b/usr.sbin/rbootd/utils.c
new file mode 100644
index 00000000000..5f891613d8a
--- /dev/null
+++ b/usr.sbin/rbootd/utils.c
@@ -0,0 +1,557 @@
+/* $NetBSD: utils.c,v 1.5 1995/10/06 05:12:22 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * 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.
+ *
+ * from: @(#)utils.c 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: utils.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)utils.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$NetBSD: utils.c,v 1.5 1995/10/06 05:12:22 thorpej Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** DispPkt -- Display the contents of an RMPCONN packet.
+**
+** Parameters:
+** rconn - packet to be displayed.
+** direct - direction packet is going (DIR_*).
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+DispPkt(rconn, direct)
+ RMPCONN *rconn;
+ int direct;
+{
+ static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u";
+ static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n";
+
+ struct tm *tmp;
+ register struct rmp_packet *rmp;
+ int i, omask;
+ u_int32_t t;
+
+ /*
+ * Since we will be working with RmpConns as well as DbgFp, we
+ * must block signals that can affect either.
+ */
+ omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
+
+ if (DbgFp == NULL) { /* sanity */
+ (void) sigsetmask(omask);
+ return;
+ }
+
+ /* display direction packet is going using '>>>' or '<<<' */
+ fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
+
+ /* display packet timestamp */
+ tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
+ fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min,
+ tmp->tm_sec, rconn->tstamp.tv_usec);
+
+ /* display src or dst addr and information about network interface */
+ fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName);
+
+ rmp = &rconn->rmp;
+
+ /* display IEEE 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
+ rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl));
+
+ /* display HP extensions to 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",
+ ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap));
+
+ /*
+ * Display information about RMP packet using type field to
+ * determine what kind of packet this is.
+ */
+ switch(rmp->r_type) {
+ case RMP_BOOT_REQ: /* boot request */
+ (void) fprintf(DbgFp, "\tBoot Request:");
+ GETWORD(rmp->r_brq.rmp_seqno, t);
+ if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ fputs(" (Send Server ID)", DbgFp);
+ else
+ fprintf(DbgFp," (Send Filename #%u)",t);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
+ t, ntohs(rmp->r_brq.rmp_session),
+ ntohs(rmp->r_brq.rmp_version));
+ (void) fprintf(DbgFp, "\n\t\tMachine Type: ");
+ for (i = 0; i < RMP_MACHLEN; i++)
+ (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
+ DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
+ break;
+ case RMP_BOOT_REPL: /* boot reply */
+ fprintf(DbgFp, "\tBoot Reply:\n");
+ GETWORD(rmp->r_brpl.rmp_seqno, t);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
+ t, ntohs(rmp->r_brpl.rmp_session),
+ ntohs(rmp->r_brpl.rmp_version));
+ DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
+ break;
+ case RMP_READ_REQ: /* read request */
+ (void) fprintf(DbgFp, "\tRead Request:\n");
+ GETWORD(rmp->r_rrq.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
+ t, ntohs(rmp->r_rrq.rmp_session));
+ (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
+ ntohs(rmp->r_rrq.rmp_size));
+ break;
+ case RMP_READ_REPL: /* read reply */
+ (void) fprintf(DbgFp, "\tRead Reply:\n");
+ GETWORD(rmp->r_rrpl.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
+ t, ntohs(rmp->r_rrpl.rmp_session));
+ (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n",
+ ntohs(rconn->rmplen) - ntohs(RMPREADSIZE(0)));
+ break;
+ case RMP_BOOT_DONE: /* boot complete */
+ (void) fprintf(DbgFp, "\tBoot Complete:\n");
+ (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
+ rmp->r_done.rmp_retcode,
+ ntohs(rmp->r_done.rmp_session));
+ break;
+ default: /* ??? */
+ (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
+ rmp->r_type);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fflush(DbgFp);
+
+ (void) sigsetmask(omask); /* reset old signal mask */
+}
+
+
+/*
+** GetEtherAddr -- convert an RMP (Ethernet) address into a string.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** addr - array of RMP_ADDRLEN bytes.
+**
+** Returns:
+** Pointer to static string representation of `addr'.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+*/
+char *
+GetEtherAddr(addr)
+ u_int8_t *addr;
+{
+ static char Hex[] = "0123456789abcdef";
+ static char etherstr[RMP_ADDRLEN*3];
+ register int i;
+ register char *cp;
+
+ /*
+ * For each byte in `addr', convert it to "<hexchar><hexchar>:".
+ * The last byte does not get a trailing `:' appended.
+ */
+ i = 0;
+ cp = etherstr;
+ for(;;) {
+ *cp++ = Hex[*addr >> 4 & 0xf];
+ *cp++ = Hex[*addr++ & 0xf];
+ if (++i == RMP_ADDRLEN)
+ break;
+ *cp++ = ':';
+ }
+ *cp = '\0';
+
+ return(etherstr);
+}
+
+
+/*
+** DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
+**
+** Parameters:
+** size - number of bytes to print.
+** flnm - address of first byte.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Characters are sent to `DbgFp'.
+*/
+void
+DspFlnm(size, flnm)
+ register u_int size;
+ register char *flnm;
+{
+ register int i;
+
+ (void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size);
+ for (i = 0; i < size; i++)
+ (void) fputc(*flnm++, DbgFp);
+ (void) fputs(">\n", DbgFp);
+}
+
+
+/*
+** NewClient -- allocate memory for a new CLIENT.
+**
+** Parameters:
+** addr - RMP (Ethernet) address of new client.
+**
+** Returns:
+** Ptr to new CLIENT or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new CLIENT.
+** - If malloc() fails, a log message will be generated.
+*/
+CLIENT *
+NewClient(addr)
+ u_int8_t *addr;
+{
+ CLIENT *ctmp;
+
+ if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
+ syslog(LOG_ERR, "NewClient: out of memory (%s)",
+ GetEtherAddr(addr));
+ return(NULL);
+ }
+
+ bzero(ctmp, sizeof(CLIENT));
+ bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN);
+ return(ctmp);
+}
+
+/*
+** FreeClient -- free linked list of Clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** CLIENTS will be free'd; `Clients' will be set to NULL.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeClients()
+{
+ register CLIENT *ctmp;
+
+ while (Clients != NULL) {
+ ctmp = Clients;
+ Clients = Clients->next;
+ FreeClient(ctmp);
+ }
+}
+
+/*
+** NewStr -- allocate memory for a character array.
+**
+** Parameters:
+** str - null terminated character array.
+**
+** Returns:
+** Ptr to new character array or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new character array.
+** - If malloc() fails, a log message will be generated.
+*/
+char *
+NewStr(str)
+ char *str;
+{
+ char *stmp;
+
+ if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {
+ syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
+ return(NULL);
+ }
+
+ (void) strcpy(stmp, str);
+ return(stmp);
+}
+
+/*
+** To save time, NewConn and FreeConn maintain a cache of one RMPCONN
+** in `LastFree' (defined below).
+*/
+
+static RMPCONN *LastFree = NULL;
+
+/*
+** NewConn -- allocate memory for a new RMPCONN connection.
+**
+** Parameters:
+** rconn - initialization template for new connection.
+**
+** Returns:
+** Ptr to new RMPCONN or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory may be malloc'd for the new RMPCONN (if not cached).
+** - If malloc() fails, a log message will be generated.
+*/
+RMPCONN *
+NewConn(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *rtmp;
+
+ if (LastFree == NULL) { /* nothing cached; make a new one */
+ if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
+ syslog(LOG_ERR, "NewConn: out of memory (%s)",
+ EnetStr(rconn));
+ return(NULL);
+ }
+ } else { /* use the cached RMPCONN */
+ rtmp = LastFree;
+ LastFree = NULL;
+ }
+
+ /*
+ * Copy template into `rtmp', init file descriptor to `-1' and
+ * set ptr to next elem NULL.
+ */
+ bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN));
+ rtmp->bootfd = -1;
+ rtmp->next = NULL;
+
+ return(rtmp);
+}
+
+/*
+** FreeConn -- Free memory associated with an RMPCONN connection.
+**
+** Parameters:
+** rtmp - ptr to RMPCONN to be free'd.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Memory associated with `rtmp' may be free'd (or cached).
+** - File desc associated with `rtmp->bootfd' will be closed.
+*/
+void
+FreeConn(rtmp)
+ register RMPCONN *rtmp;
+{
+ /*
+ * If the file descriptor is in use, close the file.
+ */
+ if (rtmp->bootfd >= 0) {
+ (void) close(rtmp->bootfd);
+ rtmp->bootfd = -1;
+ }
+
+ if (LastFree == NULL) /* cache for next time */
+ rtmp = LastFree;
+ else /* already one cached; free this one */
+ free((char *)rtmp);
+}
+
+/*
+** FreeConns -- free linked list of RMPCONN connections.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** connections will be free'd; `RmpConns' will be set to NULL.
+** - If LastFree is != NULL, it too will be free'd & NULL'd.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeConns()
+{
+ register RMPCONN *rtmp;
+
+ while (RmpConns != NULL) {
+ rtmp = RmpConns;
+ RmpConns = RmpConns->next;
+ FreeConn(rtmp);
+ }
+
+ if (LastFree != NULL) {
+ free((char *)LastFree);
+ LastFree = NULL;
+ }
+}
+
+/*
+** AddConn -- Add a connection to the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be added.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - RmpConn will point to new connection.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+AddConn(rconn)
+ register RMPCONN *rconn;
+{
+ if (RmpConns != NULL)
+ rconn->next = RmpConns;
+ RmpConns = rconn;
+}
+
+/*
+** FindConn -- Find a connection in the linked list of connections.
+**
+** We use the RMP (Ethernet) address as the basis for determining
+** if this is the same connection. According to the Remote Maint
+** Protocol, we can only have one connection with any machine.
+**
+** Parameters:
+** rconn - connection to be found.
+**
+** Returns:
+** Matching connection from linked list or NULL if not found.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+RMPCONN *
+FindConn(rconn)
+ register RMPCONN *rconn;
+{
+ register RMPCONN *rtmp;
+
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(rtmp);
+}
+
+/*
+** RemoveConn -- Remove a connection from the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be removed.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If found, an RMPCONN will cease to exist and it will
+** be removed from the linked list.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+RemoveConn(rconn)
+ register RMPCONN *rconn;
+{
+ register RMPCONN *thisrconn, *lastrconn;
+
+ if (RmpConns == rconn) { /* easy case */
+ RmpConns = RmpConns->next;
+ FreeConn(rconn);
+ } else { /* must traverse linked list */
+ lastrconn = RmpConns; /* set back ptr */
+ thisrconn = lastrconn->next; /* set current ptr */
+ while (thisrconn != NULL) {
+ if (rconn == thisrconn) { /* found it */
+ lastrconn->next = thisrconn->next;
+ FreeConn(thisrconn);
+ break;
+ }
+ lastrconn = thisrconn;
+ thisrconn = thisrconn->next;
+ }
+ }
+}
diff --git a/usr.sbin/rdate/Makefile b/usr.sbin/rdate/Makefile
new file mode 100644
index 00000000000..7059458f0f9
--- /dev/null
+++ b/usr.sbin/rdate/Makefile
@@ -0,0 +1,8 @@
+# @(#) $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:04 deraadt Exp $
+
+PROG= rdate
+SRCS= rdate.c
+
+MAN= rdate.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rdate/rdate.8 b/usr.sbin/rdate/rdate.8
new file mode 100644
index 00000000000..51035d91e50
--- /dev/null
+++ b/usr.sbin/rdate/rdate.8
@@ -0,0 +1,57 @@
+.\"
+.\" Copyright (c) 1994 Christos Zoulas
+.\" 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 Christos Zoulas.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: rdate.8,v 1.1.1.1 1995/10/18 08:48:04 deraadt Exp $
+.\"
+.Dd April 30, 1994
+.Dt RDATE 8
+.Os
+.Sh NAME
+.Nm rdate
+.Nd set the system's date from a remote host
+.Sh SYNOPSIS
+.Nm rdate
+.Op Fl ps
+.Ar host
+.Sh DESCRIPTION
+.Nm Rdate
+displays and sets the local date and time from the
+host name or address given as the argument. It uses the RFC868
+protocol which is usually implemented as a built-in service of
+.Xr inetd(1).
+.Pp
+Available options:
+.Pp
+.Bl -tag -width indent
+.It Fl p
+Do not set, just print the remote time
+.It Fl s
+Do not print the time.
+.Sh SEE ALSO
+.Xr inetd 1
diff --git a/usr.sbin/rdate/rdate.c b/usr.sbin/rdate/rdate.c
new file mode 100644
index 00000000000..401019e49d1
--- /dev/null
+++ b/usr.sbin/rdate/rdate.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: rdate.c,v 1.1.1.1 1995/10/18 08:48:04 deraadt Exp $
+ */
+
+/*
+ * rdate.c: Set the date from the specified host
+ *
+ * Uses the rfc868 time protocol at socket 37.
+ * Time is returned as the number of seconds since
+ * midnight January 1st 1900.
+ */
+#ifndef lint
+static char rcsid[] = "$Id: rdate.c,v 1.1.1.1 1995/10/18 08:48:04 deraadt Exp $";
+#endif /* lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+/* seconds from midnight Jan 1900 - 1970 */
+#if __STDC__
+#define DIFFERENCE 2208988800UL
+#else
+#define DIFFERENCE 2208988800
+#endif
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int pr = 0, silent = 0, s;
+ time_t tim;
+ char *hname;
+ struct hostent *hp;
+ struct protoent *pp, ppp;
+ struct servent *sp, ssp;
+ struct sockaddr_in sa;
+ extern char *__progname;
+ extern int optind;
+ int c;
+
+ while ((c = getopt(argc, argv, "ps")) != -1)
+ switch (c) {
+ case 'p':
+ pr++;
+ break;
+
+ case 's':
+ silent++;
+ break;
+
+ default:
+ goto usage;
+ }
+
+ if (argc - 1 != optind) {
+usage:
+ (void) fprintf(stderr, "Usage: %s [-ps] host\n", __progname);
+ return (1);
+ }
+ hname = argv[optind];
+
+ if ((hp = gethostbyname(hname)) == NULL) {
+ fprintf(stderr, "%s: ", __progname);
+ herror(hname);
+ exit(1);
+ }
+
+ if ((sp = getservbyname("time", "tcp")) == NULL) {
+ sp = &ssp;
+ sp->s_port = 37;
+ sp->s_proto = "tcp";
+ }
+ if ((pp = getprotobyname(sp->s_proto)) == NULL) {
+ pp = &ppp;
+ pp->p_proto = 6;
+ }
+ if ((s = socket(AF_INET, SOCK_STREAM, pp->p_proto)) == -1)
+ err(1, "Could not create socket");
+
+ bzero(&sa, sizeof sa);
+ sa.sin_family = AF_INET;
+ sa.sin_port = sp->s_port;
+
+ memcpy(&(sa.sin_addr.s_addr), hp->h_addr, hp->h_length);
+
+ if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1)
+ err(1, "Could not connect socket");
+
+ if (read(s, &tim, sizeof(time_t)) != sizeof(time_t))
+ err(1, "Could not read data");
+
+ (void) close(s);
+ tim = ntohl(tim) - DIFFERENCE;
+
+ if (!pr) {
+ struct timeval tv;
+ tv.tv_sec = tim;
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, NULL) == -1)
+ err(1, "Could not set time of day");
+ }
+ if (!silent)
+ (void) fputs(ctime(&tim), stdout);
+ return 0;
+}
diff --git a/usr.sbin/rdconfig/Makefile b/usr.sbin/rdconfig/Makefile
new file mode 100644
index 00000000000..762d02dc7ef
--- /dev/null
+++ b/usr.sbin/rdconfig/Makefile
@@ -0,0 +1,6 @@
+# $NetBSD: Makefile,v 1.1.1.1 1995/10/08 22:40:41 gwr Exp $
+
+PROG= rdconfig
+MAN= rdconfig.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rdconfig/rdconfig.8 b/usr.sbin/rdconfig/rdconfig.8
new file mode 100644
index 00000000000..cfca279227b
--- /dev/null
+++ b/usr.sbin/rdconfig/rdconfig.8
@@ -0,0 +1,76 @@
+.\"
+.\" $NetBSD: rdconfig.8,v 1.1.1.1 1995/10/08 22:40:41 gwr Exp $
+.\"
+.\" Copyright (c) 1995 Gordon W. Ross
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd July 8, 1993
+.Dt RDCONFIG 8
+.Os BSD 4
+.Sh NAME
+.Nm rdconfig
+.Nd configure RAM disks
+.Sh SYNOPSIS
+.Nm rdconfig Fl c
+.Op Fl v
+.Ar special_file
+.Ar 512-byte-blocks
+.Sh DESCRIPTION
+The
+.Nm rdconfig
+command configures RAM disk devices.
+It will associate the special file
+.Ar special_file
+with a range of user-virtual memory allocated by the
+.Nm rdconfig
+process itself. The
+.Nm rdconfig
+command should be run in the background.
+If successful, the command will not return.
+Otherwise, an error message will be printed.
+.Pp
+To "unconfigure" the ramdisk, just kill the background
+.Nm rdconfig
+process started earlier.
+.Sh FILES
+.Bl -tag -width /etc/rrd?? -compact
+.It Pa /dev/rrd??
+.It Pa /dev/rd??
+.El
+.Sh EXAMPLES
+.Pp
+.Dl rdconfig /dev/rd0a 2048 &
+.Pp
+Configures the RAM disk
+.Pa rd0a
+with one megabyte of user-space memory.
+.Sh BUGS
+The special device will become inoperative if the
+.Nm rdconfig
+process is killed while the special device is open.
+.Sh SEE ALSO
+.Xr swapon 8 ,
+.Xr mount 8 ,
+.Xr umount 8 .
diff --git a/usr.sbin/rdconfig/rdconfig.c b/usr.sbin/rdconfig/rdconfig.c
new file mode 100644
index 00000000000..158c092d721
--- /dev/null
+++ b/usr.sbin/rdconfig/rdconfig.c
@@ -0,0 +1,90 @@
+/* $NetBSD: rdconfig.c,v 1.1.1.1 1995/10/08 22:40:41 gwr Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon W. Ross
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program exists for the sole purpose of providing
+ * user-space memory for the new RAM-disk driver (rd).
+ * The job done by this is similar to mount_mfs.
+ * (But this design allows any filesystem format!)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include <dev/ramdisk.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct rd_conf rd;
+ int nblks, fd, error;
+
+ if (argc <= 2) {
+ fprintf(stderr, "usage: rdconfig <device> <%d-byte-blocks>\n",
+ DEV_BSIZE);
+ exit(1);
+ }
+
+ nblks = atoi(argv[2]);
+ if (nblks <= 0) {
+ fprintf(stderr, "invalid number of blocks\n");
+ exit(1);
+ }
+ rd.rd_size = nblks << DEV_BSHIFT;
+
+ fd = open(argv[1], O_RDWR, 0);
+ if (fd < 0) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ rd.rd_addr = mmap(NULL, rd.rd_size,
+ PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE,
+ -1, 0);
+ if (rd.rd_addr == (caddr_t)-1) {
+ perror("mmap");
+ exit(1);
+ }
+
+ /* Become server! */
+ rd.rd_type = RD_UMEM_SERVER;
+ if (ioctl(fd, RD_SETCONF, &rd)) {
+ perror("ioctl");
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/usr.sbin/repquota/Makefile b/usr.sbin/repquota/Makefile
new file mode 100644
index 00000000000..8cf7faeefc7
--- /dev/null
+++ b/usr.sbin/repquota/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+
+PROG= repquota
+MAN= repquota.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/repquota/repquota.8 b/usr.sbin/repquota/repquota.8
new file mode 100644
index 00000000000..463c2f82194
--- /dev/null
+++ b/usr.sbin/repquota/repquota.8
@@ -0,0 +1,104 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)repquota.8 8.1 (Berkeley) 6/6/93
+.\" $Id: repquota.8,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+.\"
+.Dd June 6, 1993
+.Dt REPQUOTA 8
+.Os BSD 4.2
+.Sh NAME
+.Nm repquota
+.Nd summarize quotas for a file system
+.Sh SYNOPSIS
+.Nm repquota
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm repquota
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Sh DESCRIPTION
+.Nm Repquota
+prints a summary of the disk usage and quotas for the
+specified file systems.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+Print the quotas of all the filesystems listed in
+.Pa /etc/fstab .
+.It Fl g
+Print only group quotas (the default is to print both
+group and user quotas if they exist).
+.It Fl u
+Print only user quotas (the default is to print both
+group and user quotas if they exist).
+.It Fl v
+Print a header line before printing each filesystem quotas.
+.El
+.Pp
+For each user or group, the current
+number files and amount of space (in kilobytes) is
+printed, along with any quotas created with
+.Xr edquota 8 .
+.Pp
+Only members of the operator group or the super-user may
+use this command.
+.Sh FILES
+.Bl -tag -width quota.group -compact
+.It Pa quota.user
+at the filesystem root with user quotas
+.It Pa quota.group
+at the filesystem root with group quotas
+.It Pa /etc/fstab
+for file system names and locations
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr fstab 5 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8
+.Sh DIAGNOSTICS
+Various messages about inaccessible files; self-explanatory.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/repquota/repquota.c b/usr.sbin/repquota/repquota.c
new file mode 100644
index 00000000000..a4946e0d3a1
--- /dev/null
+++ b/usr.sbin/repquota/repquota.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)repquota.c 8.1 (Berkeley) 6/6/93";*/
+static char *rcsid = "$Id: repquota.c,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * Quota report
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ufs/ufs/quota.h>
+#include <fstab.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+
+struct fileusage {
+ struct fileusage *fu_next;
+ struct dqblk fu_dqblk;
+ u_long fu_id;
+ char fu_name[1];
+ /* actually bigger */
+};
+#define FUHASH 1024 /* must be power of two */
+struct fileusage *fuhead[MAXQUOTAS][FUHASH];
+struct fileusage *lookup();
+struct fileusage *addid();
+u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
+
+int vflag; /* verbose */
+int aflag; /* all file systems */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register struct fstab *fs;
+ register struct passwd *pw;
+ register struct group *gr;
+ int gflag = 0, uflag = 0, errs = 0;
+ long i, argnum, done = 0;
+ extern char *optarg;
+ extern int optind;
+ char ch, *qfnp;
+
+ while ((ch = getopt(argc, argv, "aguv")) != EOF) {
+ switch(ch) {
+ case 'a':
+ aflag++;
+ break;
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0 && !aflag)
+ usage();
+ if (!gflag && !uflag) {
+ if (aflag)
+ gflag++;
+ uflag++;
+ }
+ if (gflag) {
+ setgrent();
+ while ((gr = getgrent()) != 0)
+ (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
+ endgrent();
+ }
+ if (uflag) {
+ setpwent();
+ while ((pw = getpwent()) != 0)
+ (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
+ endpwent();
+ }
+ setfsent();
+ while ((fs = getfsent()) != NULL) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (aflag) {
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += repquota(fs, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += repquota(fs, USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
+ (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += repquota(fs, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += repquota(fs, USRQUOTA, qfnp);
+ }
+ }
+ endfsent();
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not found in fstab\n", argv[i]);
+ exit(errs);
+}
+
+usage()
+{
+ fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
+ "repquota [-v] [-g] [-u] -a",
+ "repquota [-v] [-g] [-u] filesys ...");
+ exit(1);
+}
+
+repquota(fs, type, qfpathname)
+ register struct fstab *fs;
+ int type;
+ char *qfpathname;
+{
+ register struct fileusage *fup;
+ FILE *qf;
+ u_long id;
+ struct dqblk dqbuf;
+ char *timeprt();
+ static struct dqblk zerodqblk;
+ static int warned = 0;
+ static int multiple = 0;
+ extern int errno;
+
+ if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
+ errno == EOPNOTSUPP && !warned && vflag) {
+ warned++;
+ fprintf(stdout,
+ "*** Warning: Quotas are not compiled into this kernel\n");
+ }
+ if (multiple++)
+ printf("\n");
+ if (vflag)
+ fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
+ qfextension[type], fs->fs_file, fs->fs_spec);
+ if ((qf = fopen(qfpathname, "r")) == NULL) {
+ perror(qfpathname);
+ return (1);
+ }
+ for (id = 0; ; id++) {
+ fread(&dqbuf, sizeof(struct dqblk), 1, qf);
+ if (feof(qf))
+ break;
+ if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
+ continue;
+ if ((fup = lookup(id, type)) == 0)
+ fup = addid(id, type, (char *)0);
+ fup->fu_dqblk = dqbuf;
+ }
+ fclose(qf);
+ printf(" Block limits File limits\n");
+ printf("User used soft hard grace used soft hard grace\n");
+ for (id = 0; id <= highid[type]; id++) {
+ fup = lookup(id, type);
+ if (fup == 0)
+ continue;
+ if (fup->fu_dqblk.dqb_curinodes == 0 &&
+ fup->fu_dqblk.dqb_curblocks == 0)
+ continue;
+ printf("%-10s", fup->fu_name);
+ printf("%c%c%8d%8d%8d%7s",
+ fup->fu_dqblk.dqb_bsoftlimit &&
+ fup->fu_dqblk.dqb_curblocks >=
+ fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-',
+ fup->fu_dqblk.dqb_isoftlimit &&
+ fup->fu_dqblk.dqb_curinodes >=
+ fup->fu_dqblk.dqb_isoftlimit ? '+' : '-',
+ dbtob(fup->fu_dqblk.dqb_curblocks) / 1024,
+ dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024,
+ dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024,
+ fup->fu_dqblk.dqb_bsoftlimit &&
+ fup->fu_dqblk.dqb_curblocks >=
+ fup->fu_dqblk.dqb_bsoftlimit ?
+ timeprt(fup->fu_dqblk.dqb_btime) : "");
+ printf(" %6d%6d%6d%7s\n",
+ fup->fu_dqblk.dqb_curinodes,
+ fup->fu_dqblk.dqb_isoftlimit,
+ fup->fu_dqblk.dqb_ihardlimit,
+ fup->fu_dqblk.dqb_isoftlimit &&
+ fup->fu_dqblk.dqb_curinodes >=
+ fup->fu_dqblk.dqb_isoftlimit ?
+ timeprt(fup->fu_dqblk.dqb_itime) : "");
+ fup->fu_dqblk = zerodqblk;
+ }
+ return (0);
+}
+
+/*
+ * Check to see if target appears in list of size cnt.
+ */
+oneof(target, list, cnt)
+ register char *target, *list[];
+ int cnt;
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ if (strcmp(target, list[i]) == 0)
+ return (i);
+ return (-1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
+ sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strcpy(buf, fs->fs_mntops);
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+
+/*
+ * Routines to manage the file usage table.
+ *
+ * Lookup an id of a specific type.
+ */
+struct fileusage *
+lookup(id, type)
+ u_long id;
+ int type;
+{
+ register struct fileusage *fup;
+
+ for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
+ if (fup->fu_id == id)
+ return (fup);
+ return ((struct fileusage *)0);
+}
+
+/*
+ * Add a new file usage id if it does not already exist.
+ */
+struct fileusage *
+addid(id, type, name)
+ u_long id;
+ int type;
+ char *name;
+{
+ struct fileusage *fup, **fhp;
+ int len;
+ extern char *calloc();
+
+ if (fup = lookup(id, type))
+ return (fup);
+ if (name)
+ len = strlen(name);
+ else
+ len = 10;
+ if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
+ fprintf(stderr, "out of memory for fileusage structures\n");
+ exit(1);
+ }
+ fhp = &fuhead[type][id & (FUHASH - 1)];
+ fup->fu_next = *fhp;
+ *fhp = fup;
+ fup->fu_id = id;
+ if (id > highid[type])
+ highid[type] = id;
+ if (name) {
+ bcopy(name, fup->fu_name, len + 1);
+ } else {
+ sprintf(fup->fu_name, "%u", id);
+ }
+ return (fup);
+}
+
+/*
+ * Calculate the grace period and return a printable string for it.
+ */
+char *
+timeprt(seconds)
+ time_t seconds;
+{
+ time_t hours, minutes;
+ static char buf[20];
+ static time_t now;
+
+ if (now == 0)
+ time(&now);
+ if (now > seconds)
+ return ("none");
+ seconds -= now;
+ minutes = (seconds + 30) / 60;
+ hours = (minutes + 30) / 60;
+ if (hours >= 36) {
+ sprintf(buf, "%ddays", (hours + 12) / 24);
+ return (buf);
+ }
+ if (minutes >= 60) {
+ sprintf(buf, "%2d:%d", minutes / 60, minutes % 60);
+ return (buf);
+ }
+ sprintf(buf, "%2d", minutes);
+ return (buf);
+}
diff --git a/usr.sbin/rmt/Makefile b/usr.sbin/rmt/Makefile
new file mode 100644
index 00000000000..3a8166d1dc2
--- /dev/null
+++ b/usr.sbin/rmt/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.4 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+
+PROG= rmt
+MAN= rmt.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rmt/rmt.8 b/usr.sbin/rmt/rmt.8
new file mode 100644
index 00000000000..5c184e96ac8
--- /dev/null
+++ b/usr.sbin/rmt/rmt.8
@@ -0,0 +1,218 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\" from: @(#)rmt.8 6.5 (Berkeley) 3/16/91
+.\" $Id: rmt.8,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt RMT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rmt
+.Nd remote magtape protocol module
+.Sh SYNOPSIS
+.Nm rmt
+.Sh DESCRIPTION
+.Nm Rmt
+is a program used by the remote dump and restore programs
+in manipulating a magnetic tape drive through an interprocess
+communication connection.
+.Nm Rmt
+is normally started up with an
+.Xr rexec 3
+or
+.Xr rcmd 3
+call.
+.Pp
+The
+.Nm rmt
+program accepts requests specific to the manipulation of
+magnetic tapes, performs the commands, then responds with
+a status indication. All responses are in
+.Tn ASCII
+and in
+one of two forms.
+Successful commands have responses of:
+.Bd -filled -offset indent
+.Sm off
+.Sy A Ar number No \en
+.Sm on
+.Ed
+.Pp
+.Ar Number
+is an
+.Tn ASCII
+representation of a decimal number.
+Unsuccessful commands are responded to with:
+.Bd -filled -offset indent
+.Sm off
+.Xo Sy E Ar error-number
+.No \en Ar error-message
+.No \en
+.Xc
+.Sm on
+.Ed
+.Pp
+.Ar Error-number
+is one of the possible error
+numbers described in
+.Xr intro 2
+and
+.Ar error-message
+is the corresponding error string as printed
+from a call to
+.Xr perror 3 .
+The protocol is comprised of the
+following commands, which are sent as indicated - no spaces are supplied
+between the command and its arguments, or between its arguments, and
+.Ql \en
+indicates that a newline should be supplied:
+.Bl -tag -width Ds
+.Sm off
+.It Xo Sy \&O Ar device
+.No \en Ar mode No \en
+.Xc
+Open the specified
+.Ar device
+using the indicated
+.Ar mode .
+.Ar Device
+is a full pathname and
+.Ar mode
+is an
+.Tn ASCII
+representation of a decimal
+number suitable for passing to
+.Xr open 2 .
+If a device had already been opened, it is
+closed before a new open is performed.
+.It Xo Sy C Ar device No \en
+.Xc
+Close the currently open device. The
+.Ar device
+specified is ignored.
+.It Xo Sy L
+.Ar whence No \en
+.Ar offset No \en
+.Xc
+.Sm on
+Perform an
+.Xr lseek 2
+operation using the specified parameters.
+The response value is that returned from the
+.Xr lseek
+call.
+.Sm off
+.It Sy W Ar count No \en
+.Sm on
+Write data onto the open device.
+.Nm Rmt
+reads
+.Ar count
+bytes from the connection, aborting if
+a premature end-of-file is encountered.
+The response value is that returned from
+the
+.Xr write 2
+call.
+.Sm off
+.It Sy R Ar count No \en
+.Sm on
+Read
+.Ar count
+bytes of data from the open device.
+If
+.Ar count
+exceeds the size of the data buffer (10 kilobytes), it is
+truncated to the data buffer size.
+.Nm rmt
+then performs the requested
+.Xr read 2
+and responds with
+.Sm off
+.Sy A Ar count-read No \en
+.Sm on
+if the read was
+successful; otherwise an error in the
+standard format is returned. If the read
+was successful, the data read is then sent.
+.Sm off
+.It Xo Sy I Ar operation
+.No \en Ar count No \en
+.Xc
+.Sm on
+Perform a
+.Dv MTIOCOP
+.Xr ioctl 2
+command using the specified parameters.
+The parameters are interpreted as the
+.Tn ASCII
+representations of the decimal values
+to place in the
+.Ar mt_op
+and
+.Ar mt_count
+fields of the structure used in the
+.Xr ioctl
+call. The return value is the
+.Ar count
+parameter when the operation is successful.
+.It Sy S
+Return the status of the open device, as
+obtained with a
+.Dv MTIOCGET
+.Xr ioctl
+call. If the operation was successful,
+an ``ack'' is sent with the size of the
+status buffer, then the status buffer is
+sent (in binary).
+.El
+.Sm on
+.Pp
+Any other command causes
+.Nm rmt
+to exit.
+.Sh DIAGNOSTICS
+All responses are of the form described above.
+.Sh SEE ALSO
+.Xr rcmd 3 ,
+.Xr rexec 3 ,
+.Xr mtio 4 ,
+.Xr rdump 8 ,
+.Xr rrestore 8
+.Sh BUGS
+People tempted to use this for a remote file access protocol
+are discouraged.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/rmt/rmt.c b/usr.sbin/rmt/rmt.c
new file mode 100644
index 00000000000..b2addde8ec2
--- /dev/null
+++ b/usr.sbin/rmt/rmt.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)rmt.c 5.6 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: rmt.c,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <stdio.h>
+#include <sgtty.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/mtio.h>
+#include <errno.h>
+#include <string.h>
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+char *checkbuf();
+
+#define SSIZE 64
+char device[SSIZE];
+char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+char resp[BUFSIZ];
+
+FILE *debug;
+#define DEBUG(f) if (debug) fprintf(debug, f)
+#define DEBUG1(f,a) if (debug) fprintf(debug, f, a)
+#define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int rval;
+ char c;
+ int n, i, cc;
+
+ argc--, argv++;
+ if (argc > 0) {
+ debug = fopen(*argv, "w");
+ if (debug == 0)
+ exit(1);
+ (void) setbuf(debug, (char *)0);
+ }
+top:
+ errno = 0;
+ rval = 0;
+ if (read(0, &c, 1) != 1)
+ exit(0);
+ switch (c) {
+
+ case 'O':
+ if (tape >= 0)
+ (void) close(tape);
+ getstring(device); getstring(mode);
+ DEBUG2("rmtd: O %s %s\n", device, mode);
+ tape = open(device, atoi(mode),
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'C':
+ DEBUG("rmtd: C\n");
+ getstring(device); /* discard */
+ if (close(tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+
+ case 'L':
+ getstring(count); getstring(pos);
+ DEBUG2("rmtd: L %s %s\n", count, pos);
+ rval = lseek(tape, atoi(count), atoi(pos));
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'W':
+ getstring(count);
+ n = atoi(count);
+ DEBUG1("rmtd: W %s\n", count);
+ record = checkbuf(record, n);
+ for (i = 0; i < n; i += cc) {
+ cc = read(0, &record[i], n - i);
+ if (cc <= 0) {
+ DEBUG("rmtd: premature eof\n");
+ exit(2);
+ }
+ }
+ rval = write(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'R':
+ getstring(count);
+ DEBUG1("rmtd: R %s\n", count);
+ n = atoi(count);
+ record = checkbuf(record, n);
+ rval = read(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ (void) sprintf(resp, "A%d\n", rval);
+ (void) write(1, resp, strlen(resp));
+ (void) write(1, record, rval);
+ goto top;
+
+ case 'I':
+ getstring(op); getstring(count);
+ DEBUG2("rmtd: I %s %s\n", op, count);
+ { struct mtop mtop;
+ mtop.mt_op = atoi(op);
+ mtop.mt_count = atoi(count);
+ if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
+ goto ioerror;
+ rval = mtop.mt_count;
+ }
+ goto respond;
+
+ case 'S': /* status */
+ DEBUG("rmtd: S\n");
+ { struct mtget mtget;
+ if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
+ goto ioerror;
+ rval = sizeof (mtget);
+ (void) sprintf(resp, "A%d\n", rval);
+ (void) write(1, resp, strlen(resp));
+ (void) write(1, (char *)&mtget, sizeof (mtget));
+ goto top;
+ }
+
+ default:
+ DEBUG1("rmtd: garbage command %c\n", c);
+ exit(3);
+ }
+respond:
+ DEBUG1("rmtd: A %d\n", rval);
+ (void) sprintf(resp, "A%d\n", rval);
+ (void) write(1, resp, strlen(resp));
+ goto top;
+ioerror:
+ error(errno);
+ goto top;
+}
+
+getstring(bp)
+ char *bp;
+{
+ int i;
+ char *cp = bp;
+
+ for (i = 0; i < SSIZE; i++) {
+ if (read(0, cp+i, 1) != 1)
+ exit(0);
+ if (cp[i] == '\n')
+ break;
+ }
+ cp[i] = '\0';
+}
+
+char *
+checkbuf(record, size)
+ char *record;
+ int size;
+{
+ extern char *malloc();
+
+ if (size <= maxrecsize)
+ return (record);
+ if (record != 0)
+ free(record);
+ record = malloc(size);
+ if (record == 0) {
+ DEBUG("rmtd: cannot allocate buffer space\n");
+ exit(4);
+ }
+ maxrecsize = size;
+ while (size > 1024 &&
+ setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
+ size -= 1024;
+ return (record);
+}
+
+error(num)
+ int num;
+{
+
+ DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
+ (void) sprintf(resp, "E%d\n%s\n", num, strerror(num));
+ (void) write(1, resp, strlen(resp));
+}
diff --git a/usr.sbin/rpc.bootparamd/Makefile b/usr.sbin/rpc.bootparamd/Makefile
new file mode 100644
index 00000000000..f6d7c0b4129
--- /dev/null
+++ b/usr.sbin/rpc.bootparamd/Makefile
@@ -0,0 +1,22 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+
+CFLAGS+=-DYP
+
+PROG= rpc.bootparamd
+SRCS= bootparamd.c bootparam_prot_svc.c
+MAN= bootparams.5 rpc.bootparamd.8
+MLINKS= rpc.bootparamd.8 bootparamd.8
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+bootparam_prot_svc.c: ${DESTDIR}/usr/include/rpcsvc/bootparam_prot.x
+ rm -f bootparam_prot.x
+ ln -s ${DESTDIR}/usr/include/rpcsvc/bootparam_prot.x .
+ rm -f bootparam_prot.h
+ ln -s ${DESTDIR}/usr/include/rpcsvc/bootparam_prot.h .
+ rpcgen -m -o $@ bootparam_prot.x
+
+CLEANFILES += bootparam_prot_svc.c bootparam_prot.x bootparam_prot.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rpc.bootparamd/bootparamd.c b/usr.sbin/rpc.bootparamd/bootparamd.c
new file mode 100644
index 00000000000..1bbfc2b5ce7
--- /dev/null
+++ b/usr.sbin/rpc.bootparamd/bootparamd.c
@@ -0,0 +1,383 @@
+/*
+ * This code is not copyright, and is placed in the public domain.
+ * Feel free to use and modify. Please send modifications and/or
+ * suggestions + bug fixes to Klas Heggemann <klas@nada.kth.se>
+ *
+ * Various small changes by Theo de Raadt <deraadt@fsa.ca>
+ * Parser rewritten (adding YP support) by Roland McGrath <roland@frob.com>
+ *
+ * $Id: bootparamd.c,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/bootparam_prot.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <string.h>
+#include "pathnames.h"
+
+#define MAXLEN 800
+
+struct hostent *he;
+static char buffer[MAXLEN];
+static char hostname[MAX_MACHINE_NAME];
+static char askname[MAX_MACHINE_NAME];
+static char path[MAX_PATH_LEN];
+static char domain_name[MAX_MACHINE_NAME];
+
+extern void bootparamprog_1 __P((struct svc_req *, SVCXPRT *));
+
+int _rpcsvcdirty = 0;
+int _rpcpmstart = 0;
+int debug = 0;
+int dolog = 0;
+unsigned long route_addr, inet_addr();
+struct sockaddr_in my_addr;
+char *progname;
+char *bootpfile = _PATH_BOOTPARAMS;
+
+extern char *optarg;
+extern int optind;
+
+void
+usage()
+{
+ fprintf(stderr,
+ "usage: rpc.bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n");
+}
+
+
+/*
+ * ever familiar
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SVCXPRT *transp;
+ int i, s, pid;
+ char *rindex();
+ struct hostent *he;
+ struct stat buf;
+ char *optstring;
+ char c;
+
+ progname = rindex(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "dsr:f:")) != EOF)
+ switch (c) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'r':
+ if (isdigit(*optarg)) {
+ route_addr = inet_addr(optarg);
+ break;
+ }
+ he = gethostbyname(optarg);
+ if (!he) {
+ fprintf(stderr, "%s: No such host %s\n",
+ progname, optarg);
+ usage();
+ exit(1);
+ }
+ bcopy(he->h_addr, (char *) &route_addr, sizeof(route_addr));
+ break;
+ case 'f':
+ bootpfile = optarg;
+ break;
+ case 's':
+ dolog = 1;
+#ifndef LOG_DAEMON
+ openlog(progname, 0, 0);
+#else
+ openlog(progname, 0, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_NOTICE));
+#endif
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+
+ if (stat(bootpfile, &buf)) {
+ fprintf(stderr, "%s: ", progname);
+ perror(bootpfile);
+ exit(1);
+ }
+ if (!route_addr) {
+ get_myaddress(&my_addr);
+ bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof(route_addr));
+ }
+ if (!debug)
+ daemon();
+
+ (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS);
+
+ transp = svcudp_create(RPC_ANYSOCK);
+ if (transp == NULL) {
+ fprintf(stderr, "cannot create udp service.\n");
+ exit(1);
+ }
+ if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS,
+ bootparamprog_1, IPPROTO_UDP)) {
+ fprintf(stderr,
+ "bootparamd: unable to register BOOTPARAMPROG version %d, udp)\n",
+ BOOTPARAMVERS);
+ exit(1);
+ }
+ svc_run();
+ fprintf(stderr, "svc_run returned\n");
+ exit(1);
+}
+
+bp_whoami_res *
+bootparamproc_whoami_1_svc(whoami, rqstp)
+ bp_whoami_arg *whoami;
+ struct svc_req *rqstp;
+{
+ long haddr;
+ static bp_whoami_res res;
+
+ if (debug)
+ fprintf(stderr, "whoami got question for %d.%d.%d.%d\n",
+ 255 & whoami->client_address.bp_address_u.ip_addr.net,
+ 255 & whoami->client_address.bp_address_u.ip_addr.host,
+ 255 & whoami->client_address.bp_address_u.ip_addr.lh,
+ 255 & whoami->client_address.bp_address_u.ip_addr.impno);
+ if (dolog)
+ syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n",
+ 255 & whoami->client_address.bp_address_u.ip_addr.net,
+ 255 & whoami->client_address.bp_address_u.ip_addr.host,
+ 255 & whoami->client_address.bp_address_u.ip_addr.lh,
+ 255 & whoami->client_address.bp_address_u.ip_addr.impno);
+
+ bcopy((char *) &whoami->client_address.bp_address_u.ip_addr, (char *) &haddr,
+ sizeof(haddr));
+ he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET);
+ if (!he)
+ goto failed;
+
+ if (debug)
+ fprintf(stderr, "This is host %s\n", he->h_name);
+ if (dolog)
+ syslog(LOG_NOTICE, "This is host %s\n", he->h_name);
+
+ strcpy(askname, he->h_name);
+ if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) {
+ res.client_name = hostname;
+ getdomainname(domain_name, MAX_MACHINE_NAME);
+ res.domain_name = domain_name;
+
+ if (res.router_address.address_type != IP_ADDR_TYPE) {
+ res.router_address.address_type = IP_ADDR_TYPE;
+ bcopy(&route_addr, &res.router_address.bp_address_u.ip_addr, 4);
+ }
+ if (debug)
+ fprintf(stderr, "Returning %s %s %d.%d.%d.%d\n",
+ res.client_name, res.domain_name,
+ 255 & res.router_address.bp_address_u.ip_addr.net,
+ 255 & res.router_address.bp_address_u.ip_addr.host,
+ 255 & res.router_address.bp_address_u.ip_addr.lh,
+ 255 & res.router_address.bp_address_u.ip_addr.impno);
+ if (dolog)
+ syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d\n",
+ res.client_name, res.domain_name,
+ 255 & res.router_address.bp_address_u.ip_addr.net,
+ 255 & res.router_address.bp_address_u.ip_addr.host,
+ 255 & res.router_address.bp_address_u.ip_addr.lh,
+ 255 & res.router_address.bp_address_u.ip_addr.impno);
+
+ return (&res);
+ }
+failed:
+ if (debug)
+ fprintf(stderr, "whoami failed\n");
+ if (dolog)
+ syslog(LOG_NOTICE, "whoami failed\n");
+ return (NULL);
+}
+
+
+bp_getfile_res *
+bootparamproc_getfile_1_svc(getfile, rqstp)
+ bp_getfile_arg *getfile;
+ struct svc_req *rqstp;
+{
+ char *where, *index();
+ static bp_getfile_res res;
+ int err;
+
+ if (debug)
+ fprintf(stderr, "getfile got question for \"%s\" and file \"%s\"\n",
+ getfile->client_name, getfile->file_id);
+
+ if (dolog)
+ syslog(LOG_NOTICE, "getfile got question for \"%s\" and file \"%s\"\n",
+ getfile->client_name, getfile->file_id);
+
+ he = NULL;
+ he = gethostbyname(getfile->client_name);
+ if (!he)
+ goto failed;
+
+ strcpy(askname, he->h_name);
+ err = lookup_bootparam(askname, NULL, getfile->file_id,
+ &res.server_name, &res.server_path);
+ if (err == 0) {
+ he = gethostbyname(res.server_name);
+ if (!he)
+ goto failed;
+ bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4);
+ res.server_address.address_type = IP_ADDR_TYPE;
+ } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) {
+ /* Special for dump, answer with null strings. */
+ res.server_name[0] = '\0';
+ res.server_path[0] = '\0';
+ bzero(&res.server_address.bp_address_u.ip_addr, 4);
+ } else {
+failed:
+ if (debug)
+ fprintf(stderr, "getfile failed for %s\n",
+ getfile->client_name);
+ if (dolog)
+ syslog(LOG_NOTICE,
+ "getfile failed for %s\n", getfile->client_name);
+ return (NULL);
+ }
+
+ if (debug)
+ fprintf(stderr,
+ "returning server:%s path:%s address: %d.%d.%d.%d\n",
+ res.server_name, res.server_path,
+ 255 & res.server_address.bp_address_u.ip_addr.net,
+ 255 & res.server_address.bp_address_u.ip_addr.host,
+ 255 & res.server_address.bp_address_u.ip_addr.lh,
+ 255 & res.server_address.bp_address_u.ip_addr.impno);
+ if (dolog)
+ syslog(LOG_NOTICE,
+ "returning server:%s path:%s address: %d.%d.%d.%d\n",
+ res.server_name, res.server_path,
+ 255 & res.server_address.bp_address_u.ip_addr.net,
+ 255 & res.server_address.bp_address_u.ip_addr.host,
+ 255 & res.server_address.bp_address_u.ip_addr.lh,
+ 255 & res.server_address.bp_address_u.ip_addr.impno);
+ return (&res);
+}
+
+
+int
+lookup_bootparam(client, client_canonical, id, server, path)
+ char *client;
+ char *client_canonical;
+ char *id;
+ char **server;
+ char **path;
+{
+ FILE *f = fopen(bootpfile, "r");
+#ifdef YP
+ static char *ypbuf = NULL;
+ static int ypbuflen = 0;
+#endif
+ static char buf[BUFSIZ];
+ char *bp, *word;
+ size_t idlen = id == NULL ? 0 : strlen(id);
+ int contin = 0;
+ int found = 0;
+
+ if (f == NULL)
+ return EINVAL; /* ? */
+
+ while (fgets(buf, sizeof buf, f)) {
+ int wascontin = contin;
+ contin = buf[strlen(buf) - 2] == '\\';
+ bp = buf + strspn(buf, " \t\n");
+
+ switch (wascontin) {
+ case -1:
+ /* Continuation of uninteresting line */
+ contin *= -1;
+ continue;
+ case 0:
+ /* New line */
+ contin *= -1;
+ if (*bp == '#')
+ continue;
+ if ((word = strsep(&bp, " \t\n")) == NULL)
+ continue;
+#ifdef YP
+ /* A + in the file means try YP now */
+ if (!strcmp(word, "+")) {
+ char *ypdom;
+
+ if (yp_get_default_domain(&ypdom) ||
+ yp_match(ypdom, "bootparams", client,
+ strlen(client), &ypbuf, &ypbuflen))
+ continue;
+ bp = ypbuf;
+ word = client;
+ contin *= -1;
+ break;
+ }
+#endif
+ /* See if this line's client is the one we are
+ * looking for */
+ if (strcmp(word, client) != 0) {
+ /*
+ * If it didn't match, try getting the
+ * canonical host name of the client
+ * on this line and comparing that to
+ * the client we are looking for
+ */
+ struct hostent *hp = gethostbyname(word);
+ if (hp == NULL || strcmp(hp->h_name, client))
+ continue;
+ }
+ contin *= -1;
+ break;
+ case 1:
+ /* Continued line we want to parse below */
+ break;
+ }
+
+ if (client_canonical)
+ strncpy(client_canonical, word, MAX_MACHINE_NAME);
+
+ /* We have found a line for CLIENT */
+ if (id == NULL) {
+ (void) fclose(f);
+ return 0;
+ }
+
+ /* Look for a value for the parameter named by ID */
+ while ((word = strsep(&bp, " \t\n")) != NULL) {
+ if (!strncmp(word, id, idlen) && word[idlen] == '=') {
+ /* We have found the entry we want */
+ *server = &word[idlen + 1];
+ *path = strchr(*server, ':');
+ if (*path == NULL)
+ /* Malformed entry */
+ continue;
+ *(*path)++ = '\0';
+ (void) fclose(f);
+ return 0;
+ }
+ }
+
+ found = 1;
+ }
+
+ (void) fclose(f);
+ return found ? ENOENT : EPERM;
+}
diff --git a/usr.sbin/rpc.bootparamd/bootparams.5 b/usr.sbin/rpc.bootparamd/bootparams.5
new file mode 100644
index 00000000000..84c7999e038
--- /dev/null
+++ b/usr.sbin/rpc.bootparamd/bootparams.5
@@ -0,0 +1,78 @@
+.\"
+.\" Copyright (c) 1994 Gordon W. Ross
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: bootparams.5,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+.\"
+.Dd October 2, 1994
+.Dt BOOTPARAMS 5
+.Os
+.Sh NAME
+.Nm bootparams
+.Nd boot parameter database
+.Sh SYNOPSIS
+.Nm /etc/bootparams
+.Sh DESCRIPTION
+The
+.Nm bootparams
+file specifies the boot parameters that
+.Xr diskless
+clients may request when booting over the network.
+Each client supported by this server must have an entry in the
+.Nm bootparams
+file containing the pathnames for its
+.Nm root
+and (optionally)
+.Nm swap
+areas.
+.Pp
+Each line in the file
+(other than comment lines that begin with a #)
+specifies the client name followed by the pathnames that
+the client may request by their logical names.
+The components of the line are delimited with blank or tab,
+and may be continued onto multiple lines with a backslash.
+.Pp
+For example:
+.Bd -literal -offset indent
+dummy root=/export/dummy/root \\
+ swap=/export/dummy/swap \\
+ dump=/export/dummy/swap
+.Ed
+.Pp
+When the client named "dummy" requests the pathname for
+its logical "root" it will be given the pathname
+.Dq Pa "/export/dummy/root"
+as the response to its
+.Tn RPC
+request.
+.Sh FILES
+.Bl -tag -width /etc/bootparams -compact
+.It Pa /etc/bootparams
+default configuration file
+.El
+.Sh "SEE ALSO"
+.Xr diskless 8 ,
+.Xr rpc.bootparamd 8
diff --git a/usr.sbin/rpc.bootparamd/pathnames.h b/usr.sbin/rpc.bootparamd/pathnames.h
new file mode 100644
index 00000000000..467ed1bd28f
--- /dev/null
+++ b/usr.sbin/rpc.bootparamd/pathnames.h
@@ -0,0 +1,10 @@
+/*
+ * Written Roland McGrath <roland@frob.com> 10/15/93.
+ * Public domain.
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:48:05 deraadt Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_BOOTPARAMS "/etc/bootparams"
diff --git a/usr.sbin/rpc.bootparamd/rpc.bootparamd.8 b/usr.sbin/rpc.bootparamd/rpc.bootparamd.8
new file mode 100644
index 00000000000..f856d555b20
--- /dev/null
+++ b/usr.sbin/rpc.bootparamd/rpc.bootparamd.8
@@ -0,0 +1,62 @@
+.\" $Id: rpc.bootparamd.8,v 1.1.1.1 1995/10/18 08:48:06 deraadt Exp $
+.\" @(#)bootparamd.8
+.Dd Jan 8, 1994
+.Dt BOOTPARAMD 8
+.Os NetBSD
+.Sh NAME
+.Nm bootparamd ,
+.Nm rpc.bootparamd
+.Nd boot parameter server
+.Sh SYNOPSIS
+.Nm /usr/sbin/rpc.bootparamd
+.Op Fl d
+.Op Fl s
+.Op Fl r router
+.Op Fl f file
+.Sh DESCRIPTION
+.Nm \&Bootparamd
+is a server process that provides information to diskless clients
+necessary for booting. It consults the file
+.Dq Pa /etc/bootparams .
+It should normally be started from
+.Dq Pa /etc/rc .
+.Pp
+This version will allow the use of aliases on the hostname in the
+.Dq Pa /etc/bootparams
+file. The hostname returned in response to the booting client's whoami request
+will be the name that appears in the config file, not the canonical name.
+In this way you can keep the answer short enough
+so that machines that cannot handle long hostnames won't fail during boot.
+.Pp
+While parsing, if a line containing just ``+'' is found, and
+the YP subsystem is active, the YP map
+.Pa bootparams
+will be searched immediately.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl d
+Display the debugging information. The daemon does not fork in this
+case.
+.It Fl s
+Log the debugging information with syslog.
+.It Fl r
+Set the default router (a hostname or IP-address).
+This defaults to the machine running the server.
+.It Fl f
+Specify the file to use as boot parameter file instead of
+.Dq Pa /etc/bootparams .
+.El
+.Pp
+.Sh FILES
+.Bl -tag -width /etc/bootparams -compact
+.It Pa /etc/bootparams
+default configuration file
+.El
+.Sh "SEE ALSO"
+.Xr bootparams 5
+.Sh BUGS
+You may find the syslog loggings too verbose.
+.Pp
+It's not clear if the non-cannonical hack mentioned above is a good idea.
+.Sh AUTHOR
+Originally written by Klas Heggemann <klas@nada.kth.se>
diff --git a/usr.sbin/rpc.pcnfsd/Makefile b/usr.sbin/rpc.pcnfsd/Makefile
new file mode 100644
index 00000000000..7f753aa50e9
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/Makefile
@@ -0,0 +1,28 @@
+# $NetBSD: Makefile,v 1.3 1995/07/25 22:20:13 gwr Exp $
+
+PROG= rpc.pcnfsd
+MAN= pcnfsd.8
+MLINKS= pcnfsd.8 rpc.pcnfsd.8
+CFLAGS += -DUSER_CACHE -DWTMP -DUSE_YP -I${.OBJDIR}
+
+SRCS= pcnfsd_v1.c pcnfsd_v2.c pcnfsd_misc.c \
+ pcnfsd_cache.c pcnfsd_print.c pcnfsd_svc.c pcnfsd_xdr.c
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc -lcrypt
+
+pcnfsd_svc.c: pcnfsd.x
+ rpcgen -s udp -s tcp -I ${.CURDIR}/pcnfsd.x -o $@
+
+pcnfsd_xdr.c: pcnfsd.x
+ rpcgen -c ${.CURDIR}/pcnfsd.x -o $@
+
+pcnfsd.h: pcnfsd.x
+ rpcgen -h ${.CURDIR}/pcnfsd.x -o $@
+
+CLEANFILES += pcnfsd_svc.c pcnfsd_xdr.c pcnfsd.h
+CLEANFILES += clnt.pcnfsd pcnfsd_test.o pcnfsd_test.ln pcnfsd_clnt.*
+
+.include <bsd.prog.mk>
+
+.depend ${OBJS}: pcnfsd.h
diff --git a/usr.sbin/rpc.pcnfsd/Makefile.clnt b/usr.sbin/rpc.pcnfsd/Makefile.clnt
new file mode 100644
index 00000000000..39fc3d21cc2
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/Makefile.clnt
@@ -0,0 +1,29 @@
+# $NetBSD: Makefile.clnt,v 1.3 1995/07/25 22:20:19 gwr Exp $
+
+# This Makefile builds a client used for testing.
+
+CFLAGS += -DUSER_CACHE -DWTMP -DUSE_YP -I${.OBJDIR}
+
+PROG= clnt.pcnfsd
+SRCS= pcnfsd_test.c pcnfsd_clnt.c pcnfsd_xdr.c
+NOMAN= noman
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+# Special rules for the generated C code...
+
+pcnfsd_clnt.c: pcnfsd.x
+ rpcgen -l ${.CURDIR}/pcnfsd.x -o $@
+
+pcnfsd_xdr.c: pcnfsd.x
+ rpcgen -c ${.CURDIR}/pcnfsd.x -o $@
+
+pcnfsd.h: pcnfsd.x
+ rpcgen -h ${.CURDIR}/pcnfsd.x -o $@
+
+CLEANFILES += pcnfsd_clnt.c pcnfsd_xdr.c pcnfsd.h
+
+.include <bsd.prog.mk>
+
+.depend ${OBJS}: pcnfsd.h
diff --git a/usr.sbin/rpc.pcnfsd/README b/usr.sbin/rpc.pcnfsd/README
new file mode 100644
index 00000000000..2053b7c654e
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/README
@@ -0,0 +1,110 @@
+# $NetBSD: README,v 1.2 1995/07/25 22:20:22 gwr Exp $
+
+
+July 1995 - Ported to NetBSD by Gordon Ross <gwr@netbsd.org>
+
+Note: to build clnt.pcnfsd use the command:
+ make -f Makefile.clnt
+
+Text of original README file from Sun follows:
+----------------------------------------------------------------------
+
+This is version @(#)README 1.6 1/28/92 of the pcnfsd README file.
+----------------------------------------------------------------------
+This is the second cut at PCNFSD v2. All printing now uses the same
+SVR4 based printing model: lp, lpstat, cancel. This implies SunOS 4.1
+or later on a Sun. The printing hasn't been properly tested on SVR4,
+since my SVR4 system is a bit quirky, but authentication via shadow
+passwords works fine.
+
+The Makefile supplied will build either SunOS 4.1 or SVR4 versions;
+however you will need to tweak a couple of definitions. See the
+Makefile for details.
+
+For this round, I have frozen the rpcgen'd code and modified it by hand
+to get around a few rpcgen deficiencies. If in doubt, you can take the
+pcnfsd.x file included here off to a separate directory, rpcgen everything
+up and diff against the versions given here.
+
+You should also be sure to read the man page. I haven't tried [nt]roff'ing
+this anywhere outside SunOS, so let me know if there are any quirks.
+Note especially the /etc/pcnfsd.conf configuration model.
+
+Standard disclaimers. Read the source for more of the same.
+
+Geoff Arnold (Geoff.Arnold@Sun.COM)
+May 2, 1991
+
+----------------------------------------------------------------------
+This is the first major spin since the version I posted in May.
+Changes are described in the SCCS deltas, but anyone analysing
+or porting this should watch for the following:
+
+- Lots of SVR4 stuff. Look at the Makefile and common.h; you will
+ need to make sure that SVR4 is defined to build a version for SVR4.
+- Fixed a major bug whereby aliased printers (a.k.a. virtual printers)
+ didn't show up in the printer list.
+- Since some commands (especially lpq) can hang up forever if, say,
+ the host of a remote printer is down, the su_popen mechanism now
+ includes a watchdog timer. I HAVE NOT HAD A CHANCE TO TEST THIS
+ LOGIC ON SVR4 YET! The code was derived from the System V compatiility
+ section of the AnswerBook, so it _should_ be OK, but I can't wait to
+ test it before posting this.
+- I've mades lots of lint-suggested improvements. It doesn't lint
+ 100% cleanly yet, but it's a lot better.
+- The client testbed has been tightened up a bit and the reporting
+ is somewhat clearer. Please run it.
+
+Feedback is solicited.
+
+Geoff Arnold (Geoff.Arnold@Sun.COM)
+July 24, 1991
+
+----------------------------------------------------------------------------
+
+This version includes support for TCP as well as UDP, both in the
+server and in the test client. Some of the calls can have long
+responses, in which case TCP is the preferred transport.
+
+Jon Dreyer
+January 28, 1992
+
+----------------------------------------------------------------------------
+
+This release incorporates minor bug fixes occasioned by internal testing
+against preliminary versions of PC-NFS subsystems which actually use the
+V2 protocol features. It also addresses a security hole which was identified:
+see the comment in pcnfsd_print.c for details. This is the version
+of the daemon which we expect to send out for beta testing.
+
+Geoff Arnold
+November 16, 1991
+
+----------------------------------------------------------------------------
+
+Several people pointed out that if I was going to fix the security
+hole, I should *REALLY* fix it. So this revision checks every argument
+for every shell metacharacter. This means that if your print subsystem
+allows such characters in printer names, print job id's, user names,
+etc. you're going to have to relax the restrictions or tighten up
+elsewhere. The routine "suspicious()" in pcnfsd_print.c is the starting
+point for this.
+
+Geoff Arnold
+November 21, 1991
+
+----------------------------------------------------------------------------
+
+This version includes one more tweak on the previous security fix, plus
+a fix for the "user shell" security hole.
+
+Geoff Arnold
+December 17, 1991
+
+----------------------------------------------------------------------------
+
+Fix a stupid bug - the secondary groups array wasn't static, so it
+got overwritten, resulting in the corruption of some GIDs.
+
+Geoff Arnold
+December 18, 1991
diff --git a/usr.sbin/rpc.pcnfsd/common.h b/usr.sbin/rpc.pcnfsd/common.h
new file mode 100644
index 00000000000..641d78c7eec
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/common.h
@@ -0,0 +1,181 @@
+/* $NetBSD: common.h,v 1.2 1995/07/25 22:20:26 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.common.h 1.3 91/12/17 14:32:05 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+**
+** D I S C L A I M E R S E C T I O N , E T C .
+**
+** pcnfsd is copyrighted software, but is freely licensed. This
+** means that you are free to redistribute it, modify it, ship it
+** in binary with your system, whatever, provided:
+**
+** - you leave the Sun copyright notice in the source code
+** - you make clear what changes you have introduced and do
+** not represent them as being supported by Sun.
+** - you do not charge money for the source code (unlikely, given
+** its free availability)
+**
+** If you make changes to this software, we ask that you do so in
+** a way which allows you to build either the "standard" version or
+** your custom version from a single source file. Test it, lint
+** it (it won't lint 100%, very little does, and there are bugs in
+** some versions of lint :-), and send it back to Sun via email
+** so that we can roll it into the source base and redistribute
+** it. We'll try to make sure your contributions are acknowledged
+** in the source, but after all these years it's getting hard to
+** remember who did what.
+**
+** The main contributors have been (in no special order):
+**
+** Glen Eustace <G.Eustace@massey.ac.nz>
+** user name caching for b-i-g password files
+** Paul Emerson <paul@sdgsun.uucp>
+** cleaning up Interactive 386/ix handling, fixing the lp
+** interface, and generally tidying up the sources
+** Keith Ericson <keithe@sail.labs.tek.com>
+** more 386/ix fixes
+** Jeff Stearns <jeff@tc.fluke.com>
+** setuid/setgid for lpr
+** Peter Van Campen <petervc@sci.kun.nl>
+** fixing setuid/gid stuff, syslog
+** Ted Nolan <ted@usasoc.soc.mil>
+** /usr/adm/wtmp, other security suggestions
+**
+** Thanks to everyone who has contributed.
+**
+** Geoff Arnold, PC-NFS architect <geoff@East.Sun.COM>
+**=====================================================================
+*/
+/*
+**=====================================================================
+** C U S T O M I Z A T I O N S E C T I O N *
+** *
+** You should not uncomment these #defines in this version of pcnfsd *
+** Instead you should edit the makefile CDEFS variable. *
+** *
+**=====================================================================
+*/
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to enable the use of a
+** shadow password file
+**---------------------------------------------------------------------
+**/
+
+/* #define SHADOW_SUPPORT */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to enable the logging
+** of authentication requests to /usr/adm/wtmp
+**---------------------------------------------------------------------
+**/
+
+/* #define WTMP */
+
+/*
+**------------------------------------------------------------------------
+** Define (via Makefile) the following symbol conform to Interactive
+** System's 2.0
+**------------------------------------------------------------------------
+*/
+
+/* #define ISC_2_0 */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to use a cache of recently-used
+** user names. This has certain uses in university and other settings
+** where (1) the pasword file is very large, and (2) a group of users
+** frequently logs in together using the same account (for example,
+** a class userid).
+**---------------------------------------------------------------------
+*/
+
+/* #define USER_CACHE */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to build a System V version
+**---------------------------------------------------------------------
+*/
+
+/* #define SYSV */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to build a version that uses
+** System V style "lp" instead of BSD-style "lpr" to print
+**---------------------------------------------------------------------
+*/
+
+/* #define USE_LP */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to build a typical
+** "local feature": in this case recognizing the special printer
+** names "rotated" and "2column" and using the Adobe "enscript"
+** command to format the output appropriately.
+**---------------------------------------------------------------------
+*/
+
+/* #define HACK_FOR_ROTATED_TRANSCRIPT */
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to build a version that
+** will use the setusershell()/getusershell()/endusershell() calls
+** to determine if a password entry contains a legal shell (and therefore
+** identifies a user who may log in). The default is to check that
+** the last two characters of the shell field are "sh", which should
+** cope with "sh", "csh", "ksh", "bash".... See the routine get_pasword()
+** in pcnfsd_misc.c for more details.
+**
+** Note: For some reason that I haven't yet figured out, getusershell()
+** only seems to work when RPC_SVC_FG is defined (for debugging). It doesn't
+** seem to matter whether /etc/shells exists or not. Tracing
+** things doesn't throw any light on this.... Geoff Dec.17 '91
+*/
+
+/*
+**---------------------------------------------------------------------
+** Define (via Makefile) the following symbol to build a version that
+** will consult the NIS (formerly Yellow Pages) "auto.home" map to
+** locate the user's home directory (returned by the V2 authentication
+** procedure).
+**---------------------------------------------------------------------
+*/
+
+/* #define USE_YP */
+
+
+/* #define USE_GETUSERSHELL */
+
+
+/*
+**---------------------------------------------------------------------
+** The following should force the right things for Interactive 2.0
+**---------------------------------------------------------------------
+*/
+#ifdef ISC_2_0
+#define SYSV
+#define USE_LP
+#define SHADOW_SUPPORT
+#endif
+
+/*
+**---------------------------------------------------------------------
+** Other #define's
+**---------------------------------------------------------------------
+*/
+
+#define assert(ex) {if (!(ex)) \
+ {char asstmp[256];(void)sprintf(asstmp,"rpc.pcnfsd: Assertion failed: line %d of %s: \"%s\"\n", \
+ __LINE__, __FILE__, "ex"); (void)msg_out(asstmp); \
+ sleep (10); exit(1);}}
+
+
diff --git a/usr.sbin/rpc.pcnfsd/paths.h b/usr.sbin/rpc.pcnfsd/paths.h
new file mode 100644
index 00000000000..9c589d3cf62
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/paths.h
@@ -0,0 +1,13 @@
+/* $NetBSD: paths.h,v 1.1 1995/08/14 19:50:09 gwr Exp $ */
+
+#ifndef SPOOLDIR
+#define SPOOLDIR "/export/pcnfs"
+#endif
+
+#ifndef LPRDIR
+#define LPRDIR "/usr/bin"
+#endif
+
+#ifndef LPCDIR
+#define LPCDIR "/usr/sbin"
+#endif
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd.8 b/usr.sbin/rpc.pcnfsd/pcnfsd.8
new file mode 100644
index 00000000000..0c48ea78b82
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd.8
@@ -0,0 +1,217 @@
+.\" $NetBSD: pcnfsd.8,v 1.4 1995/08/14 19:48:07 gwr Exp $
+.\" @(#) @(#)pcnfsd.8c 1.1 9/3/91;
+.TH PCNFSD 8C "25 April 1991"
+.SH NAME
+pcnfsd \- (PC)NFS authentication and print request server
+.SH SYNOPSIS
+.B /usr/sbin/rpc.pcnfsd
+.SH DESCRIPTION
+.LP
+.B pcnfsd
+is an
+.SM RPC
+server that supports Sun ONC clients on PC (DOS, OS/2, Macintosh, and other)
+systems. This page describes version two of the
+.B pcnfsd
+server.
+.LP
+.B rpc.pcnfsd
+may be started from
+.B /etc/rc.local
+or by the
+.BR inetd (8)
+superdaemon. It reads the configuration file
+.B /etc/pcnfsd.conf
+if present, and then services RPC requests directed to
+program number 150001. This release of the
+.B pcnfsd
+daemon supports both version 1 and version 2 of the pcnfsd
+protocol. Consult the
+.B rpcgen
+source file
+.B pcnfsd.x
+for details of the protocols.
+.LP
+The requests serviced by
+.B pcnfsd
+fall into three categories: authentication, printing, and other. Only the
+authentication and printing services have administrative significance.
+.SH AUTHENTICATION
+When
+.B pcnfsd
+receives a
+.B PCNFSD_AUTH
+or
+.B PCNFSD2_AUTH
+request\**, it will "log in" the user by validating the username and
+password and returning the corresponding uid, gids, home directory,
+and umask. If
+.B pcnfsd
+was built with the
+.B WTMP
+compile-time option, it will also append a record to the
+.BR wtmp (5)
+data base. If you do not wish to record PC "logins" in this way,
+you should add a line of the form
+.RS
+.sp
+\fBwtmp off\fP
+.sp
+.RE
+to the
+.B /etc/pcnfsd.conf
+file.
+.SH PRINTING
+.LP
+.B pcnfsd
+supports a printing model based on the use of NFS to transfer
+the actual print data from the client to the server. The client system
+issues a
+.B PCNFSD_PR_INIT
+or
+.B PCNFSD2_PR_INIT
+request, and the server returns the path to a spool directory which
+the client may use and which is exported by NFS.
+.B pcnfsd
+creates a subdirectory for each of its clients: the parent
+directory is normally
+.B /export/pcnfs
+and the subdirectory is the hostname of the client system.
+If you wish to use a different parent directory, you should add a
+line of the form
+.RS
+.sp
+\fBspooldir\fP \fIpath\fP
+.sp
+.RE
+to the
+.B /etc/pcnfsd.conf
+file.
+.LP
+Once a client has mounted the spool directory using NFS
+and has transferred print data to a file in this directory, it
+will issue a
+.B PCNFSD_PR_START
+or
+.B PCNFSD2_PR_START
+request.
+.B pcnfsd
+handles this, and most other print-related requests, by
+constructing a command based on the printing services of
+the server operating system and executing the command using the
+identity of the PC user. Since this involves set-user-id privileges,
+.B pcnfsd
+must be run as root.
+.LP
+Every print request from the client includes the name of the printer
+which is to be used. In SunOS, this name corresponds to a printer
+definition in the
+.BR /etc/printcap (5)
+database. If you wish to define a non-standard way of processing
+print data, you should define a new printer and arrange for the
+client to print to this printer. There are two ways of setting up a new printer.
+The first involves the addition of an entry to
+.BR /etc/printcap (5)
+and the creation of filters to perform the required processing. This
+is outside the scope of this discussion. In addition,
+.B pcnfsd
+includes a mechanism by which you can define virtual printers known
+only to
+.B pcnfsd
+clients. Each printer is defined by a line in the
+.B /etc/pcnfsd.conf
+file of the following form
+.RS
+.sp
+\fBprinter\fP \fIname alias-for command\fP
+.sp
+.RE
+\fIname\fP is the name of the printer you want to define. \fIalias-for\fP
+is the name of a "real" printer which corresponds to this printer. For
+example, a request to
+display the queue for \fIname\fP will be translated into the
+corresponding request for the printer \fIalias-for\fP. If you have
+defined a printer in such a way that there is no "real" printer to
+which it corresponds, use a single "-" for this field. (See the
+definition of the printer
+.B test
+below for an example.) \fIcommand\fP is a
+command which will be executed whenever a file is printed on \fIname\fP.
+This command is executed by the Bourne shell,
+.B /bin/sh
+using the
+.B -c
+option. For complex operations you should
+construct an executable shell program and invoke that in \fIcommand\fP.
+Within \fIcommand\fP the following tokens will be replaced:
+.LP
+.TP 10
+.B Token
+.B Substitution
+.TP
+.SB $FILE
+Replaced by the full path name of the print data file. When
+the command has been executed, the file will be unlinked.
+.TP
+.SB $USER
+Replaced by the username of the user logged in to the client system.
+.TP
+.SB $HOST
+Replaced by the host name of the client system.
+.LP
+Consider the following example
+.B /etc/pcnfsd.conf
+file:
+.RS
+.sp
+printer rotated lw /usr/local/bin/enscript -2r \s-2$FILE\s0
+.br
+printer test - /usr/bin/cp \s-2$FILE\s0 /usr/tmp/\s-2$HOST\s0-\s-2$USER\s0
+.sp
+.RE
+If a client system prints a job on the printer
+.B rotated
+the utility
+.B enscript
+will be invoked to pre-process the file \s-2$FILE\s0. In this
+case, the
+.B -2r
+option causes the file to be printed in two-column rotated format
+on the default PostScript\(rg printer.
+If the client requests a list of the print queue for the printer
+.B rotated
+the
+.B pcnfsd
+daemon will translate this into a request for a listing for
+the printer
+.B lw.
+.LP
+The printer
+.B test
+is used only for testing. Any file sent to this printer
+will be copied into
+.B /usr/tmp.
+Any request to list the queue, check the status, etc. of printer
+.B test
+will be rejected because the \fIalias-for\fP has been specified as "-".
+.SH FILES
+.PD 0
+.TP 20
+.B /etc/pcnfsd.conf
+configuration file
+.TP 20
+.B /export/pcnfs
+default print spool directory
+.PD
+.SH "SEE ALSO"
+.BR lpr (1),
+.BR lpc (8)
+.SH HISTORY
+The
+.B pcnfsd
+source code is distributed by Sun Microsystems, Inc. with their
+.SM PC/NFS
+product under terms described in common.h in that source code.
+Those terms require that you be informed that this version of
+.B pcnfsd
+was modified to run on NetBSD and is NOT supported by Sun.
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd.x b/usr.sbin/rpc.pcnfsd/pcnfsd.x
new file mode 100644
index 00000000000..9274d768aef
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd.x
@@ -0,0 +1,638 @@
+/* $NetBSD: pcnfsd.x,v 1.2 1995/07/25 22:20:33 gwr Exp $ */
+
+/* The maximum number of bytes in a user name argument */
+const IDENTLEN = 32;
+/* The maximum number of bytes in a password argument */
+const PASSWORDLEN = 64;
+/* The maximum number of bytes in a print client name argument */
+const CLIENTLEN = 64;
+/* The maximum number of bytes in a printer name argument */
+const PRINTERNAMELEN = 64;
+/* The maximum number of bytes in a print user name argument */
+const USERNAMELEN = 64;
+/* The maximum number of bytes in a print spool file name argument */
+const SPOOLNAMELEN = 64;
+/* The maximum number of bytes in a print options argument */
+const OPTIONSLEN = 64;
+/* The maximum number of bytes in a print spool directory path */
+const SPOOLDIRLEN = 255;
+/* The maximum number of secondary GIDs returned by a V2 AUTH */
+const EXTRAGIDLEN = 16;
+/* The maximum number of bytes in a home directory spec */
+const HOMEDIRLEN = 255;
+/* The maximum number of bytes in a misc. comments string */
+const COMMENTLEN = 255;
+/* The maximum number of bytes in a print job id */
+const PRINTJOBIDLEN = 255;
+/* The maximum number of printers returned by a LIST operation */
+const PRLISTMAX = 32;
+/* The maximum number of print jobs returned by a QUEUE operation */
+const PRQUEUEMAX = 128;
+/* The maximum number of entries in the facilities list */
+const FACILITIESMAX = 32;
+/* The maximum length of an operator message */
+const MESSAGELEN = 512;
+
+
+
+typedef string ident<IDENTLEN>;
+/*
+** The type ident is used for passing an encoded user name for
+** authentication. The server should decode the string by replacing each
+** octet with the value formed by performing an exclusive-or of the octet
+** value with the value 0x5b and and'ing the result with 0x7f.
+*/
+
+typedef string message<MESSAGELEN>;
+/*
+** The type message is used for passing an alert message to the
+** system operator on the server. The text may include newlines.
+*/
+
+typedef string password<PASSWORDLEN>;
+/*
+** The type password is used for passing an encode password for
+** authentication. The server should decode the password as described
+** above.
+*/
+
+typedef string client<CLIENTLEN>;
+/*
+** The type client is used for passing the hostname of a client for
+** printing. The server may use this name in constructing the spool
+** directory name.
+*/
+
+typedef string printername<PRINTERNAMELEN>;
+/*
+** The type printername is used for passing the name of a printer on which
+** the client wishes to print.
+*/
+
+typedef string username<USERNAMELEN>;
+/*
+** The type username is used for passing the user name for a print job.
+** The server may use this in any way it chooses: it may attempt to change
+** the effective identity with which it is running to username or may
+** simply arrange for the text to be printed on the banner page.
+*/
+
+typedef string comment<COMMENTLEN>;
+/*
+** The type comment is used to pass an uninterpreted text string which
+** may be used by displayed to a human user or used for custom
+** extensions to the PCNFSD service. If you elect to extend PCNFSD
+** service in this way, please do so in a way which will avoid
+** problems if your client attempts to interoperate with a server
+** which does not support your extension. One way to do this is to
+** use the
+*/
+
+typedef string spoolname<SPOOLNAMELEN>;
+/*
+** The type spoolname is used for passing the name of a print spool file
+** (a simple filename not a pathname) within the spool directory.
+*/
+
+typedef string printjobid<PRINTJOBIDLEN>;
+/*
+** The type printjobid is used for passing the id of a print job.
+*/
+
+typedef string homedir<OPTIONSLEN>;
+/*
+** The type homedir is used to return the home directory for the user.
+** If present, it should be in the form "hostname:path", where hostname
+** and path are in a suitable form for communicating with the mount server.
+*/
+
+typedef string options<OPTIONSLEN>;
+/*
+** The type options is used for passing implementation-specific print
+** control information. The option string is a set of printable ASCII
+** characters. The first character should be ignored by the server; it is
+** reserved for client use. The second character specifies the type of
+** data in the print file. The following types are defined (an
+** implementation may define additional values):
+**
+** p - PostScript data. The client will ensure that a valid
+** PostScript header is included.
+** d - Diablo 630 data.
+** x - Generic printable ASCII text. The client will have filtered
+** out all non-printable characters other than CR, LF, TAB,
+** BS and VT.
+** r - Raw print data. The client performs no filtering.
+** u - User-defined. Reserved for custom extensions. A vanilla
+** pcnfsd server will treat this as equivalent to "r"
+**
+** If diablo data (type 'd') is specified, a formatting specification
+** string will be appended. This has the form:
+** ppnnnbbb
+** pp
+** Pitch - 10, 12 or 15.
+** nnn
+** The ``normal'' font to be used - encoded as follows:
+** Courier crn
+** Courier-Bold crb
+** Courier-Oblique con
+** Courier-BoldObliqu cob
+** Helvetica hrn
+** Helvetica-Bold hrb
+** Helvetica-Oblique hon
+** Helvetica-BoldOblique hob
+** Times-Roman trn
+** Times-Bold trb
+** Times-Italic ton
+** Times-BoldItalic tob
+** bbb
+** The ``bold'' font to be used - encoded in the same way. For example,
+** the string ``nd10hrbcob'' specifies that the print data is in Diablo
+** 630 format, it should be printed at 10 pitch, ``normal'' text should be
+** printed in Helvetica-Bold, and ``bold'' text should be printed in
+** Courier-BoldOblique.
+*/
+
+enum arstat {
+ AUTH_RES_OK = 0,
+ AUTH_RES_FAKE = 1,
+ AUTH_RES_FAIL = 2
+};
+/*
+** The type arstat is returned by PCNFSD_AUTH. A value of AUTH_RES_OK
+** indicates that the server was able to verify the ident and password
+** successfully.AUTH_RES_FAIL is returned if a verification failure
+** occurred. The value AUTH_RES_FAKE may be used if the server wishes to
+** indicate that the verification failed, but that the server has
+** synthesised acceptable values for uid and gid which the client may use
+** if it wishes.
+*/
+
+enum alrstat {
+ ALERT_RES_OK = 0,
+ ALERT_RES_FAIL = 1
+};
+/*
+** The type alrstat is returned by PCNFSD_ALERT. A value of ALERT_RES_OK
+** indicates that the server was able to notify the system operator
+** successfully. ALERT_RES_FAIL is returned if a failure occurred
+*/
+enum pirstat {
+ PI_RES_OK = 0,
+ PI_RES_NO_SUCH_PRINTER = 1,
+ PI_RES_FAIL = 2
+};
+/*
+** The type pirstat is returned by a number of print operations. PI_RES_OK
+** indicates that the operation was performed successfully. PI_RES_FAIL
+** indicates that the printer name was valid, but the operation could
+** not be performed. PI_RES_NO_SUCH_PRINTER indicates that the printer
+** name was not recognised.
+*/
+
+enum pcrstat {
+ PC_RES_OK = 0,
+ PC_RES_NO_SUCH_PRINTER = 1,
+ PC_RES_NO_SUCH_JOB = 2,
+ PC_RES_NOT_OWNER = 3,
+ PC_RES_FAIL = 4
+};
+/*
+** The type pcrstat is returned by a CANCEL, REQUEUE, HOLD, or RELEASE
+** print operation.
+** PC_RES_OK indicates that the operation was performed successfully.
+** PC_RES_NO_SUCH_PRINTER indicates that the printer name was not recognised.
+** PC_RES_NO_SUCH_JOB means that the job does not exist, or is not
+** associated with the specified printer.
+** PC_RES_NOT_OWNER means that the user does not have permission to
+** manipulate the job.
+** PC_RES_FAIL means that the job could not be manipulated for an unknown
+** reason.
+*/
+
+
+enum psrstat {
+ PS_RES_OK = 0,
+ PS_RES_ALREADY = 1,
+ PS_RES_NULL = 2,
+ PS_RES_NO_FILE = 3,
+ PS_RES_FAIL = 4
+};
+/*
+** The type psrstat is returned by PCNFSD_PR_START. A value of PS_RES_OK
+** indicates that the server has started printing the job. It is possible
+** that the reply from a PCNFSD_PR_START call may be lost, in which case
+** the client will repeat the call. If the spool file is still in
+** existence, the server will return PS_RES_ALREADY indicating that it has
+** already started printing. If the file cannot be found, PS_RES_NO_FILE
+** is returned. PS_RES_NULL indicates that the spool file was empty,
+** while PS_RES_FAIL denotes a general failure. PI_RES_FAIL is returned
+** if spool directory could not be created. The value
+** PI_RES_NO_SUCH_PRINTER indicates that the printer name was not
+** recognised.
+*/
+
+enum mapreq {
+ MAP_REQ_UID = 0,
+ MAP_REQ_GID = 1,
+ MAP_REQ_UNAME = 2,
+ MAP_REQ_GNAME = 3
+};
+/*
+** The type mapreq identifies the type of a mapping request.
+** MAP_REQ_UID requests that the server treat the value in the
+** id field as a uid and return the corresponding username in name.
+** MAP_REQ_GID requests that the server treat the value in the
+** id field as a gid and return the corresponding groupname in name.
+** MAP_REQ_UNAME requests that the server treat the value in the
+** name field as a username and return the corresponding uid in id.
+** MAP_REQ_GNAME requests that the server treat the value in the
+** name field as a groupname and return the corresponding gid in id.
+*/
+
+enum maprstat {
+ MAP_RES_OK = 0,
+ MAP_RES_UNKNOWN = 1,
+ MAP_RES_DENIED = 2
+};
+/*
+** The type maprstat indicates the success or failure of
+** an individual mapping request.
+*/
+
+/*
+**********************************************************
+** Version 1 of the PCNFSD protocol.
+**********************************************************
+*/
+struct auth_args {
+ ident id;
+ password pw;
+};
+struct auth_results {
+ arstat stat;
+ unsigned int uid;
+ unsigned int gid;
+};
+
+struct pr_init_args {
+ client system;
+ printername pn;
+};
+struct pr_init_results {
+ pirstat stat;
+ spoolname dir;
+};
+
+struct pr_start_args {
+ client system;
+ printername pn;
+ username user;
+ spoolname file;
+ options opts;
+};
+struct pr_start_results {
+ psrstat stat;
+};
+
+
+/*
+**********************************************************
+** Version 2 of the PCNFSD protocol.
+**********************************************************
+*/
+
+struct v2_info_args {
+ comment vers;
+ comment cm;
+};
+
+struct v2_info_results {
+ comment vers;
+ comment cm;
+ int facilities<FACILITIESMAX>;
+};
+
+struct v2_pr_init_args {
+ client system;
+ printername pn;
+ comment cm;
+};
+struct v2_pr_init_results {
+ pirstat stat;
+ spoolname dir;
+ comment cm;
+};
+
+struct v2_pr_start_args {
+ client system;
+ printername pn;
+ username user;
+ spoolname file;
+ options opts;
+ int copies;
+ comment cm;
+};
+struct v2_pr_start_results {
+ psrstat stat;
+ printjobid id;
+ comment cm;
+};
+
+
+
+typedef struct pr_list_item *pr_list;
+
+struct pr_list_item {
+ printername pn;
+ printername device;
+ client remhost; /* empty if local */
+ comment cm;
+ pr_list pr_next;
+};
+
+struct v2_pr_list_results {
+ comment cm;
+ pr_list printers;
+};
+
+struct v2_pr_queue_args {
+ printername pn;
+ client system;
+ username user;
+ bool just_mine;
+ comment cm;
+};
+
+typedef struct pr_queue_item *pr_queue;
+
+struct pr_queue_item {
+ int position;
+ printjobid id;
+ comment size;
+ comment status;
+ client system;
+ username user;
+ spoolname file;
+ comment cm;
+ pr_queue pr_next;
+};
+
+struct v2_pr_queue_results {
+ pirstat stat;
+ comment cm;
+ bool just_yours;
+ int qlen;
+ int qshown;
+ pr_queue jobs;
+};
+
+
+struct v2_pr_cancel_args {
+ printername pn;
+ client system;
+ username user;
+ printjobid id;
+ comment cm;
+};
+struct v2_pr_cancel_results {
+ pcrstat stat;
+ comment cm;
+};
+
+
+struct v2_pr_status_args {
+ printername pn;
+ comment cm;
+};
+struct v2_pr_status_results {
+ pirstat stat;
+ bool avail;
+ bool printing;
+ int qlen;
+ bool needs_operator;
+ comment status;
+ comment cm;
+};
+
+struct v2_pr_admin_args {
+ client system;
+ username user;
+ printername pn;
+ comment cm;
+};
+struct v2_pr_admin_results {
+ pirstat stat;
+ comment cm;
+};
+
+struct v2_pr_requeue_args {
+ printername pn;
+ client system;
+ username user;
+ printjobid id;
+ int qpos;
+ comment cm;
+};
+
+struct v2_pr_requeue_results {
+ pcrstat stat;
+ comment cm;
+};
+
+struct v2_pr_hold_args {
+ printername pn;
+ client system;
+ username user;
+ printjobid id;
+ comment cm;
+};
+struct v2_pr_hold_results {
+ pcrstat stat;
+ comment cm;
+};
+
+struct v2_pr_release_args {
+ printername pn;
+ client system;
+ username user;
+ printjobid id;
+ comment cm;
+};
+struct v2_pr_release_results {
+ pcrstat stat;
+ comment cm;
+};
+
+
+typedef struct mapreq_arg_item *mapreq_arg;
+
+struct mapreq_arg_item {
+ mapreq req;
+ int id;
+ username name;
+ mapreq_arg mapreq_next;
+};
+
+typedef struct mapreq_res_item *mapreq_res;
+
+struct mapreq_res_item {
+ mapreq req;
+ maprstat stat;
+ int id;
+ username name;
+ mapreq_res mapreq_next;
+};
+
+struct v2_mapid_args {
+ comment cm;
+ mapreq_arg req_list;
+};
+
+
+struct v2_mapid_results {
+ comment cm;
+ mapreq_res res_list;
+};
+
+struct v2_auth_args {
+ client system;
+ ident id;
+ password pw;
+ comment cm;
+};
+struct v2_auth_results {
+ arstat stat;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int gids<EXTRAGIDLEN>;
+ homedir home;
+ int def_umask;
+ comment cm;
+};
+
+struct v2_alert_args {
+ client system;
+ printername pn;
+ username user;
+ message msg;
+};
+struct v2_alert_results {
+ alrstat stat;
+ comment cm;
+};
+
+
+/*
+**********************************************************
+** Protocol description for the PCNFSD program
+**********************************************************
+*/
+/*
+** Version 1 of the PCNFSD protocol.
+**
+** -- PCNFSD_NULL() = 0
+** Null procedure - standard for all RPC programs.
+**
+** -- PCNFSD_AUTH() = 1
+** Perform user authentication - map username, password into uid, gid.
+**
+** -- PCNFSD_PR_INIT() = 2
+** Prepare for remote printing: identify exporting spool directory.
+**
+** -- PCNFSD_PR_START() = 3
+** Submit a spooled print job for printing: the print data is
+** in a file created in the spool directory.
+**
+** Version 2 of the -- PCNFSD protocol.
+**
+** -- PCNFSD2_NULL() = 0
+** Null procedure - standard for all RPC programs.
+**
+** -- PCNFSD2_INFO() = 1
+** Determine which services are supported by this implementation
+** of PCNFSD.
+**
+** -- PCNFSD2_PR_INIT() = 2
+** Prepare for remote printing: identify exporting spool directory.
+**
+** -- PCNFSD2_PR_START() = 3
+** Submit a spooled print job for printing: the print data is
+** in a file created in the spool directory.
+**
+** -- PCNFSD2_PR_LIST() = 4
+** List all printers known on the server.
+**
+** -- PCNFSD2_PR_QUEUE() = 5
+** List all or part of the queued jobs for a printer.
+**
+** -- PCNFSD2_PR_STATUS() = 6
+** Determine the status of a printer.
+**
+** -- PCNFSD2_PR_CANCEL() = 7
+** Cancel a print job.
+**
+** -- PCNFSD2_PR_ADMIN() = 8
+** Perform an implementation-dependent printer administration
+** operation.
+**
+** -- PCNFSD2_PR_REQUEUE() = 9
+** Change the queue position of a previously-submitted print job.
+**
+** -- PCNFSD2_PR_HOLD() = 10
+** Place a "hold" on a previously-submitted print job. The job
+** will remain in the queue, but will not be printed.
+**
+** -- PCNFSD2_PR_RELEASE() = 11
+** Release the "hold" on a previously-held print job.
+**
+** -- PCNFSD2_MAPID() = 12
+** Perform one or more translations between user and group
+** names and IDs.
+**
+** -- PCNFSD2_AUTH() = 13
+** Perform user authentication - map username, password into uid, gid;
+** may also return secondary gids, home directory, umask.
+**
+** -- PCNFSD2_ALERT() = 14
+** Send a message to the system operator.
+*/
+program PCNFSDPROG {
+ version PCNFSDVERS {
+ void PCNFSD_NULL(void) = 0;
+ auth_results PCNFSD_AUTH(auth_args) = 1;
+ pr_init_results PCNFSD_PR_INIT(pr_init_args) = 2;
+ pr_start_results PCNFSD_PR_START(pr_start_args) = 3;
+ } = 1;
+/*
+** Version 2 of the PCNFSD protocol.
+*/
+ version PCNFSDV2 {
+ void PCNFSD2_NULL(void) = 0;
+ v2_info_results PCNFSD2_INFO(v2_info_args) = 1;
+ v2_pr_init_results PCNFSD2_PR_INIT(v2_pr_init_args) = 2;
+ v2_pr_start_results PCNFSD2_PR_START(v2_pr_start_args) = 3;
+ v2_pr_list_results PCNFSD2_PR_LIST(void) = 4;
+ v2_pr_queue_results PCNFSD2_PR_QUEUE(v2_pr_queue_args) = 5;
+ v2_pr_status_results PCNFSD2_PR_STATUS(v2_pr_status_args) = 6;
+ v2_pr_cancel_results PCNFSD2_PR_CANCEL(v2_pr_cancel_args) = 7;
+ v2_pr_admin_results PCNFSD2_PR_ADMIN(v2_pr_admin_args) = 8;
+ v2_pr_requeue_results PCNFSD2_PR_REQUEUE(v2_pr_requeue_args) = 9;
+ v2_pr_hold_results PCNFSD2_PR_HOLD(v2_pr_hold_args) = 10;
+ v2_pr_release_results PCNFSD2_PR_RELEASE(v2_pr_release_args) = 11;
+ v2_mapid_results PCNFSD2_MAPID(v2_mapid_args) = 12;
+ v2_auth_results PCNFSD2_AUTH(v2_auth_args) = 13;
+ v2_alert_results PCNFSD2_ALERT(v2_alert_args) = 14;
+ } = 2;
+
+} = 150001;
+
+/*
+** The following forces a publically-visible msg_out()
+*/
+%#if RPC_SVC
+% static void _msgout();
+% void msg_out(msg) char *msg; {_msgout(msg);}
+%#endif
+%#if RPC_HDR
+% extern void msg_out();
+%#endif
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_cache.c b/usr.sbin/rpc.pcnfsd/pcnfsd_cache.c
new file mode 100644
index 00000000000..7868f1a4267
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_cache.c
@@ -0,0 +1,104 @@
+/* $NetBSD: pcnfsd_cache.c,v 1.2 1995/07/25 22:20:37 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_cache.c 1.1 91/09/03 12:45:14 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+** @(#)pcnfsd_cache.c 1.1 9/3/91
+**=====================================================================
+*/
+#include "common.h"
+/*
+**=====================================================================
+** I N C L U D E F I L E S E C T I O N *
+** *
+** If your port requires different include files, add a suitable *
+** #define in the customization section, and make the inclusion or *
+** exclusion of the files conditional on this. *
+**=====================================================================
+*/
+#include "pcnfsd.h"
+
+#include <stdio.h>
+#include <pwd.h>
+#include <errno.h>
+#include <string.h>
+
+extern char *crypt();
+
+
+/*
+**---------------------------------------------------------------------
+** Misc. variable definitions
+**---------------------------------------------------------------------
+*/
+
+extern int errno;
+
+#ifdef USER_CACHE
+#define CACHE_SIZE 16 /* keep it small, as linear searches are
+ * done */
+struct cache
+ {
+ int cuid;
+ int cgid;
+ char cpw[32];
+ char cuname[10]; /* keep this even for machines
+ * with alignment problems */
+ }User_cache[CACHE_SIZE];
+
+
+
+/*
+**---------------------------------------------------------------------
+** User cache support procedures
+**---------------------------------------------------------------------
+*/
+
+
+int
+check_cache(name, pw, p_uid, p_gid)
+ char *name;
+ char *pw;
+ int *p_uid;
+ int *p_gid;
+{
+ int i;
+ int c1, c2;
+
+ for (i = 0; i < CACHE_SIZE; i++) {
+ if (!strcmp(User_cache[i].cuname, name)) {
+ c1 = strlen(pw);
+ c2 = strlen(User_cache[i].cpw);
+ if ((!c1 && !c2) ||
+ !(strcmp(User_cache[i].cpw,
+ crypt(pw, User_cache[i].cpw)))) {
+ *p_uid = User_cache[i].cuid;
+ *p_gid = User_cache[i].cgid;
+ return (1);
+ }
+ User_cache[i].cuname[0] = '\0'; /* nuke entry */
+ return (0);
+ }
+ }
+ return (0);
+}
+
+void
+add_cache_entry(p)
+ struct passwd *p;
+{
+ int i;
+
+ for (i = CACHE_SIZE - 1; i > 0; i--)
+ User_cache[i] = User_cache[i - 1];
+ User_cache[0].cuid = p->pw_uid;
+ User_cache[0].cgid = p->pw_gid;
+ (void)strcpy(User_cache[0].cpw, p->pw_passwd);
+ (void)strcpy(User_cache[0].cuname, p->pw_name);
+}
+
+
+#endif /* USER_CACHE */
+
+
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c b/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c
new file mode 100644
index 00000000000..f6e316a9aa3
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c
@@ -0,0 +1,605 @@
+/* $NetBSD: pcnfsd_misc.c,v 1.2 1995/07/25 22:20:42 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+** @(#)pcnfsd_misc.c 1.5 1/24/92
+**=====================================================================
+*/
+#include "common.h"
+/*
+**=====================================================================
+** I N C L U D E F I L E S E C T I O N *
+** *
+** If your port requires different include files, add a suitable *
+** #define in the customization section, and make the inclusion or *
+** exclusion of the files conditional on this. *
+**=====================================================================
+*/
+#include "pcnfsd.h"
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef ISC_2_0
+#include <sys/fcntl.h>
+#endif
+
+#ifdef SHADOW_SUPPORT
+#include <shadow.h>
+#endif
+
+#ifdef WTMP
+int wtmp_enabled = 1;
+#endif
+
+#ifdef USE_GETUSERSHELL
+extern char *getusershell();
+#endif
+
+/*
+**---------------------------------------------------------------------
+** Other #define's
+**---------------------------------------------------------------------
+*/
+
+#define zchar 0x5b
+
+char tempstr[256];
+extern char sp_name[1024]; /* in pcnfsd_print.c */
+
+/*
+**=====================================================================
+** C O D E S E C T I O N * **=====================================================================
+*/
+/*
+**---------------------------------------------------------------------
+** Support procedures
+**---------------------------------------------------------------------
+*/
+
+
+void
+scramble(s1, s2)
+char *s1;
+char *s2;
+{
+ while (*s1)
+ {
+ *s2++ = (*s1 ^ zchar) & 0x7f;
+ s1++;
+ }
+ *s2 = 0;
+}
+
+
+
+struct passwd *
+get_password(usrnam)
+char *usrnam;
+{
+struct passwd *p;
+static struct passwd localp;
+char *pswd;
+char *ushell;
+int ok = 0;
+
+
+#ifdef SHADOW_SUPPORT
+struct spwd *sp;
+int shadowfile;
+#endif
+
+#ifdef SHADOW_SUPPORT
+ /*
+ **--------------------------------------------------------------
+ ** Check the existence of SHADOW. If it is there, then we are
+ ** running a two-password-file system.
+ **--------------------------------------------------------------
+ */
+ if (access(SHADOW, 0))
+ shadowfile = 0; /* SHADOW is not there */
+ else
+ shadowfile = 1;
+
+ setpwent();
+ if (shadowfile)
+ (void) setspent(); /* Setting the shadow password
+ * file */
+ if ((p = getpwnam(usrnam)) == (struct passwd *)NULL ||
+ (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *)NULL))
+ return ((struct passwd *)NULL);
+
+ if (shadowfile)
+ {
+ pswd = sp->sp_pwdp;
+ (void) endspent();
+ }
+ else
+ pswd = p->pw_passwd;
+
+#else
+ p = getpwnam(usrnam);
+ if (p == (struct passwd *)NULL)
+ return ((struct passwd *)NULL);
+ pswd = p->pw_passwd;
+#endif
+
+#ifdef ISC_2_0
+ /*
+ **-----------------------------------------------------------
+ ** We may have an 'x' in which case look in /etc/shadow ..
+ **-----------------------------------------------------------
+ */
+ if (((strlen(pswd)) == 1) && pswd[0] == 'x')
+ {
+ struct spwd *shadow = getspnam(usrnam);
+
+ if (!shadow)
+ return ((struct passwd *)NULL);
+ pswd = shadow->sp_pwdp;
+ }
+#endif
+ localp = *p;
+ localp.pw_passwd = pswd;
+#ifdef USE_GETUSERSHELL
+
+ setusershell();
+ while(ushell = getusershell()){
+ if(!strcmp(ushell, localp.pw_shell)) {
+ ok = 1;
+ break;
+ }
+ }
+ endusershell();
+ if(!ok)
+ return ((struct passwd *)NULL);
+#else
+/*
+ * the best we can do is to ensure that the shell ends in "sh"
+ */
+ ushell = localp.pw_shell;
+ if(strlen(ushell) < 2)
+ return ((struct passwd *)NULL);
+ ushell += strlen(ushell) - 2;
+ if(strcmp(ushell, "sh"))
+ return ((struct passwd *)NULL);
+
+#endif
+ return (&localp);
+}
+
+
+/*
+**---------------------------------------------------------------------
+** Print support procedures
+**---------------------------------------------------------------------
+*/
+
+char *
+mapfont(f, i, b)
+ char f;
+ char i;
+ char b;
+{
+ static char fontname[64];
+
+ fontname[0] = 0; /* clear it out */
+
+ switch (f) {
+ case 'c':
+ (void)strcpy(fontname, "Courier");
+ break;
+ case 'h':
+ (void)strcpy(fontname, "Helvetica");
+ break;
+ case 't':
+ (void)strcpy(fontname, "Times");
+ break;
+ default:
+ (void)strcpy(fontname, "Times-Roman");
+ goto finis ;
+ }
+ if (i != 'o' && b != 'b') { /* no bold or oblique */
+ if (f == 't') /* special case Times */
+ (void)strcat(fontname, "-Roman");
+ goto finis;
+ }
+ (void)strcat(fontname, "-");
+ if (b == 'b')
+ (void)strcat(fontname, "Bold");
+ if (i == 'o') /* o-blique */
+ (void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
+
+finis: return (&fontname[0]);
+}
+
+/*
+ * run_ps630 performs the Diablo 630 emulation filtering process. ps630
+ * was broken in certain Sun releases: it would not accept point size or
+ * font changes. If your version is fixed, undefine the symbol
+ * PS630_IS_BROKEN and rebuild pc-nfsd.
+ */
+/* #define PS630_IS_BROKEN 1 */
+
+void
+run_ps630(f, opts)
+ char *f;
+ char *opts;
+{
+ char temp_file[256];
+ char commbuf[256];
+ int i;
+
+ (void)strcpy(temp_file, f);
+ (void)strcat(temp_file, "X"); /* intermediate file name */
+
+#ifndef PS630_IS_BROKEN
+ (void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
+ opts[2], opts[3], temp_file);
+ (void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
+ (void)strcat(commbuf, " -F ");
+ (void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
+ (void)strcat(commbuf, " ");
+ (void)strcat(commbuf, f);
+#else /* PS630_IS_BROKEN */
+ /*
+ * The pitch and font features of ps630 appear to be broken at
+ * this time.
+ */
+ (void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
+#endif /* PS630_IS_BROKEN */
+
+
+ if (i = system(commbuf)) {
+ /*
+ * Under (un)certain conditions, ps630 may return -1 even
+ * if it worked. Hence the commenting out of this error
+ * report.
+ */
+ /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
+ /* exit(1); */
+ }
+ if (rename(temp_file, f)) {
+ perror("run_ps630: rename");
+ exit(1);
+ }
+ return;
+}
+
+
+
+
+/*
+**---------------------------------------------------------------------
+** WTMP update support
+**---------------------------------------------------------------------
+*/
+
+
+#ifdef WTMP
+
+#include <utmp.h>
+
+#ifndef _PATH_WTMP
+#define _PATH_WTMP "/usr/adm/wtmp"
+#endif
+
+void
+wlogin(name, req)
+ char *name;
+ struct svc_req *req;
+{
+ extern char *inet_ntoa();
+ struct sockaddr_in *who;
+ struct hostent *hp;
+ char *host;
+ struct utmp ut;
+ int fd;
+
+ if(!wtmp_enabled)
+ return;
+
+ /* Get network address of client. */
+ who = &req->rq_xprt->xp_raddr;
+
+ /* Get name of connected client */
+ hp = gethostbyaddr((char *)&who->sin_addr,
+ sizeof (struct in_addr),
+ who->sin_family);
+
+ if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
+ host = hp->h_name;
+ } else {
+ host = inet_ntoa(who->sin_addr);
+ }
+
+ (void) strcpy(ut.ut_line, "PC-NFS");
+ (void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
+ (void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
+ ut.ut_time = time( (time_t *) 0);
+
+ if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
+ (void)write(fd, (char *)&ut, sizeof(struct utmp));
+ (void)close(fd);
+ }
+}
+#endif WTMP
+
+/*
+**---------------------------------------------------------------------
+** Run-process-as-user procedures
+**---------------------------------------------------------------------
+*/
+
+
+#define READER_FD 0
+#define WRITER_FD 1
+
+static int child_pid;
+
+static char cached_user[64] = "";
+static uid_t cached_uid;
+static gid_t cached_gid;
+
+static struct sigaction old_action;
+static struct sigaction new_action;
+static struct itimerval timer;
+
+int interrupted = 0;
+static FILE *pipe_handle;
+
+static void myhandler()
+{
+ interrupted = 1;
+ fclose(pipe_handle);
+ kill(child_pid, SIGKILL);
+ msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
+}
+
+void start_watchdog(n)
+int n;
+{
+ /*
+ * Setup SIGALRM handler, force interrupt of ongoing syscall
+ */
+
+ new_action.sa_handler = myhandler;
+ sigemptyset(&(new_action.sa_mask));
+ new_action.sa_flags = 0;
+#ifdef SA_INTERRUPT
+ new_action.sa_flags |= SA_INTERRUPT;
+#endif
+ sigaction(SIGALRM, &new_action, &old_action);
+
+ /*
+ * Set interval timer for n seconds
+ */
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 0;
+ timer.it_value.tv_sec = n;
+ timer.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &timer, NULL);
+ interrupted = 0;
+
+}
+
+void stop_watchdog()
+{
+ /*
+ * Cancel timer
+ */
+
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 0;
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &timer, NULL);
+
+ /*
+ * restore old signal handling
+ */
+ sigaction(SIGALRM, &old_action, NULL);
+}
+
+
+
+FILE *
+su_popen(user, cmd, maxtime)
+ char *user;
+ char *cmd;
+ int maxtime;
+{
+ int p[2];
+ int parent_fd, child_fd, pid;
+ struct passwd *pw;
+
+ if (strcmp(cached_user, user)) {
+ pw = getpwnam(user);
+ if (!pw)
+ pw = getpwnam("nobody");
+ if (pw) {
+ cached_uid = pw->pw_uid;
+ cached_gid = pw->pw_gid;
+ strcpy(cached_user, user);
+ } else {
+ cached_uid = (uid_t) (-2);
+ cached_gid = (gid_t) (-2);
+ cached_user[0] = '\0';
+ }
+ }
+ if (pipe(p) < 0) {
+ msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
+ return (NULL);
+ }
+ parent_fd = p[READER_FD];
+ child_fd = p[WRITER_FD];
+ if ((pid = fork()) == 0) {
+ int i;
+
+ for (i = 0; i < 10; i++)
+ if (i != child_fd)
+ (void) close(i);
+ if (child_fd != 1) {
+ (void) dup2(child_fd, 1);
+ (void) close(child_fd);
+ }
+ dup2(1, 2); /* let's get stderr as well */
+
+ (void) setgid(cached_gid);
+ (void) setuid(cached_uid);
+
+ (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
+ _exit(255);
+ }
+ if (pid == -1) {
+ msg_out("rpc.pcnfsd: fork failed");
+ close(parent_fd);
+ close(child_fd);
+ return (NULL);
+ }
+ child_pid = pid;
+ close(child_fd);
+ start_watchdog(maxtime);
+ pipe_handle = fdopen(parent_fd, "r");
+ return (pipe_handle);
+}
+
+int
+su_pclose(ptr)
+ FILE *ptr;
+{
+ int pid, status;
+
+ stop_watchdog();
+
+ fclose(ptr);
+ if (child_pid == -1)
+ return (-1);
+ while ((pid = wait(&status)) != child_pid && pid != -1);
+ return (pid == -1 ? -1 : status);
+}
+
+
+/*
+** The following routine reads a file "/etc/pcnfsd.conf" if present,
+** and uses it to replace certain builtin elements, like the
+** name of the print spool directory. The configuration file
+** Is the usual kind: Comments begin with '#', blank lines are ignored,
+** and valid lines are of the form
+**
+** <keyword><whitespace><value>
+**
+** The following keywords are recognized:
+**
+** spooldir
+** printer name alias-for command
+** wtmp yes|no
+*/
+void
+config_from_file()
+{
+FILE *fd;
+char buff[1024];
+char *cp;
+char *kw;
+char *val;
+char *arg1;
+char *arg2;
+
+ if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
+ return;
+ while(fgets(buff, 1024, fd)) {
+ cp = strchr(buff, '\n');
+ *cp = '\0';
+ cp = strchr(buff, '#');
+ if(cp)
+ *cp = '\0';
+ kw = strtok(buff, " \t");
+ if(kw == NULL)
+ continue;
+ val = strtok(NULL, " \t");
+ if(val == NULL)
+ continue;
+ if(!mystrcasecmp(kw, "spooldir")) {
+ strcpy(sp_name, val);
+ continue;
+ }
+#ifdef WTMP
+ if(!mystrcasecmp(kw, "wtmp")) {
+ /* assume default is YES, just look for negatives */
+ if(!mystrcasecmp(val, "no") ||
+ !mystrcasecmp(val, "off") ||
+ !mystrcasecmp(val, "disable") ||
+ !strcmp(val, "0"))
+ wtmp_enabled = 0;;
+ continue;
+ }
+#endif
+ if(!mystrcasecmp(kw, "printer")) {
+ arg1 = strtok(NULL, " \t");
+ arg2 = strtok(NULL, "");
+ (void)add_printer_alias(val, arg1, arg2);
+ continue;
+ }
+/*
+** Add new cases here
+*/
+ }
+ fclose(fd);
+}
+
+
+/*
+** The following are replacements for the SunOS library
+** routines strcasecmp and strncasecmp, which SVR4 doesn't
+** include.
+*/
+
+mystrcasecmp(s1, s2)
+ char *s1, *s2;
+{
+
+ while (toupper(*s1) == toupper(*s2++))
+ if (*s1++ == '\0')
+ return(0);
+ return(toupper(*s1) - toupper(*--s2));
+}
+
+mystrncasecmp(s1, s2, n)
+ char *s1, *s2;
+ int n;
+{
+
+ while (--n >= 0 && toupper(*s1) == toupper(*s2++))
+ if (*s1++ == '\0')
+ return(0);
+ return(n < 0 ? 0 : toupper(*s1) - toupper(*--s2));
+}
+
+
+/*
+** strembedded - returns true if s1 is embedded (in any case) in s2
+*/
+
+int strembedded(s1, s2)
+char *s1;
+char *s2;
+{
+ while(*s2) {
+ if(!mystrcasecmp(s1, s2))
+ return 1;
+ s2++;
+ }
+ return 0;
+}
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_print.c b/usr.sbin/rpc.pcnfsd/pcnfsd_print.c
new file mode 100644
index 00000000000..7aa4cb5acb7
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_print.c
@@ -0,0 +1,1343 @@
+/* $NetBSD: pcnfsd_print.c,v 1.3 1995/08/14 19:45:18 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+** @(#)pcnfsd_print.c 1.7 1/24/92
+**=====================================================================
+*/
+#include "common.h"
+/*
+**=====================================================================
+** I N C L U D E F I L E S E C T I O N *
+** *
+** If your port requires different include files, add a suitable *
+** #define in the customization section, and make the inclusion or *
+** exclusion of the files conditional on this. *
+**=====================================================================
+*/
+#include "pcnfsd.h"
+#include <malloc.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+
+#ifndef SYSV
+#include <sys/wait.h>
+#endif
+
+#ifdef ISC_2_0
+#include <sys/fcntl.h>
+#endif
+
+#ifdef SHADOW_SUPPORT
+#include <shadow.h>
+#endif
+
+#include "paths.h"
+
+/*
+**---------------------------------------------------------------------
+** Other #define's
+**---------------------------------------------------------------------
+*/
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+/*
+** The following defintions give the maximum time allowed for
+** an external command to run (in seconds)
+*/
+#define MAXTIME_FOR_PRINT 10
+#define MAXTIME_FOR_QUEUE 10
+#define MAXTIME_FOR_CANCEL 10
+#define MAXTIME_FOR_STATUS 10
+
+#define QMAX 50
+
+/*
+** The following is derived from ucb/lpd/displayq.c
+*/
+#define SIZECOL 62
+#define FILECOL 24
+
+extern void scramble();
+extern void run_ps630();
+extern char *crypt();
+extern FILE *su_popen();
+extern int su_pclose();
+int build_pr_list();
+char *map_printer_name();
+char *expand_alias();
+void *grab();
+void free_pr_list_item();
+void free_pr_queue_item();
+pr_list list_virtual_printers();
+
+/*
+**---------------------------------------------------------------------
+** Misc. variable definitions
+**---------------------------------------------------------------------
+*/
+
+extern int errno;
+extern int interrupted; /* in pcnfsd_misc.c */
+struct stat statbuf;
+char pathname[MAXPATHLEN];
+char new_pathname[MAXPATHLEN];
+char sp_name[MAXPATHLEN] = SPOOLDIR;
+char tempstr[256];
+char delims[] = " \t\r\n:()";
+
+pr_list printers = NULL;
+pr_queue queue = NULL;
+
+/*
+**=====================================================================
+** C O D E S E C T I O N *
+**=====================================================================
+*/
+
+/*
+ * This is the latest word on the security check. The following
+ * routine "suspicious()" returns non-zero if the character string
+ * passed to it contains any shell metacharacters.
+ * Callers will typically code
+ *
+ * if(suspicious(some_parameter)) reject();
+ */
+
+int suspicious (s)
+char *s;
+{
+ if(strpbrk(pathname, ";|&<>`'#!?*()[]^") != NULL)
+ return 1;
+ return 0;
+}
+
+
+int
+valid_pr(pr)
+char *pr;
+{
+char *p;
+pr_list curr;
+ if(printers == NULL)
+ build_pr_list();
+
+ if(printers == NULL)
+ return(1); /* can't tell - assume it's good */
+
+ p = map_printer_name(pr);
+ if (p == NULL)
+ return(1); /* must be ok is maps to NULL! */
+ curr = printers;
+ while(curr) {
+ if(!strcmp(p, curr->pn))
+ return(1);
+ curr = curr->pr_next;
+ }
+
+ return(0);
+}
+
+pirstat pr_init(sys, pr, sp)
+char *sys;
+char *pr;
+char**sp;
+{
+int dir_mode = 0777;
+int rc;
+
+ *sp = &pathname[0];
+ pathname[0] = '\0';
+
+ if(suspicious(sys) || suspicious(pr))
+ return(PI_RES_FAIL);
+
+ /* get pathname of current directory and return to client */
+
+ (void)sprintf(pathname,"%s/%s",sp_name, sys);
+ (void)mkdir(sp_name, dir_mode); /* ignore the return code */
+ (void)chmod(sp_name, dir_mode);
+ rc = mkdir(pathname, dir_mode); /* DON'T ignore this return code */
+ if((rc < 0 && errno != EEXIST) ||
+ (chmod(pathname, dir_mode) != 0) ||
+ (stat(pathname, &statbuf) != 0) ||
+ !(statbuf.st_mode & S_IFDIR)) {
+ (void)sprintf(tempstr,
+ "rpc.pcnfsd: unable to set up spool directory %s\n",
+ pathname);
+ msg_out(tempstr);
+ pathname[0] = '\0'; /* null to tell client bad vibes */
+ return(PI_RES_FAIL);
+ }
+ if (!valid_pr(pr))
+ {
+ pathname[0] = '\0'; /* null to tell client bad vibes */
+ return(PI_RES_NO_SUCH_PRINTER);
+ }
+ return(PI_RES_OK);
+
+}
+
+
+psrstat pr_start2(system, pr, user, fname, opts, id)
+char *system;
+char *pr;
+char *user;
+char *fname;
+char *opts;
+char **id;
+{
+char snum[20];
+static char req_id[256];
+char cmdbuf[256];
+char resbuf[256];
+FILE *fd;
+int i;
+char *xcmd;
+char *cp;
+int failed = 0;
+
+#ifdef HACK_FOR_ROTATED_TRANSCRIPT
+char scratch[512];
+#endif
+
+
+ if(suspicious(system) ||
+ suspicious(pr) ||
+ suspicious(user) ||
+ suspicious(fname))
+ return(PS_RES_FAIL);
+
+ (void)sprintf(pathname,"%s/%s/%s",sp_name,
+ system,
+ fname);
+
+ *id = &req_id[0];
+ req_id[0] = '\0';
+
+ if (stat(pathname, &statbuf))
+ {
+ /*
+ **-----------------------------------------------------------------
+ ** We can't stat the file. Let's try appending '.spl' and
+ ** see if it's already in progress.
+ **-----------------------------------------------------------------
+ */
+
+ (void)strcat(pathname, ".spl");
+ if (stat(pathname, &statbuf))
+ {
+ /*
+ **----------------------------------------------------------------
+ ** It really doesn't exist.
+ **----------------------------------------------------------------
+ */
+
+
+ return(PS_RES_NO_FILE);
+ }
+ /*
+ **-------------------------------------------------------------
+ ** It is already on the way.
+ **-------------------------------------------------------------
+ */
+
+
+ return(PS_RES_ALREADY);
+ }
+
+ if (statbuf.st_size == 0)
+ {
+ /*
+ **-------------------------------------------------------------
+ ** Null file - don't print it, just kill it.
+ **-------------------------------------------------------------
+ */
+ (void)unlink(pathname);
+
+ return(PS_RES_NULL);
+ }
+ /*
+ **-------------------------------------------------------------
+ ** The file is real, has some data, and is not already going out.
+ ** We rename it by appending '.spl' and exec "lpr" to do the
+ ** actual work.
+ **-------------------------------------------------------------
+ */
+ (void)strcpy(new_pathname, pathname);
+ (void)strcat(new_pathname, ".spl");
+
+ /*
+ **-------------------------------------------------------------
+ ** See if the new filename exists so as not to overwrite it.
+ **-------------------------------------------------------------
+ */
+
+
+ if (!stat(new_pathname, &statbuf))
+ {
+ (void)strcpy(new_pathname, pathname); /* rebuild a new name */
+ (void)sprintf(snum, "%d", rand()); /* get some number */
+ (void)strncat(new_pathname, snum, 3);
+ (void)strcat(new_pathname, ".spl"); /* new spool file */
+ }
+ if (rename(pathname, new_pathname))
+ {
+ /*
+ **---------------------------------------------------------------
+ ** Should never happen.
+ **---------------------------------------------------------------
+ */
+ (void)sprintf(tempstr, "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
+ pathname, new_pathname);
+ msg_out(tempstr);
+ return(PS_RES_FAIL);
+ }
+
+ if (*opts == 'd')
+ {
+ /*
+ **------------------------------------------------------
+ ** This is a Diablo print stream. Apply the ps630
+ ** filter with the appropriate arguments.
+ **------------------------------------------------------
+ */
+ (void)run_ps630(new_pathname, opts);
+ }
+ /*
+ ** Try to match to an aliased printer
+ */
+ xcmd = expand_alias(pr, new_pathname, user, system);
+ if(!xcmd) {
+#ifdef SVR4
+ /*
+ * Use the copy option so we can remove the orignal
+ * spooled nfs file from the spool directory.
+ */
+ sprintf(cmdbuf, "/usr/bin/lp -c -d%s %s",
+ pr, new_pathname);
+#else /* SVR4 */
+ /* BSD way: lpr */
+ sprintf(cmdbuf, "%s/lpr -P%s %s",
+ LPRDIR, pr, new_pathname);
+#endif /* SVR4 */
+ xcmd = cmdbuf;
+ }
+ if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
+ msg_out("rpc.pcnfsd: su_popen failed");
+ return(PS_RES_FAIL);
+ }
+ req_id[0] = '\0'; /* asume failure */
+ while(fgets(resbuf, 255, fd) != NULL) {
+ i = strlen(resbuf);
+ if(i)
+ resbuf[i-1] = '\0'; /* trim NL */
+ if(!strncmp(resbuf, "request id is ", 14))
+ /* New - just the first word is needed */
+ strcpy(req_id, strtok(&resbuf[14], delims));
+ else if (strembedded("disabled", resbuf))
+ failed = 1;
+ }
+ if(su_pclose(fd) == 255)
+ msg_out("rpc.pcnfsd: su_pclose alert");
+ (void)unlink(new_pathname);
+ return((failed | interrupted)? PS_RES_FAIL : PS_RES_OK);
+}
+
+
+/*
+ * build_pr_list: determine which printers are valid.
+ * on SVR4 use "lpstat -v"
+ * on BSD use "lpc status"
+ */
+
+#ifdef SVR4
+/*
+ * In SVR4 the command to determine which printers are
+ * valid is lpstat -v. The output is something like this:
+ *
+ * device for lp: /dev/lp0
+ * system for pcdslw: hinode
+ * system for bletch: hinode (as printer hisname)
+ *
+ * On SunOS using the SysV compatibility package, the output
+ * is more like:
+ *
+ * device for lp is /dev/lp0
+ * device for pcdslw is the remote printer pcdslw on hinode
+ * device for bletch is the remote printer hisname on hinode
+ *
+ * It is fairly simple to create logic that will handle either
+ * possibility:
+ */
+int
+build_pr_list()
+{
+ pr_list last = NULL;
+ pr_list curr = NULL;
+ char buff[256];
+ FILE *p;
+ char *cp;
+ int saw_system;
+
+ p = popen("lpstat -v", "r");
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen() lp status");
+ return(0);
+ }
+
+ while(fgets(buff, 255, p) != NULL) {
+ cp = strtok(buff, delims);
+ if(!cp)
+ continue;
+ if(!strcmp(cp, "device"))
+ saw_system = 0;
+ else if (!strcmp(cp, "system"))
+ saw_system = 1;
+ else
+ continue;
+ cp = strtok(NULL, delims);
+ if(!cp || strcmp(cp, "for"))
+ continue;
+ cp = strtok(NULL, delims);
+ if(!cp)
+ continue;
+ curr = (struct pr_list_item *)
+ grab(sizeof (struct pr_list_item));
+
+ curr->pn = strdup(cp);
+ curr->device = NULL;
+ curr->remhost = NULL;
+ curr->cm = strdup("-");
+ curr->pr_next = NULL;
+
+ cp = strtok(NULL, delims);
+
+ if(cp && !strcmp(cp, "is"))
+ cp = strtok(NULL, delims);
+
+ if(!cp) {
+ free_pr_list_item(curr);
+ continue;
+ }
+
+ if(saw_system) {
+ /* "system" OR "system (as printer pname)" */
+ curr->remhost = strdup(cp);
+ cp = strtok(NULL, delims);
+ if(!cp) {
+ /* simple format */
+ curr->device = strdup(curr->pn);
+ } else {
+ /* "sys (as printer pname)" */
+ if (strcmp(cp, "as")) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ cp = strtok(NULL, delims);
+ if (!cp || strcmp(cp, "printer")) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ cp = strtok(NULL, delims);
+ if(!cp) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ curr->device = strdup(cp);
+ }
+ }
+ else if(!strcmp(cp, "the")) {
+ /* start of "the remote printer foo on bar" */
+ cp = strtok(NULL, delims);
+ if(!cp || strcmp(cp, "remote")) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ cp = strtok(NULL, delims);
+ if(!cp || strcmp(cp, "printer")) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ cp = strtok(NULL, delims);
+ if(!cp) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ curr->device = strdup(cp);
+ cp = strtok(NULL, delims);
+ if(!cp || strcmp(cp, "on")) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ cp = strtok(NULL, delims);
+ if(!cp) {
+ free_pr_list_item(curr);
+ continue;
+ }
+ curr->remhost = strdup(cp);
+ } else {
+ /* the local name */
+ curr->device = strdup(cp);
+ curr->remhost = strdup("");
+ }
+
+ if(last == NULL)
+ printers = curr;
+ else
+ last->pr_next = curr;
+ last = curr;
+
+ }
+ (void) pclose(p);
+
+ /*
+ ** Now add on the virtual printers, if any
+ */
+ if(last == NULL)
+ printers = list_virtual_printers();
+ else
+ last->pr_next = list_virtual_printers();
+
+ return(1);
+}
+
+#else /* SVR4 */
+
+/*
+ * BSD way: lpc stat
+ */
+int
+build_pr_list()
+{
+ pr_list last = NULL;
+ pr_list curr = NULL;
+ char buff[256];
+ FILE *p;
+ char *cp;
+ int saw_system;
+
+ sprintf(buff, "%s/lpc status", LPCDIR);
+ p = popen(buff, "r");
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen lpc stat");
+ return(0);
+ }
+
+ while(fgets(buff, 255, p) != NULL) {
+ if (isspace(buff[0]))
+ continue;
+
+ if ((cp = strtok(buff, delims)) == NULL)
+ continue;
+
+ curr = (struct pr_list_item *)
+ grab(sizeof (struct pr_list_item));
+
+ /* XXX - Should distinguish remote printers. */
+ curr->pn = strdup(cp);
+ curr->device = strdup(cp);
+ curr->remhost = strdup("");
+ curr->cm = strdup("-");
+ curr->pr_next = NULL;
+
+ if(last == NULL)
+ printers = curr;
+ else
+ last->pr_next = curr;
+ last = curr;
+
+ }
+ (void) fclose(p);
+
+ /*
+ ** Now add on the virtual printers, if any
+ */
+ if(last == NULL)
+ printers = list_virtual_printers();
+ else
+ last->pr_next = list_virtual_printers();
+
+ return(1);
+}
+
+#endif /* SVR4 */
+
+void *grab(n)
+int n;
+{
+ void *p;
+
+ p = (void *)malloc(n);
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: malloc failure");
+ exit(1);
+ }
+ return(p);
+}
+
+void
+free_pr_list_item(curr)
+pr_list curr;
+{
+ if(curr->pn)
+ free(curr->pn);
+ if(curr->device)
+ free(curr->device);
+ if(curr->remhost)
+ free(curr->remhost);
+ if(curr->cm)
+ free(curr->cm);
+ if(curr->pr_next)
+ free_pr_list_item(curr->pr_next); /* recurse */
+ free(curr);
+}
+
+/*
+ * build_pr_queue: used to show the print queue.
+ *
+ * Note that the first thing we do is to discard any
+ * existing queue.
+ */
+#ifdef SVR4
+
+/*
+** In SVR4 the command to list the print jobs for printer
+** lp is "lpstat lp" (or, equivalently, "lpstat -p lp").
+** The output looks like this:
+**
+** lp-2 root 939 Jul 10 21:56
+** lp-5 geoff 15 Jul 12 23:23
+** lp-6 geoff 15 Jul 12 23:23
+**
+** If the first job is actually printing the first line
+** is modified, as follows:
+**
+** lp-2 root 939 Jul 10 21:56 on lp
+**
+** I don't yet have any info on what it looks like if the printer
+** is remote and we're spooling over the net. However for
+** the purposes of rpc.pcnfsd we can simply say that field 1 is the
+** job ID, field 2 is the submitter, and field 3 is the size.
+** We can check for the presence of the string " on " in the
+** first record to determine if we should count it as rank 0 or rank 1,
+** but it won't hurt if we get it wrong.
+**/
+
+pirstat
+build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
+printername pn;
+username user;
+int just_mine;
+int *p_qlen;
+int *p_qshown;
+{
+pr_queue last = NULL;
+pr_queue curr = NULL;
+char buff[256];
+FILE *p;
+char *owner;
+char *job;
+char *totsize;
+
+ if(queue) {
+ free_pr_queue_item(queue);
+ queue = NULL;
+ }
+ *p_qlen = 0;
+ *p_qshown = 0;
+
+ pn = map_printer_name(pn);
+ if(pn == NULL || !valid_pr(pn) || suspicious(pn))
+ return(PI_RES_NO_SUCH_PRINTER);
+
+ sprintf(buff, "/usr/bin/lpstat %s", pn);
+ p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen() lpstat queue query");
+ return(PI_RES_FAIL);
+ }
+
+ while(fgets(buff, 255, p) != NULL) {
+ job = strtok(buff, delims);
+ if(!job)
+ continue;
+
+ owner = strtok(NULL, delims);
+ if(!owner)
+ continue;
+
+ totsize = strtok(NULL, delims);
+ if(!totsize)
+ continue;
+
+ *p_qlen += 1;
+
+ if(*p_qshown > QMAX)
+ continue;
+
+ if(just_mine && mystrcasecmp(owner, user))
+ continue;
+
+ *p_qshown += 1;
+
+ curr = (struct pr_queue_item *)
+ grab(sizeof (struct pr_queue_item));
+
+ curr->position = *p_qlen;
+ curr->id = strdup(job);
+ curr->size = strdup(totsize);
+ curr->status = strdup("");
+ curr->system = strdup("");
+ curr->user = strdup(owner);
+ curr->file = strdup("");
+ curr->cm = strdup("-");
+ curr->pr_next = NULL;
+
+ if(last == NULL)
+ queue = curr;
+ else
+ last->pr_next = curr;
+ last = curr;
+
+ }
+ (void) su_pclose(p);
+ return(PI_RES_OK);
+}
+
+#else /* SVR4 */
+
+pirstat
+build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
+printername pn;
+username user;
+int just_mine;
+int *p_qlen;
+int *p_qshown;
+{
+pr_queue last = NULL;
+pr_queue curr = NULL;
+char buff[256];
+FILE *p;
+char *cp;
+int i;
+char *rank;
+char *owner;
+char *job;
+char *files;
+char *totsize;
+
+ if(queue) {
+ free_pr_queue_item(queue);
+ queue = NULL;
+ }
+ *p_qlen = 0;
+ *p_qshown = 0;
+ pn = map_printer_name(pn);
+ if(pn == NULL || suspicious(pn))
+ return(PI_RES_NO_SUCH_PRINTER);
+
+ sprintf(buff, "%s/lpq -P%s", LPRDIR, pn);
+
+ p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen() lpq");
+ return(PI_RES_FAIL);
+ }
+
+ while(fgets(buff, 255, p) != NULL) {
+ i = strlen(buff) - 1;
+ buff[i] = '\0'; /* zap trailing NL */
+ if(i < SIZECOL)
+ continue;
+ if(!mystrncasecmp(buff, "rank", 4))
+ continue;
+
+ totsize = &buff[SIZECOL-1];
+ files = &buff[FILECOL-1];
+ cp = totsize;
+ cp--;
+ while(cp > files && isspace(*cp))
+ *cp-- = '\0';
+
+ buff[FILECOL-2] = '\0';
+
+ cp = strtok(buff, delims);
+ if(!cp)
+ continue;
+ rank = cp;
+
+ cp = strtok(NULL, delims);
+ if(!cp)
+ continue;
+ owner = cp;
+
+ cp = strtok(NULL, delims);
+ if(!cp)
+ continue;
+ job = cp;
+
+ *p_qlen += 1;
+
+ if(*p_qshown > QMAX)
+ continue;
+
+ if(just_mine && mystrcasecmp(owner, user))
+ continue;
+
+ *p_qshown += 1;
+
+ curr = (struct pr_queue_item *)
+ grab(sizeof (struct pr_queue_item));
+
+ curr->position = atoi(rank); /* active -> 0 */
+ curr->id = strdup(job);
+ curr->size = strdup(totsize);
+ curr->status = strdup(rank);
+ curr->system = strdup("");
+ curr->user = strdup(owner);
+ curr->file = strdup(files);
+ curr->cm = strdup("-");
+ curr->pr_next = NULL;
+
+ if(last == NULL)
+ queue = curr;
+ else
+ last->pr_next = curr;
+ last = curr;
+
+ }
+ (void) su_pclose(p);
+ return(PI_RES_OK);
+}
+
+#endif /* SVR4 */
+
+void
+free_pr_queue_item(curr)
+pr_queue curr;
+{
+ if(curr->id)
+ free(curr->id);
+ if(curr->size)
+ free(curr->size);
+ if(curr->status)
+ free(curr->status);
+ if(curr->system)
+ free(curr->system);
+ if(curr->user)
+ free(curr->user);
+ if(curr->file)
+ free(curr->file);
+ if(curr->cm)
+ free(curr->cm);
+ if(curr->pr_next)
+ free_pr_queue_item(curr->pr_next); /* recurse */
+ free(curr);
+}
+
+#ifdef SVR4
+
+/*
+** New - SVR4 printer status handling.
+**
+** The command we'll use for checking the status of printer "lp"
+** is "lpstat -a lp -p lp". Here are some sample outputs:
+**
+**
+** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
+** printer lp disabled since Thu Feb 21 22:52:36 EST 1991. available.
+** new printer
+** ---
+** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
+** unknown reason
+** printer pcdslw disabled since Fri Jul 12 22:15:37 EDT 1991. available.
+** new printer
+** ---
+** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
+** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
+** ---
+** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
+** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
+** ---
+** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
+** printer lp disabled since Sat Jul 13 12:05:20 EDT 1991. available.
+** unknown reason
+** ---
+** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
+** unknown reason
+** printer pcdslw is idle. enabled since Sat Jul 13 12:05:28 EDT 1991. available.
+**
+** Note that these are actual outputs. The format (which is totally
+** different from the lpstat in SunOS) seems to break down as
+** follows:
+** (1) The first line has the form "printername [not] accepting requests,,,"
+** This is trivial to decode.
+** (2) The second line has several forms, all beginning "printer printername":
+** (2.1) "... disabled"
+** (2.2) "... is idle"
+** (2.3) "... now printing jobid"
+** The "available" comment seems to be meaningless. The next line
+** is the "reason" code which the operator can supply when issuing
+** a "disable" or "reject" command.
+** Note that there is no way to check the number of entries in the
+** queue except to ask for the queue and count them.
+*/
+
+pirstat
+get_pr_status(pn, avail, printing, qlen, needs_operator, status)
+printername pn;
+bool_t *avail;
+bool_t *printing;
+int *qlen;
+bool_t *needs_operator;
+char *status;
+{
+char buff[256];
+char cmd[64];
+FILE *p;
+int n;
+pirstat stat = PI_RES_NO_SUCH_PRINTER;
+
+ /* assume the worst */
+ *avail = FALSE;
+ *printing = FALSE;
+ *needs_operator = FALSE;
+ *qlen = 0;
+ *status = '\0';
+
+ pn = map_printer_name(pn);
+ if(pn == NULL || !valid_pr(pn) || suspicious(pn))
+ return(PI_RES_NO_SUCH_PRINTER);
+ n = strlen(pn);
+
+ sprintf(cmd, "/usr/bin/lpstat -a %s -p %s", pn, pn);
+
+ p = popen(cmd, "r");
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen() lp status");
+ return(PI_RES_FAIL);
+ }
+
+ stat = PI_RES_OK;
+
+ while(fgets(buff, 255, p) != NULL) {
+ if(!strncmp(buff, pn, n)) {
+ if(!strstr(buff, "not accepting"))
+ *avail = TRUE;
+ continue;
+ }
+ if(!strncmp(buff, "printer ", 8)) {
+ if(!strstr(buff, "disabled"))
+ *printing = TRUE;
+ if(strstr(buff, "printing"))
+ strcpy(status, "printing");
+ else if (strstr(buff, "idle"))
+ strcpy(status, "idle");
+ continue;
+ }
+ if(!strncmp(buff, "UX:", 3)) {
+ stat = PI_RES_NO_SUCH_PRINTER;
+ }
+ }
+ (void) pclose(p);
+ return(stat);
+}
+
+#else /* SVR4 */
+
+/*
+ * BSD way: lpc status
+ */
+pirstat
+get_pr_status(pn, avail, printing, qlen, needs_operator, status)
+printername pn;
+bool_t *avail;
+bool_t *printing;
+int *qlen;
+bool_t *needs_operator;
+char *status;
+{
+ char cmd[128];
+ char buff[256];
+ char buff2[256];
+ char pname[64];
+ FILE *p;
+ char *cp;
+ char *cp1;
+ char *cp2;
+ int n;
+ pirstat stat = PI_RES_NO_SUCH_PRINTER;
+
+ /* assume the worst */
+ *avail = FALSE;
+ *printing = FALSE;
+ *needs_operator = FALSE;
+ *qlen = 0;
+ *status = '\0';
+
+ pn = map_printer_name(pn);
+ if(pn == NULL || suspicious(pn))
+ return(PI_RES_NO_SUCH_PRINTER);
+
+ sprintf(pname, "%s:", pn);
+ n = strlen(pname);
+
+ sprintf(cmd, "%s/lpc status %s", LPCDIR, pn);
+ p = popen(cmd, "r");
+ if(p == NULL) {
+ msg_out("rpc.pcnfsd: unable to popen() lp status");
+ return(PI_RES_FAIL);
+ }
+
+ while(fgets(buff, 255, p) != NULL) {
+ if(strncmp(buff, pname, n))
+ continue;
+/*
+** We have a match. The only failure now is PI_RES_FAIL if
+** lpstat output cannot be decoded
+*/
+ stat = PI_RES_FAIL;
+/*
+** The next four lines are usually if the form
+**
+** queuing is [enabled|disabled]
+** printing is [enabled|disabled]
+** [no entries | N entr[y|ies] in spool area]
+** <status message, may include the word "attention">
+*/
+ while(fgets(buff, 255, p) != NULL && isspace(buff[0])) {
+ cp = buff;
+ while(isspace(*cp))
+ cp++;
+ if(*cp == '\0')
+ break;
+ cp1 = cp;
+ cp2 = buff2;
+ while(*cp1 && *cp1 != '\n') {
+ *cp2++ = tolower(*cp1);
+ cp1++;
+ }
+ *cp1 = '\0';
+ *cp2 = '\0';
+/*
+** Now buff2 has a lower-cased copy and cp points at the original;
+** both are null terminated without any newline
+*/
+ if(!strncmp(buff2, "queuing", 7)) {
+ *avail = (strstr(buff2, "enabled") != NULL);
+ continue;
+ }
+ if(!strncmp(buff2, "printing", 8)) {
+ *printing = (strstr(buff2, "enabled") != NULL);
+ continue;
+ }
+ if(isdigit(buff2[0]) && (strstr(buff2, "entr") !=NULL)) {
+
+ *qlen = atoi(buff2);
+ continue;
+ }
+ if(strstr(buff2, "attention") != NULL ||
+ strstr(buff2, "error") != NULL)
+ *needs_operator = TRUE;
+ if(*needs_operator || strstr(buff2, "waiting") != NULL)
+ strcpy(status, cp);
+ }
+ stat = PI_RES_OK;
+ break;
+ }
+ (void) pclose(p);
+ return(stat);
+}
+
+#endif /* SVR4 */
+
+/*
+ * pr_cancel: cancel a print job
+ */
+#ifdef SVR4
+
+/*
+** For SVR4 we have to be prepared for the following kinds of output:
+**
+** # cancel lp-6
+** request "lp-6" cancelled
+** # cancel lp-33
+** UX:cancel: WARNING: Request "lp-33" doesn't exist.
+** # cancel foo-88
+** UX:cancel: WARNING: Request "foo-88" doesn't exist.
+** # cancel foo
+** UX:cancel: WARNING: "foo" is not a request id or a printer.
+** TO FIX: Cancel requests by id or by
+** name of printer where printing.
+** # su geoff
+** $ cancel lp-2
+** UX:cancel: WARNING: Can't cancel request "lp-2".
+** TO FIX: You are not allowed to cancel
+** another's request.
+**
+** There are probably other variations for remote printers.
+** Basically, if the reply begins with the string
+** "UX:cancel: WARNING: "
+** we can strip this off and look for one of the following
+** (1) 'R' - should be part of "Request "xxxx" doesn't exist."
+** (2) '"' - should be start of ""foo" is not a request id or..."
+** (3) 'C' - should be start of "Can't cancel request..."
+**
+** The fly in the ointment: all of this can change if these
+** messages are localized..... :-(
+*/
+pcrstat pr_cancel(pr, user, id)
+char *pr;
+char *user;
+char *id;
+{
+char cmdbuf[256];
+char resbuf[256];
+FILE *fd;
+pcrstat stat = PC_RES_NO_SUCH_JOB;
+
+ pr = map_printer_name(pr);
+ if(pr == NULL || suspicious(pr))
+ return(PC_RES_NO_SUCH_PRINTER);
+ if(suspicious(id))
+ return(PC_RES_NO_SUCH_JOB);
+
+ sprintf(cmdbuf, "/usr/bin/cancel %s", id);
+ if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
+ msg_out("rpc.pcnfsd: su_popen failed");
+ return(PC_RES_FAIL);
+ }
+
+ if(fgets(resbuf, 255, fd) == NULL)
+ stat = PC_RES_FAIL;
+ else if(!strstr(resbuf, "UX:"))
+ stat = PC_RES_OK;
+ else if(strstr(resbuf, "doesn't exist"))
+ stat = PC_RES_NO_SUCH_JOB;
+ else if(strstr(resbuf, "not a request id"))
+ stat = PC_RES_NO_SUCH_JOB;
+ else if(strstr(resbuf, "Can't cancel request"))
+ stat = PC_RES_NOT_OWNER;
+ else stat = PC_RES_FAIL;
+
+ if(su_pclose(fd) == 255)
+ msg_out("rpc.pcnfsd: su_pclose alert");
+ return(stat);
+}
+
+#else /* SVR4 */
+
+/*
+ * BSD way: lprm
+ */
+pcrstat pr_cancel(pr, user, id)
+char *pr;
+char *user;
+char *id;
+{
+ char cmdbuf[256];
+ char resbuf[256];
+ FILE *fd;
+ int i;
+ pcrstat stat = PC_RES_NO_SUCH_JOB;
+
+ pr = map_printer_name(pr);
+ if(pr == NULL || suspicious(pr))
+ return(PC_RES_NO_SUCH_PRINTER);
+ if(suspicious(id))
+ return(PC_RES_NO_SUCH_JOB);
+
+ sprintf(cmdbuf, "%s/lprm -P%s %s", LPRDIR, pr, id);
+ if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
+ msg_out("rpc.pcnfsd: su_popen failed");
+ return(PC_RES_FAIL);
+ }
+ while(fgets(resbuf, 255, fd) != NULL) {
+ i = strlen(resbuf);
+ if(i)
+ resbuf[i-1] = '\0'; /* trim NL */
+ if(strstr(resbuf, "dequeued") != NULL)
+ stat = PC_RES_OK;
+ if(strstr(resbuf, "unknown printer") != NULL)
+ stat = PC_RES_NO_SUCH_PRINTER;
+ if(strstr(resbuf, "Permission denied") != NULL)
+ stat = PC_RES_NOT_OWNER;
+ }
+ if(su_pclose(fd) == 255)
+ msg_out("rpc.pcnfsd: su_pclose alert");
+ return(stat);
+}
+#endif /* SVR4 */
+
+/*
+** New subsystem here. We allow the administrator to define
+** up to NPRINTERDEFS aliases for printer names. This is done
+** using the "/etc/pcnfsd.conf" file, which is read at startup.
+** There are three entry points to this subsystem
+**
+** void add_printer_alias(char *printer, char *alias_for, char *command)
+**
+** This is invoked from "config_from_file()" for each
+** "printer" line. "printer" is the name of a printer; note that
+** it is possible to redefine an existing printer. "alias_for"
+** is the name of the underlying printer, used for queue listing
+** and other control functions. If it is "-", there is no
+** underlying printer, or the administrative functions are
+** not applicable to this printer. "command"
+** is the command which should be run (via "su_popen()") if a
+** job is printed on this printer. The following tokens may be
+** embedded in the command, and are substituted as follows:
+**
+** $FILE - path to the file containing the print data
+** $USER - login of user
+** $HOST - hostname from which job originated
+**
+** Tokens may occur multiple times. If The command includes no
+** $FILE token, the string " $FILE" is silently appended.
+**
+** pr_list list_virtual_printers()
+**
+** This is invoked from build_pr_list to generate a list of aliased
+** printers, so that the client that asks for a list of valid printers
+** will see these ones.
+**
+** char *map_printer_name(char *printer)
+**
+** If "printer" identifies an aliased printer, this function returns
+** the "alias_for" name, or NULL if the "alias_for" was given as "-".
+** Otherwise it returns its argument.
+**
+** char *expand_alias(char *printer, char *file, char *user, char *host)
+**
+** If "printer" is an aliased printer, this function returns a
+** pointer to a static string in which the corresponding command
+** has been expanded. Otherwise ot returns NULL.
+*/
+#define NPRINTERDEFS 16
+int num_aliases = 0;
+struct {
+ char *a_printer;
+ char *a_alias_for;
+ char *a_command;
+} alias [NPRINTERDEFS];
+
+
+
+void
+add_printer_alias(printer, alias_for, command)
+char *printer;
+char *alias_for;
+char *command;
+{
+ if(num_aliases < NPRINTERDEFS) {
+ alias[num_aliases].a_printer = strdup(printer);
+ alias[num_aliases].a_alias_for =
+ (strcmp(alias_for, "-") ? strdup(alias_for) : NULL);
+ if(strstr(command, "$FILE"))
+ alias[num_aliases].a_command = strdup(command);
+ else {
+ alias[num_aliases].a_command = (char *)grab(strlen(command) + 8);
+ strcpy(alias[num_aliases].a_command, command);
+ strcat(alias[num_aliases].a_command, " $FILE");
+ }
+ num_aliases++;
+ }
+}
+
+pr_list list_virtual_printers()
+{
+pr_list first = NULL;
+pr_list last = NULL;
+pr_list curr = NULL;
+int i;
+
+
+ if(num_aliases == 0)
+ return(NULL);
+
+ for (i = 0; i < num_aliases; i++) {
+ curr = (struct pr_list_item *)
+ grab(sizeof (struct pr_list_item));
+
+ curr->pn = strdup(alias[i].a_printer);
+ if(alias[i].a_alias_for == NULL)
+ curr->device = strdup("");
+ else
+ curr->device = strdup(alias[i].a_alias_for);
+ curr->remhost = strdup("");
+ curr->cm = strdup("(alias)");
+ curr->pr_next = NULL;
+ if(last == NULL)
+ first = curr;
+ else
+ last->pr_next = curr;
+ last = curr;
+
+ }
+ return(first);
+}
+
+
+char *
+map_printer_name(printer)
+char *printer;
+{
+int i;
+ for (i = 0; i < num_aliases; i++){
+ if(!strcmp(printer, alias[i].a_printer))
+ return(alias[i].a_alias_for);
+ }
+ return(printer);
+}
+
+static void
+substitute(string, token, data)
+char *string;
+char *token;
+char *data;
+{
+char temp[512];
+char *c;
+
+ while(c = strstr(string, token)) {
+ *c = '\0';
+ strcpy(temp, string);
+ strcat(temp, data);
+ c += strlen(token);
+ strcat(temp, c);
+ strcpy(string, temp);
+ }
+}
+
+char *
+expand_alias(printer, file, user, host)
+char *printer;
+char *file;
+char *user;
+char *host;
+{
+static char expansion[512];
+int i;
+ for (i = 0; i < num_aliases; i++){
+ if(!strcmp(printer, alias[i].a_printer)) {
+ strcpy(expansion, alias[i].a_command);
+ substitute(expansion, "$FILE", file);
+ substitute(expansion, "$USER", user);
+ substitute(expansion, "$HOST", host);
+ return(expansion);
+ }
+ }
+ return(NULL);
+}
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_test.c b/usr.sbin/rpc.pcnfsd/pcnfsd_test.c
new file mode 100644
index 00000000000..1a3561435e6
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_test.c
@@ -0,0 +1,572 @@
+/* $NetBSD: pcnfsd_test.c,v 1.2 1995/07/25 22:21:01 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_test.c 1.2 92/01/27 18:00:39 SMI */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <malloc.h>
+#include "pcnfsd.h"
+
+CLIENT *cl;
+CLIENT *cl2;
+char *server;
+char spooldirbuff[256];
+char filenamebuff[256];
+char last_id[32] = "";
+
+void free_pr_list_item();
+void free_pr_queue_item();
+void good();
+void bad();
+
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+
+char *host_name;
+char *printer;
+char *user_name;
+char *passwd;
+char *transport = "udp";
+
+ if((argc < 6) || (argc > 7)) {
+ fprintf(stderr, "usage: %s server host printer user password [transport]\n",
+ argv[0]);
+ exit(1);
+ }
+
+ server = argv[1];
+ host_name = argv[2];
+ printer = argv[3];
+ user_name = argv[4];
+ passwd = argv[5];
+ if (argc == 7)
+ transport = argv[6];
+
+ cl = clnt_create(server, PCNFSDPROG, PCNFSDVERS, transport);
+ if(cl == NULL) {
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+ cl2 = clnt_create(server, PCNFSDPROG, PCNFSDV2, transport);
+ if(cl2 == NULL) {
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+ good();
+ test_v2_info();
+ good();
+ test_v2_auth(host_name, user_name, passwd);
+ bad("Invalid password");
+ test_v2_auth(host_name, user_name, "bogus");
+ good();
+ test_v2_list();
+ good();
+ test_v2_init(host_name, printer);
+ good();
+ test_v2_start(host_name, printer, user_name, "foo", "foo");
+ good();
+ test_v2_start(host_name, printer, user_name, "bar", "bar");
+ bad("No such file to print");
+ test_v2_start(host_name, printer, user_name, "bletch", "gack");
+ good();
+ test_v2_queue(printer, user_name, FALSE);
+ if(strlen(last_id)) {
+ bad("Cancelling job with bad username");
+ test_v2_cancel(host_name, printer, "nosuchuser", last_id);
+ good();
+ test_v2_cancel(host_name, printer, user_name, last_id);
+ }
+ bad("Cancelling unknown job");
+ test_v2_cancel(host_name, printer, user_name, "99999");
+ bad("Cancelling job on invalid printer");
+ test_v2_cancel(host_name, "nosuchprinter", user_name, last_id);
+ good();
+ test_v2_queue(printer, user_name, TRUE);
+ bad("Checking queue on invalid printer");
+ test_v2_queue("nosuchprinter", user_name, TRUE);
+ good();
+ test_v2_stat(printer);
+ bad("Checking status of invalid printer");
+ test_v2_stat("nosuchprinter");
+ good();
+ test_v2_map();
+ exit(0);
+/*NOTREACHED*/
+}
+
+#define zchar 0x5b
+
+void
+scramble(s1, s2)
+char *s1;
+char *s2;
+{
+ while (*s1)
+ {
+ *s2++ = (*s1 ^ zchar) & 0x7f;
+ s1++;
+ }
+ *s2 = 0;
+}
+
+
+
+test_v2_info()
+{
+v2_info_args a;
+v2_info_results *rp;
+int *gp;
+int i;
+
+ a.vers = "Sun Microsystems PCNFSD test subsystem V1";
+ a.cm = "-";
+ printf("\ninvoking pr_info_2\n");
+
+ rp = pcnfsd2_info_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+
+ printf("results: vers = '%s', cm = '%s'\n",
+ rp->vers, rp->cm);
+ printf("facilities_len = %d\n", rp->facilities.facilities_len);
+ if (rp->facilities.facilities_len) {
+ gp = rp->facilities.facilities_val;
+ for(i = 0; i < rp->facilities.facilities_len; i++)
+ printf(" procedure %2d: %6d\n", i, *gp++);
+ printf("\n");
+ }
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->facilities.facilities_val)
+ free(rp->facilities.facilities_val);
+ if(rp->vers)
+ free(rp->vers);
+
+ return(0);
+}
+
+test_v2_auth(host_name, user_name , pwrd)
+char *host_name;
+char *user_name;
+char *pwrd;
+{
+v2_auth_args a;
+v2_auth_results *rp;
+char uname[32];
+char pw[64];
+u_int *gp;
+int i;
+
+ scramble(user_name, uname);
+ scramble(pwrd, pw);
+ a.system = host_name;
+ a.id = uname;
+ a.pw = pw;
+ a.cm = "-";
+ printf("\ninvoking pr_auth_2\n");
+
+ rp = pcnfsd2_auth_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+
+ if(rp->stat == AUTH_RES_FAIL)
+ printf("results: stat = AUTH_RES_FAIL\n");
+ else {
+ printf("results: stat = %d, uid = %u, gid = %u,\n homedir= '%s', cm = '%s'\n",
+ rp->stat, rp->uid, rp->gid, rp->home, rp->cm);
+ printf("gids_len = %d", rp->gids.gids_len);
+ if (rp->gids.gids_len) {
+ gp = rp->gids.gids_val;
+ for(i = 0; i < rp->gids.gids_len; i++)
+ printf(" %u", *gp++);
+ printf("\n");
+ }
+ }
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->gids.gids_val)
+ free(rp->gids.gids_val);
+ if(rp->home)
+ free(rp->home);
+
+ return(0);
+}
+
+test_v2_init(host_name, printer)
+char *host_name;
+char *printer;
+{
+v2_pr_init_args a;
+v2_pr_init_results *rp;
+
+ a.system = host_name;
+ a.pn = printer;
+ a.cm = "-";
+ printf("\ninvoking pr_init_2\n");
+
+ rp = pcnfsd2_pr_init_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: stat = %d, dir = '%s', cm = '%s'\n",
+ rp->stat, rp->dir, rp->cm);
+ strcpy(spooldirbuff, rp->dir);
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->dir)
+ free(rp->dir);
+ return(0);
+}
+
+
+test_v2_start(host_name, printer, user_name, tag1, tag2)
+char *host_name;
+char *printer;
+char *user_name;
+char *tag1;
+char *tag2;
+{
+v2_pr_start_args a;
+v2_pr_start_results *rp;
+FILE *fp;
+ printf("\ntesting start print v2\n");
+
+ if(strcmp(server, "localhost")) {
+ printf("sorry - can only test start print on 'localhost'\n");
+ return(1);
+ }
+
+ sprintf(filenamebuff, "%s/%s", spooldirbuff, tag1);
+
+ fp = fopen(filenamebuff, "w");
+ if(fp == NULL) {
+ perror("creating test file");
+ return(1);
+ }
+ (void)fputs("foo bar bletch\n", fp);
+ (void)fclose(fp);
+
+ a.system = host_name;
+ a.pn = printer;
+ a.user = user_name;
+ a.file = tag2;
+ a.opts = "xxxx";
+ a.copies = 1;
+ a.cm = "-";
+
+ printf("\ninvoking pr_start_2\n");
+
+ rp = pcnfsd2_pr_start_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: stat = %d, jobid = '%s', cm = '%s'\n",
+ rp->stat, rp->id, rp->cm);
+ if(rp->stat == PS_RES_OK)
+ strcpy(last_id, rp->id);
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->id)
+ free(rp->id);
+ return(0);
+}
+
+
+test_v2_cancel(host_name, printer, user_name, id)
+char *host_name;
+char *printer;
+char *user_name;
+char *id;
+{
+v2_pr_cancel_args a;
+v2_pr_cancel_results *rp;
+ printf("\ntesting cancel print v2\n");
+
+ a.system = host_name;
+ a.pn = printer;
+ a.user = user_name;
+ a.id = id;
+ a.cm = "-";
+
+ printf("\ninvoking pr_cancel_2 for job %s on printer %s\n",
+ id, printer);
+
+ rp = pcnfsd2_pr_cancel_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: stat = %d, cm = '%s'\n",
+ rp->stat, rp->cm);
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ return(0);
+}
+test_v2_list()
+{
+char a;
+v2_pr_list_results *rp;
+pr_list curr;
+
+
+ printf("\ninvoking pr_list_2\n");
+
+ rp = pcnfsd2_pr_list_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: cm = '%s', printerlist:\n", rp->cm);
+ curr = rp->printers;
+ while(curr) {
+ printf(" name '%s' ", curr->pn);
+ if(strlen(curr->remhost))
+ printf("remote: srvr '%s', name '%s'",
+ curr->remhost,
+ curr->device);
+ else
+ printf("local device = '%s'", curr->device);
+ printf(", cm = '%s'\n", curr->cm);
+ curr = curr->pr_next;
+ }
+ printf("end of list\n");
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->printers) {
+ printf("freeing results\n");
+ free_pr_list_item(rp->printers);
+ }
+ return(0);
+}
+
+
+void
+free_pr_list_item(curr)
+pr_list curr;
+{
+ if(curr->pn)
+ free(curr->pn);
+ if(curr->remhost)
+ free(curr->remhost);
+ if(curr->device)
+ free(curr->device);
+ if(curr->cm)
+ free(curr->cm);
+ if(curr->pr_next)
+ free_pr_list_item(curr->pr_next); /* recurse */
+ free(curr);
+}
+
+
+
+test_v2_queue(printer, user_name, private)
+char *printer;
+char *user_name;
+int private;
+{
+struct v2_pr_queue_args a;
+v2_pr_queue_results *rp;
+pr_queue curr;
+
+ a.pn = printer;
+ a.system = "foo";
+ a.user = user_name;
+ a.just_mine = private;
+ a.cm = "no";
+
+ printf("\ninvoking pr_queue_2 (just_mine = %d)\n", private);
+
+ rp = pcnfsd2_pr_queue_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: stat = %d, qlen = %d, qshown = %d cm = '%s', queue:\n",
+ rp->stat, rp->qlen, rp->qshown, rp->cm);
+ curr = rp->jobs;
+ while(curr) {
+ printf("rank = %2d, id = '%s', size = '%s', status = '%s'\n",
+ curr->position,
+ curr->id,
+ curr->size,
+ curr->status);
+ printf(" user = '%s', file = '%s', cm = '%s'\n",
+ curr->user,
+ curr->file,
+ curr->cm);
+ curr = curr->pr_next;
+ }
+ printf("end of list\n");
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->jobs) {
+ printf("freeing results\n");
+ free_pr_queue_item(rp->jobs);
+ }
+ return(0);
+}
+
+
+
+void
+free_pr_queue_item(curr)
+pr_queue curr;
+{
+ if(curr->id)
+ free(curr->id);
+ if(curr->size)
+ free(curr->size);
+ if(curr->status)
+ free(curr->status);
+ if(curr->system)
+ free(curr->system);
+ if(curr->user)
+ free(curr->user);
+ if(curr->file)
+ free(curr->file);
+ if(curr->cm)
+ free(curr->cm);
+ if(curr->pr_next)
+ free_pr_queue_item(curr->pr_next); /* recurse */
+ free(curr);
+}
+
+
+
+test_v2_stat(printer)
+char *printer;
+{
+v2_pr_status_args a;
+v2_pr_status_results *rp;
+
+ printf("\ntesting status print v2\n");
+
+ a.pn = printer;
+ a.cm = "-";
+
+ printf("\ninvoking pr_status_2\n");
+
+ rp = pcnfsd2_pr_status_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: stat = %d, cm = '%s'\n",
+ rp->stat, rp->cm);
+ if(rp->stat == PI_RES_OK) {
+ printf("avail = %s, ", (rp->avail ? "YES" : "NO"));
+ printf("printing = %s, ", (rp->printing ? "YES" : "NO"));
+ printf("needs_operator = %s, ", (rp->needs_operator ? "YES" : "NO"));
+ printf("qlen = %d, status = '%s'\n", rp->qlen, rp->status);
+ }
+/* free up allocated strings */
+ if(rp->cm)
+ free(rp->cm);
+ if(rp->status)
+ free(rp->status);
+ return(0);
+}
+
+struct mapreq_arg_item * make_mapreq_entry(t, i, n, next)
+mapreq t;
+int i;
+char *n;
+struct mapreq_arg_item *next;
+{
+struct mapreq_arg_item *x;
+ x = (struct mapreq_arg_item *)malloc(sizeof(struct mapreq_arg_item));
+ if(x == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(123);
+ }
+ x->req = t;
+ x->id = i;
+ x->name = (n ? n : "");
+ x->mapreq_next = next;
+ return(x);
+}
+
+test_v2_map()
+{
+v2_mapid_args a;
+v2_mapid_results *rp;
+struct mapreq_res_item *rip;
+
+ a.cm = "-";
+ a.req_list = make_mapreq_entry(MAP_REQ_UID, 906, NULL,
+ make_mapreq_entry(MAP_REQ_GID, 1, NULL,
+ make_mapreq_entry(MAP_REQ_UNAME, 0, "root",
+ make_mapreq_entry(MAP_REQ_GNAME, 0, "wheel",
+ make_mapreq_entry(MAP_REQ_UNAME, 0, "bogus", NULL)))));
+
+ printf("\ninvoking pr_mapid_2\n");
+ rp = pcnfsd2_mapid_2(&a, cl2);
+
+ if(rp == NULL) {
+ clnt_perror(cl2, server);
+ return(1);
+ }
+ printf("results: cm = '%s', result list %s\n",
+ rp->cm, rp->res_list ? "follows" : "omitted");
+ rip = rp->res_list;
+ while(rip) {
+ printf("request type = %d, status = %d, id = %d, name = '%s'\n",
+ rip->req, rip->stat, rip->id,
+ (rip->name ? rip->name : "(NULL)"));
+ rip = rip->mapreq_next;
+ }
+/* XXX should free up results */
+
+
+
+return(0);
+}
+
+
+void
+good()
+{
+printf("\n");
+printf("********************************************************\n");
+printf("********************************************************\n");
+printf("** The following test is expected to SUCCEED **\n");
+printf("********************************************************\n");
+printf("********************************************************\n");
+}
+
+void
+bad(reason)
+char *reason;
+{
+printf("\n");
+printf("********************************************************\n");
+printf("********************************************************\n");
+printf("** The following test is expected to FAIL **\n");
+printf("** Reason: **\n");
+printf("** %50s **\n", reason);
+printf("********************************************************\n");
+printf("********************************************************\n");
+}
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_v1.c b/usr.sbin/rpc.pcnfsd/pcnfsd_v1.c
new file mode 100644
index 00000000000..0b3219b5c02
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_v1.c
@@ -0,0 +1,162 @@
+/* $NetBSD: pcnfsd_v1.c,v 1.2 1995/07/25 22:21:19 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_v1.c 1.1 91/09/03 12:41:50 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+** @(#)pcnfsd_v1.c 1.1 9/3/91
+**=====================================================================
+*/
+#include "common.h"
+
+/*
+**=====================================================================
+** I N C L U D E F I L E S E C T I O N *
+** *
+** If your port requires different include files, add a suitable *
+** #define in the customization section, and make the inclusion or *
+** exclusion of the files conditional on this. *
+**=====================================================================
+*/
+#include "pcnfsd.h"
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <string.h>
+
+#ifndef SYSV
+#include <sys/wait.h>
+#endif
+
+#ifdef ISC_2_0
+#include <sys/fcntl.h>
+#endif
+
+#ifdef SHADOW_SUPPORT
+#include <shadow.h>
+#endif
+
+/*
+**---------------------------------------------------------------------
+** Other #define's
+**---------------------------------------------------------------------
+*/
+
+extern void scramble();
+extern char *crypt();
+
+#ifdef WTMP
+extern void wlogin();
+#endif
+
+extern struct passwd *get_password();
+
+/*
+**---------------------------------------------------------------------
+** Misc. variable definitions
+**---------------------------------------------------------------------
+*/
+
+int buggit = 0;
+
+/*
+**=====================================================================
+** C O D E S E C T I O N *
+**=====================================================================
+*/
+
+
+/*ARGSUSED*/
+void *pcnfsd_null_1_svc(arg, req)
+void *arg;
+struct svc_req *req;
+{
+static char dummy;
+return((void *)&dummy);
+}
+
+auth_results *pcnfsd_auth_1_svc(arg, req)
+auth_args *arg;
+struct svc_req *req;
+{
+static auth_results r;
+
+char uname[32];
+char pw[64];
+int c1, c2;
+struct passwd *p;
+
+
+ r.stat = AUTH_RES_FAIL; /* assume failure */
+ r.uid = (int)-2;
+ r.gid = (int)-2;
+
+ scramble(arg->id, uname);
+ scramble(arg->pw, pw);
+
+#ifdef USER_CACHE
+ if(check_cache(uname, pw, &r.uid, &r.gid)) {
+ r.stat = AUTH_RES_OK;
+#ifdef WTMP
+ wlogin(uname, req);
+#endif
+ return (&r);
+ }
+#endif
+
+ p = get_password(uname);
+ if (p == (struct passwd *)NULL)
+ return (&r);
+
+ c1 = strlen(pw);
+ c2 = strlen(p->pw_passwd);
+ if ((c1 && !c2) || (c2 && !c1) ||
+ (strcmp(p->pw_passwd, crypt(pw, p->pw_passwd))))
+ {
+ return (&r);
+ }
+ r.stat = AUTH_RES_OK;
+ r.uid = p->pw_uid;
+ r.gid = p->pw_gid;
+#ifdef WTMP
+ wlogin(uname, req);
+#endif
+
+#ifdef USER_CACHE
+ add_cache_entry(p);
+#endif
+
+return(&r);
+}
+
+pr_init_results *pcnfsd_pr_init_1_svc(pi_arg, req)
+pr_init_args *pi_arg;
+struct svc_req *req;
+{
+static pr_init_results pi_res;
+
+ pi_res.stat =
+ (pirstat) pr_init(pi_arg->system, pi_arg->pn, &pi_res.dir);
+
+return(&pi_res);
+}
+
+pr_start_results *pcnfsd_pr_start_1_svc(ps_arg, req)
+pr_start_args *ps_arg;
+struct svc_req *req;
+{
+static pr_start_results ps_res;
+char *dummyptr;
+
+ ps_res.stat =
+ (psrstat) pr_start2(ps_arg->system, ps_arg->pn, ps_arg->user,
+ ps_arg ->file, ps_arg->opts, &dummyptr);
+
+return(&ps_res);
+}
+
diff --git a/usr.sbin/rpc.pcnfsd/pcnfsd_v2.c b/usr.sbin/rpc.pcnfsd/pcnfsd_v2.c
new file mode 100644
index 00000000000..da9bab8b23b
--- /dev/null
+++ b/usr.sbin/rpc.pcnfsd/pcnfsd_v2.c
@@ -0,0 +1,569 @@
+/* $NetBSD: pcnfsd_v2.c,v 1.4 1995/08/14 19:50:10 gwr Exp $ */
+
+/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_v2.c 1.2 91/12/18 13:26:13 SMI */
+/*
+**=====================================================================
+** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
+** @(#)pcnfsd_v2.c 1.2 12/18/91
+**=====================================================================
+*/
+#include "common.h"
+/*
+**=====================================================================
+** I N C L U D E F I L E S E C T I O N *
+** *
+** If your port requires different include files, add a suitable *
+** #define in the customization section, and make the inclusion or *
+** exclusion of the files conditional on this. *
+**=====================================================================
+*/
+#include "pcnfsd.h"
+
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <string.h>
+
+#ifdef USE_YP
+#include <rpcsvc/ypclnt.h>
+#endif
+
+#ifndef SYSV
+#include <sys/wait.h>
+#endif
+
+#ifdef ISC_2_0
+#include <sys/fcntl.h>
+#endif
+
+#ifdef SHADOW_SUPPORT
+#include <shadow.h>
+#endif
+
+/*
+**---------------------------------------------------------------------
+** Other #define's
+**---------------------------------------------------------------------
+*/
+
+void fillin_extra_groups();
+extern void scramble();
+extern void *grab();
+extern char *crypt();
+extern int build_pr_list();
+extern pirstat build_pr_queue();
+extern psrstat pr_start();
+extern psrstat pr_start2();
+extern pcrstat pr_cancel();
+extern pirstat get_pr_status();
+
+extern struct passwd *get_password();
+
+#ifdef WTMP
+extern void wlogin();
+#endif
+
+#ifdef USE_YP
+char *find_entry();
+#endif
+
+/*
+**---------------------------------------------------------------------
+** Misc. variable definitions
+**---------------------------------------------------------------------
+*/
+
+extern pr_list printers;
+extern pr_queue queue;
+
+/*
+**=====================================================================
+** C O D E S E C T I O N *
+**=====================================================================
+*/
+
+
+static char no_comment[] = "No comment";
+static char not_supported[] = "Not supported";
+static char pcnfsd_version[] = "@(#)pcnfsd_v2.c 1.2 - rpc.pcnfsd V2.0 (c) 1991 Sun Technology Enterprises, Inc.";
+
+/*ARGSUSED*/
+void *pcnfsd2_null_2_svc(arg, req)
+void*arg;
+struct svc_req *req;
+{
+static char dummy;
+return((void *)&dummy);
+}
+
+v2_auth_results *pcnfsd2_auth_2_svc(arg, req)
+v2_auth_args *arg;
+struct svc_req *req;
+{
+static v2_auth_results r;
+
+char uname[32];
+char pw[64];
+int c1, c2;
+struct passwd *p;
+static u_int extra_gids[EXTRAGIDLEN];
+static char home[256];
+#ifdef USE_YP
+char *yphome;
+char *cp;
+#endif /*USE_YP*/
+
+
+ r.stat = AUTH_RES_FAIL; /* assume failure */
+ r.uid = (int)-2;
+ r.gid = (int)-2;
+ r.cm = &no_comment[0];
+ r.gids.gids_len = 0;
+ r.gids.gids_val = &extra_gids[0];
+ home[0] = '\0';
+ r.home = &home[0];
+ r.def_umask = umask(0);
+ (void)umask(r.def_umask); /* or use 022 */
+
+ scramble(arg->id, uname);
+ scramble(arg->pw, pw);
+
+#ifdef USER_CACHE
+ if(check_cache(uname, pw, &r.uid, &r.gid)) {
+ r.stat = AUTH_RES_OK;
+#ifdef WTMP
+ wlogin(uname, req);
+#endif
+ fillin_extra_groups
+ (uname, r.gid, &r.gids.gids_len, extra_gids);
+#ifdef USE_YP
+ yphome = find_entry(uname, "auto.home");
+ if(yphome) {
+ strcpy(home, yphome);
+ free(yphome);
+ cp = strchr(home, ':');
+ cp++;
+ cp = strchr(cp, ':');
+ if(cp)
+ *cp = '/';
+ }
+#endif
+ return (&r);
+ }
+#endif
+
+ p = get_password(uname);
+ if (p == (struct passwd *)NULL)
+ return (&r);
+
+ c1 = strlen(pw);
+ c2 = strlen(p->pw_passwd);
+ if ((c1 && !c2) || (c2 && !c1) ||
+ (strcmp(p->pw_passwd, crypt(pw, p->pw_passwd))))
+ {
+ return (&r);
+ }
+ r.stat = AUTH_RES_OK;
+ r.uid = p->pw_uid;
+ r.gid = p->pw_gid;
+#ifdef WTMP
+ wlogin(uname, req);
+#endif
+ fillin_extra_groups(uname, r.gid, &r.gids.gids_len, extra_gids);
+
+#ifdef USE_YP
+ yphome = find_entry(uname, "auto.home");
+ if(yphome) {
+ strcpy(home, yphome);
+ free(yphome);
+ cp = strchr(home, ':');
+ cp++;
+ cp = strchr(cp, ':');
+ if(cp)
+ *cp = '/';
+ }
+#endif
+
+#ifdef USER_CACHE
+ add_cache_entry(p);
+#endif
+
+return(&r);
+
+}
+
+v2_pr_init_results *pcnfsd2_pr_init_2_svc(arg, req)
+v2_pr_init_args *arg;
+struct svc_req *req;
+{
+static v2_pr_init_results res;
+
+ res.stat =
+ (pirstat) pr_init(arg->system, arg->pn, &res.dir);
+ res.cm = &no_comment[0];
+
+
+return(&res);
+}
+
+v2_pr_start_results *pcnfsd2_pr_start_2_svc(arg, req)
+v2_pr_start_args *arg;
+struct svc_req *req;
+{
+static v2_pr_start_results res;
+
+ res.stat =
+ (psrstat) pr_start2(arg->system, arg->pn, arg->user,
+ arg ->file, arg->opts, &res.id);
+ res.cm = &no_comment[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_pr_list_results *pcnfsd2_pr_list_2_svc(arg, req)
+void *arg;
+struct svc_req *req;
+{
+static v2_pr_list_results res;
+
+ if(printers == NULL)
+ (void)build_pr_list();
+ res.cm = &no_comment[0];
+ res.printers = printers;
+
+return(&res);
+}
+
+v2_pr_queue_results *pcnfsd2_pr_queue_2_svc(arg, req)
+v2_pr_queue_args *arg;
+struct svc_req *req;
+{
+static v2_pr_queue_results res;
+
+ res.stat = build_pr_queue(arg->pn, arg->user,
+ arg->just_mine, &res.qlen, &res.qshown);
+ res.cm = &no_comment[0];
+ res.just_yours = arg->just_mine;
+ res.jobs = queue;
+
+
+return(&res);
+}
+
+v2_pr_status_results *pcnfsd2_pr_status_2_svc(arg, req)
+v2_pr_status_args *arg;
+struct svc_req *req;
+{
+static v2_pr_status_results res;
+static char status[128];
+
+ res.stat = get_pr_status(arg->pn, &res.avail, &res.printing,
+ &res.qlen, &res.needs_operator, &status[0]);
+ res.status = &status[0];
+ res.cm = &no_comment[0];
+
+return(&res);
+}
+
+v2_pr_cancel_results *pcnfsd2_pr_cancel_2_svc(arg, req)
+v2_pr_cancel_args *arg;
+struct svc_req *req;
+{
+static v2_pr_cancel_results res;
+
+ res.stat = pr_cancel(arg->pn, arg->user, arg->id);
+ res.cm = &no_comment[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_pr_requeue_results *pcnfsd2_pr_requeue_2_svc(arg, req)
+v2_pr_requeue_args *arg;
+struct svc_req *req;
+{
+static v2_pr_requeue_results res;
+ res.stat = PC_RES_FAIL;
+ res.cm = &not_supported[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_pr_hold_results *pcnfsd2_pr_hold_2_svc(arg, req)
+v2_pr_hold_args *arg;
+struct svc_req *req;
+{
+static v2_pr_hold_results res;
+
+ res.stat = PC_RES_FAIL;
+ res.cm = &not_supported[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_pr_release_results *pcnfsd2_pr_release_2_svc(arg, req)
+v2_pr_release_args *arg;
+struct svc_req *req;
+{
+static v2_pr_release_results res;
+
+ res.stat = PC_RES_FAIL;
+ res.cm = &not_supported[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_pr_admin_results *pcnfsd2_pr_admin_2_svc(arg, req)
+v2_pr_admin_args *arg;
+struct svc_req *req;
+{
+static v2_pr_admin_results res;
+/*
+** The default action for admin is to fail.
+** If someone wishes to implement an administration
+** mechanism, and isn't worried about the security
+** holes, go right ahead.
+*/
+
+ res.cm = &not_supported[0];
+ res.stat = PI_RES_FAIL;
+
+return(&res);
+}
+
+void
+free_mapreq_results(p)
+mapreq_res p;
+{
+ if(p->mapreq_next)
+ free_mapreq_results(p->mapreq_next); /* recurse */
+ if(p->name)
+ (void)free(p->name);
+ (void)free(p);
+ return;
+}
+
+static char *
+my_strdup(s)
+char *s;
+{
+char *r;
+ r = (char *)grab(strlen(s)+1);
+ strcpy(r, s);
+ return(r);
+}
+
+v2_mapid_results *pcnfsd2_mapid_2_svc(arg, req)
+v2_mapid_args *arg;
+struct svc_req *req;
+{
+static v2_mapid_results res;
+struct passwd *p_passwd;
+struct group *p_group;
+
+mapreq_arg a;
+mapreq_res next_r;
+mapreq_res last_r = NULL;
+
+
+ if(res.res_list) {
+ free_mapreq_results(res.res_list);
+ res.res_list = NULL;
+ }
+
+ a = arg->req_list;
+ while(a) {
+ next_r = (struct mapreq_res_item *)
+ grab(sizeof(struct mapreq_res_item));
+ next_r->stat = MAP_RES_UNKNOWN;
+ next_r->req = a->req;
+ next_r->id = a->id;
+ next_r->name = NULL;
+ next_r->mapreq_next = NULL;
+
+ if(last_r == NULL)
+ res.res_list = next_r;
+ else
+ last_r->mapreq_next = next_r;
+ last_r = next_r;
+ switch(a->req) {
+ case MAP_REQ_UID:
+ p_passwd = getpwuid((uid_t)a->id);
+ if(p_passwd) {
+ next_r->name = my_strdup(p_passwd->pw_name);
+ next_r->stat = MAP_RES_OK;
+ }
+ break;
+ case MAP_REQ_GID:
+ p_group = getgrgid((gid_t)a->id);
+ if(p_group) {
+ next_r->name = my_strdup(p_group->gr_name);
+ next_r->stat = MAP_RES_OK;
+ }
+ break;
+ case MAP_REQ_UNAME:
+ next_r->name = my_strdup(a->name);
+ p_passwd = getpwnam(a->name);
+ if(p_passwd) {
+ next_r->id = p_passwd->pw_uid;
+ next_r->stat = MAP_RES_OK;
+ }
+ break;
+ case MAP_REQ_GNAME:
+ next_r->name = my_strdup(a->name);
+ p_group = getgrnam(a->name);
+ if(p_group) {
+ next_r->id = p_group->gr_gid;
+ next_r->stat = MAP_RES_OK;
+ }
+ break;
+ }
+ if(next_r->name == NULL)
+ next_r->name = my_strdup("");
+ a = a->mapreq_next;
+ }
+
+ res.cm = &no_comment[0];
+
+return(&res);
+}
+
+
+/*ARGSUSED*/
+v2_alert_results *pcnfsd2_alert_2_svc(arg, req)
+v2_alert_args *arg;
+struct svc_req *req;
+{
+static v2_alert_results res;
+
+ res.stat = ALERT_RES_FAIL;
+ res.cm = &not_supported[0];
+
+return(&res);
+}
+
+/*ARGSUSED*/
+v2_info_results *pcnfsd2_info_2_svc(arg, req)
+v2_info_args *arg;
+struct svc_req *req;
+{
+static v2_info_results res;
+static int facilities[FACILITIESMAX];
+static int onetime = 1;
+
+#define UNSUPPORTED -1
+#define QUICK 100
+#define SLOW 2000
+
+ if(onetime) {
+ onetime = 0;
+ facilities[PCNFSD2_NULL] = QUICK;
+ facilities[PCNFSD2_INFO] = QUICK;
+ facilities[PCNFSD2_PR_INIT] = QUICK;
+ facilities[PCNFSD2_PR_START] = SLOW;
+ facilities[PCNFSD2_PR_LIST] = QUICK; /* except first time */
+ facilities[PCNFSD2_PR_QUEUE] = SLOW;
+ facilities[PCNFSD2_PR_STATUS] = SLOW;
+ facilities[PCNFSD2_PR_CANCEL] = SLOW;
+ facilities[PCNFSD2_PR_ADMIN] = UNSUPPORTED;
+ facilities[PCNFSD2_PR_REQUEUE] = UNSUPPORTED;
+ facilities[PCNFSD2_PR_HOLD] = UNSUPPORTED;
+ facilities[PCNFSD2_PR_RELEASE] = UNSUPPORTED;
+ facilities[PCNFSD2_MAPID] = QUICK;
+ facilities[PCNFSD2_AUTH] = QUICK;
+ facilities[PCNFSD2_ALERT] = QUICK;
+ }
+ res.facilities.facilities_len = PCNFSD2_ALERT+1;
+ res.facilities.facilities_val = facilities;
+
+ res.vers = &pcnfsd_version[0];
+ res.cm = &no_comment[0];
+
+return(&res);
+}
+
+
+
+void
+fillin_extra_groups(uname, main_gid, len, extra_gids)
+char *uname;
+u_int main_gid;
+int *len;
+u_int extra_gids[EXTRAGIDLEN];
+{
+struct group *grp;
+char **members;
+int n = 0;
+
+ setgrent();
+
+ while(n < EXTRAGIDLEN) {
+ grp = getgrent();
+ if(grp == NULL)
+ break;
+ if(grp->gr_gid == main_gid)
+ continue;
+ for(members = grp->gr_mem; members && *members; members++) {
+ if(!strcmp(*members, uname)) {
+ extra_gids[n++] = grp->gr_gid;
+ break;
+ }
+ }
+ }
+ endgrent();
+ *len = n;
+}
+
+#ifdef USE_YP
+/* the following is from rpcsvc/yp_prot.h */
+#define YPMAXDOMAIN 64
+/*
+ * find_entry returns NULL on any error (printing a message) and
+ * otherwise returns a pointer to the malloc'd result. The caller
+ * is responsible for free()ing the result string.
+ */
+char *
+find_entry(key, map)
+char *key;
+char *map;
+{
+ int err;
+ char *val = NULL;
+ char *cp;
+ int len = 0;
+ static char domain[YPMAXDOMAIN+1];
+
+ if(getdomainname(domain, YPMAXDOMAIN) ) {
+ msg_out("rpc.pcnfsd: getdomainname failed");
+ return(NULL);
+ }
+
+ if (err = yp_bind(domain)) {
+#ifdef DEBUG
+ msg_out("rpc.pcnfsd: yp_bind failed");
+#endif
+ return(NULL);
+ }
+
+ err = yp_match(domain, map, key, strlen(key), &val, &len);
+
+ if (err) {
+ msg_out("rpc.pcnfsd: yp_match failed");
+ return(NULL);
+ }
+
+ if(cp = strchr(val, '\n'))
+ *cp = '\0'; /* in case we get an extra NL at the end */
+ return(val);
+}
+
+#endif
diff --git a/usr.sbin/rwhod/Makefile b/usr.sbin/rwhod/Makefile
new file mode 100644
index 00000000000..8f1610796f0
--- /dev/null
+++ b/usr.sbin/rwhod/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+
+PROG= rwhod
+MAN= rwhod.8
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rwhod/rwhod.8 b/usr.sbin/rwhod/rwhod.8
new file mode 100644
index 00000000000..c4007d28208
--- /dev/null
+++ b/usr.sbin/rwhod/rwhod.8
@@ -0,0 +1,147 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" from: @(#)rwhod.8 8.2 (Berkeley) 12/11/93
+.\" $Id: rwhod.8,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+.\"
+.Dd December 11, 1993
+.Dt RWHOD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rwhod
+.Nd system status server
+.Sh SYNOPSIS
+.Nm rwhod
+.Sh DESCRIPTION
+.Nm Rwhod
+is the server which maintains the database used by the
+.Xr rwho 1
+and
+.Xr ruptime 1
+programs. Its operation is predicated on the ability to
+.Em broadcast
+messages on a network.
+.Pp
+.Nm Rwhod
+operates as both a producer and consumer of status information.
+As a producer of information it periodically
+queries the state of the system and constructs
+status messages which are broadcast on a network.
+As a consumer of information, it listens for other
+.Nm rwhod
+servers' status messages, validating them, then recording
+them in a collection of files located in the directory
+.Pa /var/rwho .
+.Pp
+The server transmits and receives messages at the port indicated
+in the ``rwho'' service specification; see
+.Xr services 5 .
+The messages sent and received, are of the form:
+.Bd -literal -offset indent
+struct outmp {
+ char out_line[8]; /* tty name */
+ char out_name[8]; /* user id */
+ long out_time; /* time on */
+};
+
+struct whod {
+ char wd_vers;
+ char wd_type;
+ char wd_fill[2];
+ int wd_sendtime;
+ int wd_recvtime;
+ char wd_hostname[32];
+ int wd_loadav[3];
+ int wd_boottime;
+ struct whoent {
+ struct outmp we_utmp;
+ int we_idle;
+ } wd_we[1024 / sizeof (struct whoent)];
+};
+.Ed
+.Pp
+All fields are converted to network byte order prior to
+transmission. The load averages are as calculated by the
+.Xr w 1
+program, and represent load averages over the 5, 10, and 15 minute
+intervals prior to a server's transmission; they are multiplied by 100
+for representation in an integer. The host name
+included is that returned by the
+.Xr gethostname 2
+system call, with any trailing domain name omitted.
+The array at the end of the message contains information about
+the users logged in to the sending machine. This information
+includes the contents of the
+.Xr utmp 5
+entry for each non-idle terminal line and a value indicating the
+time in seconds since a character was last received on the terminal line.
+.Pp
+Messages received by the
+.Xr rwho
+server are discarded unless they originated at an
+.Xr rwho
+server's port. In addition, if the host's name, as specified
+in the message, contains any unprintable
+.Tn ASCII
+characters, the
+message is discarded. Valid messages received by
+.Nm rwhod
+are placed in files named
+.Pa whod.hostname
+in the directory
+.Pa /var/rwho .
+These files contain only the most recent message, in the
+format described above.
+.Pp
+Status messages are generated approximately once every
+3 minutes.
+.Nm Rwhod
+performs an
+.Xr nlist 3
+on
+.Pa /netbsd
+every 30 minutes to guard against
+the possibility that this file is not the system
+image currently operating.
+.Sh SEE ALSO
+.Xr rwho 1 ,
+.Xr ruptime 1
+.Sh BUGS
+There should be a way to relay status information between networks.
+Status information should be sent only upon request rather than continuously.
+People often interpret the server dying
+or network communication failures
+as a machine going down.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c
new file mode 100644
index 00000000000..8a1accd50d9
--- /dev/null
+++ b/usr.sbin/rwhod/rwhod.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";*/
+static char rcsid[] = "$Id: rwhod.c,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <protocols/rwhod.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmp.h>
+
+/*
+ * Alarm interval. Don't forget to change the down time check in ruptime
+ * if this is changed.
+ */
+#define AL_INTERVAL (3 * 60)
+
+char myname[MAXHOSTNAMELEN];
+
+/*
+ * We communicate with each neighbor in a list constructed at the time we're
+ * started up. Neighbors are currently directly connected via a hardware
+ * interface.
+ */
+struct neighbor {
+ struct neighbor *n_next;
+ char *n_name; /* interface name */
+ struct sockaddr *n_addr; /* who to send to */
+ int n_addrlen; /* size of address */
+ int n_flags; /* should forward?, interface flags */
+};
+
+struct neighbor *neighbors;
+struct whod mywd;
+struct servent *sp;
+int s, utmpf;
+
+#define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))
+
+int configure __P((int));
+void getboottime __P((int));
+void onalrm __P((int));
+void quit __P((char *));
+void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
+int verify __P((char *));
+#ifdef DEBUG
+char *interval __P((int, char *));
+void Sendto __P((int, char *, int, int, char *, int));
+#define sendto Sendto
+#endif
+
+int
+main(argc, argv)
+ int argc;
+ char argv[];
+{
+ struct sockaddr_in from;
+ struct stat st;
+ char path[64];
+ int on = 1;
+ char *cp;
+ struct sockaddr_in sin;
+
+ if (getuid()) {
+ fprintf(stderr, "rwhod: not super user\n");
+ exit(1);
+ }
+ sp = getservbyname("who", "udp");
+ if (sp == NULL) {
+ fprintf(stderr, "rwhod: udp/who: unknown service\n");
+ exit(1);
+ }
+#ifndef DEBUG
+ daemon(1, 0);
+#endif
+ if (chdir(_PATH_RWHODIR) < 0) {
+ (void)fprintf(stderr, "rwhod: %s: %s\n",
+ _PATH_RWHODIR, strerror(errno));
+ exit(1);
+ }
+ (void) signal(SIGHUP, getboottime);
+ openlog("rwhod", LOG_PID, LOG_DAEMON);
+ /*
+ * Establish host name as returned by system.
+ */
+ if (gethostname(myname, sizeof(myname) - 1) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ exit(1);
+ }
+ if ((cp = index(myname, '.')) != NULL)
+ *cp = '\0';
+ strncpy(mywd.wd_hostname, myname, sizeof(myname) - 1);
+ utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
+ if (utmpf < 0) {
+ syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
+ exit(1);
+ }
+ getboottime(0);
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ exit(1);
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = sp->s_port;
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ exit(1);
+ }
+ if (!configure(s))
+ exit(1);
+ signal(SIGALRM, onalrm);
+ onalrm(0);
+ for (;;) {
+ struct whod wd;
+ int cc, whod, len = sizeof(from);
+
+ cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,
+ (struct sockaddr *)&from, &len);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "recv: %m");
+ continue;
+ }
+ if (from.sin_port != sp->s_port) {
+ syslog(LOG_WARNING, "%d: bad from port",
+ ntohs(from.sin_port));
+ continue;
+ }
+ if (wd.wd_vers != WHODVERSION)
+ continue;
+ if (wd.wd_type != WHODTYPE_STATUS)
+ continue;
+ if (!verify(wd.wd_hostname)) {
+ syslog(LOG_WARNING, "malformed host name from %x",
+ from.sin_addr);
+ continue;
+ }
+ (void) sprintf(path, "whod.%s", wd.wd_hostname);
+ /*
+ * Rather than truncating and growing the file each time,
+ * use ftruncate if size is less than previous size.
+ */
+ whod = open(path, O_WRONLY | O_CREAT, 0644);
+ if (whod < 0) {
+ syslog(LOG_WARNING, "%s: %m", path);
+ continue;
+ }
+#if ENDIAN != BIG_ENDIAN
+ {
+ int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
+ struct whoent *we;
+
+ /* undo header byte swapping before writing to file */
+ wd.wd_sendtime = ntohl(wd.wd_sendtime);
+ for (i = 0; i < 3; i++)
+ wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
+ wd.wd_boottime = ntohl(wd.wd_boottime);
+ we = wd.wd_we;
+ for (i = 0; i < n; i++) {
+ we->we_idle = ntohl(we->we_idle);
+ we->we_utmp.out_time =
+ ntohl(we->we_utmp.out_time);
+ we++;
+ }
+ }
+#endif
+ (void) time((time_t *)&wd.wd_recvtime);
+ (void) write(whod, (char *)&wd, cc);
+ if (fstat(whod, &st) < 0 || st.st_size > cc)
+ ftruncate(whod, cc);
+ (void) close(whod);
+ }
+}
+
+/*
+ * Check out host name for unprintables
+ * and other funnies before allowing a file
+ * to be created. Sorry, but blanks aren't allowed.
+ */
+int
+verify(name)
+ register char *name;
+{
+ register int size = 0;
+
+ while (*name) {
+ if (!isascii(*name) || !(isalnum(*name) || ispunct(*name)))
+ return (0);
+ name++, size++;
+ }
+ return (size > 0);
+}
+
+int utmptime;
+int utmpent;
+int utmpsize = 0;
+struct utmp *utmp;
+int alarmcount;
+
+void
+onalrm(signo)
+ int signo;
+{
+ register struct neighbor *np;
+ register struct whoent *we = mywd.wd_we, *wlast;
+ register int i;
+ struct stat stb;
+ double avenrun[3];
+ time_t now;
+ int cc;
+
+ now = time(NULL);
+ if (alarmcount % 10 == 0)
+ getboottime(0);
+ alarmcount++;
+ (void) fstat(utmpf, &stb);
+ if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
+ utmptime = stb.st_mtime;
+ if (stb.st_size > utmpsize) {
+ utmpsize = stb.st_size + 10 * sizeof(struct utmp);
+ if (utmp)
+ utmp = (struct utmp *)realloc(utmp, utmpsize);
+ else
+ utmp = (struct utmp *)malloc(utmpsize);
+ if (! utmp) {
+ fprintf(stderr, "rwhod: malloc failed\n");
+ utmpsize = 0;
+ goto done;
+ }
+ }
+ (void) lseek(utmpf, (off_t)0, L_SET);
+ cc = read(utmpf, (char *)utmp, stb.st_size);
+ if (cc < 0) {
+ fprintf(stderr, "rwhod: %s: %s\n",
+ _PATH_UTMP, strerror(errno));
+ goto done;
+ }
+ wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1];
+ utmpent = cc / sizeof(struct utmp);
+ for (i = 0; i < utmpent; i++)
+ if (utmp[i].ut_name[0]) {
+ memcpy(we->we_utmp.out_line, utmp[i].ut_line,
+ sizeof(utmp[i].ut_line));
+ memcpy(we->we_utmp.out_name, utmp[i].ut_name,
+ sizeof(utmp[i].ut_name));
+ we->we_utmp.out_time = htonl(utmp[i].ut_time);
+ if (we >= wlast)
+ break;
+ we++;
+ }
+ utmpent = we - mywd.wd_we;
+ }
+
+ /*
+ * The test on utmpent looks silly---after all, if no one is
+ * logged on, why worry about efficiency?---but is useful on
+ * (e.g.) compute servers.
+ */
+ if (utmpent && chdir(_PATH_DEV)) {
+ syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV);
+ exit(1);
+ }
+ we = mywd.wd_we;
+ for (i = 0; i < utmpent; i++) {
+ if (stat(we->we_utmp.out_line, &stb) >= 0)
+ we->we_idle = htonl(now - stb.st_atime);
+ we++;
+ }
+ (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
+ for (i = 0; i < 3; i++)
+ mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
+ cc = (char *)we - (char *)&mywd;
+ mywd.wd_sendtime = htonl(time(0));
+ mywd.wd_vers = WHODVERSION;
+ mywd.wd_type = WHODTYPE_STATUS;
+ for (np = neighbors; np != NULL; np = np->n_next)
+ (void)sendto(s, (char *)&mywd, cc, 0,
+ np->n_addr, np->n_addrlen);
+ if (utmpent && chdir(_PATH_RWHODIR)) {
+ syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
+ exit(1);
+ }
+done:
+ (void) alarm(AL_INTERVAL);
+}
+
+void
+getboottime(signo)
+ int signo;
+{
+ int mib[2];
+ size_t size;
+ struct timeval tm;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ size = sizeof(tm);
+ if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) {
+ syslog(LOG_ERR, "cannot get boottime: %m");
+ exit(1);
+ }
+ mywd.wd_boottime = htonl(tm.tv_sec);
+}
+
+void
+quit(msg)
+ char *msg;
+{
+ syslog(LOG_ERR, msg);
+ exit(1);
+}
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+void
+rt_xaddrs(cp, cplim, rtinfo)
+ register caddr_t cp, cplim;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct sockaddr *sa;
+ register int i;
+
+ memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
+/*
+ * Figure out device configuration and select
+ * networks which deserve status information.
+ */
+int
+configure(s)
+ int s;
+{
+ register struct neighbor *np;
+ register struct if_msghdr *ifm;
+ register struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ size_t needed;
+ int mib[6], flags = 0, len;
+ char *buf, *lim, *next;
+ struct rt_addrinfo info;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ quit("route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ quit("malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ quit("actual retrieval of interface table");
+ lim = buf + needed;
+
+ sdl = NULL; /* XXX just to keep gcc -Wall happy */
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ flags = ifm->ifm_flags;
+ continue;
+ }
+ if ((flags & IFF_UP) == 0 ||
+ (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
+ continue;
+ if (ifm->ifm_type != RTM_NEWADDR)
+ quit("out of sync parsing NET_RT_IFLIST");
+ ifam = (struct ifa_msghdr *)ifm;
+ info.rti_addrs = ifam->ifam_addrs;
+ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
+ &info);
+ /* gag, wish we could get rid of Internet dependencies */
+#define dstaddr info.rti_info[RTAX_BRD]
+#define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr
+#define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port
+ if (dstaddr == 0 || dstaddr->sa_family != AF_INET)
+ continue;
+ PORT_SA(dstaddr) = sp->s_port;
+ for (np = neighbors; np != NULL; np = np->n_next)
+ if (memcmp(sdl->sdl_data, np->n_name,
+ sdl->sdl_nlen) == 0 &&
+ IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr))
+ break;
+ if (np != NULL)
+ continue;
+ len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1;
+ np = (struct neighbor *)malloc(len);
+ if (np == NULL)
+ quit("malloc of neighbor structure");
+ memset(np, 0, len);
+ np->n_flags = flags;
+ np->n_addr = (struct sockaddr *)(np + 1);
+ np->n_addrlen = dstaddr->sa_len;
+ np->n_name = np->n_addrlen + (char *)np->n_addr;
+ np->n_next = neighbors;
+ neighbors = np;
+ memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen);
+ memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen);
+ }
+ free(buf);
+ return (1);
+}
+
+#ifdef DEBUG
+void
+Sendto(s, buf, cc, flags, to, tolen)
+ int s;
+ char *buf;
+ int cc, flags;
+ char *to;
+ int tolen;
+{
+ register struct whod *w = (struct whod *)buf;
+ register struct whoent *we;
+ struct sockaddr_in *sin = (struct sockaddr_in *)to;
+
+ printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
+ printf("hostname %s %s\n", w->wd_hostname,
+ interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));
+ printf("load %4.2f, %4.2f, %4.2f\n",
+ ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
+ ntohl(w->wd_loadav[2]) / 100.0);
+ cc -= WHDRSIZE;
+ for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) {
+ time_t t = ntohl(we->we_utmp.out_time);
+ printf("%-8.8s %s:%s %.12s",
+ we->we_utmp.out_name,
+ w->wd_hostname, we->we_utmp.out_line,
+ ctime(&t)+4);
+ we->we_idle = ntohl(we->we_idle) / 60;
+ if (we->we_idle) {
+ if (we->we_idle >= 100*60)
+ we->we_idle = 100*60 - 1;
+ if (we->we_idle >= 60)
+ printf(" %2d", we->we_idle / 60);
+ else
+ printf(" ");
+ printf(":%02d", we->we_idle % 60);
+ }
+ printf("\n");
+ }
+}
+
+char *
+interval(time, updown)
+ int time;
+ char *updown;
+{
+ static char resbuf[32];
+ int days, hours, minutes;
+
+ if (time < 0 || time > 3*30*24*60*60) {
+ (void) sprintf(resbuf, " %s ??:??", updown);
+ return (resbuf);
+ }
+ minutes = (time + 59) / 60; /* round to minutes */
+ hours = minutes / 60; minutes %= 60;
+ days = hours / 24; hours %= 24;
+ if (days)
+ (void) sprintf(resbuf, "%s %2d+%02d:%02d",
+ updown, days, hours, minutes);
+ else
+ (void) sprintf(resbuf, "%s %2d:%02d",
+ updown, hours, minutes);
+ return (resbuf);
+}
+#endif
diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile
new file mode 100644
index 00000000000..4a44cc10948
--- /dev/null
+++ b/usr.sbin/sa/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+
+PROG= sa
+MAN= sa.8
+SRCS= main.c pdb.c usrdb.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h
new file mode 100644
index 00000000000..e3d031ae17a
--- /dev/null
+++ b/usr.sbin/sa/extern.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: extern.h,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <db.h>
+
+/* structures */
+
+struct cmdinfo {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ u_long ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
+
+struct userinfo {
+ u_long ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/* typedefs */
+
+typedef int (*cmpf_t) __P((const DBT *, const DBT *));
+
+/* external functions in sa.c */
+int main __P((int, char **));
+
+/* external functions in pdb.c */
+int pacct_init __P((void));
+void pacct_destroy __P((void));
+int pacct_add __P((const struct cmdinfo *));
+int pacct_update __P((void));
+void pacct_print __P((void));
+
+/* external functions in usrdb.c */
+int usracct_init __P((void));
+void usracct_destroy __P((void));
+int usracct_add __P((const struct cmdinfo *));
+int usracct_update __P((void));
+void usracct_print __P((void));
+
+/* variables */
+
+extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+extern int cutoff;
+extern cmpf_t sa_cmp;
+
+/* some #defines to help with db's stupidity */
+
+#define DB_CLOSE(db) \
+ ((*(db)->close)(db))
+#define DB_GET(db, key, data, flags) \
+ ((*(db)->get)((db), (key), (data), (flags)))
+#define DB_PUT(db, key, data, flags) \
+ ((*(db)->put)((db), (key), (data), (flags)))
+#define DB_SYNC(db, flags) \
+ ((*(db)->sync)((db), (flags)))
+#define DB_SEQ(db, key, data, flags) \
+ ((*(db)->seq)((db), (key), (data), (flags)))
diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c
new file mode 100644
index 00000000000..c42482e2d11
--- /dev/null
+++ b/usr.sbin/sa/main.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char copright[] =
+"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
+ All rights reserved.\n";
+
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $";
+#endif
+
+/*
+ * sa: system accounting
+ */
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int acct_load __P((char *, int));
+static u_quad_t decode_comp_t __P((comp_t));
+static int cmp_comm __P((const char *, const char *));
+static int cmp_usrsys __P((const DBT *, const DBT *));
+static int cmp_avgusrsys __P((const DBT *, const DBT *));
+static int cmp_dkio __P((const DBT *, const DBT *));
+static int cmp_avgdkio __P((const DBT *, const DBT *));
+static int cmp_cpumem __P((const DBT *, const DBT *));
+static int cmp_avgcpumem __P((const DBT *, const DBT *));
+static int cmp_calls __P((const DBT *, const DBT *));
+
+int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+int cutoff = 1;
+
+static char *dfltargv[] = { _PATH_ACCT };
+static int dfltargc = (sizeof(dfltargv)/sizeof(char *));
+
+/* default to comparing by sum of user + system time */
+cmpf_t sa_cmp = cmp_usrsys;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char ch;
+ int error;
+
+ while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1)
+ switch (ch) {
+ case 'a':
+ /* print all commands */
+ aflag = 1;
+ break;
+ case 'b':
+ /* sort by per-call user/system time average */
+ bflag = 1;
+ sa_cmp = cmp_avgusrsys;
+ break;
+ case 'c':
+ /* print percentage total time */
+ cflag = 1;
+ break;
+ case 'd':
+ /* sort by averge number of disk I/O ops */
+ dflag = 1;
+ sa_cmp = cmp_avgdkio;
+ break;
+ case 'D':
+ /* print and sort by total disk I/O ops */
+ Dflag = 1;
+ sa_cmp = cmp_dkio;
+ break;
+ case 'f':
+ /* force no interactive threshold comprison */
+ fflag = 1;
+ break;
+ case 'i':
+ /* do not read in summary file */
+ iflag = 1;
+ break;
+ case 'j':
+ /* instead of total minutes, give sec/call */
+ jflag = 1;
+ break;
+ case 'k':
+ /* sort by cpu-time average memory usage */
+ kflag = 1;
+ sa_cmp = cmp_avgcpumem;
+ break;
+ case 'K':
+ /* print and sort by cpu-storage integral */
+ sa_cmp = cmp_cpumem;
+ Kflag = 1;
+ break;
+ case 'l':
+ /* seperate system and user time */
+ lflag = 1;
+ break;
+ case 'm':
+ /* print procs and time per-user */
+ mflag = 1;
+ break;
+ case 'n':
+ /* sort by number of calls */
+ sa_cmp = cmp_calls;
+ break;
+ case 'q':
+ /* quiet; error messages only */
+ qflag = 1;
+ break;
+ case 'r':
+ /* reverse order of sort */
+ rflag = 1;
+ break;
+ case 's':
+ /* merge accounting file into summaries */
+ sflag = 1;
+ break;
+ case 't':
+ /* report ratio of user and system times */
+ tflag = 1;
+ break;
+ case 'u':
+ /* first, print uid and command name */
+ uflag = 1;
+ break;
+ case 'v':
+ /* cull junk */
+ vflag = 1;
+ cutoff = atoi(optarg);
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+ "usage: sa [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n");
+ exit(1);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* various argument checking */
+ if (fflag && !vflag)
+ errx(1, "only one of -f requires -v");
+ if (fflag && aflag)
+ errx(1, "only one of -a and -v may be specified");
+ /* XXX need more argument checking */
+
+ if (!uflag) {
+ /* initialize tables */
+ if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
+ errx(1, "process accounting initialization failed");
+ if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
+ errx(1, "user accounting initialization failed");
+ }
+
+ if (argc == 0) {
+ argc = dfltargc;
+ argv = dfltargv;
+ }
+
+ /* for each file specified */
+ for (; argc > 0; argc--, argv++) {
+ int fd;
+
+ /*
+ * load the accounting data from the file.
+ * if it fails, go on to the next file.
+ */
+ fd = acct_load(argv[0], sflag);
+ if (fd < 0)
+ continue;
+
+ if (!uflag && sflag) {
+#ifndef DEBUG
+ sigset_t nmask, omask;
+ int unmask = 1;
+
+ /*
+ * block most signals so we aren't interrupted during
+ * the update.
+ */
+ if (sigfillset(&nmask) == -1) {
+ warn("sigfillset");
+ unmask = 0;
+ error = 1;
+ }
+ if (unmask &&
+ (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
+ warn("couldn't set signal mask ");
+ unmask = 0;
+ error = 1;
+ }
+#endif /* DEBUG */
+
+ /*
+ * truncate the accounting data file ASAP, to avoid
+ * losing data. don't worry about errors in updating
+ * the saved stats; better to underbill than overbill,
+ * but we want every accounting record intact.
+ */
+ if (ftruncate(fd, 0) == -1) {
+ warn("couldn't truncate %s", argv);
+ error = 1;
+ }
+
+ /*
+ * update saved user and process accounting data.
+ * note errors for later.
+ */
+ if (pacct_update() != 0 || usracct_update() != 0)
+ error = 1;
+
+#ifndef DEBUG
+ /*
+ * restore signals
+ */
+ if (unmask &&
+ (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
+ warn("couldn't restore signal mask");
+ error = 1;
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * close the opened accounting file
+ */
+ if (close(fd) == -1) {
+ warn("close %s", argv);
+ error = 1;
+ }
+ }
+
+ if (!uflag && !qflag) {
+ /* print any results we may have obtained. */
+ if (!mflag)
+ pacct_print();
+ else
+ usracct_print();
+ }
+
+ if (!uflag) {
+ /* finally, deallocate databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_destroy();
+ if (sflag || (mflag && !qflag))
+ usracct_destroy();
+ }
+
+ exit(error);
+}
+
+static int
+acct_load(pn, wr)
+ char *pn;
+ int wr;
+{
+ struct acct ac;
+ struct cmdinfo ci;
+ ssize_t rv;
+ int fd, i;
+
+ /*
+ * open the file
+ */
+ fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
+ if (fd == -1) {
+ warn("open %s %s", pn, wr ? "for read/write" : "read-only");
+ return (-1);
+ }
+
+ /*
+ * read all we can; don't stat and open because more processes
+ * could exit, and we'd miss them
+ */
+ while (1) {
+ /* get one accounting entry and punt if there's an error */
+ rv = read(fd, &ac, sizeof(struct acct));
+ if (rv == -1)
+ warn("error reading %s", pn);
+ else if (rv > 0 && rv < sizeof(struct acct))
+ warnx("short read of accounting data in %s", pn);
+ if (rv != sizeof(struct acct))
+ break;
+
+ /* decode it */
+ ci.ci_calls = 1;
+ for (i = 0; i < sizeof(ac.ac_comm) && ac.ac_comm[i] != '\0';
+ i++) {
+ char c = ac.ac_comm[i];
+
+ if (!isascii(c) || iscntrl(c)) {
+ ci.ci_comm[i] = '?';
+ ci.ci_flags |= CI_UNPRINTABLE;
+ } else
+ ci.ci_comm[i] = c;
+ }
+ if (ac.ac_flag & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = decode_comp_t(ac.ac_etime);
+ ci.ci_utime = decode_comp_t(ac.ac_utime);
+ ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+
+ if (!uflag) {
+ /* and enter it into the usracct and pacct databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_add(&ci);
+ if (sflag || (mflag && !qflag))
+ usracct_add(&ci);
+ } else if (!qflag)
+ printf("%6u %12.2lf cpu %12quk mem %12qu io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / (double) AHZ,
+ ci.ci_mem, ci.ci_io, ci.ci_comm);
+ }
+
+ /* finally, return the file descriptor for possible truncation */
+ return (fd);
+}
+
+static u_quad_t
+decode_comp_t(comp)
+ comp_t comp;
+{
+ u_quad_t rv;
+
+ /*
+ * for more info on the comp_t format, see:
+ * /usr/src/sys/kern/kern_acct.c
+ * /usr/src/sys/sys/acct.h
+ * /usr/src/usr.bin/lastcomm/lastcomm.c
+ */
+ rv = comp & 0x1fff; /* 13 bit fraction */
+ comp >>= 13; /* 3 bit base-8 exponent */
+ while (comp--)
+ rv <<= 3;
+
+ return (rv);
+}
+
+/* sort commands, doing the right thing in terms of reversals */
+static int
+cmp_comm(s1, s2)
+ const char *s1, *s2;
+{
+ int rv;
+
+ rv = strcmp(s1, s2);
+ if (rv == 0)
+ rv = -1;
+ return (rflag ? rv : -rv);
+}
+
+/* sort by total user and system time */
+static int
+cmp_usrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+ u_quad_t t1, t2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average user and system time */
+static int
+cmp_avgusrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+ double t1, t2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
+
+ t2 = c2.ci_utime + c2.ci_stime;
+ t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by total number of disk I/O operations */
+static int
+cmp_dkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_io < c2.ci_io)
+ return -1;
+ else if (c1.ci_io == c2.ci_io)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average number of disk I/O operations */
+static int
+cmp_avgdkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-storage integral */
+static int
+cmp_cpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_mem < c2.ci_mem)
+ return -1;
+ else if (c1.ci_mem == c2.ci_mem)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-time average memory usage */
+static int
+cmp_avgcpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+ u_quad_t t1, t2;
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+ n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
+ n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the number of invocations */
+static int
+cmp_calls(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_calls < c2.ci_calls)
+ return -1;
+ else if (c1.ci_calls == c2.ci_calls)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
diff --git a/usr.sbin/sa/pathnames.h b/usr.sbin/sa/pathnames.h
new file mode 100644
index 00000000000..d5671a147f4
--- /dev/null
+++ b/usr.sbin/sa/pathnames.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+ */
+
+#define _PATH_ACCT "/var/account/acct"
+#define _PATH_SAVACCT "/var/account/savacct"
+#define _PATH_USRACCT "/var/account/usracct"
diff --git a/usr.sbin/sa/pdb.c b/usr.sbin/sa/pdb.c
new file mode 100644
index 00000000000..57af0114b73
--- /dev/null
+++ b/usr.sbin/sa/pdb.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: pdb.c,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int check_junk __P((struct cmdinfo *));
+static void add_ci __P((const struct cmdinfo *, struct cmdinfo *));
+static void print_ci __P((const struct cmdinfo *, const struct cmdinfo *));
+
+static DB *pacct_db;
+
+int
+pacct_init()
+{
+ DB *saved_pacct_db;
+ int error;
+
+ pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
+ if (pacct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
+ NULL);
+ if (saved_pacct_db == NULL) {
+ error = errno == ENOENT ? 0 : -1;
+ if (error)
+ warn("retrieving process accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing process accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout: if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ }
+
+out: if (error != 0)
+ pacct_destroy();
+ return (error);
+}
+
+void
+pacct_destroy()
+{
+ if (DB_CLOSE(pacct_db) < 0)
+ warn("destroying process accounting stats");
+}
+
+int
+pacct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct cmdinfo newci;
+ char keydata[sizeof(ci->ci_comm)];
+ int rv;
+
+ memcpy(&keydata, ci->ci_comm, sizeof(keydata));
+ key.data = &keydata;
+ key.size = strlen(keydata);
+
+ rv = DB_GET(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %s from process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* XXX compare size if paranoid */
+ /* add the old data to the new data */
+ memcpy(&newci, data.data, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ memset(&newci, 0, sizeof(newci));
+ memcpy(newci.ci_comm, key.data, key.size);
+ }
+
+ add_ci(ci, &newci);
+
+ data.data = &newci;
+ data.size = sizeof(newci);
+ rv = DB_PUT(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %s to process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 1) {
+ warnx("duplicate key %s in process accounting stats",
+ ci->ci_comm);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pacct_update()
+{
+ DB *saved_pacct_db;
+ DBT key, data;
+ int error, serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, NULL);
+ if (saved_pacct_db == NULL) {
+ warn("creating process accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving process accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_pacct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+ if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+pacct_print()
+{
+ BTREEINFO bti;
+ DBT key, data, ndata;
+ DB *output_pacct_db;
+ struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
+ int rv;
+
+ memset(&ci_total, 0, sizeof(ci_total));
+ strcpy(ci_total.ci_comm, "");
+ memset(&ci_other, 0, sizeof(ci_other));
+ strcpy(ci_other.ci_comm, "***other");
+ memset(&ci_junk, 0, sizeof(ci_junk));
+ strcpy(ci_junk.ci_comm, "**junk**");
+
+ /*
+ * Retrieve them into new DB, sorted by appropriate key.
+ * At the same time, cull 'other' and 'junk'
+ */
+ memset(&bti, 0, sizeof(bti));
+ bti.compare = sa_cmp;
+ output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (output_pacct_db == NULL) {
+ warn("couldn't sort process accounting stats");
+ return;
+ }
+
+ ndata.data = NULL;
+ ndata.size = 0;
+ rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ memcpy(&ci, cip, sizeof(ci));
+
+ /* add to total */
+ add_ci(&ci, &ci_total);
+
+ if (vflag && ci.ci_calls <= cutoff &&
+ (fflag || check_junk(&ci))) {
+ /* put it into **junk** */
+ add_ci(&ci, &ci_junk);
+ goto next;
+ }
+ if (!aflag &&
+ ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
+ /* put into ***other */
+ add_ci(&ci, &ci_other);
+ goto next;
+ }
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+
+next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ }
+
+ /* insert **junk** and ***other */
+ if (ci_junk.ci_calls != 0) {
+ data.data = &ci_junk;
+ data.size = sizeof(ci_junk);
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+ if (ci_other.ci_calls != 0) {
+ data.data = &ci_other;
+ data.size = sizeof(ci_other);
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+
+ /* print out the total */
+ print_ci(&ci_total, &ci_total);
+
+ /* print out; if reversed, print first (smallest) first */
+ rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ memcpy(&ci, cip, sizeof(ci));
+
+ print_ci(&ci, &ci_total);
+
+ rv = DB_SEQ(output_pacct_db, &data, &ndata,
+ rflag ? R_NEXT : R_PREV);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ }
+ DB_CLOSE(output_pacct_db);
+}
+
+static int
+check_junk(cip)
+ struct cmdinfo *cip;
+{
+ char *cp;
+ size_t len;
+
+ fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls);
+ cp = fgetln(stdin, &len);
+
+ return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
+}
+
+static void
+add_ci(fromcip, tocip)
+ const struct cmdinfo *fromcip;
+ struct cmdinfo *tocip;
+{
+ tocip->ci_calls += fromcip->ci_calls;
+ tocip->ci_etime += fromcip->ci_etime;
+ tocip->ci_utime += fromcip->ci_utime;
+ tocip->ci_stime += fromcip->ci_stime;
+ tocip->ci_mem += fromcip->ci_mem;
+ tocip->ci_io += fromcip->ci_io;
+}
+
+static void
+print_ci(cip, totalcip)
+ const struct cmdinfo *cip, *totalcip;
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8qu ", cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_calls / (double) totalcip->ci_calls);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ else
+ printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_etime / (double) totalcip->ci_etime);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.2fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ (cip->ci_utime + cip->ci_stime) / (double)
+ (totalcip->ci_utime + totalcip->ci_stime));
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag)
+ if (!uflow)
+ printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
+ else
+ printf("%8 ", "*ignore*");
+
+ if (Dflag)
+ printf("%10qutio ", cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10quk*sec ", cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
diff --git a/usr.sbin/sa/sa.8 b/usr.sbin/sa/sa.8
new file mode 100644
index 00000000000..b8d58c1ec88
--- /dev/null
+++ b/usr.sbin/sa/sa.8
@@ -0,0 +1,246 @@
+.\"
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: sa.8,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $
+.\"
+.Dd February 25, 1994
+.Dt SA 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm sa
+.Nd print system accounting statistics
+.Sh SYNOPSIS
+.Nm sa
+.Op Fl abcdDfijkKlmnqrstu
+.Op Fl v Ar cutoff
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm sa
+utility reports on, cleans up,
+and generally maintains system
+accounting files.
+.Pp
+.Nm Sa
+is able to condense the information in
+.Pa /var/account/acct
+into the summary files
+.Pa /var/account/savacct
+and
+.Pa /var/account/usracct ,
+which contain system statistics according
+to command name and login id, respectively.
+This condensation is desirable because on a
+large system,
+.Pa /var/account/acct
+can grow by hundreds of blocks per day.
+The summary files are normally read before
+the accounting file, so that reports include
+all available information.
+.Pp
+If file names are supplied, they are read instead of
+.Pa /var/account/account .
+After each file is read, if the summary
+files are being updated, an updated summary will
+be saved to disk. Only one report is printed,
+after the last file is processed.
+.Pp
+The labels used in the output indicate the following, except
+where otherwise specified by individual options:
+.Bl -tag -width k*sec
+.It Dv avio
+Average number of I/O operations per execution
+.It Dv cp
+Sum of user and system time, in minutes
+.It Dv cpu
+Same as
+.Dv cp
+.It Dv k
+CPU-time averaged core usage, in 1k units
+.It Dv k*sec
+CPU storage integral, in 1k-core seconds
+.It Dv re
+Real time, in minutes
+.It Dv s
+System time, in minutes
+.It Dv tio
+Total number of I/O operations
+.It Dv u
+User time, in minutes
+.El
+.Pp
+The options to
+.Nm sa
+are:
+.Bl -tag -width Ds
+.It Fl a
+List all command names, including those containing unprintable
+characters and those used only once. By default,
+.Nm sa
+places all names containing unprintable characters and
+those used only once under the name ``***other''.
+.It Fl b
+If printing command statistics, sort output by the sum of user and system
+time divided by number of calls.
+.It Fl c
+In addition to the number of calls and the user, system and real times
+for each command, print their percentage of the total over all commands.
+.It Fl d
+If printing command statistics, sort by the average number of disk
+I/O operations. If printing user statistics, print the average number of
+disk I/O operations per user.
+.It Fl D
+If printing command statistics, sort and print by the total number
+of disk I/O operations.
+.It Fl f
+Force no interactive threshold comparison with the
+.Fl v
+option.
+.It Fl i
+Do not read in the summary files.
+.It Fl j
+Instead of the total minutes per category, give seconds per call.
+.It Fl k
+If printing command statistics, sort by the cpu-time average memory
+usage. If printing user statistics, print the cpu-time average
+memory usage.
+.It Fl K
+If printing command statistics, print and sort by the cpu-storage integral.
+.It Fl l
+Separate system and user time; normally they are combined.
+.It Fl m
+Print per-user statistics rather than per-command statistics.
+.It Fl n
+Sort by number of calls.
+.It Fl q
+Create no output other than error messages.
+.It Fl r
+Reverse order of sort.
+.It Fl s
+Truncate the accounting files when done and merge their data
+into the summary files.
+.It Fl t
+For each command, report the ratio of real time to the sum
+of user and system cpu times.
+If the cpu time is too small to report, ``*ignore*'' appears in
+this field.
+.It Fl u
+Superseding all other flags, for each entry
+in the accounting file, print the user ID, total seconds of cpu usage,
+total memory usage, number of I/O operations performed, and
+command name.
+.It Fl v Ar cutoff
+For each command used
+.Ar cutoff
+times or fewer, print the command name and await a reply
+from the terminal. If the reply begins with ``y'', add
+the command to the category ``**junk**''. This flag is
+used to strip garbage from the report.
+.El
+.Pp
+By default, per-command statistics will be printed. The number of
+calls, the total elapsed time in minutes, total cpu and user time
+in minutes, average number of I/O operations, and CPU-time
+averaged core usage will be printed. If the
+.Fl m
+option is specified, per-user statistics will be printed, including
+the user name, the number of commands invoked, total cpu time used
+(in minutes), total number of I/O operations, and CPU storage integral
+for each user. If the
+.Fl u
+option is specified, the uid, user and system time (in seconds),
+CPU storage integral, I/O usage, and command name will be printed
+for each entry in the accounting data file.
+.Pp
+If the
+.Fl u
+flag is specified, all flags other than
+.Fl q
+are ignored. If the
+.Fl m
+flag is specified, only the
+.Fl b ,
+.Fl d ,
+.Fl i ,
+.Fl k ,
+.Fl q ,
+and
+.Fl s
+flags are honored.
+.Pp
+The
+.Nm sa
+utility exits 0 on success, and >0 if an error occurs.
+.Sh FILES
+.Bl -tag -width /var/account/usracct -compact
+.It Pa /var/account/acct
+raw accounting data file
+.It Pa /var/account/savacct
+per-command accounting summary database
+.It Pa /var/account/usracct
+per-user accounting summary database
+.El
+.Sh SEE ALSO
+.Xr ac 8 ,
+.Xr acct 5 ,
+.Xr accton 8 ,
+.Xr lastcomm 1
+.Sh BUGS
+The number of options to this program is absurd, especially considering
+that there's not much logic behind their lettering.
+.Pp
+The field labels should be more consistent.
+.Pp
+NetBSD's VM system does not record the CPU storage integral.
+.Sh CAVEATS
+While the behavior of the options in this version of
+.Nm sa
+was modeled after the original version, there are some intentional
+differences and undoubtedly some unintentional ones as well. In
+particular, the
+.Fl q
+option has been added, and the
+.Fl m
+option now understands more options than it used to.
+.Pp
+The formats of the summary files created by this version of
+.Nm sa
+are very different than the those used by the original version.
+This is not considered a problem, however, because the accounting record
+format has changed as well (since user ids are now 32 bits).
+.Sh HISTORY
+.Nm Sa
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+Its date of origin is unknown to the author.
+.Sh AUTHOR
+.Bl -tag
+Chris G. Demetriou, cgd@postgres.berkeley.edu
+.El
diff --git a/usr.sbin/sa/usrdb.c b/usr.sbin/sa/usrdb.c
new file mode 100644
index 00000000000..fe7ecb99fc8
--- /dev/null
+++ b/usr.sbin/sa/usrdb.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: usrdb.c,v 1.1.1.1 1995/10/18 08:48:07 deraadt Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int uid_compare __P((const DBT *, const DBT *));
+
+static DB *usracct_db;
+
+int
+usracct_init()
+{
+ DB *saved_usracct_db;
+ BTREEINFO bti;
+ int error;
+
+ memset(&bti, 0, sizeof(bti));
+ bti.compare = uid_compare;
+
+ usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (usracct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
+ &bti);
+ if (saved_usracct_db == NULL) {
+ error = (errno == ENOENT) ? 0 : -1;
+ if (error)
+ warn("retrieving user accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing user accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing user accounting summary");
+ error = -1;
+ }
+ }
+
+out:
+ if (error != 0)
+ usracct_destroy();
+ return (error);
+}
+
+void
+usracct_destroy()
+{
+ if (DB_CLOSE(usracct_db) < 0)
+ warn("destroying user accounting stats");
+}
+
+int
+usracct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct userinfo newui;
+ u_long uid;
+ int rv;
+
+ uid = ci->ci_uid;
+ key.data = &uid;
+ key.size = sizeof(uid);
+
+ rv = DB_GET(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %d from user accounting stats", uid);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* add the old data to the new data */
+ memcpy(&newui, data.data, data.size);
+ if (newui.ui_uid != uid) {
+ warnx("key %d != expected record number %d",
+ newui.ui_uid, uid);
+ warnx("inconsistent user accounting stats");
+ return (-1);
+ }
+ } else { /* it's not there; zero it and copy the key */
+ memset(&newui, 0, sizeof(newui));
+ newui.ui_uid = ci->ci_uid;
+ }
+
+ newui.ui_calls += ci->ci_calls;
+ newui.ui_utime += ci->ci_utime;
+ newui.ui_stime += ci->ci_stime;
+ newui.ui_mem += ci->ci_mem;
+ newui.ui_io += ci->ci_io;
+
+ data.data = &newui;
+ data.size = sizeof(newui);
+ rv = DB_PUT(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %d to user accounting stats", uid);
+ return (-1);
+ } else if (rv != 0) {
+ warnx("DB_PUT returned 1");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+usracct_update()
+{
+ DB *saved_usracct_db;
+ DBT key, data;
+ BTREEINFO bti;
+ u_long uid;
+ int error, serr, nerr;
+
+ memset(&bti, 0, sizeof(bti));
+ bti.compare = uid_compare;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, &bti);
+ if (saved_usracct_db == NULL) {
+ warn("creating user accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving user accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_usracct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+out:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+usracct_print()
+{
+ DBT key, data;
+ struct userinfo uistore, *ui = &uistore;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ memcpy(ui, data.data, sizeof(struct userinfo));
+
+ printf("%-8s %9qu ",
+ user_from_uid(ui->ui_uid, 0), ui->ui_calls);
+
+ t = (double) (ui->ui_utime + ui->ui_stime) /
+ (double) AHZ;
+ if (t < 0.0001) /* kill divide by zero */
+ t = 0.0001;
+
+ printf("%12.2lf%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
+ else
+ printf("%12qu%s", ui->ui_io, "tio");
+
+ /* t is always >= 0.0001; see above */
+ if (kflag)
+ printf("%12qu%s", ui->ui_mem / t, "k");
+ else
+ printf("%12qu%s", ui->ui_mem, "k*sec");
+
+ printf("\n");
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+ }
+}
+
+static int
+uid_compare(k1, k2)
+ const DBT *k1, *k2;
+{
+ u_long d1, d2;
+
+ memcpy(&d1, k1->data, sizeof(d1));
+ memcpy(&d2, k2->data, sizeof(d2));
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
diff --git a/usr.sbin/screenblank/Makefile b/usr.sbin/screenblank/Makefile
new file mode 100644
index 00000000000..e9a0acce9a6
--- /dev/null
+++ b/usr.sbin/screenblank/Makefile
@@ -0,0 +1,9 @@
+# $NetBSD: Makefile,v 1.1 1995/07/12 04:57:47 thorpej Exp $
+# @(#)Makefile 8.1 (Berkeley) 5/31/93
+
+PROG= screenblank
+
+DPADD= ${LIBM}
+LDADD= -lm
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/screenblank/pathnames.h b/usr.sbin/screenblank/pathnames.h
new file mode 100644
index 00000000000..5446d7073b9
--- /dev/null
+++ b/usr.sbin/screenblank/pathnames.h
@@ -0,0 +1,38 @@
+/* $NetBSD: pathnames.h,v 1.1 1995/07/12 04:57:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _PATH_SCREENBLANKPID "/var/run/screenblank.pid"
+#define _PATH_KEYBOARD "/dev/kbd"
+#define _PATH_MOUSE "/dev/mouse"
+#define _PATH_FB "/dev/fb"
diff --git a/usr.sbin/screenblank/screenblank.1 b/usr.sbin/screenblank/screenblank.1
new file mode 100644
index 00000000000..b61b727fcdc
--- /dev/null
+++ b/usr.sbin/screenblank/screenblank.1
@@ -0,0 +1,97 @@
+.\" $NetBSD: screenblank.1,v 1.1 1995/07/12 04:57:50 thorpej Exp $
+.\"
+.\" Copyright (c) 1995 Jason R. Thorpe.
+.\" 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 for the NetBSD Project
+.\" by Jason R. Thorpe.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd June 7, 1995
+.Dt SCREENBLANK 1
+.Os
+.Sh NAME
+.Nm screenblank
+.Nd screen saver daemon for the Sun 3 and SPARC
+.Sh SYNOPSIS
+.Nm screenblank
+.Op Fl k | Fl m
+.Op Fl d Ar timeout
+.Op Fl e Ar timeout
+.Op Fl f Ar framebuffer
+.Sh DESCRIPTION
+.Nm Screenblank
+disables the framebuffer if the keyboard and mouse are idle for a period
+of time, and re-enables the framebuffer when keyboard or mouse activity
+resumes.
+.Pp
+When killed with a SIGINT, SIGHUP, or SIGTERM,
+.Nm screenblank
+will re-enable the framebuffer. The pid can be found in the file
+.Pa /var/run/screenblank.pid .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl k
+Do not check the keyboard for activity.
+.It Fl m
+Do not check the mouse for activity.
+.It Fl d Ar timeout
+Wait the number of seconds specified by
+.Ar timeout ,
+expressed in the format `xxx.xxx', before disabling the framebuffer due to
+inactivity. The default is 600 seconds (10 minutes).
+.It Fl e Ar timeout
+Wait the number of seconds specified by
+.Ar timeout ,
+expressed in the format `xxx.xxx', before re-enabling the framebuffer once
+activity resumes. The default is .25 seconds.
+.It Fl f Ar framebuffer
+Use the framebuffer device
+.Ar framebuffer
+instead of the default
+.Pa /dev/fb .
+.El
+.Pp
+Note that the
+.Fl k
+and
+.Fl m
+flags are mutually exclusive.
+.Sh FILES
+.Bl -tag -width "/var/run/screenblank.pid "
+.It /dev/kbd
+The keyboard device.
+.It /dev/mouse
+The mouse device.
+.It /dev/console
+The console device.
+.It /dev/fb
+The default framebuffer.
+.It /var/run/screenblank.pid
+File containing the pid of
+.Nm screenblank .
+.El
diff --git a/usr.sbin/screenblank/screenblank.c b/usr.sbin/screenblank/screenblank.c
new file mode 100644
index 00000000000..dcd5d59ad6c
--- /dev/null
+++ b/usr.sbin/screenblank/screenblank.c
@@ -0,0 +1,321 @@
+/* $NetBSD: screenblank.c,v 1.1 1995/07/12 04:57:51 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Screensaver daemon for the Sun 3 and SPARC.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <machine/fbio.h>
+
+#include "pathnames.h"
+
+struct dev_stat {
+ LIST_ENTRY(dev_stat) ds_link; /* linked list */
+ char *ds_path; /* path to device */
+ int ds_isfb; /* boolean; framebuffer? */
+ time_t ds_atime; /* time device last accessed */
+ time_t ds_mtime; /* time device last modified */
+};
+LIST_HEAD(ds_list, dev_stat) ds_list;
+
+extern char *__progname;
+
+static void add_dev __P((char *, int));
+static void change_state __P((int));
+static void cvt_arg __P((char *, struct timeval *));
+static void logpid __P((void));
+static void sighandler __P((int, int, struct sigcontext *));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct dev_stat *dsp;
+ struct timeval timo_on, timo_off, *tvp;
+ struct sigaction sa;
+ struct stat st;
+ int ch, change, fflag = 0, kflag = 0, mflag = 0, state;
+
+ LIST_INIT(&ds_list);
+
+ /*
+ * Set the default timeouts: 10 minutes on, .25 seconds off.
+ */
+ timo_on.tv_sec = 600;
+ timo_on.tv_usec = 0;
+ timo_off.tv_sec = 0;
+ timo_off.tv_usec = 250000;
+
+ while ((ch = getopt(argc, argv, "d:e:f:km")) != -1) {
+ switch (ch) {
+ case 'd':
+ cvt_arg(optarg, &timo_on);
+ break;
+
+ case 'e':
+ cvt_arg(optarg, &timo_off);
+ break;
+
+ case 'f':
+ fflag = 1;
+ add_dev(optarg, 1);
+ break;
+
+ case 'k':
+ if (mflag || kflag)
+ usage();
+ kflag = 1;
+ break;
+
+ case 'm':
+ if (kflag || mflag)
+ usage();
+ mflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ if (argc)
+ usage();
+
+ /*
+ * Add the keyboard, mouse, and default framebuffer devices
+ * as necessary. We _always_ check the console device.
+ */
+ add_dev(_PATH_CONSOLE, 0);
+ if (!kflag)
+ add_dev(_PATH_KEYBOARD, 0);
+ if (!mflag)
+ add_dev(_PATH_MOUSE, 0);
+ if (!fflag)
+ add_dev(_PATH_FB, 1);
+
+ /* Ensure that the framebuffer is on. */
+ state = FBVIDEO_ON;
+ change_state(state);
+ tvp = &timo_on;
+
+ /*
+ * Make sure the framebuffer gets turned back on when we're
+ * killed.
+ */
+ sa.sa_handler = sighandler;
+ sa.sa_mask = 0;
+ sa.sa_flags = SA_NOCLDSTOP;
+ if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL) ||
+ sigaction(SIGHUP, &sa, NULL))
+ err(1, "sigaction");
+
+ /* Detach. */
+ if (daemon(0, 0))
+ err(1, "daemon");
+ logpid();
+
+ /* Start the state machine. */
+ for (;;) {
+ change = 0;
+ for (dsp = ds_list.lh_first; dsp != NULL;
+ dsp = dsp->ds_link.le_next) {
+ /* Don't check framebuffers. */
+ if (dsp->ds_isfb)
+ continue;
+ if (stat(dsp->ds_path, &st) < 0)
+ err(1, "stat: %s", dsp->ds_path);
+ if (st.st_atime > dsp->ds_atime) {
+ change = 1;
+ dsp->ds_atime = st.st_atime;
+ }
+ if (st.st_mtime > dsp->ds_mtime) {
+ change = 1;
+ dsp->ds_mtime = st.st_mtime;
+ }
+ }
+
+ switch (state) {
+ case FBVIDEO_ON:
+ if (!change) {
+ state = FBVIDEO_OFF;
+ change_state(state);
+ tvp = &timo_off;
+ }
+ break;
+
+ case FBVIDEO_OFF:
+ if (change) {
+ state = FBVIDEO_ON;
+ change_state(state);
+ tvp = &timo_on;
+ }
+ break;
+ }
+
+ if (select(0, NULL, NULL, NULL, tvp) < 0)
+ err(1, "select");
+ }
+ /* NOTREACHED */
+}
+
+static void
+add_dev(path, isfb)
+ char *path;
+ int isfb;
+{
+ struct dev_stat *dsp1, *dsp2;
+
+ /* Create the entry... */
+ dsp1 = malloc(sizeof(struct dev_stat));
+ if (dsp1 == NULL)
+ errx(1, "can't allocate memory for %s", path);
+ bzero(dsp1, sizeof(struct dev_stat));
+ dsp1->ds_path = path;
+ dsp1->ds_isfb = isfb;
+
+ /* ...and put it in the list. */
+ if (ds_list.lh_first == NULL) {
+ LIST_INSERT_HEAD(&ds_list, dsp1, ds_link);
+ } else {
+ for (dsp2 = ds_list.lh_first; dsp2->ds_link.le_next != NULL;
+ dsp2 = dsp2->ds_link.le_next)
+ /* Nothing. */ ;
+ LIST_INSERT_AFTER(dsp2, dsp1, ds_link);
+ }
+}
+
+/* ARGSUSED */
+static void
+sighandler(sig, code, context)
+ int sig, code;
+ struct sigcontext *context;
+{
+
+ /* Kill the pid file and re-enable the framebuffer before exit. */
+ (void)unlink(_PATH_SCREENBLANKPID);
+ change_state(FBVIDEO_ON);
+ exit(0);
+}
+
+static void
+change_state(state)
+ int state;
+{
+ struct dev_stat *dsp;
+ int fd;
+
+ for (dsp = ds_list.lh_first; dsp != NULL; dsp = dsp->ds_link.le_next) {
+ /* Don't change the state of non-framebuffers! */
+ if (dsp->ds_isfb == 0)
+ continue;
+ if ((fd = open(dsp->ds_path, O_RDWR, 0)) < 0) {
+ warn("open: %s", dsp->ds_path);
+ continue;
+ }
+ if (ioctl(fd, FBIOSVIDEO, &state) < 0)
+ warn("ioctl: %s", dsp->ds_path);
+ (void)close(fd);
+ }
+}
+
+static void
+cvt_arg(arg, tvp)
+ char *arg;
+ struct timeval *tvp;
+{
+ char *cp;
+ double seconds = 0.0, exponent = -1.0;
+ int period = 0;
+
+ for (cp = arg; *cp != '\0'; ++cp) {
+ if (*cp == '.') {
+ if (period)
+ errx(1, "invalid argument: %s", arg);
+ period = 1;
+ continue;
+ }
+
+ if (!isdigit(*cp))
+ errx(1, "invalid argument: %s", arg);
+
+ if (period) {
+ seconds = seconds + ((*cp - '0') * pow(10.0, exponent));
+ exponent -= 1.0;
+ } else
+ seconds = (seconds * 10.0) + (*cp - '0');
+ }
+
+ tvp->tv_sec = (long)seconds;
+ tvp->tv_usec = (long)((seconds - tvp->tv_sec) * 1000000);
+}
+
+static void
+logpid()
+{
+ FILE *fp;
+
+ if ((fp = fopen(_PATH_SCREENBLANKPID, "w")) != NULL) {
+ fprintf(fp, "%u\n", getpid());
+ (void)fclose(fp);
+ }
+}
+
+static void
+usage()
+{
+
+ fprintf(stderr, "usage: %s [-k | -m] [-d timeout] [-e timeout] %s\n",
+ __progname, "[-f framebuffer]");
+ exit(1);
+}
diff --git a/usr.sbin/sendmail/FAQ b/usr.sbin/sendmail/FAQ
new file mode 100644
index 00000000000..743dc362fca
--- /dev/null
+++ b/usr.sbin/sendmail/FAQ
@@ -0,0 +1,343 @@
+ Sendmail Version 8
+ Frequently Asked Questions
+ Version 8.4 of 4/20/94
+
+
+This FAQ is specific to Version 8 of sendmail. Other questions,
+particularly regarding compilation and configuration, are answered
+in src/READ_ME and cf/README.
+
+----------------------------------------------------------------------
+ * Where can I get Version 8?
+
+ Via anonymous FTP from FTP.CS.Berkeley.EDU in /ucb/sendmail.
+----------------------------------------------------------------------
+ * What are the differences between Version 8 and other versions?
+
+ See doc/changes/changes.me in the sendmail distribution.
+----------------------------------------------------------------------
+ * What happened to sendmail 6.x and 7.x?
+
+ When I released a new version of sendmail, I changed it to
+ Release 6. Development continued in that tree until 4.4BSD
+ was released, when everything on the 4.4 tape was set to be
+ version 8.1. Version 7.x never existed.
+----------------------------------------------------------------------
+ * Version 8 requires a new version of "make". Where can I get this?
+
+ Actually, Version 8 does not require a new version of "make".
+ It includes a collection of Makefiles for different architectures,
+ only one or two of which require the new "make". If you are
+ porting to a new architecture, start with Makefile.dist.
+
+ If you really do want the new make, it is available on any of
+ the BSD Net2 or 4.4-Lite distribution sites. These include:
+
+ ftp.uu.net /systems/unix/bsd-sources
+ gatekeeper.dec.com /.0/BSD/net2
+ ucquais.cba.uc.edu /pub/net2
+ ftp.luth.se /pub/unix/4.3bsd/net2
+
+ Diffs and instructions for building this version of make under
+ SunOS 4.1.x are available on ftp.css.itd.umich.edu in
+ /pub/systems/sun/Net2-make.sun4.diff.Z.
+----------------------------------------------------------------------
+ * What macro package do I use to format the V8 man pages?
+
+ The BSD group switched over the the ``mandoc'' macros for
+ the 4.4 release. These include more hooks designed for
+ hypertext handling. However, new man pages won't format
+ under the old man macros. Fortunately, old man pages will
+ format under the new mandoc macros.
+
+ Get the new macros with the BSD Net2 or 4.4-Lite release.
+
+ This macro set is also available with newer versions of groff.
+----------------------------------------------------------------------
+ * What books are available describing sendmail?
+
+ There is one book available devoted to sendmail:
+
+ Costales, Allman, and Rickert, _Sendmail_. O'Reilly &
+ Associates.
+
+ Several books have sendmail chapters, for example:
+
+ Nemeth, Snyder, and Seebass, _Unix System Administration
+ Handbook_. Prentice-Hall.
+ Carl-Mitchell and Quarterman, _Practical Internetworking with
+ TCP/IP and UNIX_. Addison-Wesley.
+ Hunt, _TCP/IP Network Administration_. O'Reilly & Associates.
+
+ Another book about sendmail is due out "soon":
+
+ Avolio & Vixie, _Sendmail Theory and Practice_. Digital
+ Press (release date unknown).
+----------------------------------------------------------------------
+ * How do I make all my addresses appear to be from a single host?
+
+ Using the V8 configuration macros, use:
+
+ MASQUERADE_AS(my.dom.ain)
+
+ This will cause all addresses to be sent out as being from
+ the indicated domain.
+----------------------------------------------------------------------
+ * How do I rewrite my From: lines to read ``First_Last@My.Domain''?
+
+ There are a couple of ways of doing this. This describes using
+ the "user database" code. This is still experimental, and was
+ intended for a different purpose -- however, it does work
+ with a bit of care. It does require that you have the Berkeley
+ "db" package installed (it won't work with DBM).
+
+ First, create your input file. This should have lines like:
+
+ loginname:mailname First_Last
+ First_Last:maildrop loginname
+
+ Install it in (say) /etc/userdb. Create the database:
+
+ makemap btree /etc/userdb.db < /etc/userdb
+
+ You can then create a config file that uses this. You will
+ have to include the following in your .mc file:
+
+ define(confUSERDB_SPEC, /etc/userdb.db)
+ FEATURE(notsticky)
+----------------------------------------------------------------------
+ * So what was the user database feature intended for?
+
+ The intent was to have all information for a given user (where
+ the user is the unique login name, not an inherently non-unique
+ full name) in one place. This would include phone numbers,
+ addresses, and so forth. The "maildrop" feature is because
+ Berkeley does not use a centralized mail server (there are a
+ number of reasons for this that are mostly historic), and so
+ we need to know where each user gets his or her mail delivered --
+ i.e., the mail drop.
+
+ We are in the process of setting up our environment so that
+ mail sent to an unqualified "name" goes to that person's
+ preferred maildrop; mail sent to "name@host" goes to that
+ host. The purpose of "FEATURE(notsticky)" is to cause
+ "name@host" to be looked up in the user database for delivery
+ to the maildrop.
+----------------------------------------------------------------------
+ * Why are you so hostile to using full names for e-mail addresses?
+
+ Because full names are not unique. For example, the computer
+ community has two Andy Tannenbaums and two Peter Deutsches.
+ At one time, Bell Labs had two Stephen R. Bournes with offices
+ a few doors apart. You can create alternative addresses
+ (e.g., Stephen_R_Bourne_2), but that's even worse -- which
+ one of them has to have their name desecrated in this way?
+ And you can bet that they will get most of the other person's
+ email.
+
+ So called "full names" are just longer versions of unique
+ names. Rather that lulling people into a sense of security,
+ I'd rather that it be clear that these handles are arbitrary.
+ People should use good user agents that have alias mappings
+ so that they can attach arbitrary names for their personal
+ use to those with whom they correspond.
+
+ Even worse is fuzzy matching in e-mail -- this can make good
+ addresses turn bad. For example, I'm currently (to the best
+ of my knowledge) the only ``Allman'' at Berkeley, so mail
+ sent to "Allman@Berkeley.EDU" should get to me. But if
+ another Allman ever appears, this address could suddenly
+ become ambiguous. I've been the only Allman at Berkeley for
+ over fifteen years -- to suddenly have this "good address"
+ bounce mail because it is ambiguous would be a heinous wrong.
+
+ Finger services should be as fuzzy as possible. Mail services
+ should be unique.
+----------------------------------------------------------------------
+ * When I use sendmail V8 with a Sun config file I get lines like:
+
+ /etc/sendmail.cf: line 273: replacement $3 out of bounds
+
+ the line in question reads:
+
+ R$*<@$%y>$* $1<@$2.LOCAL>$3 user@ether
+
+ what does this mean? How do I fix it?
+
+ V8 doesn't recognize the Sun "$%y" syntax, so as far as it
+ is concerned, there is only a $1 and a $2 (but no $3) in this
+ line. Read Rick McCarty's paper on "Converting Standard Sun
+ Config Files to Sendmail Version 8", in the contrib directory
+ (file "converting.sun.configs") on the sendmail distribution
+ for a full discussion of how to do this.
+----------------------------------------------------------------------
+ * Should I use a wildcard MX for my domain?
+
+ If at all possible, no.
+
+ Wildcard MX records have lots of semantic "gotcha"s. For
+ example, they will match a host "unknown.your.domain" -- if
+ you don't explicitly test for unknown hosts in your domain,
+ you will get "config error: mail loops back to myself"
+ errors.
+----------------------------------------------------------------------
+ * I'm connected to the network via a SLIP link. Sometimes my sendmail
+ process hangs (although it looks like part of the message has been
+ transfered). Everything else works. What's wrong?
+
+ Most likely, the problem isn't sendmail at all, but the low
+ level network connection. It's important that the MTU (Maximum
+ Transfer Unit) for the SLIP connection be set properly at both
+ ends. If they disagree, large packets will be trashed and
+ the connection will hang.
+----------------------------------------------------------------------
+ * I just upgraded to 8.x and suddenly I'm getting messages in my
+ syslog of the form "collect: I/O error on connection". What is
+ going wrong?
+
+ Nothing. This is just a diagnosis of a condition that had
+ not been diagnosed before. If you are getting a lot of these
+ from a single host, there is probably some incompatibility
+ between 8.x and that host. If you get a lot of them in general,
+ you may have network problems that are causing connections to
+ get reset.
+----------------------------------------------------------------------
+ * How can I get sendmail to deliver local mail to $HOME/.mail
+ instead of into /usr/spool/mail (or /usr/mail)?
+
+ This is a local mailer issue, not a sendmail issue. Either
+ modify your local mailer (source code will be required) or
+ change the program called in the "local" mailer configuration
+ description to be a new program that does this local delivery.
+ I understand that "procmail" works well, although I haven't
+ used it myself.
+
+ You might be interested in reading the paper ``HLFSD: Delivering
+ Email to your $HOME'' available in the Proceedings of the
+ USENIX System Administration (LISA VII) Conference (November
+ 1993). This is also available via public FTP from
+ ftp.cs.columbia.edu:/pub/hlfsd/{README.hlfsd,hlfsd.ps}.
+----------------------------------------------------------------------
+ * Under V8, the "From " header gets mysteriously munged when I send
+ to an alias.
+
+ ``It's not a bug, it's a feature.'' This happens when you have
+ a "owner-list" alias and you send to "list". V8 propogates the
+ owner information into the envelope sender field (which appears
+ as the "From " header on UNIX mail or as the Return-Path: header)
+ so that downstream errors are properly returned to the mailing
+ list owner instead of to the sender. In order to make this
+ appear as sensible as possible to end users, I recommend making
+ the owner point to a "request" address -- for example:
+
+ list: :include:/path/name/list.list
+ owner-list: list-request
+ list-request: eric
+
+ This will make message sent to "list" come out as being
+ "From list-request" instead of "From eric".
+----------------------------------------------------------------------
+ * There are four UUCP mailers listed in the configuration files.
+ Which one should I use?
+
+ The choice is partly a matter of local preferences and what is
+ running at the other end of your UUCP connection. Unlike good
+ protocols that define what will go over the wire, UUCP uses
+ the policy that you should do what is right for the other end;
+ if they change, you have to change. This makes it hard to
+ do the right thing, and discourages people from updating their
+ software. In general, if you can avoid UUCP, please do.
+
+ If you can't avoid it, you'll have to find the version that is
+ closest to what the other end accepts. Following is a summary
+ of the UUCP mailers available.
+
+ uucp-old (obsolete name: "uucp")
+ This is the oldest, the worst (but the closest to UUCP) way of
+ sending messages accros UUCP connections. It does bangify
+ everything and prepends $U (your UUCP name) to the sender's
+ address (which can already be a bang path itself). It can
+ only send to one address at a time, so it spends a lot of
+ time copying duplicates of messages. Avoid this if at all
+ possible.
+
+ uucp-new (obsolete name: "suucp")
+ The same as above, except that it assumes that in one rmail
+ command you can specify several recipients. It still has a
+ lot of other problems.
+
+ uucp-dom
+ This UUCP mailer keeps everything as domain addresses.
+ Basically, it uses the SMTP mailer rewriting rules.
+
+ Unfortunately, a lot of UUCP mailer transport agents require
+ bangified addresses in the envelope, although you can use
+ domain-based addresses in the message header. (The envelope
+ shows up as the From_ line on UNIX mail.) So....
+
+ uucp-uudom
+ This is a cross between uucp-new (for the envelope addresses)
+ and uucp-dom (for the header addresses). It bangifies the
+ envelope sender (From_ line in messages) without adding the
+ local hostname, unless there is no host name on the address
+ at all (e.g., "wolf") or the host component is a UUCP host name
+ instead of a domain name ("somehost!wolf" instead of
+ "some.dom.ain!wolf").
+
+ Examples:
+
+ We are on host grasp.insa-lyon.fr (UUCP host name "grasp"). The
+ following summarizes the sender rewriting for various mailers.
+
+ Mailer sender rewriting in the envelope
+ ------ ------ -------------------------
+ uucp-{old,new} wolf grasp!wolf
+ uucp-dom wolf wolf@grasp.insa-lyon.fr
+ uucp-uudom wolf grasp.insa-lyon.fr!wolf
+
+ uucp-{old,new} wolf@fr.net grasp!fr.net!wolf
+ uucp-dom wolf@fr.net wolf@fr.net
+ uucp-uudom wolf@fr.net fr.net!wolf
+
+ uucp-{old,new} somehost!wolf grasp!somehost!wolf
+ uucp-dom somehost!wolf somehost!wolf@grasp.insa-lyon.fr
+ uucp-uudom somehost!wolf grasp.insa-lyon.fr!somehost!wolf
+----------------------------------------------------------------------
+ * I'm trying to to get my mail to go into queue only mode, and it
+ delivers the mail interactively anyway. (Or, I'm trying to use
+ the "don't deliver to expensive mailer" flag, and it doesn't
+ delivers the mail interactively anyway.) I can see it does it:
+ here's the output of "sendmail -v foo@somehost" (or Mail -v or
+ equivalent).
+
+ The -v flag to sendmail (which is implied by the -v flag to
+ Mail and other programs in that family) tells sendmail to
+ watch the transaction. Since you have explicitly asked to
+ see what's going on, it assumes that you do not want to to
+ auto-queue, and turns that feature off. Remove the -v flag
+ and use a "tail -f" of the log instead to see what's going on.
+
+ If you are trying to use the "don't deliver to expensive mailer"
+ flag (mailer flag "e"), be sure you also turn on global option
+ "c" -- otherwise it ignores the mailer flag.
+----------------------------------------------------------------------
+ * I'm getting "Local configuration error" messages, such as:
+
+ 553 relay.domain.net config error: mail loops back to myself
+ 554 <user@domain.net>... Local configuration error
+
+ How can I solve this problem?
+
+ You have asked mail to the domain (e.g., domain.net) to be
+ forwarded to a specific host (in this case, relay.domain.net)
+ by using an MX record, but the relay machine doesn't recognize
+ itself as domain.net. Add domain.net to /etc/sendmail.cw
+ (if you are using FEATURE(use_cw_file)) or add "Cw domain.net"
+ to your configuration file.
+----------------------------------------------------------------------
+ * I want to run Sendmail version 8 on my DEC system, but you don't
+ have MAIL11V3 support in sendmail. How do I handle this?
+
+ Get Paul Vixie's reimplementation of the mail11 protocol
+ from gatekeeper.dec.com in /pub/DEC/gwtools.
+----------------------------------------------------------------------
diff --git a/usr.sbin/sendmail/KNOWNBUGS b/usr.sbin/sendmail/KNOWNBUGS
new file mode 100644
index 00000000000..f34c6b738c1
--- /dev/null
+++ b/usr.sbin/sendmail/KNOWNBUGS
@@ -0,0 +1,131 @@
+
+
+ K N O W N B U G S I N S E N D M A I L
+ (for 8.6.7)
+
+
+The following are bugs or deficiencies in sendmail that I am aware of
+but which have not been fixed in the current release. You probably
+want to get the most up to date version of this from FTP.CS.Berkeley.EDU
+in /ucb/sendmail/KNOWNBUGS. For descriptions of bugs that have been
+fixed, see the file RELEASE_NOTES (in the root directory of the sendmail
+distribution).
+
+This list is not guaranteed to be complete.
+
+
+* Null bytes are not handled properly.
+
+ Sendmail should handle full binary data. As it stands, it handles
+ any value from 0x01-0xFF in the body and 0x01-0x80 and 0xA0-0xFF in
+ the header. Notably missing is 0x00, which would require a major
+ restructuring of the code -- for example, almost no C library support
+ could be used to handle strings.
+
+* Duplicate error messages.
+
+ Sometimes identical, duplicate error messages can be generated. As
+ near as I can tell, this is rare and relatively innocuous.
+
+* No "exposed users" in "nullrelay" configuration.
+
+ The "nullrelay" configuration hides all addresses behind the mail
+ hub name. Some sites might prefer to expose some names such as
+ root. This information is always available in Received: lines.
+
+* $c (hop count) macro improperly set.
+
+ The $c macro is supposed to contain the current hop count, for use
+ when calling a mailer. This macro is initialized too early, and
+ is always zero (or the value of the -c command line flag, if any).
+ This macro will probably be removed entirely in a future release;
+ I don't believe there are any mailers left that require it.
+
+* If you EXPN a list or user that has a program mailer, the output of
+ EXPN will include ``@local.host.name''. You can't actually mail to
+ this address. It's not clear what the right behaviour is in this
+ circumstance.
+
+* REDIRECT aliases don't work with `n' option.
+
+ If you have option `n' set when you use newaliases and have
+ REDIRECT addresses in your aliases file, you'll get the error
+ messages during the newaliases instead of when email is sent to
+ the address in question. The workaround is to turn off the `n'
+ option.
+
+* MX records that point at non-existent hosts work strangly.
+
+ Consider the DNS records:
+
+ hostH MX 1 hostA
+ MX 2 hostB
+ hostA A 128.32.8.9
+
+ (note that there is no A record for hostB). If hostA is down,
+ an attempt to send to hostH gives "host unknown" -- that is, it
+ reflects out the status on the last host it tries, which in this
+ case is hostB, which is unknown. It probably ought to eliminate
+ hostB early in processing.
+
+* NAME environment variables with commas break.
+
+ If you define your NAME environment variable to have a comma
+ (e.g., ``Lastname, Firstname''), and you are using the $q definition
+ that uses ``name <address>'' format, sendmail treats the first and
+ last names as two addresses, thus producing a bogus From line. You
+ can work around this by changing the $q definition to use
+ ``address (name)''.
+
+* \231 considered harmful.
+
+ Header addresses that have the \231 character (and possibly others
+ in the range \201 - \237) behave in odd and usually unexpected ways.
+
+* DEC Alphas (OSF/1 1.3) sometimes time out on sending mail.
+
+ I have one report that DEC Alphas acting as SMTP clients sometimes
+ will apparently not see the "250 OK" message in response to the
+ dot that indicates the end of the message. This only happens if
+ the message is run from the queue -- if it gets through on first
+ try, everything is fine. I have been unable to reproduce this
+ problem at Berkeley.
+
+* accept() problem on SVR4.
+
+ Apparently, the sendmail daemon loop (doing accept()s on the network)
+ can get into a wierd state on SVR4; it starts logging ``SYSERR:
+ getrequests: accept: Protocol Error''. The workaround is to kill
+ and restart the sendmail daemon. We don't have an SVR4 system at
+ Berkeley that carries more than token mail load, so I can't validate
+ this. It is likely to be a glitch in the sockets emulation, since
+ "Protocol Error" is not possible error code with Berkeley TCP/IP.
+
+ I've also had someone report the message ``sendmail: accept:
+ SIOCGPGRP failed errno 22'' on an SVR4 system. This message is
+ not in the sendmail source code, so I assume it is also a bug
+ in the sockets emulation. (Errno 22 is EINVAL "Invalid Argument"
+ on all the systems I have available, including Solaris 2.x.)
+
+* Sending user deletion not done properly in :include: lists.
+
+ If you don't have the "m" (me too) option set, then a person
+ sending to a list that contains themselves should not get a copy
+ of the message. However, if that list points to a :include: file
+ that has one address per line, this will break, and the sender
+ will always get a copy of their own message, just as though the
+ "m" option were set.
+
+ You can eliminate this by adding commas at the end of each line
+ of the :include: file.
+
+* Excessive mailing list nesting can run out of file descriptors.
+
+ If you have a mailing list that includes lots of other mailing
+ lists, each of which has a separate owner, you can run out of
+ file descriptors. Each mailing list with a separate owner uses
+ one open file descriptor (prior to 8.6.6 it was three open
+ file descriptors per list). This is particularly egregious if
+ you have your connection cache set to be large.
+
+(Version 8.18, last updated 3/14/94)
diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile
new file mode 100644
index 00000000000..e1d97b61556
--- /dev/null
+++ b/usr.sbin/sendmail/Makefile
@@ -0,0 +1,28 @@
+# @(#)Makefile 8.3 (Berkeley) 2/27/94
+
+SUBDIR= src mailstats makemap praliases cf/cf
+.if make(install)
+SUBDIR+= doc/intro doc/op
+.endif
+
+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/usr.sbin/sendmail/READ_ME b/usr.sbin/sendmail/READ_ME
new file mode 100644
index 00000000000..016fa7f49c9
--- /dev/null
+++ b/usr.sbin/sendmail/READ_ME
@@ -0,0 +1,239 @@
+/*-
+ * @(#)READ_ME 8.10 (Berkeley) 4/13/94
+ */
+
+ SENDMAIL RELEASE 8
+
+This directory has the latest sendmail software from Berkeley. See
+doc/op/op.me for a summary of changes since 5.67.
+
+Report any bugs to sendmail@CS.Berkeley.EDU.
+
+The latest version of sendmail is kept on FTP.CS.Berkeley.EDU, directory
+/ucb/sendmail; check there for the latest revision.
+
+
++--------------+
+| MANUAL PAGES |
++--------------+
+
+The sendmail manual pages use contemporary Berkeley troff macros. If
+your system does not process these manual pages, you can pick up the
+new macros in a BSD Net/2 FTP site (e.g. on FTP.UU.NET, the files
+/systems/unix/bsd-sources/share/tmac/me/strip.sed and
+/systems/unix/bsd-sources/share/tmac/*).
+
+The strip.sed file is only used in installation.
+
+After installation, edit tmac.doc and tmac.andoc to reflect the
+installation path of the tmac files. Those files contain pointers to
+/usr/share/tmac/, and those pointers are not changed by the `make
+install` process.
+
+Rename the existing tmac.an to be tmac.an.old, and rename tmac.andoc
+to be tmac.an.
+
+tmac.an will choose between tmac.an.old, your old macros, or tmac.doc,
+which are the new macros, so that both the new man pages and the
+existing man pages will be translated properly.
+
+I'm also told that the groff distribution from MIT has a tmac.doc
+macro set that is compatible with these macros.
+
+
++-----------------------+
+| RELATED DOCUMENTATION |
++-----------------------+
+
+There are other files you should read. Rooted in this directory are:
+
+ CHANGES-R5-R8
+ Describes changes between Release 5 and Release 8 of sendmail.
+ There are some things that may behave somewhat differently.
+ For example, the rules governing when :include: files will
+ be read have been tightened up for security reasons.
+ FAQ
+ Answers to Frequently Asked Questions.
+ KNOWNBUGS
+ Known bugs in the current release. I try to keep this up
+ to date -- get the latest version from FTP.CS.Berkeley.EDU
+ in /ucb/sendmail/KNOWNBUGS.
+ RELEASE_NOTES
+ A detailed description of the changes in each version. This
+ is quite long, but informative.
+ src/READ_ME
+ Details on compiling and installing sendmail.
+ cf/README
+ Details on configuring sendmail.
+ doc/op/op.me
+ The sendmail Installation & Operations Guide. Be warned: if
+ you are running this off on SunOS or some other system with an
+ old version of -me, you need to add the following macro to the
+ macros:
+
+ .de sm
+ \s-1\\$1\\s0\\$2
+ ..
+
+ This sets a word in a smaller pointsize.
+
+
++--------------+
+| RELATED RFCS |
++--------------+
+
+There are several related RFCs that you may wish to read -- they are
+available via anonymous FTP to several sites, including nic.ddn.mil
+(directory rfc), ftp.nisc.sri.com (rfc), nis.nsf.net (RFC),
+nisc.jvnc.net (rfc), venera.isi.edu (in-notes), and wuarchive.wustl.edu
+(info/rfc). They can also be retrieved via electronic mail by sending
+email to one of:
+
+ mail-server@nisc.sri.com
+ Put "send rfcNNN" in message body
+ nis-info@nis.nsf.net
+ Put "send RFCnnn.TXT-1" in message body
+ sendrfc@jvnc.net
+ Put "RFCnnn" as Subject: line
+
+Important RFCs for electronic mail are:
+
+ RFC821 SMTP protocol
+ RFC822 Mail header format
+ RFC974 MX routing
+ RFC976 UUCP mail format
+ RFC1123 Host requirements (modifies 821, 822, and 974)
+ RFC1413 Identification server
+ RFC1341 MIME: Multipurpose Internet Mail Extensions
+ RFC1344 Implications of MIME for Internet Mail Gateways
+
+Other standards that may be of interest (but which are less directly
+relevant to sendmail) are:
+
+ RFC987 Mapping between RFC822 and X.400
+ RFC1049 Content-Type header field (extension to RFC822)
+
+Warning to AIX users: this version of sendmail does not implement
+MB, MR, or MG DNS resource records, as defined as experiments in
+RFC883.
+
+
++-------------------+
+| DATABASE ROUTINES |
++-------------------+
+
+IF YOU WANT TO RUN THE NEW BERKELEY DB SOFTWARE: **** DO NOT ****
+use the version that was on the Net2 tape -- it has a number of
+nefarious bugs that were bad enough when I got them; you shouldn't have
+to go through the same thing. Instead, get a new version via public
+FTP from ftp.CS.Berkeley.EDU, file ucb/4bsd/db.tar.Z. This software
+is highly recommended; it gets rid of several stupid limits, it's much
+faster, and the interface is nicer to animals and plants. You will
+also probably find that you have to add -I/where/you/put/db/include
+to the sendmail makefile to get db.h to work properly.
+
+Be sure you remove ndbm.h and ndbm.o from the db distribution. These
+will cause problems with sendmail because sendmail already understands
+about NEWDB and NDBM coexisting.
+
+
++--------------------+
+| Host Name Services |
++--------------------+
+
+If you compile with NAMED_BIND (the default) sendmail will use
+DNS (the Domain Name System) for most host name lookups. If
+you do not have DNS running at your site you may have to turn
+this off to cause sendmail to use NIS and/or the /etc/hosts file.
+In particular, on SunOS you have to choose to use DNS (which
+you should do if you are attached to the Internet, otherwise
+you lose MX records, which are required) or NIS -- there is no
+way to try both.
+
+If you are using NIS and /etc/hosts, it is critical that you
+list the long (fully qualified) name first in the /etc/hosts file
+used to build the NIS database. For example, the line should read
+
+ 128.32.149.68 mastodon.CS.Berkeley.EDU mastodon
+
+**** NOT ****
+
+ 128.32.149.68 mastodon mastodon.CS.Berkeley.EDU
+
+If you use the wrong order, sendmail will conclude that your
+canonical name is the short version and use that in messages.
+The name "mastodon" doesn't mean much outside of Berkeley,
+and so this creates incorrect and unreplyable messages.
+
+
++-------------+
+| USE WITH MH |
++-------------+
+
+This version of sendmail notices and reports certain kinds of SMTP
+protocol violations that were ignored by older versions. If you
+are running MH you may wish to install the patch in contrib/mh.patch
+that will prevent these warning reports. This patch also works
+with the old version of sendmail, so it's safe to go ahead and
+install it.
+
+
++-----------+
+| MAKEFILES |
++-----------+
+
+The Makefiles in this release use the new Berkeley "make" that is
+available in BSD Net/2 and 4.4BSD. If you are using this version
+of make, you may notice one or two places where the Makefile includes
+"../../Makefile.inc". This file is not included with the sendmail
+distribution because it's not part of sendmail. However, it is,
+in toto:
+
+ # @(#)Makefile.inc 8.1 (Berkeley) 6/6/93
+
+ BINDIR?= /usr/sbin
+
+The other directories should all have Makefile.dist files that work
+on the old make, albeit without all the niceties included.
+
+You can also get a new Berkeley make from the Net2 release (available
+on many public FTP archives). This version should also interpret old
+Makefiles, so you could drop it in as your default make.
+
+For more details, see src/READ_ME.
+
+
++---------------------+
+| DIRECTORY STRUCTURE |
++---------------------+
+
+The structure of this directory tree is:
+
+cf Source for Berkeley configuration files. These are
+ different than what you've seen before. They are a
+ fairly dramatic rewrite, requiring the new sendmail
+ (since they use new features).
+contrib Some contributed tools to help with sendmail. THESE
+ ARE NOT SUPPORTED by Berkeley -- contact the original
+ authors if you have problems. (This directory is not
+ on the 4.4BSD tape.)
+doc Documentation. If you are getting source, read
+ op.me -- it's long, but worth it.
+mailstats Statistics printing program. It has the pathname of
+ sendmail.st compiled in, so if you've changed that,
+ beware. This isn't all that useful.
+makemap A program that creates the keyed maps used by the $( ... $)
+ construct in sendmail. It is primitive but effective.
+ It takes a very simple input format, so you will probably
+ expect to preprocess must human-convenient formats
+ using sed scripts before this program will like them.
+ But it should be functionally complete.
+praliases A program to print the DBM version of the aliases file.
+ It hasn't been converted to understand the new Berkeley
+ DB format (which we are using).
+rmail Source for rmail(8). This is used as a delivery
+ agent for for UUCP, and could presumably be used by
+ other non-socket oriented mailers. Older versions of
+ rmail are probably deficient.
+src Source for the sendmail program itself.
+test Some test scripts (currently only for compilation aids).
diff --git a/usr.sbin/sendmail/RELEASE_NOTES b/usr.sbin/sendmail/RELEASE_NOTES
new file mode 100644
index 00000000000..98f746193a3
--- /dev/null
+++ b/usr.sbin/sendmail/RELEASE_NOTES
@@ -0,0 +1,2646 @@
+ SENDMAIL RELEASE NOTES
+ @(#)RELEASE_NOTES 8.6.12.1 (Berkeley) 3/28/95
+
+This listing shows the version of the sendmail binary, the version
+of the sendmail configuration files, the date of release, and a
+summary of the changes in that release.
+
+8.6.12/8.6.12 95/03/28
+ Fix to IDENT code (it was getting the size of the reply buffer
+ too small, so nothing was ever accepted). Fix from several
+ people, including Allan Johannesen, Shane Castle of the
+ Boulder County Information Services, and Jeff Smith of
+ Warwick University (all arrived within a few hours of
+ each other!).
+ Fix a problem that could cause large jobs to run out of
+ file descriptors on systems that use vfork() rather
+ than fork().
+
+8.6.11/8.6.11 95/03/08
+ The ``possible attack'' message would be logged more often
+ than necessary if you are using Pine as a user agent.
+ The wrong host would be reported in the ``possible attack''
+ message when attempted from IDENT.
+ In some cases the syslog buffer could be overflowed when
+ reporting the ``possible attack'' message. This can
+ cause denial of service attacks. Truncate the message
+ to 80 characters to prevent this problem.
+ When reading the IDENT response a loop is needed around the
+ read from the network to ensure that you don't get
+ partial lines.
+ Password entries without any shell listed (that is, a null
+ shell) wouldn't match as "ok". Problem noted by
+ Rob McMahon.
+ When running BIND 4.9.x a problem could occur because the
+ _res.options field is initialized differently than it
+ was historically -- this requires that sendmail call
+ res_init before it tweaks any bits.
+ Fix an incompatibility in openxscript() between the file open mode
+ and the stdio mode passed to fdopen. This caused UnixWare
+ 2.0 to have conniptions. Fix from Martin Sohnius of
+ Novell Labs Europe.
+ Fix problem with static linking of local getopt routine when
+ using GNU's ld command. Fix from John Kennedy of
+ Cal State Chico.
+ It was possible to turn off privacy flags. Problem noted by
+ *Hobbit*.
+ Be more paranoid about writing files. Suggestions by *Hobbit*
+ and Liudvikas Bukys.
+ MAKEMAP: fixes for 64 bit machines (DEC Alphas in particular)
+ from Spider Boardman.
+ CONFIG: No changes (version number only, to keep it in sync
+ with the binaries).
+
+8.6.10/8.6.10 95/02/10
+ SECURITY: Diagnose bogus values to some command line flags that
+ could allow trash to get into headers and qf files.
+ Validate the name of the user returned by the IDENT protocol.
+ Some systems that really dislike IDENT send intentionally
+ bogus information. Problem pointed out by Michael Bushnell
+ of the Free Software Foundation. Has some security
+ implications.
+ Fix a problem causing error messages about DNS problems when
+ the host name contained a percent sign to act oddly
+ because it was passed as a printf-style format string.
+ In some cases this could cause core dumps.
+ Avoid possible buffer overrun in returntosender() if error
+ message is quite ling. From Fletcher Mattox of the
+ University of Texas.
+ Fix a problem that would silently drop "too many hops" error
+ messages if and only if you were sending to an alias.
+ From Jon Giltner of the University of Colorado and
+ Dan Harton of Oak Ridge National Laboratory.
+ Fix a bug that caused core dumps on some systems if -d11.2 was
+ set and e->e_message was null. Fix from Bruce Nagel of
+ Data General.
+ Fix problem that can still cause df files to be left around
+ after "hop count exceeded" messages. Fix from Andrew
+ Chang and Shau-Ping Lo of SunSoft.
+ Fix a problem that can cause buffer overflows on very long
+ user names (as might occur if you piped to a program
+ with a lot of arguments).
+ Avoid returning an error and re-queueing if the host signature
+ is null; this can occur on addresses like ``user@.''.
+ Problem noted by Wesley Craig and the University of
+ Michigan.
+ Avoid possible calls to malloc(0) if MCI caching is turned
+ off. Bug fix from Pierre David of the Laboratoire
+ Parallelisme, Reseaux, Systemes et Modelisation (PRiSM),
+ Universite de Versailles - St Quentin, and Jacky
+ Thibault.
+ Make a local copy of the line being sent via senttolist() -- in
+ some cases, buffers could get trashed by map lookups
+ causing it to do unexpected things. This also simplifies
+ some of the map code.
+ CONFIG: No changes (version number only, to keep it in sync
+ with the binaries).
+
+8.6.9/8.6.9 94/04/19
+ Do all mail delivery completely disconnected from any terminal.
+ This provides consistency with daemon delivery and
+ may have some security implications.
+ Make sure that malloc doesn't get called with zero size,
+ since that fails on some systems. Reported by Ed
+ Hill of the University of Iowa.
+ Fix multi-line values for $e (SMTP greeting message). Reported
+ by Mike O'Connor of Ford Motor Company.
+ Avoid syserr if no NIS domain name is defined, but the map it
+ is trying to open is optional. From Win Bent of USC.
+ Changes for picky compilers from Ed Gould of Digital Equipment.
+ Hesiod support for UDB from Todd Miller of the University of
+ Colorado. Use "hesiod" as the service name in the U
+ option.
+ Fix a problem that failed to set the "authentic" host name (that
+ is, the one derived from the socket info) if you called
+ sendmail -bs from inetd. Based on code contributed by
+ Todd Miller (this problem was also reported by Guy Helmer
+ of Dakota State University). This also fixes a related
+ problem reported by Liudvikas Bukys of the University of
+ Rochester.
+ Parameterize "nroff -h" in all the Makefiles so people with
+ variant versions can use them easily. Suggested by
+ Peter Collinson of Hillside Systems.
+ SMTP "MAIL" commands with multiple ESMTP parameters required two
+ spaces between parameters instead of one. Reported by
+ Valdis Kletnieks of Virginia Tech.
+ Reduce the number of system calls during message collection by
+ using global timeouts around the collect() loop. This
+ code was contributed by Eric Wassenaar.
+ If the initial hostname name gathering results in a name
+ without a dot (usually caused by NIS misconfiguration)
+ and BIND is compiled in, directly access DNS to get
+ the canonical name. This should make life easier for
+ Solaris systems. If it still can't be resolved, and
+ if the name server is listed as "required", try again
+ in 30 seconds. If that also fails, exit immediately to
+ avoid bogus "config error: mail loops back to myself"
+ messages.
+ Improve the "MAIL DELETED BECAUSE OF LACK OF DISK SPACE" error
+ message to explain how much space was available and
+ sound a bit less threatening. Suggested by Stan Janet
+ of the National Institute of Standards and Technology.
+ If mail is delivered to an alias that has an owner, deliver any
+ requested return-receipt immediately, and strip the
+ Return-Receipt-To: header from the subsequent message.
+ This prevents a certain class of denial of service
+ attack, arguably gives more reasonable semantics, and
+ moves things more towards what will probably become a
+ network standard. Suggested by Christopher Davis of
+ Kapor Enterprises.
+ Add a "noreceipts" privacy flag to turn off all return receipts
+ without recompiling.
+ Avoid printing ESMTP parameters as part of the error message
+ if there are errors during parsing. This change is
+ purely cosmetic.
+ Avoid sending out error messages during the collect phase of
+ SMTP; there is an MVS mailer from UCLA that gets
+ confused by this. Of course, I think it's their bug....
+ Check for the $j macro getting undefined, losing a dot, or getting
+ lost from $=w in the daemon before accepting a connection;
+ if it is, it dumps state, prints a LOG_ALERT message,
+ and drops core for debugging. This is an attempt to
+ track down a bug that I thought was long since gone.
+ If you see this, please forward the log fragment to
+ sendmail@CS.Berkeley.EDU.
+ Change OLD_NEWDB from a #ifdef to a #if so it can be turned off
+ with -DOLD_NEWDB=0 on the command line. From Christophe
+ Wolfhugel.
+ Instead of trying to truncate the listen queue for the server
+ SMTP port when the load average is too high, just close
+ the port completely and reopen it later as needed.
+ This ensures that the other end gets a quick "connection
+ refused" response, and that the connection can be
+ recovered later. In particular, some socket emulations
+ seem to get confused if you tweak the listen queue
+ size around and can never start listening to connections
+ again. The down side is that someone could start up
+ another daemon process in the interim, so you could
+ have multiple daemons all not listening to connections;
+ this could in turn cause the sendmail.pid file to be
+ incorrect. A better approach might be to accept the
+ connection and give a 421 code, but that could break
+ other mailers in mysterious ways and have paging behaviour
+ implications.
+ Fix a glitch in TCP-level debugging that caused flag 16.101 to
+ set debugging on the wrong socket. From Eric Wassenaar.
+ When creating a df* temporary file, be sure you truncate any
+ existing data in the file -- otherwise system crashes
+ and the like could result in extra data being sent.
+ DOC: Replace the CHANGES-R5-R8 readme file with a paper in the
+ doc directory. This includes some additional
+ information.
+ CONFIG: change UUCP rules to never add $U! or $k! on the front
+ of recipient envelope addresses. This should have been
+ handled by the $&h trick, but broke if people were
+ mixing domainized and UUCP addresses. They should
+ probably have converted all the way over to uucp-uudom
+ instead of uucp-{new,old}, but the failure mode was to
+ loop the mail, which was bad news.
+ Portability fixes:
+ Newer BSDI systems (several people).
+ Older BSDI systems from Christophe Wolfhugel.
+ Intergraph CLIX, from Paul Southworth of CICNet.
+ UnixWare, from Evan Champion.
+ NetBSD from Adam Glass.
+ Solaris from Quentin Campbell of the University of
+ Newcastle upon Tyne.
+ IRIX from Dean Cookson and Bill Driscoll of Mitre
+ Corporation.
+ NCR 3000 from Kevin Darcy of Chrysler Corporation.
+ SunOS (it has setsid() and setvbuf() calls) from
+ Jonathan Kamens of OpenVision Technologies.
+ HP-UX from Tor Lillqvist.
+ New Files:
+ src/Makefile.CLIX
+ src/Makefile.NCR3000
+ doc/changes/Makefile
+ doc/changes/changes.me
+ doc/changes/changes.ps
+
+8.6.8/8.6.6 94/03/21
+ SECURITY: it was possible to read any file as root using the
+ E (error message) option. Reported by Richard Jones;
+ fixed by Michael Corrigan and Christophe Wolfhugel.
+
+8.6.7/8.6.6 94/03/14
+ SECURITY: it was possible to get root access by using wierd
+ values to the -d flag. Thanks to Alain Durand of
+ INRIA for forwarding me the notice from the bugtraq
+ list.
+
+8.6.6/8.6.6 94/03/13
+ SECURITY: the ability to give files away on System V-based
+ systems proved dangerous -- don't run as the owner
+ of a :include: file on a system that allows giveaways.
+ Unfortunately, this also applies to determining a
+ valid shell.
+ IMPORTANT: Previous versions weren't expiring old connections
+ in the connection cache for a long time under some
+ circumstances. This could result in resource exhaustion,
+ both at your end and at the other end. This checks the
+ connections for timeouts much more frequently. From
+ Doug Anderson of NCSC.
+ Fix a glitch that snuck in that caused programs to be run as
+ the sender instead of the recipient if the mail was
+ from a local user to another local user. From
+ Motonori Nakamura of Kyoto University.
+ Fix "wildcard" on /etc/shell matching -- instead of looking
+ for "*", look for "/SENDMAIL/ANY/SHELL/". From
+ Bryan Costales of ICSI.
+ Change the method used to declare the "statfs" availability;
+ instead of HASSTATFS and/or HASUSTAT with a ton of
+ tweaking in conf.c, there is a single #define called
+ SFS_TYPE which takes on one of six values (SFS_NONE
+ for no statfs availability, SFS_USTAT for the ustat(2)
+ syscall, SFS_4ARGS for a four argument statfs(2) call,
+ and SFS_VFS, SFS_MOUNT, or SFS_STATFS for a two argument
+ statfs(2) call with the declarations in <sys/vfs.h>,
+ <sys/mount.h>, or <sys/statfs.h> respectively).
+ Fix glitch in NetInfo support that could return garbage if
+ there was no "/locations/sendmail" property. From
+ David Meyer of the University of Virginia.
+ Change HASFLOCK from defined/not-defined to a 0/1 definition
+ to allow Linux to turn it off even though it is a
+ BSD-like system.
+ Allow setting of "ident" timeout to zero to turn off the ident
+ protocol entirely.
+ Make 7-bit stripping local to a connection (instead of to a
+ mailer); this allows you to specify that SMTP is a
+ 7-bit channel, but revert to 8-bit should it advertise
+ that it supports 8BITMIME. You still have to specify
+ mailer flag 7 to get this stripping at all.
+ Improve makesendmail script so it handles more cases automatically.
+ Tighten up restrictions on taking ownership of :include: files
+ to avoid problems on systems that allow you to give away
+ files.
+ Fix a problem that made it impossible to rebuild the alias
+ file if it was on a read-only file system. From
+ Harry Edmon of the University of Washington.
+ Improve MX randomization function. From John Gardiner Myers
+ of CMU.
+ Fix a minor glitch causing a bogus message to be printed (used
+ %s instead of %d in a printf string for the line number)
+ when a bad queue file was read. From Harry Edmon.
+ Allow $s to remain NULL on locally generated mail. I'm not
+ sure this is necessary, but a lot of people have complained
+ about it, and there is a legitimate question as to whether
+ "localhost" is legal as an 822-style domain.
+ Fix a problem with very short line lengths (mailer L= flag) in
+ headers. This causes a leading space to be added onto
+ continuation lines (including in the body!), and also
+ tries to wrap headers containing addresses (From:, To:,
+ etc) intelligently at the shorter line lengths. Problem
+ Reported by Lars-Johan Liman of SUNET Operations Center.
+ Log the real user name when logging syserrs, since these can have
+ security implications. Suggested by several people.
+ Fix address logging of cached connections -- it used to always
+ log the numeric address as zero. This is a somewhat
+ bogus implementation in that it does an extra system
+ call, but it should be an inexpensive one. Fix from
+ Motonori Nakamura.
+ Tighten up handling of short syslog buffers even more -- there
+ were cases where the outgoing relay= name was too long
+ to share a line with delay= and mailer= logging.
+ Limit the overhead on split envelopes to one open file descriptor
+ per envelope -- previously the overhead was three
+ descriptors. This was in response to a problem reported
+ by P{r (Pell) Emanuelsson.
+ Fixes to better handle the case of unexpected connection closes;
+ this redirects the output to the transcript so the info
+ is not lost. From Eric Wassenaar.
+ Fix potential string overrun if you macro evaluate a string that
+ has a naked $ at the end. Problem noted by James Matheson
+ <jmrm@eng.cam.ac.uk>.
+ Make default error number on $#error messages 553 (``Requested
+ action not taken: mailbox name not allowed'') instead of
+ 501 (``Syntax error in parameters or arguments'') to
+ avoid bogus "protocol error" messages.
+ Strip off any existing trailing dot on names during $[ ... $]
+ lookup. This prevents it from ending up with two dots
+ on the end of dot terminated names. From Wesley Craig
+ of the University of Michigan and Bryan Costales of ICSI.
+ Clean up file class reading so that the debugging information is
+ more informative. It hadn't been using setclass, so you
+ didn't see the class items being added.
+ Avoid core dump if you are running a version of sendmail where
+ NIS is compiled in, and you specify an NIS map, but
+ NIS is not running. Fix from John Oleynick of
+ Rutgers.
+ Diagnose bizarre case where res_search returns a failure value,
+ but sets h_errno to a success value.
+ Make sure that "too many hops" messages are considered important
+ enough to send an error to the Postmaster (that is, the
+ address specified in the P option). This fix should
+ help problems that cause the df file to be left around
+ sometimes -- unfortunately, I can't seem to reproduce
+ the problem myself.
+ Avoid core dump (null pointer reference) on EXPN command; this
+ only occurred if your log level was set to 10 or higher
+ and the target account was an alias or had a .forward file.
+ Problem noted by Janne Himanka.
+ Avoid "denial of service" attacks by someone who is flooding your
+ SMTP port with bad commands by shutting the connection
+ after 25 bad commands are issued. From Kyle Jones of
+ UUNET.
+ Fix core dump on error messages with very long "to" buffers;
+ fmtmsg overflows the message buffer. Fixed by trimming
+ the to address to 203 characters. Problem reported by
+ John Oleynick.
+ Fix configuration for HASFLOCK -- there were some spots where
+ a #ifndef was incorrectly #ifdef. Pointed out by
+ George Baltz of the University of Maryland.
+ Fix a typo in savemail() that could cause the error message To:
+ lists to be incorrect in some places. From Motonori
+ Nakamura.
+ Fix a glitch that can cause duplicate error messages on split
+ envelopes where an address on one of the lists has a
+ name server failure. Fix from Voradesh Yenbut of the
+ University of Washington.
+ Fix possible bogus pointer reference on ESMTP parameters that
+ don't have an ``=value'' part.
+ CNAME loops caused an error message to be generated, but also
+ re-queued the message. Changed to just re-queue the
+ message (it's really hard to just bounce it because
+ of the wierd way the name server works in the presence
+ of CNAME loops). Problem noted by James M.R.Matheson
+ of Cambridge University.
+ Avoid giving ``warning: foo owned process doing -bs'' messages
+ if they use ``MAIL FROM:<foo>'' where foo is their true
+ user name. Suggested by Andreas Stolcke of ICSI.
+ Change the NAMED_BIND compile flag to be a 0/1 flag so you can
+ override it easily in the Makefile -- that is, you can
+ turn it off using -DNAMED_BIND=0.
+ If a gethostbyname(...) of an address with a trailing dot fails,
+ try it without the trailing dot. This is because if
+ you have a version of gethostbyname() that falls back
+ to NIS or the /etc/hosts file it will fail to find
+ perfectly reasonable names that just don't happen to
+ be dot terminated in the hosts file. You don't want to
+ strip the dot first though because we're trying to ensure
+ that country names that match one of your subdomains get
+ a chance.
+ PRALIASES: fix bogus output on non-null-terminated strings.
+ From Bill Gianopoulos of Raytheon.
+ CONFIG: Avoid rewriting anything that matches $w to be $j.
+ This was in code intended to only catch the self-literal
+ address (that is, [1.2.3.4], where 1.2.3.4 is your
+ IP address), but the code was broken. However, it will
+ still do this if $M is defined; this is necessary to
+ get client configurations to work (sigh). Note that this
+ means that $M overrides :mailname entries in the user
+ database! Problem noted by Paul Southworth.
+ CONFIG: Fix definition of Solaris help file location. From
+ Steve Cliffe <steve@gorgon.cs.uow.edu.au>.
+ CONFIG: Fix bug that broke news.group.USENET mappings.
+ CONFIG: Allow declaration of SMTP_MAILER_MAX, FAX_MAILER_MAX,
+ and USENET_MAILER_MAX to tweak the maximum message
+ size for various mailers.
+ CONFIG: Change definition of USENET_MAILER_ARGS to include argv[0]
+ instead of assuming that it is "inews" for consistency
+ with other mailers. From Michael Corrigan of UC San Diego.
+ CONFIG: When mail is forwarded to a LOCAL_RELAY or a MAIL_HUB,
+ qualify the address in the SMTP envelope as user@{relay|hub}
+ instead of user@$j. From Bill Wisner of The Well.
+ CONFIG: Fix route-addr syntax in nullrelay configuration set.
+ CONFIG: Don't turn off case mapping of user names in the local
+ mailer for IRIX. This was different than most every other
+ system.
+ CONFIG: Avoid infinite loops on certainly list:; syntaxes in
+ envelope. Noted by Thierry Besancon
+ <besancon@excalibur.ens.fr>.
+ CONFIG: Don't include -z by default on uux line -- most systems
+ don't want it set by default. Pointed out by Philippe
+ Michel of Thomson CSF.
+ CONFIG: Fix some bugs with mailertables -- for example, if your
+ host name was foo.bar.ray.com and you matched against
+ ".ray.com", the old implementation bound %1 to "bar"
+ instead of "foo.bar". Also, allow "." in the mailertable
+ to match anything -- essentially, take over SMART_HOST.
+ This also moves matching of explicit local host names
+ before the mailertable so they don't have to be special
+ cased in the mailertable data. Reported by Bill
+ Gianopoulos of Raytheon; the fix for the %1 binding
+ problem was contributed by Nicholas Comanos of the
+ University of Sydney.
+ CONFIG: Don't include "root" in class $=L (users to deliver
+ locally, even if a hub or relay exists) by default.
+ This is because of the known bug where definition of
+ both a LOCAL_RELAY and a MAIL_HUB causes $=L to ignore
+ both and deliver into the local mailbox.
+ CONFIG: Move up bitdomain and uudomain handling so that they
+ are done before .UUCP class matching; uudomain was
+ reported as ineffective before. This also frees up
+ diversion 8 for future use. Problem reported by Kimmo
+ Suominen.
+ CONFIG: Don't try to convert dotted IP address (e.g., [1.2.3.4])
+ into host names. As pointed out by Jonathan Kamens,
+ these are often used because either the forward or reverse
+ mapping is broken; this translation makes it broken again.
+ DOC: Clarify $@ and $: in the Install & Op Guide. From Kimmo
+ Suominen.
+ Portability fixes:
+ Unicos from David L. Kensiski of Sterling Sofware.
+ DomainOS from Don Lewis of Silicon Systems.
+ GNU m4 1.0.3 from Karst Koymans of Utrecht University.
+ Convex from Kimmo Suominen <kim@tac.nyc.ny.us>.
+ NetBSD from Adam Glass <glass@sun-lamp.cs.berkeley.edu>.
+ BSD/386 from Tony Sanders of BSDI.
+ Apollo from Eric Wassenaar.
+ DGUX from Doug Anderson.
+ Sequent DYNIX/ptx 2.0 from Tim Wright of Sequent.
+ NEW FILES:
+ src/Makefile.DomainOS
+ src/Makefile.PTX
+ src/Makefile.SunOS.5.1
+ src/Makefile.SunOS.5.2
+ src/Makefile.SunOS.5.x
+ src/mailq.1
+ cf/ostype/domainos.m4
+ doc/op/Makefile
+ doc/intro/Makefile
+ doc/usenix/Makefile
+
+8.6.5/8.6.5 94/01/13
+ Security fix: /.forward could be owned by anyone (the test
+ to allow root to own any file was backwards). From
+ Bob Campbell at U.C. Berkeley.
+ Security fix: group ids were not completely set when programs
+ were invoked. This caused programs to have group
+ permissions they should not have had (usually group
+ daemon instead of their own group). In particular,
+ Perl scripts would refuse to run.
+ Security: check to make sure files that are written are not
+ symbolic links (at least under some circumstances).
+ Although this does not respond to a specific known
+ attack, it's just a good idea. Suggested by
+ Christian Wettergren.
+ Security fix: if a user had an NFS mounted home directory on
+ a system with a restricted shell listed in their
+ /etc/passwd entry, they could still execute any
+ program by putting that in their .forward file.
+ This fix prevents that by insisting that their shell
+ appear in /etc/shells before allowing a .forward to
+ execute a program or write a file. You can disable
+ this by putting "*" in /etc/shells. It also won't
+ permit world-writable :include: files to reference
+ programs or files (there's no way to disable this).
+ These behaviours are only one level deep -- for
+ example, it is legal for a world-writable :include:
+ file to reference an alias that writes a file, on
+ the assumption that the alias file is well controlled.
+ Security fix: root was not treated suspiciously enough when
+ looking into subdirectories. This would potentially
+ allow a cracker to examine files that were publically
+ readable but in a non-publically searchable directory.
+ Fix a problem that causes an error on QUIT on a cached
+ connection to create problems on the current job.
+ These are typically unrelated, so errors occur in
+ the wrong place.
+ Reset CurrentLA in sendall() -- this makes sendmail queue
+ runs more responsive to load average, and fixes a
+ problem that ignored the load average in locally
+ generated mail. From Eric Wassenaar.
+ Fix possible core dump on aliases with null LHS. From
+ John Orthoefer of BB&N.
+ Revert to using flock() whenever possible -- there are just
+ too many bugs in fcntl() locking, particularly over
+ NFS, that cause sendmail to fail in perverse ways.
+ Fix a bug that causes the connection cache to get confused
+ when sending error messages. This resulted in
+ "unexpected close" messages. It should fix itself
+ on the following queue run. Problem noted by
+ Liudvikas Bukys of the University of Rochester.
+ Include $k in $=k as documented in the Install & Op Guide.
+ This seems odd, but it was documented.... From
+ Michael Corrigan of UCSD.
+ Fix problem that caused :include:s from alias files to be
+ forced to be owned by root instead of daemon
+ (actually DefUid). From Tim Irvin.
+ Diagnose unrecognized I option values -- from Mortin Forssen
+ of the Chalmers University of Technology.
+ Make "error" mailer work consistently when there is no error
+ code associated with it -- previously it returned OK
+ even though there was a real problem. Now it assumes
+ EX_UNAVAILABLE.
+ Fix bug that caused the last header line of messages that had
+ no body and which were terminated with EOF instead of
+ "." to be discarded. Problem noted by Liudvikas Bukys.
+ Fix core dump on SMTP mail to programs that failed -- it tried
+ to go to a "next MX host" when none existed, causing
+ a core dump. From der Mouse at McGill University.
+ Change IDENTPROTO from a defined/not defined to a 0/1 switch;
+ this makes it easier to turn it off (using
+ -DIDENTPROTO=0 in the Makefile). From der Mouse.
+ Fix YP_MASTER_NAME store to use the unupdated result of
+ gethostname() (instead of myhostname(), which tries
+ to fully qualify the name) to be consistent with
+ SunOS. If your hostname is unqualified, this fixes
+ transfers to slave servers. Bug noted by Keith
+ McMillan of Ameritech Services, Inc.
+ Fix Ultrix problem: gethostbyname() can return a very large
+ (> 500) h_length field, which causes the sockaddr
+ to be trashed. Use the size of the sockaddr instead.
+ Fix from Bob Manson of Ohio State.
+ Don't assume "-a." on host lookups if NAMED_BIND is not
+ defined -- this confuses gethostbyname on hosts
+ file lookups, which doesn't understand the trailing
+ dot convention.
+ Log SMTP server subprocesses that die with a signal instead
+ of from a clean exit.
+ If you don't have option "I" set, don't assume that a DNS
+ "host unknown" message is authoritative -- it
+ might still be found in /etc/hosts.
+ Fix a problem that would cause Deferred: messages to be sent
+ as the subject of an error message, even though the
+ actual cause of a message was more severe than that.
+ Problem noted by Chris Seabrook of OSSI.
+ Fix race condition in DBM alias file locking. From Kyle
+ Jones of UUNET.
+ Limit delivery syslog line length to avoid bugs in some
+ versions of syslog(3). This adds a new compile time
+ variable SYSLOG_BUFSIZE. From Jay Plett of Princeton
+ University, which is in turn derived from IDA.
+ Fix quotes inside of comments in addresses -- previously
+ it insisted that they be balanced, but the 822 spec
+ says that they should be ignored.
+ Dump open file state to syslog upon receiving SIGUSR1 (for
+ debugging). This also evaluates ruleset 89, if set
+ (with the null input), and logs the result. This
+ should be used sparingly, since the rewrite process
+ is not reentrant.
+ Change -qI, -qR, and -qS flags to be case-insensitive as
+ documented in the Bat Book.
+ If the mailer returned EX_IOERR or EX_OSERR, sendmail did not
+ return an error message and did not requeue the message.
+ Fix based on code from Roland Dirlewanger of
+ Reseau Regional Aquarel, Bordeaux, France.
+ Fix a problem that caused a seg fault if you got a 421 error
+ code during some parts of connection initialization.
+ I've only seen this when talking to buggy mailers on
+ the other end, but it shouldn't give a seg fault in
+ any case. From Amir Plivatsky.
+ Fix core dump caused by a ruleset call that returns null.
+ Fix from Bryan Costales of ICSI.
+ Full-Name: field was being ignored. Fix from Motonori Nakamura
+ of Kyoto University.
+ Fix a possible problem with very long input lines in setproctitle.
+ From P{r Emanuelsson.
+ Avoid putting "This is a warning message" out on return receipts.
+ Suggested by Douglas Anderson.
+ Detect loops caused by recursive ruleset calls. Suggested by
+ Bryan Costales.
+ Initialize non-alias maps during alias rebuilds -- they may be
+ needed for parsing. Problem noted by Douglas Anderson.
+ Log sender address even if no message was collected in SMTP
+ (e.g., if all RCPTs failed). Suggested by Motonori
+ Nakamura.
+ Don't reflect the owner-list contents into the envelope sender
+ address if the value contains ", :, /, or | (to avoid
+ illegal addresses appearing there).
+ Efficiency hack for toktype macro -- from Craig Partridge of
+ BB&N.
+ Clean up DNS error printing so that a host name is always
+ included.
+ Remember to set $i during queue runs. Reported by Stephen
+ Campbell of Dartmouth University.
+ If ${HOSTALIASES} is set, use it during canonification so that
+ headers are properly mapped. Reported by Anne Bennett
+ of Concordia University.
+ Avoid printing misleading error message if SMTP mailer (not
+ using [IPC]) should die on a core dump.
+ Avoid incorrect diagnosis of "file 1 closed" when it is caused
+ by the other end closing the connection. From
+ Dave Morrison of Oracle.
+ Improve several of the error messages printed by "mailq"
+ to include a host name or other useful information.
+ Add NetInfo preliminary support for NeXT systems. From Vince
+ DeMarco.
+ Fix a glitch that sometimes caused :include:s that pointed to
+ NFS filesystems that were down to give an "aliasing/
+ forwarding loop broken" message instead of queueing
+ the message for retry. Noted by William C Fenner of
+ the NRL Connection Machine Facility.
+ Fix a problem that could cause a core dump if the input sequence
+ had (or somehow acquired) a \231 character.
+ Make sure that route-addrs always have <angle brackets> around
+ them in non-SMTP envelopes (SMTP envelopes already do
+ this properly).
+ Avoid wierd headers on unbalanced punctuation of the form:
+ ``Joe User <user)'' -- this caused reference to the
+ null macro. Fix from Rick McCarty of IO.COM.
+ Fix a problem that caused an alias "user: user@local.host" to
+ not have the QNOTREMOTE bit set; this caused configs
+ to act as if FEATURE(notsticky) was defined even when
+ it was not. The effect of the problem was to make it
+ very hard to to set up satellite sites that had a few
+ local accounts, with everything else forwarded to a
+ corporate hub. Reported by Detlef Drewanz of the
+ University of Rostock and Mark Frost of NCD.
+ Change queuing to not call rulesets 3, {1 or 2}, 4 on header
+ addresses. This is more efficient (fewer name server
+ calls) and fixes certain unusual configurations, such
+ as those that have ruleset 4 do something that is
+ non-idempotent unless a mailer-specific ruleset did
+ something else. Problem reported by Brian J. Coan
+ of the Institute for Global Communications.
+ Fix the "obsolete argument" routine in main to better understand
+ new arguments. For example, if you used ``sendmail
+ -C config -v -q'' it would choke on the -q because
+ the -C would stop looking for old-format arguments.
+ Fix the code that was intended to allow two users to forward their
+ mail to the same program and have them appear unique.
+ Portability fixes for:
+ SCO UNIX from Murray Kucherawy.
+ SCO Open Server 3.2v4 from Philippe Brand.
+ System V Release 4 from Rick Ellis and others.
+ OSF/1 from Steve Campbell.
+ DG/UX from Ben Mesander of the USGS and Bryan Curnutt
+ of Stoner Associates.
+ Motorola SysV88 from Kevin Johnson of Motorola.
+ Solaris 2.3 from Casper H.S. Dik of the University
+ of Amsterdam and John Caruso of University
+ of Maryland.
+ FreeBSD from Ollivier Robert.
+ NetBSD from Adam Glass.
+ TitanOS from Kate Hedstrom of Rutgers University.
+ Irix from Bryan Curnutt.
+ Dynix from Jim Davis of the University of Arizona.
+ RISC/os.
+ Linux from John Kennedy of California State University
+ at Chico.
+ Solaris 2.x from Tony Boner of the U.S. Air Force.
+ NEXTSTEP 3.x from Vince DeMarco.
+ HP-UX from various people. NOTA BENE: the location
+ of the config file has moved to /usr/lib
+ to match the HP-UX version of sendmail.
+ CONFIG: Don't do any recipient rewriting on relay mailer;
+ since this is intended only for internal use, the
+ usual RFC 821/822/1123 rules can be relaxed. The
+ main point of this is to avoid munging (ugh) UUCP
+ addresses when relaying internally.
+ CONFIG: fix typo in mailer/uucp.m4 that mutilates list:;
+ syntax addresses delivered via UUCP. Solution
+ provided by Peter Wemm.
+ CONFIG: fix thumb-fumble in default UUCP relaying in ruleset
+ zero; it caused double @ signs in addresses. From
+ Irving Reid of the University of Toronto.
+ CONFIG: Portability fixes for SCO Unix 3.2 with TCP/IP 1.2.1
+ from Markku Toijala of ICL Personal Systems Oy.
+ CONFIG: Add trailing "." on pseudo-domains for consistency;
+ this fixes a problem (noted by Al Whaley of Sunnyside)
+ that made it hard to recognize your own pseudodomain
+ names.
+ CONFIG: catch "@host" syntax errors (i.e., null local-parts)
+ rather than letting them get "local configuration
+ error"s. Problem noted by John Gardiner Myers.
+ CONFIG: add uucp-uudom mailer variant, based on code posted
+ by Spider Boardman <spider@Orb.Nashua.NH.US>; this
+ has uucp-dom semantics but old UUCP syntax. This
+ also permits "uucp-old" as an alias for "uucp" and
+ "uucp-new" as a synonym for "suucp" for consistency.
+ CONFIG: add POP mailer support (from Kimmo Suominen
+ <kim@grendel.lut.fi>).
+ CONFIG: drop CSNET_RELAY support -- CSNET is long gone.
+ CONFIG: fix bug caused with domain literal addresses (e.g.,
+ ``[128.32.131.12]'') when FEATURE(allmasquerade)
+ was set; it would get an additional @masquerade.host
+ added to the address. Problem noted by Peter Wan
+ of Georgia Tech.
+ CONFIG: make sure that the local UUCP name is in $=w. From
+ Jim Murray of Stratus.
+ CONFIG: changes to UUCP rewriting to simulate IDA-style "V"
+ mailer flag. Briefly, if you are sending to host
+ "foo", then it rewrites "foo!...!baz" to "...!baz",
+ "foo!baz" remains "foo!baz", and anything else has
+ the local name prepended.
+ CONFIG: portability fixes for HP-UX.
+ DOC: several minor problems fixed in the Install & Op Guide.
+ MAKEMAP: fix core dump problem on lines that are too long or
+ which lack newline. From Mark Delany.
+ MAILSTATS: print sums of columns (total messages & kbytes
+ in and out of the system). From Tom Ferrin of UC
+ San Francisco Computer Graphics Lab.
+ SIGNIFICANT USER- OR SYSAD-VISIBLE CHANGES:
+ On HP-UX, /etc/sendmail.cf has been moved to
+ /usr/lib/sendmail.cf to match HP sendmail.
+ Permissions have been tightened up on world-writable
+ :include: files and accounts that have shells
+ that are not listed in /etc/shells. This may
+ cause some .forward files that have worked
+ before to start failing.
+ SIGUSR1 dumps some state to the log.
+ NEW FILES:
+ src/Makefile.DGUX
+ src/Makefile.Dynix
+ src/Makefile.FreeBSD
+ src/Makefile.Mach386
+ src/Makefile.NetBSD
+ src/Makefile.RISCos
+ src/Makefile.SCO
+ src/Makefile.SVR4
+ src/Makefile.Titan
+ cf/mailer/pop.m4
+ cf/ostype/bsdi1.0.m4
+ cf/ostype/dgux.m4
+ cf/ostype/dynix3.2.m4
+ cf/ostype/sco3.2.m4
+ makemap/Makefile.dist
+ praliases/Makefile.dist
+
+8.6.4/8.6.4 93/10/31
+ Repair core-dump problem (write to read-only memory segment)
+ if you fall back to the return-to-Postmaster case in
+ savemail. Problem reported by Richard Liu.
+ Immediately diagnose bogus sender addresses in SMTP. This
+ makes quite certain that crackers can't use this
+ class of attack.
+ Reliability Fix: check return value from fclose() and fsync()
+ in a few critical places.
+ Minor problem in initsys() that reversed a condition for
+ redirecting the output channel on queue runs. It's
+ not clear this code even does anything. From Eric
+ Wassenaar of the Dutch National Institute for Nuclear
+ and High-Energy Physics.
+ Fix some problems that caused queue runs to do "too much work",
+ such as double-reading the Errors-To: header. From
+ Eric Wassenaar.
+ Error messages on writing the temporary file (including the
+ data file) were getting suppressed in SMTP -- this
+ fix causes them to be properly reported. From Eric
+ Wassenaar.
+ Some changes to support AF_UNIX sockets -- this will only
+ really become relevant in the next release, but some
+ people need it for local patches. From Michael
+ Corrigan of UC San Diego.
+ Use dynamically allocated memory (instead of static buffers)
+ for macros defined in initsys() and settime(); since
+ these can have different values depending on which
+ envelope they are in. From Eric Wassenaar.
+ Improve logging to show ctladdr on to= logging; this tells you
+ what uid/gid processes ran as.
+ Fix a problem that caused error messages to be discarded if
+ the sender address was unparseable for some reason;
+ this was supposed to fall back to the "return to
+ postmaster" case.
+ Improve aliaswait backoff algorithm.
+ Portability patches for Linux (8.6.3 required another header
+ file) (from Karl London) and SCO UNIX.
+ CONFIG: patch prog mailer to not strip host name off of envelope
+ addresses (so that it matches local again). From
+ Christopher Davis.
+ CONFIG: change uucp-dom mailer so that "<>" translates to $n;
+ this prevents uux from seeing lines with null names like
+ ``From Sat Oct 30 14:55:31 1993''. From Motonori
+ Nakamura of Kyoto University.
+ CONFIG: handle <list:;> syntax correctly. This isn't legal, but
+ it shouldn't fail miserably. From Motonori Nakamura.
+
+8.6.3/8.6.3 93/10/24
+ IMPORTANT FIX: Fix several problems that caused open files to
+ be "lost" during queue runs; this overflowed the open
+ file table on large runs. An assumption that fdopen
+ always succeeds sometimes resulted in core dumps when
+ this happens; sometimes the message is delivered twice,
+ sometimes (probably) infinite times. This problem in
+ various form was reported by P{r (Pell) Emanuelsson and
+ Robert Campbell of U.C. Berkeley.
+ Special diagnosis of EMFILE error conditions -- it now prints
+ the known open file descriptors so you can figure out
+ what is consuming so much resources.
+ Fix a couple of problems caused by early address parsing
+ errors -- one caused it to return a "this is only a
+ warning" when it really wasn't, and the other started
+ parsing through a random pointer. The first was
+ noted by Eric Wassenaar.
+ Fix an infinite loop problem caused by null components in the
+ host signature. Problem noted by Jan Sorensen.
+ Be sure to reset the "current date" when sending an error
+ message -- PostMasterCopy messages were being sent
+ with an old Date: header.
+ Fix a problem that caused duplicated mail when sendmail was
+ (1) compiled without HASFLOCK, (2) you are sending to
+ an alias that has an owner-* alias, (3) you execute
+ sendmail with -t flag, (4) you run in -odb mode, and
+ (5) the sender specifies both the alias name and
+ another alias [i.e., the envelope is split], then
+ duplicate messages are sent. The problem description
+ and one-line fix are from Motonori Nakamura of Kyoto
+ University.
+ Avoid a problem that causes error messages to be discarded
+ in some cases -- this was the result of a "fix" to
+ avoid duplicate error messages, but two are better
+ than zero. Reported by Tim Rylance.
+ Fix a minor botch in checkfd012() -- fix from Dave Hill of
+ Computervision R&D Ltd.
+ Remove "X-Authentication-Warning: <user> set sender to <address>
+ using -f" entirely -- it is far too eager to include
+ this, and it is confusing folks. I'll try to make it
+ work "right" in 8.7. Problem noted by Yoshitaka
+ Tokugawa of dit Co., Ltd.
+ Fix a race condition with the errno value in tick() and
+ reapchild() -- this caused occasional misdiagnosis
+ of problems. Kyle Jones of UUNET helped this along.
+ Repair rule loop-detection code. From Michael Corrigan of
+ U.C. San Diego.
+ Fix a problem that caused sender domain addition (C mailer
+ flag to be ignored if you use -odq or use -odb with
+ a high load average. Problem reported by Jim Murray
+ of Stratus.
+ Fix ident protocol on multi-homed machines. It was not
+ always using the correct interface. Fix from J.R.
+ Oldroyd of Opal.
+ Previously, sendmail assumed that any SMTP greeting message
+ that wasn't 2xx was a temporary failure -- it should
+ only take 4xx as a temporary failure, and return a
+ solid error message on anything else -- for example,
+ to allow you to reject connections on a workstation
+ that is MXed to a mail server.
+ Portability enhancements for 386BSD/FreeBSD/NetBSD from
+ Ollivier Robert.
+ CONFIG: FEATURE(always_add_domain) didn't always add the domain;
+ in particular, on local mail it modified the header sender
+ but not the header recipient address(es). Reported by
+ Jeffrey Honig of Cornell University. Also, strip
+ any host from envelope recipient address(es), since
+ local mailers don't understand host names -- this is
+ to help mailertable entries. From Christopher Davis.
+ CONFIG: masquerading didn't apply to addresses that already
+ had a domain. This change replaces a local hostname
+ by the masquerade name in the SMTP mailer (previously
+ it only added the masquerade name if it didn't already
+ have a domain name). Several people complained about
+ this.
+
+8.6.2/8.6.2 93/10/15
+ Put a "successful delivery" message in the transcript for
+ addresses that get return-receipts.
+ Put a prominent "this is only a warning" message in warning
+ messages -- some people don't read carefully enough
+ and end up sending the message several times.
+ Include reason for temporary failure in the "warning" return
+ message. Currently, it just says "cannot send for
+ four hours".
+ Fix the "Original message received" time generated for
+ returntosender messages. It was previously listed as
+ the current time. Bug reported by Eric Hagberg of
+ Cornell University Medical College.
+ If there is an error when writing the body of a message,
+ don't send the trailing dot and wait for a response
+ in sender SMTP, as this could cause the connection to
+ hang up under some bizarre circumstances. From Eric
+ Wassenaar.
+ Fix some server SMTP synchronization problems caused when
+ connections fail during message collection. From
+ Eric Wassenaar.
+ Fix a problem that can cause srvrsmtp to reject mail if the
+ name server is down -- it accepts the RCPT but rejects
+ the DATA command. Problem reported by Jim Murray of
+ Stratus.
+ Fix a problem that can cause core dumps if the config file
+ incorrectly resolves to a null hostname. Reported by
+ Allan Johannesen of WPI.
+ Non-root use of -C flag, dangerous -f flags, and use of -oQ
+ by non-root users were not put into
+ X-Authentication-Warning:s as intended because the
+ config file hadn't set the PrivacyFlags yet. Fix
+ from Sven-Ove Westberg of the University of Lulea.
+ Under very odd circumstances, the alias file rebuild code
+ could get confused as to whether a database was
+ open or not.
+ Check "vendor code" on the end of V lines -- this is
+ intended to provide a hook for vendor-specific
+ configuration syntax. (This is a "new feature",
+ but I've made an exception to my rule in a belief
+ that this is a highly exceptional case.)
+ Portability fixes for DG/UX (from Douglas Anderson of NCSC),
+ SCO Unix (from Murray Kucherawy), A/UX, and OSF/1
+ (from Jon Forrest of UC Berkeley)
+ CONFIG: fix ``mailer:host'' form of UUCP relay naming.
+
+8.6.1/8.6 93/10/08
+ Portability fixes for A/UX and Encore UMAX V.
+ Fix error message handling -- if you had a name server down
+ causing an error during parsing, that message was never
+ propogated to the queue file.
+
+8.6/8.6 93/10/05
+ Configuration cleanup: make it easier to undo IDENTPROTO in
+ conf.h (other systems have the same bug).
+ If HASGETDTABLESIZE and _SC_OPEN_MAX are both defined, assume
+ getdtablesize() instead of sysconf(); a disturbingly
+ large number of systems defined _SC_OPEN_MAX in the
+ header files but don't have the syscall.
+ Another patch to really truly ignore MX records in getcanonname
+ if trymx == FALSE.
+ Fix problem that caused the "250 IAA25499 Message accepted for
+ delivery" message to be omitted if there was an error
+ in the header of the message (e.g., a bad Errors-To:
+ line). Pointed out by Michael Corrigan of UCSD.
+ Announce name of host we are chatting when we get errors; this
+ is an IDA-ism suggested by Christophe Wolfhugel.
+ Portability fixes for Alpha OSF/1 (from Anthony Baxter of the
+ Australian Artificial Intelligence Institute), SCO Unix
+ (from Murray Kucherawy of Hookup Communication Corp.),
+ NeXT (from Vince DeMarco and myself), Linux (from
+ Karl London <karl@borg.demon.co.uk>), BSDI (from
+ Christophe Wolfhugel, and SVR4 on Dell (from Kimmo
+ Suominen), AUX 3.0 on Macintosh, and ANSI C compilers.
+ Some changes to get around gcc optimizer bugs. From Takahiro
+ Kanbe.
+ Fix error recovery in queueup if another tf file of the same
+ name already exists. Problem stumbled over by Bill
+ Wisner of The Well.
+ Output YP_MASTER_NAME and YP_LAST_MODIFIED without null bytes.
+ Problem noted by Keith McMillan of Ameritech Services.
+ Deal with group permissions properly when opening .forward and
+ :include: files. This relaxes the 8.1C restrictions
+ slightly more. This includes proper setting of groups
+ when reading :include: files, allowing you to read some
+ files that you should be able to read but have previously
+ been denied unless you owned them or they had "other"
+ read permission.
+ Make certain that $j is in $=w (after the .cf is read) so that
+ if the user is forced to override some silly system,
+ MX suppression will still work.
+ Fix a couple of efficiency problems where newstr was double-
+ calling expensive routines. In at least one case, it
+ wasn't guaranteed that they would always return the
+ same result. Problem noted by Christophe Wolfhugel.
+ Fix null pointer dereference in putoutmsg -- only on an error
+ condition from a non-SMTP mailer. From Motonori
+ Nakamura.
+ Macro expand "C" line class definitions before scanning so that
+ "CX $Z" works.
+ Fix problem that caused error message to be sent while still
+ trying to send the original message if the connection
+ is closed during a DATA command after getting an error
+ on an RCPT command (pretty obscure). Problem reported
+ by John Myers of CMU.
+ Fix reply to NOOP to be 250 instead of 200 -- this is a long
+ term bug.
+ Fix a nasty bug causing core dumps when returning the "warning:
+ cannot deliver for N hours -- will keep trying" message;
+ it only occurred if you had PostMasterCopy set and
+ only on some architectures. Although sendmail would
+ keep trying, it would send error messages on each
+ queue interval. This is an important fix.
+ Allow u and g options to take user and group names respectively.
+ Don't do a chdir into the queue directory in -bt mode to make
+ ruleset testing a bit easier.
+ Don't allow users to turn off logging (using -oL) on the command
+ line -- command line can only raise, not lower, logging
+ level.
+ Set $u to the original recipient on the SMTP transaction or on
+ the command line. This is only done if there is exactly
+ one recipient. Technically, this does not meet the
+ specs, because it does not guarantee a domain on the
+ address.
+ Fix a problem that dumped error messages on bad addresses if
+ you used the -t flag. Problem noted by Josh Smith of
+ Harvey Mudd College.
+ Given an address such as ``<foo> <bar>'', auto-quote the first
+ ``<foo>'' part, giving ``"<foo>" <bar>''. This is to
+ avoid the problem of people who use angle brackets in
+ their full name information.
+ Fix a null pointer dereference if you set option "l", have
+ an Errors-To: header in the message, and have Errors-To:
+ defined in the config file H lines. From J.R. Oldroyd.
+ Put YPCOMPAT on #ifdef NIS instead -- it's one less thing to get
+ wrong when compiling. Suggested by Rick McCarty of TI.
+ Fix a problem that could pass negative SIZE parameter if the
+ df file got lost; this would cause servers to always
+ give a temporary failure, making the problem even worse.
+ Problem noted by Allan Johannesen of WPI.
+ Add "ident" timeout (one of the "r" option selectors) for IDENT
+ protocol timeouts (30s default). Requested by Murray
+ Kucherawy of HookUp Communication Corp. to handle bogus
+ PC TCP/IP implementations.
+ Change $w default definition to be just the first component of
+ the domain name on config level 5. The $j macro defaults
+ to the FQDN; $m remains as before. This lets well-behaved
+ config files use any of the short, long, or subdomain
+ names.
+ Add makesendmail script in src to try to automate multi-architecture
+ builds. I know, this is sub-optimal, but it is still
+ helpful.
+ Fix very obscure race condition that can cause a queue run to
+ get a queue file for an already completed job. This
+ problem has existed for years. Problem noted by the
+ long suffering Allan Johannesen of WPI.
+ Fix a problem that caused the raw sender name to be passed to
+ udbsender instead of the canonified name -- this caused
+ it to sometimes miss records that it should have found.
+ Relax check of name on HELO packet so that a program using -bs
+ that claims to be itself works properly.
+ Restore rewriting of $: part of address through 2, R, 4 in
+ buildaddr -- this requires passing a lot of flags to get
+ it right. Unlike old versions, this ONLY rewrites
+ recipient addresses, not sender addresses.
+ Fix a bug that caused core dumps in config files that cannot
+ resolve /file/name style addresses. Fix from Jonathan
+ Kamens of OpenVision Technologies.
+ Fix problem with fcntl locking that can cause error returns to
+ be lost if the lock is lost; this required fully
+ queueing everything, dropping the envelope (so errors
+ would get returned), and then re-reading the queue from
+ scratch.
+ Fix a problem that caused aliases that redefine an otherwise
+ true address to still send to the original address
+ if and only if the alias failed in certain bizarre
+ ways (e.g, if they pointed at a list:; syntax address).
+ Problem pointed out by Jonathan Kamens.
+ Remove support for frozen configuration files. They caused
+ more trouble than it was worth.
+ Fix problem that can cause error messages to get ignored when
+ using both -odb and -t flags. Problem noted by Rob
+ McNicholas at U.C. Berkeley.
+ Include all "normal" variations on hostname in $=w. For example,
+ if the host name is vangogh.cs.berkeley.edu, $=w will
+ contain vangogh, vangogh.cs, and vangogh.cs.berkeley.edu.
+ Add "restrictqrun" privacy flag -- without this, anyone can run
+ the queue.
+ Reset SmtpPhase global on initial connection creation so that
+ messages don't come out with stale information.
+ Pass an "ext" argument to lockfile so that error/log messages
+ will properly reflect the true filename being locked.
+ Put all [...] address forms into $=w -- this eliminates the need
+ for MAXIPADDR in conf.h. Suggested by John Gardiner
+ Myers of CMU.
+ Fix a bug that can cause qf files to be left around even after
+ an SMTP RSET command. Problem and fix from Michael
+ Corrigan.
+ Don't send a PostMasterCopy to errors when the Precedence: is
+ negative. Error reports still go to the envelope
+ sender address.
+ Add LA_SHORT for load averages.
+ Lock sendmail.st file when posting statistics.
+ Add "SendBufSize" and "RcvBufSize" suboptions to "O" option to
+ set the size of the TCP send and receive buffers; if you
+ run over a slow slip line you may need to set these down
+ (although it would be better to fix the SLIP implementation
+ so that it's not necessary to recompile every program
+ that does bulk data transfer).
+ Allow null defaults on $( ... $) lookups. Problem reported by
+ Amir Plivatsky.
+ Diagnose crufty S and V config lines. This resulted from an
+ observation that some people were using the SITE macro
+ without the SITECONFIG macro first, which was causing
+ bogus config files that were not caught.
+ Fix makemap -f flag to turn off case folding (it was turning it
+ on instead). THIS IS A USER VISIBLE CHANGE!!!
+ Fix a problem that caused multiple error messages to be sent if
+ you used "sendmail -t -oem -odb", your system uses fcntl
+ locking, and one of the recipient addresses is unknown.
+ Reset uid earlier in include() so that recursive .forwards or
+ :include:s don't use the wrong uid.
+ If file descriptor 0, 1, or 2 was closed when sendmail was
+ called, the code to recover the descriptor was broken.
+ This sometimes (only sometimes) caused problems with the
+ alias file. Fix from Motonori Nakamura.
+ Fix a problem that caused aliaswait to go into infinite recursion
+ if the @:@ metasymbol wasn't found in the alias file.
+ Improve error message on newaliases if database files cannot be
+ opened or if running with no database format defined.
+ Do a better estimation of the size of error messages when NoReturn
+ is set. Problem noted by P{r (Pell) Emanuelsson.
+ Fix a problem causing the "c" option (don't connect to expensive
+ mailers) to be ignored in SMTP. Problem noted and the
+ solution suggested by Robert Elz of Munnari University.
+ Improve connection caching algorithm by passing "[host]" to
+ hostsignature, which strips the square brackets and
+ returns the real name. This allows mailertable entries
+ to match regular entries.
+ Re-enable Return-Receipt-To: -- people seem to want this stupid
+ feature, even if it doesn't work right.
+ Catch and log attempts to try the "wiz" command in server SMTP.
+ This also ups the log level from LOG_NOTICE to LOG_CRIT.
+ Be more generous at assigning $z to the home directory -- do this
+ for programs that are specified through a .forward file.
+ Fix from Andrew Chang of Sun Microsystems.
+ Always save a fatal error message in preference to a non-fatal
+ error message so that the "subject" line of return
+ messages is the best possible.
+ CONFIG: reduce the number of quotes needed to quote configuration
+ parameters with commas: two quotes should work now, e.g.,
+ define(ALIAS_FILE, ``/etc/aliases,/etc/aliases.local'').
+ CONFIG: class $=Z is a set of UUCP hosts that use uucp-dom
+ connections (domain-ized UUCP).
+ CONFIG: fix bug in default maps (-o must be before database file
+ name). Pointed out by Christophe Wolfhugel.
+ CONFIG: add FEATURE(nodns) to state that we are not relying on
+ DNS. This would presumably be used in UUCP islands.
+ CONFIG: add OSTYPE(nextstep) and OSTYPE(linux).
+ CONFIG: log $u in Received: line. This is in technical violation
+ of the standards, since it doesn't guarantee a domain
+ on the address.
+ CONFIG: don't assume "m" in local mailer flags -- this means that
+ if you redefine LOCAL_MAILER_FLAGS you will have to include
+ the "m" flag should you want it. Apparently some Solaris 2.2
+ installations can't handle multiple local recipients.
+ Problem noted by Josh Smith.
+ CONFIG: add confDOMAIN_NAME to set $j (if undefined, $j defaults).
+ CONFIG: change default version level from 4 to 5.
+ CONFIG: add FEATURE(nullclient) to create a config file that
+ forwards all mail to a hub without ever looking at the
+ addresses in any detail.
+ CONFIG: properly strip mailer: information off of relays when
+ used to change .BITNET form into %-hack form.
+ CONFIG: fix a problem that caused infinite loops if presented
+ with an address such as "!foo".
+ CONFIG: check for self literal (e.g., [128.32.131.12]) even if
+ the reverse "PTR" mapping is broken. There's a better
+ way to do this, but the change is fairly major and I
+ want to hold it for another release. Problem noted by
+ Bret Marquis.
+
+8.5/8.5 93/07/23
+ Serious bug: if you used a command line recipient that was unknown
+ sendmail would not send a return message (it was treating
+ everything as though it had an SMTP-style client that
+ would do the return itself). Problem noted by Josh Smith.
+ Change "trymx" option in getcanonname() to ignore all MX data,
+ even during a T_ANY query. This actually didn't break
+ anything, because the only time you called getcanonname
+ with !trymx was if you already knew there were no MX
+ records, but it is somewhat cleaner. From Motonori
+ Nakamura.
+ Don't call getcanonname from getmxrr if you already know there
+ are no DNS records matching the name.
+ Fix a problem causing error messages to always include "The
+ original message was received ... from localhost".
+ The correct original host information is now included.
+ Previous change to cf/sh/makeinfo.sh doesn't port to Ultrix (their
+ version of "test" doesn't have the -x flag). Change it
+ to use -f instead. From John Myers.
+ CONFIG: 8.4 mistakenly set the default SMTP-style mailer to
+ esmtp -- it should be smtp.
+ CONFIG: send all relayed mail using confRELAY_MAILER (defaults
+ to "relay" (a variant of "smtp") if MAILER(smtp) is used,
+ else "suucp" if MAILER(uucp) is used, else "unknown");
+ this cleans up the configs somewhat. This fixes a serious
+ problem that caused route-addrs to get mistaken as relays,
+ pointed out by John Myers. WARNING: this also causes
+ the default on SMART_HOST to change from "suucp" to
+ "relay" if you have MAILER(smtp) specified.
+
+8.4/8.4 93/07/22
+ Add option `w'. If you receive a message that comes to you because
+ you are the best (lowest preference) target of an MX, and
+ you haven't explicitly recognized the source MX host in
+ your .cf file, this option will cause you to try the target
+ host directly (as if there were no MX for it at all). If
+ `w' is not set, this case is a configuration error.
+ Beware: if `w' is set, senders may get bogus errors like
+ "message timed out" or "host unknown" for problems that
+ are really configuration errors. This option is
+ disrecommended, provided only for compatibility with
+ UIUC sendmail.
+ Fix a problem that caused the incoming socket to be left open
+ when sendmail forks after the DATA command. This caused
+ calling systems to wait in FIN_WAIT_2 state until the
+ entire list was processed and the child closed -- a
+ potentially prodigious amount of time. Problem noted
+ by Neil Rickert.
+ Fix problem (created in 6.64) that caused mail sent to multiple
+ addresses, one of which was a bad address, to completely
+ suppress the sending of the message. This changes
+ handling of EF_FATALERRS somewhat, and adds an
+ EF_GLOBALERRS flag. This also fixes a potential problem
+ with duplicate error messages if there is a syntax error
+ in the header of a message that isn't noticed until late
+ in processing. Original problem pointed out by Josh Smith
+ of Harvey Mudd College. This release includes quite a bit
+ of dickering with error handling (see below).
+ Back out SMTP transaction if MAIL gets nested 501 error. This
+ will only hurt already-broken software and should help
+ humans.
+ Fix a problem that broke aliases when neither NDBM nor NEWDB were
+ compiled in. It would never read the alias file.
+ Repair unbalanced `)' and `>' (the "open" versions are already
+ repaired).
+ Logging of "done" in dropenvelope() was incorrect: it would
+ log this even when the queue file still existed. Change
+ this to only log "done" (at log level 11) when the
+ queue file is actually removed. From John Myers.
+ Log "lost connection" in server SMTP at log level 20 if there
+ is no pending transaction. Some senders just close the
+ connection rather than sending QUIT.
+ Fix a bug causing getmxrr to add a dot to the end of unqualified
+ domains that do not have MX records -- this would cause
+ the subsequent host name lookup to fail. The problem
+ only occurred if you had FEATURE(nocanonify) set.
+ Problem noted by Rick McCarty of Texas Instruments.
+ Fix invocation of setvbuf when passed a -X flag -- I had
+ unwittingly used an ANSI C extension, and this caused
+ core dumps on some machines.
+ Diagnose self-destructive alias loops on RCPT as well as EXPN.
+ Previously it just gave an empty send queue, which
+ then gave either "Need RCPT (recipient)" at the DATA
+ (confusing, since you had given an RCPT command which
+ returned 250) or just dropped the email, depending on
+ whether you were running VERBose mode. Now it usually
+ diagnoses this case as "aliasing/forwarding loop broken".
+ Unfortunately, it still doesn't adequately diagnose
+ some true error conditions.
+ Add internal concept of "warning messages" using 6xx codes.
+ These are not reported only to Postmaster. Unbalanced
+ parens, brackets, and quotes are printed as 653 codes.
+ They are always mapped to 5xx codes before use in SMTP.
+ Clean up error messages to tell both the actual address that
+ failed and the alias they arose from. This makes it
+ somewhat easier to diagnose problems. Difficulty noted
+ by Motonori Nakamura.
+ Fix a problem that inappropriately added a ctladdr to addresses
+ that shouldn't have had one during a queue run. This
+ caused error messages to be handled differently during
+ a queue run than a direct run.
+ Don't print the qf name and line number if you get errors during
+ the direct run of the queue from srvrsmtp -- this was
+ just extra stuff for users to crawl through.
+ Put command line flags on second line of pid file so you can
+ auto-restart the daemon with all appropriate arguments.
+ Use "kill `head -1 /etc/sendmail.pid`" to stop the
+ daemon, and "eval `tail -1 /etc/sendmail.pid`" to
+ restart it.
+ Remove the ``setuid(getuid())'' in main -- this caused the
+ IDENT daemon to screw up. This required that I change
+ HASSETEUID to HASSETREUID and complicate the mode
+ changing somewhat because both Ultrix and SunOS seem
+ to have a bug causing seteuid() to set the saved uid
+ as well as the effective. The program test/t_setreuid.c
+ will test to see if your implementation of setreuid(2)
+ is appropriately functional.
+ The FallBackMX (option V) handling failed to properly identify
+ fallback to yourself -- most of the code was there,
+ but it wasn't being enabled. Problem noted by Murray
+ Kucherawy of the University of Waterloo.
+ Change :include: open timeout from ETIMEDOUT to an internal
+ code EOPENTIMEOUT; this avoids adding "during SmtpPhase
+ with CurHostName" in error messages, which can be
+ confusing. Reported by Jonathan Kamens of OpenVision
+ Technologies.
+ Back out setpgrp (setpgid on POSIX systems) call to reset the
+ process group id. The original fix was to get around
+ some problems with recalcitrant MUAs, but it breaks
+ any call from a shell that creates a process group id
+ different from the process id. I could try to fix
+ this by diddling the tty owner (using tcsetpgrp or
+ equivalent) but this is too likely to break other
+ things.
+ Portability changes:
+ Support -M as equivalent to -oM on Ultrix -- apparently
+ DECnet calls sendmail with -MrDECnet -Ms<HOST> -bs
+ instead of using standard flags. Oh joy. This
+ behaviour reported by Jon Giltner of University
+ of Colorado.
+ SGI IRIX -- this includes several changes that should
+ help other strict ANSI compilers.
+ SCO Unix -- from Murray Kucherawy of HookUp Communication
+ Corporation.
+ Solaris running the Sun C compiler (which despite the
+ documentation apparently doesn't define
+ __STDC__ by default).
+ ConvexOS from Eric Schnoebelen of Convex.
+ Sony NEWS workstations and Omron LUNA workstations from
+ Motonori Nakamura.
+ CONFIG: add confTRY_NULL_MX_LIST to set option `w'.
+ CONFIG: delete `C' and `e' from default SMTP mailers flags;
+ several people have made a good argument that this
+ creates more problems than it solves (although this
+ may prove painful in the short run).
+ CONFIG: generalize all the relays to accept a "mailer:host"
+ format.
+ CONFIG: move local processing in ruleset 0 into a new ruleset
+ 98 (8 on old sendmail). Domain literal [a.b.c.d]
+ addresses are also passed through this ruleset.
+ CONFIG: if neither SMART_HOST nor MAILER(smtp) were defined,
+ internet-style addresses would "fall off the end" of
+ ruleset zero and be interpreted as local -- however,
+ the angle brackets confused the recursive call.
+ These are now diagnosed as "Unrecognized host name".
+ CONFIG: USENET rules weren't included in S0 because of a mistaken
+ ifdef(`_MAILER_USENET_') instead of
+ ifdef(`_MAILER_usenet_'). Problem found by Rein Tollevik
+ of SINTEF RUNIT, Oslo.
+ CONFIG: move up LOCAL_RULE_0 processing so that it happens very
+ early in ruleset 0; this allows .mc authors to bypass
+ things like the "short circuit" code for local addresses.
+ Prompted by a comment by Bill Wisner of The Well.
+ CONFIG: add confSMTP_MAILER to define the mailer used (smtp or
+ esmtp) to send SMTP mail. This allows you to default
+ to esmtp but use a mailertable or other override to
+ deal with broken servers. This logic was pointed out
+ to me by Bill Wisner. Ditto for confLOCAL_MAILER.
+ Changes to cf/sh/makeinfo.sh to make it portable to SVR4
+ environments. Ugly as sin.
+
+8.3/8.3 93/07/13
+ Fix setuid problems introduced in 8.2 that caused messages
+ like "Cannot create qfXXXXXX: Invalid argument"
+ or "Cannot reopen dfXXXXXX: Permission denied". This
+ involved a new compile flag "HASSETEUID" that takes
+ the place of the old _POSIX_SAVED_IDS -- it turns out
+ that the POSIX interface is broken enough to break
+ some systems badly. This includes some fixes for
+ HP-UX. Also fixes problems where the real uid is
+ not reset properly on startup (from Neil Rickert).
+ Fix a problem that caused timed out messages to not report the
+ addresses that timed out. Error messages are also more
+ "user friendly".
+ Drop required bandwidth on connections from 64 bytes/sec to
+ 16 bytes/sec.
+ Further Solaris portability changes -- doesn't require the BSD
+ compatibility library. This also adds a new
+ "HASGETDTABLESIZE" compile flag which can be used if
+ you want to use getdtablesize(2) instead of sysconf(2).
+ These are loosely based on changes from David Meyer at
+ University of Oregon. This now seems to work, at least
+ for quick test cases.
+ Fix a problem that can cause duplicate error messages to be
+ sent if you are in SMTP, you send to multiple addresses,
+ and at least one of those addresses is good and points
+ to an account that has a .forward file (whew!).
+ Fix a problem causing messages to be discarded if checkcompat()
+ returned EX_TEMPFAIL (because it didn't properly mark
+ the "to" address). Problem noted by John Myers.
+ Fix dfopen to return NULL if the open failed; I was depending
+ on fdopen(-1) returning NULL, which isn't the case. This
+ isn't serious, but does result in wierd error diagnoses.
+ From Michael Corrigan.
+ CONFIG: add UUCP_MAX_SIZE M4 macro to set the maximum size of
+ messages sent through UUCP-family mailers. Suggested
+ by Bill Wisner of The Well.
+ CONFIG: if both MAILER(uucp) and MAILER(smtp) are specified,
+ include a "uucp-dom" mailer that uses domain-style
+ addressing. Suggested by Bill Wisner.
+ CONFIG: Add LOCAL_SHELL_FLAGS and LOCAL_SHELL_ARGS to match
+ LOCAL_MAILER_FLAGS and LOCAL_MAILER_ARGS. Suggested by
+ Christophe Wolfhugel.
+ CONFIG: Add OSTYPE(aix3). From Christophe Wolfhugel.
+
+8.2/8.2 93/07/11
+ Don't drop out on config file parse errors in -bt mode.
+ On older configuration files, assume option "l" (use Errors-To
+ header) for back compatibility. NOTE: this DOES NOT
+ imply an endorsement of the Errors-To: header in any way.
+ Accept -x flag on AIX-3 as well as OSF/1. Why, why, why???
+ Don't log errors on EHLO -- it isn't a "real" error for an old
+ SMTP server to give an error on this command, and
+ logging it in the transcript can be confusing. Fix
+ from Bill Wisner.
+ IRIX compatibility changes provided by Dan Rich
+ <drich@sandman.lerc.nasa.gov>.
+ Solaris 2 compatibility changes. Provided by Bob Cunningham
+ <bob@kahala.soest.hawaii.edu>, John Oleynick
+ <juo@klinzhai.rutgers.edu>
+ Debugging: -d17 was overloaded (hostsignature and usersmtp.c);
+ move usersmtp (smtpinit and smtpmailfrom) to -d18 to
+ match the other flags in that file.
+ Flush transcript before fork in mailfile(). From Eric Wassenaar.
+ Save h_errno in mci struct and improve error message display.
+ Changes from Eric Wassenaar.
+ Open /dev/null for the transcript if the create of the xf file
+ failed; this avoids at least one possible null pointer
+ reference in very wierd cases. From Eric Wassenaar.
+ Clean up statistics gathering; it was over-reporting because of
+ forks. From Eric Wassenaar.
+ Fix problem that causes old Return-Path: line to override new
+ Return-Path: line (conf.c needs H_FORCE to avoid
+ re-using old value). From Motonori Nakamura.
+ Fix broken -m flag in K definition -- even if -m (match only)
+ was specified, it would still replace the key with the
+ value. Noted by Rick McCarty of Texas Instruments.
+ If the name server timed out over several days, no "timed out"
+ message would ever be sent back. The timeout code
+ has been moved from markfailure() to dropenvelope()
+ so that all such failures should be diagnosted. Pointed
+ out by Christophe Wolfhugel and others.
+ Relax safefile() constraints: directories in an include or
+ forward path must be readable by self if the controlling
+ user owns the entry, readable by all otherwise (e.g.,
+ when reading your .forward file, you have to own and
+ have X permssion in it; everyone needs X permission in
+ the root and directories leading up to your home);
+ include files must be readable by anyone, but need not
+ be owned by you.
+ If _POSIX_SAVED_IDS is defined, setuid to the owner before
+ reading a .forward file; this gets around some problems
+ on NFS mounts if root permission is not exported and
+ the user's home directory isn't x'able.
+ Additional NeXT portability enhancements from Axel Zinser.
+ Additional HP-UX portability enhancements from Brian Bullen.
+ Add a timeout around SMTP message writes; this assumes you can
+ get throughput of at least 64 bytes/second. Note that
+ this does not impact the "datafinal" default, which
+ is separate; this is just intended to work around
+ network clogs that will occur before the final dot
+ is sent. From Eric Wassenaar.
+ Change map code to set the "include null" flag adaptively --
+ it initially tries both, but if it finds anything
+ matching without a null it never tries again with a
+ null and vice versa. If -N is specified, it never
+ tries without the null and creates new maps with a
+ null byte. If -O is specified, it never tries with
+ the null (for efficiency). If -N and -O are specified,
+ you get -NO (get it?) lookup at all, so this would
+ be a bad idea. If you don't specify either -N or -O,
+ it adapts.
+ Fix recognition of "same from address" so that MH submissions
+ will insert the appropriate full name information;
+ this used to work and got broken somewhere along the
+ way.
+ Some changes to eliminate some unnecessary SYSERRs in the
+ log. For example, if you lost a connection, don't
+ bother reporting that fact on the connection you lost.
+ Add some "extended debugging" flags to try to track down
+ why we get occassional problems with file descriptor
+ one being closed when execing a mailer; it seems to
+ only happen when there has been another error in the
+ same transaction. This requires XDEBUG, defined
+ by default in conf.h.
+ Add "-X filename" command line flag, which logs both sides of
+ all SMTP transactions. This is intended ONLY for
+ debugging bad implementations of other mailers; start
+ it up, send a message from a mailer that is failing,
+ and then kill it off and examine the indicated log.
+ This output is not intended to be particularly human
+ readable. This also adds the HASSETVBUF compile
+ flag, defaulted on if your compiler defines __STDC__.
+ CONFIG: change SMART_HOST to override an SMTP mailer. If you
+ have a local net that should get direct connects, you
+ will need to use LOCAL_NET_CONFIG to catch these hosts.
+ See cf/README for an example.
+ CONFIG: add LOCAL_MAILER_ARGS (default: `mail -d $u') to handle
+ sites that don't use the -d flag.
+ CONFIG: hide recipient addresses as well as sender addresses
+ behind $M if FEATURE(allmasquerade) is specified; this
+ has been requested by several people, but can break
+ local aliases. For example, if you mail to "localalias"
+ this will be rewritten as "localalias@masqueradehost";
+ although initial delivery will work, replies will be
+ broken. Use it sparingly.
+ CONFIG: add FEATURE(domaintable). This maps unqualified domains
+ to qualified domains in headers. I believe this is
+ largely equivalent to the IDA feature of the same name.
+ CONFIG: use $U as UUCP name instead of $k. This permits you
+ to override the "system name" as your UUCP name --
+ in particular, to use domain-ized UUCP names. From
+ Bill Wisner of The Well.
+ CONFIG: create new mailer "esmtp" that always tries EHLO
+ first. This is currently unused in the config files,
+ but could be used in a mailertable entry.
+
+8.1C/8.1B 93/06/27
+ Serious security bug fix: it was possible to read any file on
+ the system, regardless of ownership and permissions.
+ If a subroutine returns a fully qualified address, return it
+ immediately instead of feeding it back into rewriting.
+ This fixes a problem with mailertable lookups.
+ CONFIG: fix some M4 frotz (concat => CONCAT)
+
+8.1B/8.1A 93/06/12
+ Serious bug fix: pattern matching backup algorithm stepped by
+ two tokens in classes instead of one. Found by Claus
+ Assmann at University of Kiel, Germany.
+
+8.1A/8.1A 93/06/08
+ Another mailertable fix....
+
+8.1/8.1 93/06/07
+ 4.4BSD freeze. No semantic changes.
+
+6.65/6.34 93/06/06
+ Fix some lintish problems.
+ Fix some cases where server SMTP behaved poorly when handed bogus
+ input, pointed out by Eric Wassenaar.
+ CONFIG: fix some more (sigh) mailertable bugs -- thanks to
+ Motonori Nakamura of Kyoto University (again).
+
+6.64/6.33 93/06/05
+ Don't send 050 (-v) information after the 250 response to a QUIT
+ command in srvrsmtp -- clients usually close the connection
+ at this point, and it causes bogus error messages.
+ Don't send messages that have errors on input (such as unbalanced
+ parentheses) during SMTP transactions, since a return
+ message has (probably) already been sent.
+ Give better diagnostics on timeouts during network reads, including
+ information similar to the SMTP phase.
+ Fix bug that caused SMTP messages to deliver synchronously; this
+ happened after the DATA 250, and hence caused reading the
+ next command to be delayed.
+ Ignore Errors-To: header unless 'l' (lower case el) header is
+ specified. The Errors-To: header violates RFC 1123.
+ Errors-To: was only needed to take the place of the
+ envelope sender in the days when most Unix mailers
+ didn't understand about the two kinds of senders.
+ Don't send warning messages in response to automatically generated
+ messages (that is, those From:<>).
+ CONFIG: fix some rather stupid typos in the mailertable code
+ pointed out by Motonori Nakamura of Kyoto University.
+ CONFIG: add confUSE_ERRORS_TO configuration option.
+ CONFIG: if ALWAYS_ADD_DOMAIN is selected, try to use $M
+ (masquerade name) instead of $j.
+ CONFIG: don't add dots to relay names (added in 6.29); it breaks
+ several things, and can be simulated by dot terminating
+ the names of relays. For example, use:
+ DBbit.net.relay.
+ (note the trailing dot).
+
+6.63/6.32 93/06/01
+ Fix prototypes to eliminate chars in argument lists -- some
+ compilers are pissy about this.
+ Log protocol ($r) and body type if set so we can determine if
+ the adaptive algorithms are working.
+ Pessimize on locking of database files (particularly for NEWDB
+ databases) during opens. There were problems with
+ processes opening the file while it was rebuilt; since
+ NEWDB caches heavily, the reader opened an empty file,
+ which is an error. If your system has the ability to
+ lock atomically on open, this works properly; otherwise,
+ there are race conditions.
+ Check mod time on .pag file instead of .dir in NDBM aliases
+ because the .dir file doesn't get updated for small
+ alias files. From John Gardiner Myers of CMU.
+ More Solaris portability -- it now compiles on Solaris, but
+ hangs up in gethostbyname().
+ Move setting of RES_DEBUG flag before first myhostname() call
+ so we can see name server traffic on that call.
+ Fsync() queue files.
+ Fix a problem that causes -bi to try to rebuild maps other than
+ the alias file(s).
+ Fix a problem that caused udb to reject entries from any but
+ the first database listed.
+ Rearrange doc subdirectory for 4.4BSD release tape.
+ CONFIG: put $r into the Received line. This was an oversight.
+ CONFIG: fix typo (call to ruleset 99 should have been rulset 90).
+ CONFIG: move "auxiliary" subroutines to be in ruleset 90-99
+ range -- in the long run, single digit rulesets may
+ become reserved for builtin use by sendmail.
+ CONFIG: fix major problem that causes host aliases (that is,
+ anything in $=w != $j) to not be recognized. This has
+ been around since 6.30.
+
+6.62/6.31 93/05/28
+ BETA RELEASE
+ Fix recursive syserr (if there is an error printing a syserr
+ message). This makes the code much less eager to consider
+ a write error as serious. This also includes some
+ heuristics to be clever about closed connections.
+ Lock NEWDB files during gets. This requires version 1.5 or later
+ of the db library. If you have an older version, you
+ can use -DOLD_NEWDB. This will go away in a few weeks.
+ Fix problem causing aliases that use host maps to get overwritten.
+ Do appropriate byte swapping on port numbers in ident protocol
+ code. Fix from Allan Johannesen of WPI.
+ Defer opening of map files to the same time as alias files so that
+ the daemon will tend to pick up new versions more promptly.
+ Prototype a bunch more functions.
+ Some Solaris 2.1 changes (still doesn't link though).
+ Try to simplify Makefiles by including more subordinate #defines
+ in conf.h (based on OS type).
+ CONFIG: check for domains if FEATURE(mailertable) is defined.
+ For example, if the host name is "knecht.cs.berkeley.edu"
+ it will search the following mailertable keys:
+ knecht.cs.berkeley.edu
+ .cs.berkeley.edu
+ .berkeley.edu
+ .edu
+ This could be used to replace the special relays for bitnet
+ and similar nets.
+
+6.61/6.30 93/05/24
+ Fix problem that prevented appending dots on canonified host
+ names. This breaks tons of config files -- very
+ important fix.
+ Fix improper pointer dereference in response to HELO command.
+ Fix core dump if debugging set in map_rewrite.
+ CONFIG: add FEATURE(always_add_domain) to always attach the
+ local domain (only impacts local mail).
+ CONFIG: try to avoid turning names into $j -- although
+ technically a host can only have one "canonical name",
+ it seems to be common practice to have several.
+
+6.60/6.29 93/05/22
+ Major change: merge alias databases with maps. This expands and
+ changes the map class interface but fixes a bunch of bugs.
+ The important user-visible change is that the file name
+ in a K line now does not include the ".db" extension; this
+ is added automatically. Also, the -d (NIS domain) flag is
+ missing from the K config line; use @domain instead.
+ When compiling, the *_MAP names are gone -- just compile
+ in NDBM, NEWDB, and/or NIS support.
+ Announce mailer/host/user triple on -bv flag -- from Brian
+ Bullen of Stirling University.
+ Don't send more than one line in response to HELO -- it confuses
+ Pony Express, which then behaves very badly. However,
+ this change does send two line 220 greetings, with the
+ second line reading "ESMTP spoken here". The usersmtp
+ module recognizes this and goes into ESMTP mode regardless
+ of the setting of the "a" mailer flag. Thus, "a" means
+ "always try EHLO".
+ AIX portability changes (thanks to Christophe Wolfhugel of
+ Herve Schauer Consultants (Paris) for providing me with
+ an INSA account for this purpose). Lightly tested. Use
+ -D_AIX3. This probably breaks compatibility with some
+ older systems (e.g., 4.2bsd) but still works on SunOS
+ 4.1.2, Ultrix 4.2A, HP-UX 8.07, OSF/1 T1.3, and AIX 3.2.3.
+ Fix a problem causing an error message loop if the output channel
+ is hosed.
+ Add the Makefiles that I use for various environments -- some are
+ Berkeley make versions and some are old make versions.
+ My makefile for the NeXT box has gotten lost, alas!
+ PRALIASES: support for printing NEWDB databases. From
+ Michael J. Corrigan of U.C. San Diego.
+ CONFIG: don't pass pseudo-domains to $[ ... $] (if you have
+ a wildcard MX it can have wierd results). From
+ Christophe Wolfhugel.
+ CONFIG: dot terminate relay hostnames in S0. From Christophe
+ Wolfhugel.
+
+6.59/6.28 93/05/13
+ Log version with SMTP daemon startup message.
+ Adjust setproctitle to work on NetBSD and BSD/386.
+ Fix null pointer reference in MX fallback code.
+ A bunch of minor fixes from Eric Wassenaar:
+ If deliver cannot execv the mailer, return EX_OSERR
+ instead of EX_TEMPFAIL (to give better
+ error messages).
+ Consistently malloc e_message.
+ Catch degenerate case of calling returntosender()
+ with an empty returnq.
+ MIME reformatting.
+
+6.58/6.28 93/05/13
+ Fix bug that can cause incorrect verbose display of user smtp
+ messages.
+ Disable SMTP VERB command if PRIV_NOEXPN is set (since this
+ could reveal the same information.
+ Allow failure when reading SMTP greeting message to go on to
+ next MX host.
+ Add "MIME-Version: 1.0" header if using MIME (this was NOT
+ included in RFC 1344, but Bill King of Allan-Bradley
+ Company forwarded me email from Nathaniel Borenstein
+ claiming that it was an inadvertent omission).
+ Don't use Content-Type: X-message-header. According to John
+ Myers of CMU, many MIME readers will completely ignore
+ the data if they don't recognize it. Instead, just
+ add a blank line to make it a legal (empty) message.
+ Fix problem causing dots to keep getting appended to cached
+ hostnames. This can cause buffer overrun conditions.
+ The problem was found by Erik Forsberg of Retix,
+ although I used a different bug fix than he provided.
+ Fix parsing of split header/envelope rewriting specs -- from
+ Eric Forsberg.
+ Fix from Eric Wassenaar to correct To: lists in error messages.
+
+6.57/6.28 93/05/11
+ Fix minor glitch causing extra ctladdrs to be output to queue
+ file. Just an annoyance.
+ Cache results of name server canonification lookups to avoid
+ backed up queue runs.
+ Major rewrite of alias.c: considerable cleanup, plus sample
+ (untested) support for NIS aliases. The "A" option
+ can now be a comma separated list (or be repeated) --
+ that is, you can have multiple alias databases. Each
+ database can have the syntax ``class:file''; if no class
+ is specified, the "implicit" class is assumed. Implicit
+ searches through a list of compiled in types -- hash,
+ dbm, nis, and stab. Alias files are searched in the
+ order they are listed. For example:
+ OAhash:/etc/aliases.local,/etc/aliases
+ OAnis:mail.aliases@my.nis.domain
+ first searches the hash database /etc/aliases.local,
+ then the regular /etc/aliases database, then the NIS
+ map "mail.aliases" in the NIS domain "my.nis.domain".
+ If in Verbose mode (probably from VERB command) run SMTP job
+ in foreground and don't do RCPT optimizations.
+ Add udb :mailsender as equivalent to owner- for regular aliases.
+ Delete option 8; add option 7 that means the opposite. That is,
+ default to 8-bit mode; a special option is needed to
+ force sendmail into 7 bit mode.
+ Send error messages in encapsulated MIME format.
+ New compile flag "NIS" that turns on NIS alias and NIS map
+ support.
+ Add "j" option to send error messages in MIME (RFC 1341)
+ encapsulated message format per RFC 1344. The
+ syntax is pretty ugly if you don't have MIME-aware
+ user agents.
+ Clean up message handling (for display in mailq output).
+ New setproctitle implementation for 4.4bsd.
+ Create files (such as ~/dead.letter) using mode FileMode (the
+ F option value) instead of 0666.
+ Fix bug causing output of EXPN command to not be fully qualified.
+ This may cause some problems with UUCP addresses that
+ will require some config file assistance -- specifically,
+ the $: part has to include the host name for this output
+ to make sense.
+ Fix a problem that sometimes diagnosed errors and still sent the
+ message if the header syntax was bad.
+ Fix a bug that caused an error message to be emailed when sendmail
+ was operating in -bv mode.
+ Add "ListenQueueSize" keyword to daemon options option (OO) to
+ set the queue size parameter passed to listen(). You
+ will normally have to tweak your kernel to up this.
+ Strip spaces off of beginning of message-id before logging (in
+ case it was folded across lines).
+ Tweak compile flags in daemon.c -- there were some cases where
+ it wouldn't work without NETINET.
+ Change *file* mailer to output all the usual default headers
+ (From, Date, Message-Id). It gets used when sending
+ back error messages.
+ CONFIG: explicitly catch and diagnose list:; syntax in ruleset
+ zero -- this is not a valid recipient syntax according
+ to RFC 821.
+ CONFIG: add confMIME_FORMAT_ERRORS to send error messages in
+ MIME format. Defaults to on.
+ CONFIG: add SMTP_MAILER_FLAGS and UUCP_MAILER_FLAGS to augment
+ the flags for those mailers.
+
+6.56/6.27 93/05/01
+ Fix problem that causes the fallback mail to postmaster
+ (case ESM_POSTMASTER in savemail()) to not look at
+ aliases (ugh).
+ Some more HPUX tweaking (compile flag hpux => __hpux so it
+ still works in ANSI mode).
+ Don't try to flock non-regular files when mailing to a file.
+ In particular, this was a problem if you tried to
+ send to /dev/null.
+ Fix a wierd bug that can cause senders to be queued as
+ recipients if the name server is down when the mail
+ is initially sent. This hack just ignores sender
+ deletion (essentially, it sets the MeToo flag) if there
+ is a TEMPFAIL during processing of the sender address.
+ Obscure.
+ Fix a dangling else problem -- from Brian Bullen from University
+ of Stirling, UK.
+ Add the "b" mailer flag to force a blank line on the end of
+ messages. Some brilliant versions of /bin/mail insist
+ on this but do not add it themselves.
+ Add the "g" mailer flag to prevent user SMTP from sending
+ "MAIL From:<>". This is only intended to be a
+ transitional gesture, and should not be used if at
+ all possible. It appears that Berkeley and IDA
+ config files have always handled this properly; the
+ UK config kit apparently does not.
+ Don't lowercase and then capitalize header field names -- leave
+ them with original capitalization. Fixes from Bill
+ King of Allen-Bradley Company.
+ Further cleanup and improved reporting of error messages,
+ particularly conditions that cause messages to be
+ requeued for future delivery.
+ Tweak syslog priorities in some cases.
+ CONFIG: clean up route-addr on UUCP addresses.
+
+6.55/6.25 93/04/27
+ HPUX 8.07 compatibility changes in getla() -- I had to make
+ these changes to get it to work at Berkeley, although
+ others seem to have been working before (???).
+ Various patches to XLA code.
+ Fix problem that causes setuid bit on files to be ignored from
+ SMTP or in queue runs. Problem noted by Jason Ornstein
+ of Under The Wire, Inc.
+ Fix problem that can cause CNAMEs to be ignored.
+ Generalize getmxrr to match local host in $=w instead of a
+ single name passed in.
+ Some cleanup from Eric Wassenaar:
+ Use FileMailer instead of ProgMailer in two places.
+ Eliminate duplicate 8th-bit stripping in commaize.
+ Fix a problem with mis-parsing of backslash escapes
+ under some circumstances.
+ NIS map fix (was always including trailing null character)
+ from Mike Glendinning of Ingres UK.
+ Add "a" mailer flag to try using ESMTP. It tries the EHLO
+ command and if that fails falls back to regular SMTP.
+ Also parses EHLO option keywords. If host supports
+ SIZE extension, this is added to the MAIL FROM:
+ command.
+ Extend "b" option to include a second value which is the
+ maximum message size this server is willing to accept.
+ For example, a value of "10/1000000" says that there
+ must be ten blocks free, and sendmail will reject
+ any message larger than one megabyte.
+ Some portability hooks for NeXT (this could be applicable
+ to Mach in general). You have to create an empty
+ file called "unistd.h" to get it to compile.
+ Adjust config values (MAXLINE, MAXATOM, and PSBUFSIZE) to
+ be more generous.
+ Add X400-Received: to the list of headers tagged with H_TRACE
+ in conf.c. From Bill King, Allen-Bradley Co.
+
+6.54/6.25 93/04/19
+ Fix problem that caused redefinition of SMTP and QUEUE compile
+ flags. Pointed out by Jon Forrest of the Sequoia 2000
+ project at Berkeley.
+ Properly handle \! hack -- it was treating host\!user as one
+ token (host!user) instead of three (host, !, user).
+ Fix from Eric Wassenaar of NIKHEF-H.
+ Fix compilation problem in getauthinfo() if IDENTPROTO is off.
+ Turn off DEFNAMES and DNSRCH when getting the hostsignature
+ (i.e., MX records) in level 1 configuration files; this
+ matches the old behaviour. From Motonori Nakamura of
+ Kyoto University.
+ Improve error message printing -- if sent through an alias,
+ error messages include the name of the alias in the
+ message. Unfortunately, in order to make this work
+ properly in queue runs, this changes the format of the
+ C line in the qf file. The relatively uselessness of
+ the previous information was pointed out to me by
+ Allan E Johannesen of WPI.
+ Add XLA compile flag to add hooks to Christophe Wolfhugel's
+ extended load average code. This is still in very early
+ form. For information regarding the guts of the xla
+ code, contact Christophe.Wolfhugel@grasp.insa-lyon.fr.
+ Additional hooks for detecting tempfails in rewriting rules
+ (that is, in map lookups).
+
+6.53/6.25 93/04/15
+ Properly diagnose ruleset zero returning null (instead of a mailer
+ triple). From Motonori Nakamura of Kyoto University.
+ More generalization of socket code for other protocols.
+ Shorten timeouts on reverse name lookups -- since they are done
+ during connection establishment, long timeouts here can
+ cause higher level timeouts. This mainly serves to accept
+ mail from hosts that do not have proper reverse (PTR) DNS
+ records set up.
+ Reset e_statmsg before each mailer invocation to avoid bogus
+ messages in the log.
+ Redefine $r, $s, and $_ in error envelopes so you don't get
+ incorrect cruft in the error message. Problem noted by
+ Motonori Nakamura of Kyoto University.
+ Fix a problem that can cause failure to return errors to Postmaster
+ in certain cases. From Motonori Nakamura.
+ Fix a problem that can cause some systems to give duplicate error
+ messages when a bad syntax address such as "<a" is presented
+ to an SMTP server. It doesn't seem to occur on all
+ machines. From Motonori Nakamura.
+ Default IDENTPROTO off for Ultrix and HPUX, which apparently have
+ the interesting "feature" that when they receive a "Host
+ unreachable" message they closes all open connections to
+ that host. However, some firewall gateways send this message
+ if you try to connect to an unauthorized port, such as the
+ IDENT port (113). Thus, no email can be received from such
+ hosts. There is some evidence that versions of Ultrix before
+ 4.3 do not have this problem. Thanks to Tom Ivar Helbekkmo
+ for pointing out this behaviour to me and to Michael Corrigan
+ of U.C. San Diego for informing me about the HPUX problem.
+ Allow IPC mailers to return a colon-separated list of hosts in the
+ $@ clause; these are searched in order as though they were
+ MX records.
+ When sending an error report, print the list of addresses tagged
+ as bad. Requested by Allan E Johannesen of WPI.
+ Change map function calls to return a status code. This gets
+ passed back as the result of rewrite. Parseaddr marks
+ the address as a QUEUEUP address if the return code is
+ EX_TEMPFAIL. All this to queue properly if the name
+ server is down. This code is not well tested. This code
+ changes the interface to map lookup functions (a fifth
+ parameter, int *statp, is added). Feature requested by
+ Dan Oscarsson.
+ Don't delete quotes (in the dequote map) if there are spaces in
+ the string, since this would cause them to be replaced by
+ the SpaceSub character.
+ Accept BODY=8BITMIME on SMTP MAIL command. This isn't advertised
+ because the 8BIT to 7BIT translation doesn't exist yet.
+ This does add a "bodytype" field to both envelope and
+ queue file and a -B command line flag to pass the type in
+ during direct invocations.
+ Discard return error messages only on responses to responses to
+ responses, not on responses to responses. That is, the
+ algorithm is to try return to sender, then return to
+ postmaster, then discard. Previously it discarded
+ immediately if the return to sender pass failed.
+ CONFIG: back out change to hide unqualified hostnames behind %-hack.
+ This screws up local aliases and .forward files.
+ CONFIG: add FEATURE(nocanonify) to turn off calls to $[ ... $];
+ some sites only handle completely canonified names.
+ Requested by John Gardiner Myers of CMU.
+ CONFIG: some UUCP code was still included even if FEATURE(nouucp)
+ was specified.
+
+6.52/6.24 93/04/10
+ Clean up some minor glitches on error return messages pointed out
+ by Motonori Nakamura of Kyoto University.
+ Fix reply() to not reset SmtpReplyBuffer on fatal errors; this
+ was supposed to reset SmtpMsg Buffer. This makes the
+ client side code virtually useless. Reported by Allan
+ E Johannesen of WPI and Phil Brandenberger of Swarthmore.
+ Better debug messages if fuzzy is disabled, suggested by Allan
+ E Johannesen of WPI.
+ Offset SmtpReplyBuffer by four in usersmtp when checking for
+ loopback. From Eric Wassenaar.
+ Don't set $s until after runinchild in srvrsmtp -- otherwise
+ it gets cleared. From Eric Wassenaar.
+ Implement IDA-style $&x for deferred macro expansion.
+ More POSIX compatibility.
+ CONFIG: Hide unqualified hostnames behind %-hack using $s as the
+ actual sender. This is only done if $r is non-null, that
+ is, if this is not locally submitted mail.
+ CONFIG: Add FEATURE(bitdomain) allowing mapping of BITNET host
+ names to internet domains. A program contributed by
+ John Gardiner Myers of CMU to create the maps is included
+ in the contrib directory (in the "misc" tar file).
+ CONFIG: Add FEATURE(uucpdomain) for a similar mapping for UUCP
+ hosts. There is currently no tool to create this map.
+
+6.51/6.23 93/04/04
+ Add D= mailer flag to specify a path of possible working directories
+ in which to execute the mailer. This is intended for the
+ prog mailer; some shells can get upset if they don't have
+ access to the current directory.
+ Add RFC 1413 (IDENT) protocol support. This is only very loosely
+ tested. This adds a $_ macro to be the authenticated
+ info (in ``user@domain [address]'' form) and debug flag
+ 9 to trace the protocol.
+ Check for loopbacks in usersmtp instead of srvrsmtp -- there is no
+ reason for a local agent to not be talking to the localhost
+ (although the inverse is not true).
+ Add a few hooks for automated map rebuilding. This is certainly
+ not done yet.
+ CONFIG: Have prog mailer specify a path of ``D=$z:/'' -- that is,
+ user's home directory then the root.
+ CONFIG: Log RFC 1413 identification in Received: line.
+
+6.50/6.22 93/04/01
+ Fixes to requeueing code to make it compute priority, nrcpts,
+ and the like properly.
+
+6.49/6.22 93/04/01
+ Diagnose incorrect privacy flags. Suggested by Bryan Costales
+ of ICSI.
+ Some ANSI C fixes.
+ Arrange to quote backslashes as well as other special characters
+ in the phrase part of a route-addr.
+ Some fixes to FallBackMX code suggested by Motonori Nakamura of
+ Kyoto University.
+ More vigorous zeroing of CurHostAddr to avoid logging of bogus
+ host addresses when you are actually just printing
+ information from the MCI structure; problem noted by
+ Michael Corrigan of U.C. San Diego.
+ Don't ignore rest of queue if any job is not runnable. This can
+ also cause an incorrect job to be lost. Fix from
+ Eric Wassenaar.
+ Always respond "quickly" to RCPT command; do alias expansion and
+ the like later. This also means that mail for lists that
+ have errors will be acccepted, and an error sent back
+ later. This is done by instantiating the queue file
+ and then immediately running and requeueing it.
+
+6.48/6.22 93/03/30
+ Fix incorrect diagnosis of infinite loop in ruleset. Problem noted
+ by several people.
+ Improve information printed when infinite loops are discovered.
+ Zero CurHostAddr to fix erroneous internet addresses in log when no
+ addresses can be bound. Pointed out by Motonori Nakamura
+ of Kyoto University.
+ "Probe" SMTP connections using RSET instead of NOOP "just in case".
+ Suggested by John Gardiner Myers of CMU.
+ Don't warn about -f if you are setting sender to yourself.
+
+6.47/6.22 93/03/29
+ Fix incompatible call to endmailer in smtpquit which causes core
+ dumps. Noted by Allan E Johannesen of WPI.
+ HPUX portability changes from Michael J. Corrigan of UC San Diego.
+ Require MAIL before RCPT command in srvrsmtp.c. This had been
+ intentional from the 821 draft days when the order wasn't
+ clear, but is silly now.
+ Fix bug in nis_magic routine that was initializing parameters
+ incorrectly. Fix from Takahiro Kanbe of Fuji Xerox
+ Information Systems Co., Ltd.
+ Change default for PrivacyFlags in conf.c to 0 -- since it always
+ "or"s in new values, there was no way to turn off the
+ AuthWarning stuff.
+ Add O option to set SMTP daemon options.
+ Add V option to set fallback MX host. This always sorts at lower
+ priority than anything it gets from the name server. It
+ should only be used for environments with very bad network
+ connectivity. Requested by several people.
+ Log sending info. It's not clear this is a good idea.
+ CONFIG: fix typo in mailertable code. Noted by Phil Brandenberger
+ of Swarthmore.
+ CONFIG: add confDAEMON_OPTIONS and confFALLBACK_MX to set options
+ O and V, respectively.
+
+6.46/6.21 93/03/26
+ Fix botch in server SMTP that broke transactions that did not
+ use HELO first (like MH). Fix from Michael Corrigan
+ of U.C. San Diego.
+ Fall back to other MX records if there is an error anywhere
+ in delivery (actually on MAIL or DATA -- RCPT is harder).
+ Suggested by John Gardiner Myers and Motonori Nakamura.
+ Revert to non-prototypes -- it turns out that our ANSI C
+ compiler is more forgiving than most others about
+ mixing prototyped extern declarations with non-prototyped
+ function definitions.
+ Fix a problem with multi-word class matching pointed out by
+ Neil Rickert. Given:
+ CX b a.b.c
+ R$+ $=X $+ $: $1 < $2 > $3
+ the input "user@a.b.c" failed instead of being properly
+ rewritten as "user@a.<b>.c".
+ Neil also convinced me that it was correct that $~ should match
+ only one token -- the problem is that it's always possible
+ to add another token, so $~ matches far too eagerly.
+
+6.45/6.21 93/03/25
+ Implement multi-word classes (properly!).
+
+6.44/6.21 93/03/25
+ Add X-Authentication-Warning: headers to clue users into possible
+ attempts to forge mail. This is on the authwarnings
+ privacy flag, but is the default. Suggested by Bryan
+ Costales of ICSI.
+ Pass default units for convtime in so they can be more reasonable.
+ Allow config files to always add a new Comments: header (i.e.,
+ they will be added even if an old one already exists).
+ Suggested by Bryan Costales of ICSI.
+ Allow config files to delete an existing Return-Path: header.
+ These should only be added at final delivery. Suggested
+ by Bryan Costales of ICSI.
+ Some debugging additions. Suggested by Bryan Costales of ICSI.
+ Clean up logging of Family 0 addresses. Noted by David Muir
+ Sharnoff and others.
+ Add a "dequote" map class. This allows config files to strip
+ quotes off of addresses. Note that this is not a builtin
+ map, just a class -- so you have to define the map
+ using the K line.
+ Fix a bug in the queueup() loop getting a locked tf where in
+ very odd cases it can fall off the bottom and core dump.
+ Of course, it was P{r Emanuelsson who found it....
+ Open a new transcript when splitting an envelope. Problem found
+ by Allan E Johannesen of WPI.
+ Improved error output in endmailer if the mailer core dumps.
+ CONFIG: Fix typo in UUCP mailer definition.
+ CONFIG: Default several of the new options on: eight bit input,
+ privacy flags set to "authwarnings", and message warning
+ set to 4h.
+ CONFIG: Use dequote map.
+
+6.43/6.20 93/03/23
+ Fix problem with assumption of an sa_len field in a generic
+ sockaddr -- it turns out that most vendors haven't
+ picked up this (very important) fix.
+ Change compilation flags for daemon code -- select one or both
+ of NETINET or NETISO, but don't ever set DAEMON manually.
+ CONFIG: add FEATURE(mailertable) to do IDA-style mailertables.
+
+6.42/6.19 93/03/19
+ Use Postmaster as default fallback return address, not root.
+ POSIX changes for file descriptor handling.
+ Diagnose errors writing new queue file.
+ If you change the owner using an owner- alias, also change the
+ error mode to EM_MAIL so that errors don't get dropped
+ into an inappropriate directory. Problem noted by
+ Allan E Johannesen of WPI.
+ If you are su'ed to root, send email as who you really are, not
+ as root. From Brian Kantor of U.C. San Diego.
+ Allow warning messages to be sent after a configurable interval
+ has passed without delivery. The message is sent only
+ once per envelope. This changes the format of the qf
+ file to have an F line, and the format of the T option
+ to accept take the format "return/warn" (both intervals).
+ Don't force all local names to lower case -- this was left over
+ from the wierd handling of case mapping on aliases. It
+ is now driven (as expected) by the "u" mailer flag.
+ Problem noted by P{r Emanuelsson.
+ Fix problem that caused headers on returned email to be trashed;
+ they were getting freed, but are still accessible via
+ BlankEnvelope.
+ Fix problem that caused bogus ids to be created on returned
+ mail.
+ Add support for ISO and other non-INET networking. This is by
+ no means finished yet. This does assume a lot of other
+ system support, like a version of gethostbyname that
+ returns non-AF_INET addresses.
+ CONFIG: change default on prog mailer to keep upper case in
+ user names (i.e., in the program command line).
+ CONFIG: strip trailing dots off of hosts in uucp mailer before
+ convert to bang format.
+ CONFIG: create new "relay" mailer for $R (LOCAL_RELAY) and $H
+ (MAIL_HUB) delivery that doesn't add local domain. Note
+ that this violates 821, but is probably "more correct"
+ for what we are trying to do. Problem pointed out by
+ Michael Graff of Iowa State.
+
+6.41/6.18 93/03/18
+ Clean up unnecessary creates of queue ids (i.e., empty qf files)
+ when not needed, such as when starting up an SMTP
+ connection.
+ Fix problem where split envelopes aren't instantiated in the queue.
+ This is quite a serious bug.
+ Owner- aliases had problems with leading spaces causing a
+ premature delimitation.
+
+6.40/6.18 93/03/18
+ Have ending 250 (after DATA) include the id; suggested by
+ Brian Kantor of UC San Diego.
+ Add logging on envelope splitting.
+ Change queue ids to have one more letter encoding the hour of
+ the day so that during a single day there is a greater
+ likelihood of uniqueness; requested by Brian Kantor.
+
+6.39/6.18 93/03/18
+ Fix minor compile problem if LOCKF is defined.
+ Define size of tobuf in conf.h. Observed by Toshinari Takahashi
+ of Toshiba.
+ Restore e_sender -- this is equivalent to e_from.q_paddr without
+ decorations such as angle brackets and comments.
+ OSF/1 on Alpha changes from Allan E Johannesen of WPI.
+ CONFIG: fix typo in S3 for list syntax (;: => :;). Thanks to
+ Christopher Hoover for noting the problem.
+
+6.38/6.17 93/03/17
+ Pass envelope to disconnect to avoid another use of CurEnv, which
+ can apparently end up being null at inopportune times.
+ Log "received from" as "relay=" for consistency (suggested by
+ John Gardiner Myers).
+ Fix major bug in header handling: if no From: line existed in
+ the header (so sendmail inserts one), and the sender is
+ an alias that has an owner, the From: line shows the
+ owner (as well as the envelope). Fixed by early binding
+ the headers (which will change debugging output).
+ HPUX portability patches from Michael J. Corrigan of UC San Diego.
+ Some attempts to adapt better to out of open file conditions.
+ Some changes to ctladdr handling in queue files.
+
+6.37/6.17 93/03/16
+ MAJOR CHANGE: delete e_sender and e_returnpath (why are these
+ different from e_from?) and $< macro.
+ Log correct IP address in relay= field even if the connection
+ times out.
+ Log "received from [RESPONSE]" on EF_RESPONSE messages (from
+ John Gardiner Myers).
+ Fixes to SysExMsg logging (sometimes just got "message: %s"
+ instead of "message: error message"), noted by Eric
+ Wassenaar. Also reported by Motonori Nakamura.
+ Improvements to MX piggybacking code, from Motonori Nakamura.
+ Fix case where CurHostName points to an auto variable that has
+ been deallocated (from Motonori Nakamura).
+ Fix bug causing newlines to be included in aliases if option
+ "n" (check alias RHS) is set; bug noted by David Muir
+ Sharnoff.
+ Fix problem causing user names that should be mapped to lower
+ case to not be mapped if they are sent during a queue
+ run. This greatly simplifies the case mapping code.
+ Problem noted by Allan E Johannesen of WPI.
+ Don't do recipient address rewriting in buildaddr. This
+ improperly did recipient rewriting on sender addresses,
+ and just seems bogus in general -- but the change could
+ break some .cf files.
+ Pass TZ envariable to child processes for System V.
+ CONFIG: allow LOCAL_RULE_1 and LOCAL_RULE_2 if you want to
+ define those rulesets.
+ KNOWN PROBLEM: I have seen some problems on SunOS that causes
+ the User Data Base to give errors on some addresses. I
+ have tracked the problem back at least as far as 93.02.15
+ (version 6.22). Running with debugging on makes it
+ go away, so I conclude that it is referencing uninitialized
+ stack data. I haven't been able to track this down yet.
+
+6.36/6.16 93/03/08
+ Allow local mailer to specify $@host -- this lets you assign the
+ "foo" part of jgm+foo to $h for passing in to the local
+ mailer.
+ Additional debug printing in getcanonname (show query type).
+ Don't add the e_fromdomain on sender addresses -- this interacts
+ wierdly with the owner- code.
+ Improve delivery logging to not log obvious or meaningless stuff.
+ Include numeric IP address in Received: lines per RFC 1123 section
+ 5.2.8.
+ Fixed a bug in checking stat() return value if restrictmailq is
+ set. Also, check the entire group set instead of just the
+ primary group. Both from John Gardiner Myers.
+ Don't have usrerr automatically print errno, since this is often
+ misleading.
+ Use transienterror() in makeconnection after connect() fails and
+ in openmailer after execve() fails (from Eric Wassenaar).
+ Also moved transienterror() from util.c to conf.c.
+ Clean up from= logging on response messages.
+ Undo patch allowing prescan to return a null vector -- it breaks
+ too many things.
+ Config: FEATURE(notsticky) lets you use UDB for everything coming
+ in to the machine, even if it is specifically targetted
+ to this machine. Without it, UDB is bypassed if the user
+ name is fully qualified.
+ Config: fix another minor botch with <> (local mailer wasn't
+ mapping them properly).
+
+6.35/6.15 93/03/05
+ Fix getrealhostname to return null if sinlen <= 0 -- this can
+ occur if stdin is a pipe.
+ Avoid infinite loop in getcanonname if name server return
+ NO_DATA (for example).
+ Config: avoid having C flag qualify list syntax and error syntax.
+
+6.34/6.14 93/03/05
+ Fix logging in deliver to not pass too many parameters to Ultrix
+ versions of syslog.
+ Don't write the pid file until after the daemon has actually
+ opened and conditioned the connection.
+ Consider addresses "different" if their q_uids differ (so that
+ two users forwarding to the same program will be seen
+ as different, rather than the same).
+ Fix problem with bad parameters in main() -- they set ExitStat
+ but don't exit.
+ Fix null pointer references through RealHostName -- painfully
+ discovered by Allan E Johannesen of WPI.
+ Fix bug causing user@@localhost to core dump (yuch).
+ Config: don't put two @host.dom.ain on users in $=E in SMTP
+ mailer. Also, catch user@ (no host) in ruleset 0.
+
+6.33/6.13 93/03/03
+ Config: add confCW_FILE as the name of the cw configuration file
+ (defaults to /etc/sendmail.cw). From P{r Emanuelsson.
+ Allow prescan to return a pointer to an empty list -- this is
+ not an error. Also, clean up error reporting to avoid
+ double errors (prescan reports once, then the caller
+ reports again).
+ Changes to avoid trusting T_ANY queries -- run them, but if you
+ don't get the info you expected, do T_A and T_MX queries
+ anyhow. This also fixes an oversight where _res.options
+ bits were being ignored.
+ If PRIV_NOVRFY is set, use 252 response code instead of 502 per
+ RFC 1123 section 5.2.3. It's not 100% clear that this
+ is correct, but it probably works better with stupid
+ mailers that do a VRFY and only check the first digit.
+
+6.32/6.12 93/03/02
+ Fix uninitialized variable "protocol" in smtp code.
+ Include <unistd.h> in sendmail.h -- move towards POSIX/ANSI.
+ Additional hooks for RFC 1427 (ESMTP SIZE extension). This
+ includes requiring that enoughspace() know the system
+ block size, which will undoubtedly break most ports.
+ Trace flag 19 in use for srvrsmtp.c.
+ Additional logging -- notably the sending mailer name. This
+ also changes the delivery logging to strict field=value
+ syntax.
+ Fix some problems with messages getting sent even to addresses
+ that had been marked bad -- from Eric Wassenaar.
+ More WIDE changes: accept host name inside [...] as non-MXed
+ host. This is intended ONLY for use inside firewalled
+ environments, where the MX points at the gateway.
+ Change .cf file conventions so that mapping for <> addresses
+ don't have an @ in them (to avoid confusing the C mailer
+ flag). Pointed out by Neil Rickert.
+ Config extensions for Sam Leffler's FlexFAX software.
+
+6.31/6.10 93/02/28
+ Fix some more bugs in alias owner code -- there were some wierd
+ cases where an error in a non-aliased name would override
+ the return info in an aliased name with an owner.
+ Changes from WIDE Project, forwarded to me by Motonori Nakamura:
+ Log actual delivery host (after MX et al); from
+ yasuhiro@dcl.co.jp.
+ Log daemon startup.
+ Deliver Postmaster copies without a body.
+ Better logging of SMTP senders.
+ Send all program email as daemon even when local.
+ As requested in various forms from many people, accept -qIstring
+ to limit queue runs to jobs with queue-id matching string.
+ Similarly for -qRstring for recipients, -qSstring for
+ senders.
+ Initial hooks for ESMTP support (see RFC 1425).
+ Fixed a syntax error in the UUCP mailer specification that caused
+ core dumps on startup.
+ Check for missing A= or P= arguments in mailer definitions.
+
+6.30/6.10 93/02/27
+ Require FROZENCONFIG compilation flag to include frozen
+ configuration code. Frozen configuration is really
+ not a very good idea any more, particularly in shared
+ library environments.
+ Do better checking of errno after opens of :include: and .forward
+ files to defer delivery on network and other transient
+ errors. Suggestion from Craig Everhart.
+ Fix minor botch in read timeout macro processing.
+ Add FEATURE(nouucp) to config files for sites that know absolutely
+ nothing about UUCP.
+ Add built cf files to distribution tape and clarify how to build
+ them if you don't have the Berkeley make.
+ Some sizeof(long) portability changes for the Alpha, from Allan
+ E Johannesen.
+ Add "restrictmailq" privacy flag -- if set, only people in the same
+ group as your queue directory can print the queue. If you
+ set this, be sure you also restrict access to log files....
+ Fix another bug in owner-list stuff that can cause data files to
+ be "lost".
+ Fix a bug with queue runs that cause forwards to yourself to go
+ into alias/forwarding loops. I'm still iffy about this
+ fix.
+ Fix from Eric Wassenaar for suppression of return message code.
+
+6.29/6.9 93/02/24
+ Fix yet another problem in alias owner code -- put the wrong return
+ address on the enclosed return-to-sender letter.
+
+6.28/6.9 93/02/24
+ Fix botch in alias owner code that caused it to not operate if the
+ error was detected locally.
+
+6.27/6.9 93/02/24
+ M_LOCAL => M_LOCALMAILER to avoid conflict with Ultrix include
+ file <sys/mount.h>.
+ Miscellaneous bug fixes from Eric Wassenaar:
+ sendmail -bv -t logs the from line even though in verify
+ mode only.
+ sendmail -v can go into queue mode if shouldqueue returns
+ TRUE.
+ Add route-addr pruning per RFC 1123 section 5.3.3. This can be
+ disabled using the "R" option.
+ Delete (always undocumented) -R flag (save original recipients);
+ there are ways to syslog(3) these now.
+ Clean up SMTP reply codes -- specify them as needed in the code,
+ instead of in conf.c -- this was needed during the NCP to
+ TCP transition, but seems silly now. This also changes
+ parameters to message and nmessage.
+ Have mailstats read the .cf file to find the sendmail.st file and
+ get text versions of mailer names. An initial version of
+ this code was provided by Tuominen Keijo (although the
+ comments indicate the good bits were written by "E.V.").
+ Add yet more System V compatibility hacks.
+ Fix bug in VRFY code (assumes everything must be a local user).
+ Allow specification of any of the hard-wired pathnames in the
+ Makefile.
+ Delete concept of "trusted users" -- this really didn't provide
+ any security anyway, and caused some problems.
+ Delete last vestige of support for the word "at" as an equivalent
+ to the character "@".
+ Propagate owner-foo alias information into the envelope sender.
+ Based on code from John Gardiner Myers. This is a major
+ semantic change -- beware!
+ Allow $@ on LHS to indicate "match zero" -- this is used to match
+ the null expression.
+
+6.26/6.8 93/02/21
+ Don't "lose" queue runs. Very important fix from (who else?)
+ Eric Wassenaar.
+ Completely reset state on RSET command -- from Eric Wassenaar.
+ Send error messages and return receipts using an envelope sender
+ of <> regardless of the setting of $n. Rewriting rules
+ can undo this if they feel the necessity, as might be
+ needed for networks that don't understand the syntax.
+ This is permitted by RFC 821 section 3.6 and required by
+ RFC 1123 section 5.3.3. THIS REQUIRES VERSION 4 CONFIG
+ FILES because the rulesets must be able to parse <>
+ properly.
+ Don't ever send error messages to "<>" -- they will get sent to
+ the local postmaster or dumped in /usr/tmp/dead.letter
+ instead. Per RFC 1123 section 5.3.3.
+ Explicitly check for email to yourself as a dotted quad. You
+ have to call $[ [ ... ] $] to get this.
+ Up the message timeout to five days per RFC 1123 section 5.3.1.1.
+ Make all read timeouts individually configurable, as strongly
+ recommended by RFC 1123 section 5.3.2.
+ Use f_bavail (blocks available to regular users) instead of f_bfree
+ (blocks available to superuser) in free block checks.
+ Change $d macro to be the current time, not the origination time,
+ since this is consistent with how it is used now.
+ Generalization of enoughspace from Eric Wassenaar covering
+ SGI, Apollo, HPUX, Ultrix, and SunOS.
+ Ignore process group signals -- some front ends can do this if
+ you kill a window too quickly. From Eric Wassenaar.
+ Change umask to 022.
+
+6.25/6.8 93/02/20
+ Close all cached connections before calling mailers and after
+ forking for delivery (caused double closes which resulted
+ in false errors).
+ Add FEATURE(redirect) in config files -- this allows you to alias
+ old addresses to a pointer to the new address that will
+ give a 551 error message, but not deliver the mail.
+ Some code changes to make the 551 errors look pretty.
+ Names of M4 program paths in config files have changed -- they
+ are all XXX_MAILER_PATH now, to match XXX_MAILER_FLAGS.
+ Fix a bug in the QSELFREF code having to do with empty .forward
+ files, reported by Eric Wassenaar.
+ Add option "p" (privacy flags); this allows you to tune how
+ picky the SMTP server will be. This also adds the
+ confPRIVACY_FLAGS M4 macro in the config files.
+ Add option "b" (minimum blocks free). If there are fewer than
+ this number of blocks free on the filesystem containing
+ the queue directory, the SMTP MAIL command will return
+ a 452 response and ask you to try again later. This
+ also adds the confMIN_FREE_BLOCKS M4 macro in the config
+ files.
+ Made VRFY just verify (doesn't expand aliases and .forward files);
+ EXPN does full expansion. RCPT in queue-only mode also
+ doesn't chase aliases and .forward.
+
+6.24/6.7 93/02/19
+ Increase the number of domain search entries in domain.c to allow
+ for the extra "" entry indicating the root domain.
+ Reported by Motonori Nakamura of Kyoto U.
+ Add a "SMART_HOST" in the configs for UUCP-connected sites that
+ want to forward all mail with extra "@"s to that site.
+ Also allows SMART_HOST, LOCAL_RELAY, and MAIL_HUB to
+ be specified as ``mailer:hostname'' to use an alternate
+ mailer.
+ Clarified and updated some wording in the Operations Guide.
+ Add the "c" mailer flag -- this suppresses all comment parts of
+ addresses (requested by John Curran of NEARnet).
+ Have -v print prompts in -bt mode even if stdin is not a terminal
+ (default behaviour is to be silent if not reading from
+ a terminal). Suggested by Bryan Costales, ICSI.
+ Move the metacharacters from C0 space (\001-\037) into C1 space
+ (\201-\237). This also fixes a bunch of potential bugs
+ with G1 characters (\240-\276) in headers relating to
+ negative numbers passed to isspace() et al.
+ Add YP_LAST_MODIFIED and YP_MASTER_NAME to DBM version of alias
+ database if YPCOMPAT is #defined. Enhancement from
+ Takahiro Kanbe of Fuji Xerox Information Systems Co., Ltd.
+ Add "list" Precedence (-30); this can be used with old sendmails
+ which will map to precedence 0 (which will return error
+ messages). Suggested by Stephen R. van den Berg.
+ Many bug fixes from Eric Wassenaar of the National Institute for
+ Nuclear and High-Energy Physics, Amsterdam:
+ Clear timeouts properly on open failures in include().
+ Don't dereference through NULL if no home directory found.
+ Re-establish SIGCHLD signal on System 5 in reapchild().
+ Avoid NULL pointer reference on -pFOO flag.
+ Properly handle backslash escapes in comments.
+ Correctly check reply status on SMTP NOOP command.
+ Properly save SMTP error message if peer gives
+ "Service Shutting Down" message.
+ Avoid writing to the transcript if it couldn't be opened.
+ Signal errors in SMTP children to parent properly.
+ Handle self references in a list more globally (include a
+ QSELFREF bit in the address flags). This enhancement
+ was suggested by Eric Wassenaar.
+ Use initgroups() in hpux, even though it's System-V based. The
+ HASINITGROUPS compile flag can set this on other systems.
+ This HPUX behaviour was pointed out by Eric Wassenaar.
+
+6.23/6.6 93/02/16
+ Clean up handling of LogLevel to make it easier to figure out
+ what's on what level.
+ Change log levels to have some consistency:
+ 1 serious system failures, security problems
+ 2 lost communications, protocol failures
+ 3 other serious failures
+ 4 minor errors
+ 5 message collection
+ 6 vrfy logging, creation of return-to-sender
+ 7 delivery failures
+ 8 delivery successes
+ 9 delivery tempfails (queue ups)
+ 10 database expansion
+ >64 debugging
+ Allow IDA-style separated processing on S= and R= in Mailer
+ definition lines. Note that rulesets 1 and 2 are
+ still used for both addresses as before. Bruce Lilly
+ gave a convincing argument that RFC976 insists on
+ this behaviour.
+ Added some time zones to arpatounix -- they may not be in the
+ standards, but they are in use. However, I may delete
+ arpatounix entirely -- there appears to be no reason
+ for it to exist.
+ Change to UUCP mailer (in cf directory) to try to do a saner job.
+ I'm still not certain about this mailer in general.
+
+6.22/6.5 93/02/15
+ Fix bug that prevents saving letters in ~/dead.letter.
+ Don't add angle brackets in VRFY command if angle brackets already
+ exist in the address.
+ Fix bogus error message in udbexpand.
+ Null terminate host buffers in buildaddr (broken in 6.21) --
+ IMPORTANT FIX!!
+
+6.21/6.5 93/02/15
+ Fix another incorrect error message in alias.c, found by Azuma
+ Okamoto.
+ Fix a couple of problems in the more-configurable config files,
+ found by Tom Ivar Helbekkmo.
+ Fix problem with quoted :include: entries.
+ Don't duplicate the filename on verbose printing of .forward and
+ :include: contents.
+ Extend size of prescan buffer (to allow bigger addresses). Also,
+ detect some buffer overflows.
+ Log user SMTP protocol errors (log level 4).
+
+6.20/6.4 93/02/14
+ Fix another problem in the MCI state machine caused when there
+ were errors generated from the other end to commands
+ other than RCPT.
+
+6.19/6.4 93/02/14
+ Include load average support for DEC Alpha running OSF/1.
+ Fix multiple-response problem with errors in MAIL From: line.
+ Fix SMTP reply codes for invalid address syntaxes (give 501;
+ never give multiple error messages for a single message).
+ Fix problem where a cached connection timeout rejects all
+ later connects to that host.
+ Fix incorrect error message if alias.c is compiled with DBM only.
+ Additional changes to fix nested conditionals (from Bruce Lilly).
+ Recover more gracefully from operating system failures, particularly
+ NULL returns from openmailer (from Noritoshi Demizu,
+ OMRON Corporation).
+ Log forward, alias, and userdb expand operations on log level 10;
+ concept suggested by P{r (Pell) Emanuelsson.
+ Changes for HPUX 8.07 compatibility.
+
+6.18/6.4 93/02/12
+ Allow any config option to be set using an M4 define.
+ Change UNAME compile flag to HASUNAME for IDA compatibility
+ (besides, it's a better name).
+ Note in README that on SunOS it must be linked -Bstatic.
+ Fairly major change in domain.c to handle wildcard MX records
+ more rationally. NOTE: the "w" option (no wildcard MX
+ records match local domain) has been eliminated.
+ Fix some unset variable references pointed out by Bruce Lilly.
+ Fix host name in process titles when using cached connection.
+
+6.17/6.3 93/01/28
+ Fix System 5 compatibility changes to be compatible with the rest
+ of the world.
+
+6.16/6.3 93/01/28
+ Experimental fix for problem handling errors in the SMTP
+ protocol in conjunction with connection caching.
+ System 5 compatibility changes.
+
+6.15/6.3 93/01/26
+ Fix a bug that causes local mail delivered using -odq to be
+ eliminated as a duplicate (because it matched the
+ ctladdr, now passed in as a C line). These changes
+ are pretty tricky......
+
+6.14/6.3 93/01/25
+ Add debugging for some MCI errors.
+
+6.13/6.3 93/01/22
+ Fix -e compatibility flag to take a value.
+ Fix a couple of minor compilation warnings on Sun cc.
+ Improve error messages in a few cases to be more self-explanatory.
+
+6.12/6.3 93/01/21
+ Fix yet-another problem with environment handling, pointed out
+ by Yoshitaka Tokugawa and Tom Ivar Helbekkmo.
+ Some heuristics to try to limit resource exhaustion problems
+ if a downstream host has been down for a long time.
+ Fix problem with incorrect host name being logged in "Connection
+ timed out" messages (from Tom Ivar Helbekkmo).
+ Fix some ANSI C problems (from Takahiro Kanbe).
+ Properly log message sender on returned mail during queue run.
+ Count number of recipients properly.
+ Fix a problem in yp map code.
+ Diagnose "message timed out" (from Motonori Nakamura).
+
+6.11/6.3 93/01/20
+ Fix problem with address delimitor inside quotes.
+ Define $k and $=k to be the UUCP name (from the uname call)
+ based on code from Bruce Lilly.
+
+6.10/6.2 93/01/18
+ Implement arpatounix (largely code from Bruce Lilly).
+ Log more info (suggested by John Myers).
+ Allow nested $?...$|...$. (inspired by code from Bruce Lilly of
+ Sony US).
+ POSIX compatibility (noted by Keith Bostic).
+ Handle SMTP MAIL command errors properly (urged by several people,
+ notably John Myers of CMU).
+ Do early diagnosis of .cf errors (notably referencing a RHS
+ substitution that isn't on the LHS).
+ Adjust checkpointing to better handle batched recipients, suggested
+ by John Myers.
+ Fix miscellaneous bugs.
+ (config files:) Implement MAIL_HUB for all local mail (to handle
+ NFS-mounted directories) as urged by Tom Ivar Helbekkmo
+ of the Norwegian School of Economics.
+
+6.9/6.1 93/01/13
+ Environment handling simplification/bug fix -- child processes
+ get a minimal, fixed environment. This avoids different
+ behaviour in queue runs.
+ Handle commas inside comments properly.
+ Properly limit large messages submitted in -obq mode.
+
+6.8/6.1 93/01/10
+ Check mtime of thaw file against .cf and sendmail binary, based on
+ code from John Myers.
+
+6.7/6.1 93/01/10
+ MX piggybacking, based on code from John Myers@CMU.
+ Allow checkcompat to return -1 to mean tempfail.
+ Bug fix in m_mno computation.
+
+6.6/6.1 93/01/09
+ Tuning of queueing functions as recommended by John Gardiner Myers.
+ Return mail headers (no body) on messages with negative precedence.
+ Minor other bug fixes.
+
+6.5/6.1 93/01/03
+ Fix botch causing queued headers to have ?XX? prefixes.
+
+6.4/6.1 93/01/02
+ Changes to recognize special mailer types (e.g., file) early.
+
+6.3/6.1 93/01/01
+ Pass timeouts to sfgets.
+ Check for control characters in addresses.
+ Fixed deferred error reporting.
+ Report duplicate aliases.
+ Handle mixed case recursive aliases.
+ Misc bug fixes.
+
+6.2/6.1 92/12/30
+ Put return-receipt-to on a conf.c flag (but don't set it).
+ Fix minor syslog problem.
diff --git a/usr.sbin/sendmail/cf/README b/usr.sbin/sendmail/cf/README
new file mode 100644
index 00000000000..d20549739ce
--- /dev/null
+++ b/usr.sbin/sendmail/cf/README
@@ -0,0 +1,1232 @@
+
+
+ NEW SENDMAIL CONFIGURATION FILES
+
+ Eric Allman <eric@CS.Berkeley.EDU>
+
+ @(#)README 8.28 (Berkeley) 4/14/94
+
+
+This document describes the sendmail configuration files being used
+at Berkeley. These use features in the new (R8) sendmail, and although
+there is an ``OLDSENDMAIL'' mode, they haven't really been tested on
+old versions of sendmail and cannot be expected to work well.
+
+These configuration files are probably not as general as previous
+versions, and don't handle as many of the weird cases automagically.
+I was able to simplify by them for two reasons. First, the network
+has become more consistent -- for example, at this point, everyone
+on the internet is supposed to be running a name server, so hacks to
+handle NIC-registered hosts can go away. Second, I assumed that a
+subdomain would be running SMTP internally -- UUCP is presumed to be
+a long-haul protocol. I realize that this is not universal, but it
+does describe the vast majority of sites with which I am familiar,
+including those outside the US.
+
+Of course, the downside of this is that if you do live in a weird
+world, things are going to get weirder for you. I'm sorry about that,
+but at the time we at Berkeley had a problem, and it seemed like the
+right thing to do.
+
+This package requires a post-V7 version of m4; if you are running the
+4.2bsd, SysV.2, or 7th Edition version, I suggest finding a friend with
+a newer version. You can m4-expand on their system, then run locally.
+SunOS's /usr/5bin/m4 or BSD-Net/2's m4 both work. GNU m4 version 1.1
+also works. Unfortunately, I'm told that the M4 on BSDI 1.0 doesn't
+work -- you'll have to use a Net/2 or GNU version.
+
+IF YOU DON'T HAVE A BERKELEY MAKE, don't despair! Just run
+"m4 foo.mc > foo.cf" -- that should be all you need. There is also
+a fairly crude (but functional) Makefile.dist that works on the
+old version of make.
+
+To get started, you may want to look at tcpproto.mc (for TCP-only
+sites), uucpproto.mc (for UUCP-only sites), and clientproto.mc (for
+clusters of clients using a single mail host). Others are versions
+that we use at Berkeley, although not all are in current use. For
+example, ucbarpa has gone away, but I've left ucbarpa.mc in because
+it demonstrates some interesting techniques.
+
+I'm not pretending that this README describes everything that these
+configuration files can do; clever people can probably tweak them
+to great effect. But it should get you started.
+
+*******************************************************************
+*** BE SURE YOU CUSTOMIZE THESE FILES! They have some ***
+*** Berkeley-specific assumptions built in, such as the name ***
+*** of our UUCP-relay. You'll want to create your own domain ***
+*** description, and use that in place of domain/Berkeley.m4. ***
+*******************************************************************
+
+
++--------------------------+
+| INTRODUCTION AND EXAMPLE |
++--------------------------+
+
+Configuration files are contained in the subdirectory "cf", with a
+suffix ".mc". They must be run through "m4" to produce a ".cf" file.
+
+Let's examine a typical .mc file (cf/cs-exposed.mc):
+
+ divert(-1)
+ #
+ # Copyright (c) 1983 Eric P. Allman
+ # Copyright (c) 1988 The Regents of the University of California.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms are permitted
+ # provided that the above copyright notice and this paragraph are
+ # duplicated in all such forms and that any documentation,
+ # advertising materials, and other materials related to such
+ # distribution and use acknowledge that the software was developed
+ # by the University of California, Berkeley. The name of the
+ # University may not be used to endorse or promote products derived
+ # from this software without specific prior written permission.
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ #
+
+The divert(-1) will delete the crud in the resulting output file.
+The copyright notice is what your lawyers require. Our lawyers require
+the one that I've included in my files. A copyleft is a copyright by
+another name.
+
+The next line MUST be
+
+ include(`../m4/cf.m4')
+
+This will pull in the M4 macros you will need to make sense of
+everything else. As the saying goes, don't think about it, just
+do it. If you don't do it, don't bother reading the rest of this
+file.
+
+ VERSIONID(`<SCCS or RCS version id>')
+
+VERSIONID is a macro that stuffs the version information into the
+resulting file. We use SCCS; you could use RCS, something else, or
+omit it completely. This is not the same as the version id included
+in SMTP greeting messages -- this is defined in m4/version.m4.
+
+ DOMAIN(cs.exposed)
+
+This example exposes the host inside of the CS subdomain -- that is,
+it doesn't try to hide the name of the workstation to the outside
+world. Changing this to DOMAIN(cs.hidden) would have made outgoing
+messages refer to "<username>@CS.Berkeley.EDU" instead of using the
+local hostname. Internally this is effected by using
+"MASQUERADE_AS(CS.Berkeley.EDU)".
+
+ MAILER(smtp)
+
+These describe the mailers used at the default CS site site. The
+local mailer is always included automatically.
+
+
++--------+
+| OSTYPE |
++--------+
+
+Note that cf/cs-exposed.mc omits an OSTYPE macro -- this assumes
+default Computer Science Division environment. There are several
+explicit environments available: bsd4.3, bsd4.4, hpux, irix, osf1,
+riscos4.5, sunos3.5, sunos4.1, and ultrix4.1. These change things
+like the location of the alias file and queue directory. Some of
+these files are identical to one another.
+
+Operating system definitions are easy to write. They may define
+the following variables (everything defaults, so an ostype file
+may be empty).
+
+ALIAS_FILE [/etc/aliases] The location of the text version
+ of the alias file(s). It can be a comma-separated
+ list of names (but be sure you quote values with
+ comments in them -- for example, use
+ define(`ALIAS_FILE', `a,b')
+ to get "a" and "b" both listed as alias files;
+ otherwise the define() primitive only sees "a").
+HELP_FILE [/usr/lib/sendmail.hf] The name of the file
+ containing information printed in response to
+ the SMTP HELP command.
+QUEUE_DIR [/var/spool/mqueue] The directory containing
+ queue files.
+STATUS_FILE [/etc/sendmail.st] The file containing status
+ information.
+LOCAL_MAILER_PATH [/bin/mail] The program used to deliver local mail.
+LOCAL_MAILER_FLAGS [rmn] The flags used by the local mailer. The
+ flags lsDFM are always included.
+LOCAL_MAILER_ARGS [mail -d $u] The arguments passed to deliver local
+ mail.
+LOCAL_SHELL_PATH [/bin/sh] The shell used to deliver piped email.
+LOCAL_SHELL_FLAGS [eu] The flags used by the shell mailer. The
+ flags lsDFM are always included.
+LOCAL_SHELL_ARGS [sh -c $u] The arguments passed to deliver "prog"
+ mail.
+USENET_MAILER_PATH [/usr/lib/news/inews] The name of the program
+ used to submit news.
+USENET_MAILER_FLAGS [rlsDFMmn] The mailer flags for the usenet mailer.
+USENET_MAILER_ARGS [-m -h -n] The command line arguments for the
+ usenet mailer.
+USENET_MAILER_MAX [100000] The maximum size of messages that will
+ be accepted by the usenet mailer.
+SMTP_MAILER_FLAGS [undefined] Flags added to SMTP mailer. Default
+ flags are `mDFMUX' (and `a' for esmtp mailer).
+SMTP_MAILER_MAX [undefined] The maximum size of messages that will
+ be transported using the smtp or esmtp mailers.
+UUCP_MAILER_FLAGS [undefined] Flags added to UUCP mailer. Default
+ flags are `DFMhuU' (and `m' for suucp mailer, minus
+ `U' for uucp-dom mailer).
+UUCP_MAILER_ARGS [uux - -r -z -a$f -gC $h!rmail ($u)] The arguments
+ passed to the UUCP mailer.
+UUCP_MAX_SIZE [100000] The maximum size message accepted for
+ transmission by the UUCP mailers.
+FAX_MAILER_PATH [/usr/local/lib/fax/mailfax] The program used to
+ submit FAX messages.
+FAX_MAILER_MAX [100000] The maximum size message accepted for
+ transmission by FAX.
+
++---------+
+| DOMAINS |
++---------+
+
+You will probably want to collect domain-dependent defines into one
+file, referenced by the DOMAIN macro. For example, our Berkeley
+domain file includes definitions for several internal distinguished
+hosts:
+
+UUCP_RELAY The host that will forward UUCP-addressed email.
+ If not defined, all UUCP sites must be directly
+ connected.
+BITNET_RELAY The host that will forward BITNET-addressed email.
+ If not defined, the .BITNET pseudo-domain won't work.
+LOCAL_RELAY The site that will handle unqualified names -- that
+ is, names with out an @domain extension. If not set,
+ they are assumed to belong on this machine. This
+ allows you to have a central site to store a
+ company- or department-wide alias database. This
+ only works at small sites, and there are better
+ methods.
+
+Each of these can be either ``mailer:hostname'' (in which case the
+mailer is the internal mailer name, such as ``suucp'' and the hostname
+is the name of the host as appropriate for that mailer) or just a
+``hostname'', in which case a default mailer type (usually ``relay'',
+a variant on SMTP) is used. WARNING: if you have a wildcard MX
+record matching your domain, you probably want to define these to
+have a trailing dot so that you won't get the mail diverted back
+to yourself.
+
+The domain file can also be used to define a domain name, if needed
+(using "DD<domain>") and set certain site-wide features. If all hosts
+at your site masquerade behind one email name, you could also use
+MASQUERADE_AS here.
+
+You do not have to define a domain -- in particular, if you are a
+single machine sitting off somewhere, it is probably more work than
+it's worth. This is just a mechanism for combining "domain dependent
+knowledge" into one place.
+
++---------+
+| MAILERS |
++---------+
+
+There are fewer mailers supported in this version than the previous
+version, owing mostly to a simpler world.
+
+local The local and prog mailers. You will almost always
+ need these; the only exception is if you relay ALL
+ your mail to another site. This mailer is included
+ automatically.
+
+smtp The Simple Mail Transport Protocol mailer. This does
+ not hide hosts behind a gateway or another other
+ such hack; it assumes a world where everyone is
+ running the name server. This file actually defines
+ three mailers: "smtp" for regular (old-style) SMTP to
+ other servers, "esmtp" for extended SMTP to other
+ servers, and "relay" for transmission to our
+ RELAY_HOST or MAILER_HUB.
+
+uucp The Unix-to-Unix Copy Program mailer. Actually, this
+ defines two mailers, "uucp" and "suucp". The latter
+ is for when you know that the UUCP mailer at the other
+ end can handle multiple recipients in one transfer.
+ When you invoke this, sendmail looks for all names in
+ the $=U class and sends them to the uucp-old mailer; all
+ names in the $=Y class are sent to uucp-new; and all
+ names in the $=Z class are sent to uucp-uudom. Note that
+ this is a function of what version of rmail runs on
+ the receiving end, and hence may be out of your control.
+ If smtp is defined, it also defines "uucp-dom" and
+ "uucp-uudom" mailers that use domain-style rewriting.
+ See the section below describing UUCP mailers in more
+ detail.
+
+usenet Usenet (network news) delivery. If this is specified,
+ an extra rule is added to ruleset 0 that forwards all
+ local email for users named ``group.usenet'' to the
+ ``inews'' program. Note that this works for all groups,
+ and may be considered a security problem.
+
+fax Facsimile transmission. This is experimental and based
+ on Sam Leffler's FlexFAX software. For more information,
+ see below.
+
+pop Post Office Protocol.
+
+
++----------+
+| FEATURES |
++----------+
+
+Special features can be requested using the "FEATURE" macro. For
+example, the .mc line:
+
+ FEATURE(use_cw_file)
+
+tells sendmail that you want to have it read an /etc/sendmail.cw
+file to get values for class $=w. The FEATURE may contain a single
+optional parameter -- for example:
+
+ FEATURE(mailertable, dbm /usr/lib/mailertable)
+
+Available features are:
+
+use_cw_file Read the file /etc/sendmail.cw file to get alternate
+ names for this host. This might be used if you were
+ on a host that MXed for a dynamic set of other
+ hosts. If the set is static, just including the line
+ "Cw<name1> <name2> ..." is probably superior.
+ The actual filename can be overridden by redefining
+ confCW_FILE.
+
+redirect Reject all mail addressed to "address.REDIRECT" with
+ a ``551 User not local; please try <address>'' message.
+ If this is set, you can alias people who have left
+ to their new address with ".REDIRECT" appended.
+
+nouucp Don't do anything special with UUCP addresses at all.
+
+nocanonify Don't pass addresses to $[ ... $] for canonification.
+ This would generally only be used by sites that only
+ act as mail gateways or which have user agents that do
+ full canonification themselves. You may also want to
+ use "define(`confBIND_OPTS',`-DNSRCH -DEFNAMES')" to
+ turn off the usual resolver options that do a similar
+ thing.
+
+notsticky By default, email sent to "user@local.host" are marked
+ as "sticky" -- that is, the local addresses aren't
+ matched against UDB and don't go through ruleset 5.
+ This features disables this treatment. It would
+ normally be used on network gateway machines.
+
+mailertable Include a "mailer table" which can be used to override
+ routing for particular domains. The argument of the
+ FEATURE may be the key definition. If none is specified,
+ the definition used is:
+ hash -o /etc/mailertable
+ Keys in this database are fully qualified domain names
+ or partial domains preceded by a dot -- for example,
+ "vangogh.CS.Berkeley.EDU" or ".CS.Berkeley.EDU".
+ Values must be of the form:
+ mailer:domain
+ where "mailer" is the internal mailer name, and "domain"
+ is where to send the message. These maps are not
+ reflected into the message header.
+
+domaintable Include a "domain table" which can be used to provide
+ full domains on unqualified (single word) hosts. The
+ argument of the FEATURE may be the key definition. If
+ none is specified, the definition used is:
+ hash -o /etc/domaintable
+ The key in this table is the unqualified host name; the
+ value is the fully qualified domain. Anything in the
+ domaintable is reflected into headers; that is, this
+ is done in ruleset 3.
+
+bitdomain Look up bitnet hosts in a table to try to turn them into
+ internet addresses. The table can be built using the
+ bitdomain program contributed by John Gardiner Myers.
+ The argument of the FEATURE may be the key definition; if
+ none is specified, the definition used is:
+ hash -o /etc/bitdomain.db
+ Keys are the bitnet hostname; values are the corresponding
+ internet hostname.
+
+uucpdomain Similar feature for UUCP hosts. The default map definition
+ is:
+ hash -o /etc/uudomain.db
+ At the moment there is no automagic tool to build this
+ database.
+
+always_add_domain
+ Include the local host domain even on locally delivered
+ mail. Normally it is not added unless it is already
+ present.
+
+allmasquerade If masquerading is enabled (using MASQUERADE_AS), this
+ feature will cause recipient addresses to also masquerade
+ as being from the masquerade host. Normally they get
+ the local hostname. Although this may be right for
+ ordinary users, it can break local aliases. For example,
+ if you send to "localalias", the originating sendmail will
+ find that alias and send to all members, but send the
+ message with "To: localalias@masqueradehost". Since that
+ alias likely does not exist, replies will fail. Use this
+ feature ONLY if you can guarantee that the ENTIRE
+ namespace on your masquerade host supersets all the
+ local entries.
+
+nodns We aren't running DNS at our site (for example,
+ we are UUCP-only connected). It's hard to consider
+ this a "feature", but hey, it had to go somewhere.
+
+nullclient This is a special case -- it creates a stripped down
+ configuration file containing nothing but support for
+ forwarding all mail to a central hub via a local
+ SMTP-based network. The argument is the name of that
+ hub.
+
+ The only other feature that should be used in conjunction
+ with this one is "nocanonify" (this causes addresses to
+ be sent unqualified via the SMTP connection; normally
+ they are qualifed with the masquerade name, which
+ defaults to the name of the hub machine). No mailers
+ should be defined. No aliasing or forwarding is done.
+
+
++-------+
+| HACKS |
++-------+
+
+Some things just can't be called features. To make this clear,
+they go in the hack subdirectory and are referenced using the HACK
+macro. These will tend to be site-dependent. The release
+includes the Berkeley-dependent "cssubdomain" hack (that makes
+sendmail accept local names in either Berkeley.EDU or CS.Berkeley.EDU;
+this is intended as a short-term aid while we move hosts into
+subdomains.
+
+
++--------------------+
+| SITE CONFIGURATION |
++--------------------+
+
+Complex sites will need more local configuration information, such as
+lists of UUCP hosts they speak with directly. This can get a bit more
+tricky. For an example of a "complex" site, see cf/ucbvax.mc.
+
+If your host is known by several different names, you need to augment
+the $=w class. This is a list of names by which you are known, and
+anything sent to an address using a host name in this list will be
+treated as local mail. You can do this in two ways: either create
+the file /etc/sendmail.cw containing a list of your aliases (one per
+line), and use ``FEATURE(use_cw_file)'' in the .mc file, or add the
+line:
+
+ Cw alias.host.name
+
+at the end of that file. See the ``vangogh.mc'' file for an example.
+Be sure you use the fully-qualified name of the host, rather than a
+short name.
+
+The SITECONFIG macro allows you to indirectly reference site-dependent
+configuration information stored in the siteconfig subdirectory. For
+example, the line
+
+ SITECONFIG(uucp.ucbvax, ucbvax, U)
+
+reads the file uucp.ucbvax for local connection information. The
+second parameter is the local name (in this case just "ucbvax" since
+it is locally connected, and hence a UUCP hostname). The third
+parameter is the name of both a macro to store the local name (in
+this case, $U) and the name of the class (e.g., $=U) in which to store
+the host information read from the file. Another SITECONFIG line reads
+
+ SITECONFIG(uucp.ucbarpa, ucbarpa.Berkeley.EDU, W)
+
+This says that the file uucp.ucbarpa contains the list of UUCP sites
+connected to ucbarpa.Berkeley.EDU. The $=W class will be used to
+store this list, and $W is defined to be ucbarpa.Berkeley.EDU, that
+is, the name of the relay to which the hosts listed in uucp.ucbarpa
+are connected. [The machine ucbarpa is gone now, but I've left
+this out-of-date configuration file around to demonstrate how you
+might do this.]
+
+Note that the case of SITECONFIG with a third parameter of ``U'' is
+special; the second parameter is assumed to be the UUCP name of the
+local site, rather than the name of a remote site, and the UUCP name
+is entered into $=w (the list of local hostnames) as $U.UUCP.
+
+The siteconfig file (e.g., siteconfig/uucp.ucbvax.m4) contains nothing
+more than a sequence of SITE macros describing connectivity. For
+example:
+
+ SITE(cnmat)
+ SITE(sgi olympus)
+
+The second example demonstrates that you can use two names on the
+same line; these are usually aliases for the same host (or are at
+least in the same company).
+
+
++--------------------+
+| USING UUCP MAILERS |
++--------------------+
+
+It's hard to get UUCP mailers right because of the extremely ad hoc
+nature of UUCP addressing. These config files are really designed
+for domain-based addressing, even for UUCP sites.
+
+There are four UUCP mailers available. The choice of which one to
+use is partly a matter of local preferences and what is running at
+the other end of your UUCP connection. Unlike good protocols that
+define what will go over the wire, UUCP uses the policy that you
+should do what is right for the other end; if they change, you have
+to change. This makes it hard to do the right thing, and discourages
+people from updating their software. In general, if you can avoid
+UUCP, please do.
+
+The major choice is whether to go for a domainized scheme or a
+non-domainized scheme. This depends entirely on what the other
+end will recognize. If at all possible, you should encourage the
+other end to go to a domain-based system -- non-domainized addresses
+don't work entirely properly.
+
+The four mailers are:
+
+ uucp-old (obsolete name: "uucp")
+ This is the oldest, the worst (but the closest to UUCP) way of
+ sending messages accros UUCP connections. It does bangify
+ everything and prepends $U (your UUCP name) to the sender's
+ address (which can already be a bang path itself). It can
+ only send to one address at a time, so it spends a lot of
+ time copying duplicates of messages. Avoid this if at all
+ possible.
+
+ uucp-new (obsolete name: "suucp")
+ The same as above, except that it assumes that in one rmail
+ command you can specify several recipients. It still has a
+ lot of other problems.
+
+ uucp-dom
+ This UUCP mailer keeps everything as domain addresses.
+ Basically, it uses the SMTP mailer rewriting rules.
+
+ Unfortunately, a lot of UUCP mailer transport agents require
+ bangified addresses in the envelope, although you can use
+ domain-based addresses in the message header. (The envelope
+ shows up as the From_ line on UNIX mail.) So....
+
+ uucp-uudom
+ This is a cross between uucp-new (for the envelope addresses)
+ and uucp-dom (for the header addresses). It bangifies the
+ envelope sender (From_ line in messages) without adding the
+ local hostname, unless there is no host name on the address
+ at all (e.g., "wolf") or the host component is a UUCP host name
+ instead of a domain name ("somehost!wolf" instead of
+ "some.dom.ain!wolf").
+
+Examples:
+
+We are on host grasp.insa-lyon.fr (UUCP host name "grasp"). The
+following summarizes the sender rewriting for various mailers.
+
+Mailer sender rewriting in the envelope
+------ ------ -------------------------
+uucp-{old,new} wolf grasp!wolf
+uucp-dom wolf wolf@grasp.insa-lyon.fr
+uucp-uudom wolf grasp.insa-lyon.fr!wolf
+
+uucp-{old,new} wolf@fr.net grasp!fr.net!wolf
+uucp-dom wolf@fr.net wolf@fr.net
+uucp-uudom wolf@fr.net fr.net!wolf
+
+uucp-{old,new} somehost!wolf grasp!somehost!wolf
+uucp-dom somehost!wolf somehost!wolf@grasp.insa-lyon.fr
+uucp-uudom somehost!wolf grasp.insa-lyon.fr!somehost!wolf
+
+If you are using one of the domainized UUCP mailers, you really want
+to convert all UUCP addresses to domain format -- otherwise, it will
+do it for you (and probably not the way you expected). For example,
+if you have the address foo!bar!baz (and you are not sending to foo),
+the heuristics will add the @uucp.relay.name or @local.host.name to
+this address. However, if you map foo to foo.host.name first, it
+will not add the local hostname. You can do this using the uucpdomain
+feature.
+
+
++-------------------+
+| TWEAKING RULESETS |
++-------------------+
+
+For more complex configurations, you can define special rules.
+The macro LOCAL_RULE_3 introduces rules that are used in canonicalizing
+the names. Any modifications made here are reflected in the header.
+
+A common use is to convert old UUCP addreses to SMTP addresses using
+the UUCPSMTP macro. For example:
+
+ LOCAL_RULE_3
+ UUCPSMTP(decvax, decvax.dec.com)
+ UUCPSMTP(research, research.att.com)
+
+will cause addresses of the form "decvax!user" and "research!user"
+to be converted to "user@decvax.dec.com" and "user@research.att.com"
+respectively.
+
+This could also be used to look up hosts in a database map:
+
+ LOCAL_RULE_3
+ R$* < @ $+ > $* $: $1 < @ $(hostmap $2 $) > $3
+
+This map would be defined in the LOCAL_CONFIG portion, as shown below.
+
+Similarly, LOCAL_RULE_0 can be used to introduce new parsing rules.
+For example, new rules are needed to parse hostnames that you accept
+via MX records. For example, you might have:
+
+ LOCAL_RULE_0
+ R$+ <@ host.dom.ain.> $#uucp $@ cnmat $: $1 < @ host.dom.ain.>
+
+You would use this if you had installed an MX record for cnmat.Berkeley.EDU
+pointing at this host; this rule catches the message and forwards it on
+using UUCP.
+
+You can also tweak rulesets 1 and 2 using LOCAL_RULE_1 and LOCAL_RULE_2.
+These rulesets are normally empty.
+
+A similar macro is LOCAL_CONFIG. This introduces lines added after the
+boilerplate option setting but before rulesets, and can be used to
+declare local database maps or whatever. For example:
+
+ LOCAL_CONFIG
+ Khostmap hash /etc/hostmap.db
+ Kyplocal nis -m hosts.byname
+
+
++---------------------------+
+| MASQUERADING AND RELAYING |
++---------------------------+
+
+You can have your host masquerade as another using
+
+ MASQUERADE_AS(host.domain)
+
+This causes outgoing SMTP mail to be labeled as coming from the
+indicated domain, rather than $j. One normally masquerades as one
+of one's own subdomains (for example, it's unlikely that I would
+choose to masquerade as an MIT site).
+
+The masquerade name is not normally canonified, so it is important
+that it be your One True Name, that is, fully qualified and not a
+CNAME.
+
+there are always users that need to be "exposed" -- that is, their
+internal site name should be displayed instead of the masquerade name.
+Root is an example. You can add users to this list using
+
+ EXPOSED_USER(usernames)
+
+This adds users to class E; you could also use something like
+
+ FE/etc/sendmail.cE
+
+You can also arrange to relay all unqualified names (that is, names
+without @host) to a relay host. For example, if you have a central
+email server, you might relay to that host so that users don't have
+to have .forward files or aliases. You can do this using
+
+ define(`LOCAL_RELAY', mailer:hostname)
+
+The ``mailer:'' can be omitted, in which case the mailer defaults to
+"smtp". There are some user names that you don't want relayed, perhaps
+because of local aliases. A common example is root, which may be
+locally aliased. You can add entries to this list using
+
+ LOCAL_USER(usernames)
+
+This adds users to class L; you could also use something like
+
+ FL/etc/sendmail.cL
+
+If you want all incoming mail sent to a centralized hub, as for a
+shared /var/spool/mail scheme, use
+
+ define(`MAIL_HUB', mailer:hostname)
+
+Again, ``mailer:'' defaults to "smtp". If you define both LOCAL_RELAY
+and MAIL_HUB, unqualified names will be sent to the LOCAL_RELAY and
+other local names will be sent to MAIL_HUB. Names in $=L will be
+delivered locally, so you MUST have aliases or .forward files for them.
+
+For example, if are on machine mastodon.CS.Berkeley.EDU, the following
+combinations of settings will have the indicated effects:
+
+email sent to.... eric eric@mastodon.CS.Berkeley.EDU
+
+LOCAL_RELAY set to mail.CS.Berkeley.EDU (delivered locally)
+mail.CS.Berkeley.EDU
+
+MAIL_HUB set to mammoth.CS.Berkeley.EDU mammoth.CS.Berkeley.EDU
+mammoth.CS.Berkeley.EDU
+
+Both LOCAL_RELAY and mail.CS.Berkeley.EDU mammoth.CS.Berkeley.EDU
+MAIL_HUB set as above
+
+If you want all outgoing mail to go to a central relay site, define
+SMART_HOST as well. Briefly:
+
+ LOCAL_RELAY applies to unqualifed names (e.g., "eric").
+ MAIL_HUB applies to names qualified with the name of the
+ local host (e.g., "eric@mastodon.CS.Berkeley.EDU").
+ SMART_HOST applies to names qualified with other hosts.
+
+However, beware that other relays (e.g., UUCP_RELAY, BITNET_RELAY, and
+FAX_RELAY) take precedence over SMART_HOST, so if you really want
+absolutely everything to go to a single central site you will need to
+unset all the other relays -- or better yet, find or build a minimal
+config file that does this.
+
+
++-------------------------------+
+| NON-SMTP BASED CONFIGURATIONS |
++-------------------------------+
+
+These configuration files are designed primarily for use by SMTP-based
+sites. I don't pretend that they are well tuned for UUCP-only or
+UUCP-primarily nodes (the latter is defined as a small local net
+connected to the rest of the world via UUCP). However, there is one
+hook to handle some special cases.
+
+You can define a ``smart host'' that understands a richer address syntax
+using:
+
+ define(`SMART_HOST', mailer:hostname)
+
+In this case, the ``mailer:'' defaults to "relay". Any messages that
+can't be handled using the usual UUCP rules are passed to this host.
+
+If you are on a local SMTP-based net that connects to the outside
+world via UUCP, you can use LOCAL_NET_CONFIG to add appropriate rules.
+For example:
+
+ define(`SMART_HOST', suucp:uunet)
+ LOCAL_NET_CONFIG
+ R$* < @ $* .$m. > $* $#smtp $@ $2.$m. $: $1 < @ $2.$m. > $3
+
+This will cause all names that end in your domain name ($m) via
+SMTP; anything else will be sent via suucp (smart UUCP) to uunet.
+If you have FEATURE(nocanonify), you may need to omit the dots after
+the $m. If you are running a local DNS inside your domain which is
+not otherwise connected to the outside world, you probably want to
+use:
+
+ define(`SMART_HOST', smtp:fire.wall.com)
+ LOCAL_NET_CONFIG
+ R$* < @ $* . > $* $#smtp $@ $2. $: $1 < @ $2. > $3
+
+That is, send directly only to things you found in your DNS lookup;
+anything else goes through SMART_HOST.
+
+If you are not running DNS at all, it is important to use
+FEATURE(nodns) to avoid having sendmail queue everything waiting
+for the name server to come up.
+
+
++-----------+
+| WHO AM I? |
++-----------+
+
+Normally, the $j macro is automatically defined to be your fully
+qualified domain name (FQDN). Sendmail does this by getting your
+host name using gethostname and then calling gethostbyname on the
+result. For example, in some environments gethostname returns
+only the root of the host name (such as "foo"); gethostbyname is
+supposed to return the FQDN ("foo.bar.com"). In some (fairly rare)
+cases, gethostbyname may fail to return the FQDN. In this case
+you MUST define confDOMAIN_NAME to be your fully qualified domain
+name. This is usually done using:
+
+ Dmbar.com
+ define(`confDOMAIN_NAME', `$w.$m')dnl
+
+
++--------------------+
+| USING MAILERTABLES |
++--------------------+
+
+To use FEATURE(mailertable), you will have to create an external
+database containing the routing information for various domains.
+For example, a mailertable file in text format might be:
+
+ .my.domain xnet:%1.my.domain
+ uuhost1.my.domain suucp:uuhost1
+ .bitnet smtp:relay.bit.net
+
+This should normally be stored in /etc/mailertable. The actual
+database version of the mailertable is built using:
+
+ makemap hash /etc/mailertable.db < /etc/mailertable
+
+The semantics are simple. Any LHS entry that does not begin with
+a dot matches the full host name indicated. LHS entries beginning
+with a dot match anything ending with that domain name -- that is,
+they can be thought of as having a leading "*" wildcard. Matching
+is done in order of most-to-least qualified -- for example, even
+though ".my.domain" is listed first in the above example, an entry
+of "uuhost1.my.domain" will match the second entry since it is
+more explicit.
+
+The RHS should always be a "mailer:host" pair. The mailer is the
+configuration name of a mailer (that is, an `M' line in the
+sendmail.cf file). The "host" will be the hostname passed to
+that mailer. In domain-based matches (that is, those with leading
+dots) the "%1" may be used to interpolate the wildcarded part of
+the host name. For example, the first line above sends everything
+addressed to "anything.my.domain" to that same host name, but using
+the (presumably experimental) xnet mailer.
+
+
++--------------------------------+
+| USING USERDB TO MAP FULL NAMES |
++--------------------------------+
+
+The user database was not originally intended for mapping full names
+to login names (e.g., Eric.Allman => eric), but some people are using
+it that way. (I would recommend that you set up aliases for this
+purpose instead -- since you can specify multiple alias files, this
+is fairly easy.) The intent was to locate the default maildrop at
+a site, but allow you to override this by sending to a specific host.
+
+If you decide to set up the user database in this fashion, it is
+imperative that you also specify FEATURE(notsticky) -- otherwise,
+e-mail sent to Full.Name@local.host.name will be rejected.
+
+To build the internal form of the user databae, use:
+
+ makemap btree /usr/data/base.db < /usr/data/base.txt
+
+
++------------------+
+| FlexFAX SOFTWARE |
++------------------+
+
+Sam Leffler's FlexFAX software is still in beta test -- but he expects a
+public version out "later this week" [as of 3/1/93]. The following
+blurb is direct from Sam:
+
+ Header: /usr/people/sam/fax/RCS/HOWTO,v 1.14 93/05/24 11:42:16 sam Exp
+
+ How To Obtain This Software (in case all you get is this file)
+ --------------------------------------------------------------
+ The source code is available for public ftp on
+ sgi.com sgi/fax/v2.1.src.tar.Z
+ (192.48.153.1)
+
+ You can also obtain inst'able images for Silicon Graphics machines from
+ sgi.com sgi/fax/v2.1.inst.tar
+ (192.48.153.1)
+
+ For example,
+ % ftp -n sgi.com
+ ....
+ ftp> user anonymous
+ ... <type in password>
+ ftp> cd sgi/fax
+ ftp> binary
+ ftp> get v2.1.src.tar.Z
+
+ In general, the latest version of the 2.1 release of the software is
+ always available as "v2.1.src.tar.Z" or "v2.1.inst.tar" in the ftp
+ directory. This file is a link to the appropriate released version (so
+ don't waste your time retrieving the linked file as well!) Any files of
+ the form v2.1.*.patch are shell scripts that can be used to patch older
+ versions of the source code. For example, the file v2.1.0.patch would
+ contain patches to update v2.1.0.tar.Z. (Note to beta testers: this is
+ different than the naming conventions used during beta testing.) Patch
+ files only work to go between consecutive versions, so if you are
+ multiple versions behind the latest release, you will need to apply
+ each patch file between your current version and the latest.
+
+
+ Obtaining the Software by Electronic Mail
+ -----------------------------------------
+ Do not send me requests for the software; they will be ignored (without
+ response). If you cannot use FTP at all, there is a service called
+ "ftpmail" available from gatekeeper.dec.com: you can send e-mail to
+ this machine and it will use FTP to retrieve files for you and send you
+ the files back again via e-mail. To find out more about the ftpmail
+ service, send a message to "ftpmail@gatekeeper.dec.com" whose body
+ consists of the single line "help".
+
+
+ Obtaining the Software Within Silicon Graphics
+ ----------------------------------------------
+ Internal to Silicon Graphics there are inst'able images on the host
+ flake.asd in the directory /usr/dist. Thus you can do something like:
+
+ % inst -f flake.asd.sgi.com:/usr/dist/flexfax
+
+ to install the latest version of the software on your machine.
+
+
+ What to do Once You've Retrieved Stuff
+ --------------------------------------
+ The external distributions come in a compressed or uncompressed tar
+ file. To extract the source distribution:
+
+ % zcat v2.1.src.tar.Z | tar xf -
+
+ (uncompress and extract individual files in current directory). To
+ unpack and install the client portion of the inst'able distribution:
+
+ % mkdir dist
+ % cd dist; tar xf ../v2.1.inst.tar; cd ..
+ % inst -f dist/flexfax
+ ...
+ inst> go
+
+ (Note, the dist subdirectory is because some versions of inst fail if
+ the files are in the current directory.) Server binaries are also
+ included in the inst'able images as flexfax.server.*. They are not
+ installed by default, so to get them also you need to do:
+
+ % inst -f flexfax
+ ...
+ inst> install flexfax.server.*
+ inst> go
+
+ The SGI binaries were built for Version 4.0.5H of the IRIX operating
+ system. They should work w/o problem on earlier versions of the
+ system, but I have not fully tested this. Also, note that to install a
+ server on an SGI machine, you need to have installed the Display
+ PostScript execution environment product (dps_eoe). Otherwise, the fax
+ server will not be able to convert PostScript to facsimile for
+ transmission.
+
+ If you are working from the source distribution, look at the file
+ README in the top of the source tree. If you are working from the inst
+ images, the subsystem flexfax.man.readme contains the README file and
+ other useful pieces of information--the installed files are placed in
+ the directory /usr/local/doc/flexfax). Basically you will need to run
+ the faxaddmodem script to setup and configure your fax modem. Consult
+ the README file and the manual page for faxaddmodem for information.
+
+
+ FlexFAX Mail List
+ -----------------
+ A mailing list for users of this software is located on sgi.com.
+ If you want to join this mailing list or have a list-related request
+ such as getting your name removed from it, send a request to
+
+ majordomo@whizzer.wpd.sgi.com
+
+ For example, to subscribe, send the line "subscribe flexfax" in
+ the body of your message. The line "help" will return a list of
+ the commands understood by the mailing list management software.
+
+ Submissions (including bug reports) should be directed to:
+
+ flexfax@sgi.com
+
+ When corresponding about this software please always specify what
+ version you have, what system you're running on, and, if the problem is
+ specific to your modem, identify the modem and firmware revision.
+
+
++--------------------------------+
+| TWEAKING CONFIGURATION OPTIONS |
++--------------------------------+
+
+There are a large number of configuration options that don't normally
+need to be changed. However, if you feel you need to tweak them, you
+can define the following M4 variables. This list is shown in four
+columns: the name you define, the default value for that definition,
+the option or macro that is affected (either Ox for an option or Dx
+for a macro), and a brief description. Greater detail of the semantics
+can be found in the Installation and Operations Guide.
+
+Some options are likely to be deprecated in future versions -- that is,
+the option is only included to provide back-compatibility. These are
+marked with "*".
+
+Remember that these options are M4 variables, and hence may need to
+be quoted. In particular, arguments with commas will usually have to
+be ``double quoted, like this phrase'' to avoid having the comma
+confuse things. This is common for alias file definitions and for
+the read timeout.
+
+M4 Variable Name Default Mac/Opt Description
+================ ======= ======= ===========
+confMAILER_NAME MAILER-DAEMON Dn The sender name used for
+ internally generated
+ outgoing messages.
+confFROM_LINE From $g $d Dl The From_ line used when
+ sending to files or programs.
+confFROM_HEADER $?x$x <$g>$|$g$. The format of an internally
+ Dq generated From: address.
+confOPERATORS .:%@!^/[] Do Address operator characters.
+confSMTP_LOGIN_MSG $j Sendmail $v/$Z ready at $b
+ De The initial (spontaneous)
+ SMTP greeting message.
+confSEVEN_BIT_INPUT False O7 Force input to seven bits?
+confALIAS_WAIT 10 Oa Wait (in minutes) for alias
+ file rebuild.
+confMIN_FREE_BLOCKS 4 Ob Minimum number of free blocks
+ on queue filesystem to accept
+ SMTP mail.
+confBLANK_SUB . OB Blank (space) substitution
+ character.
+confCON_EXPENSIVE False Oc Avoid connecting immediately
+ to mailers marked expensive?
+confCHECKPOINT_INTERVAL 10 OC Checkpoint queue files
+ every N recipients.
+confDELIVERY_MODE background Od Default delivery mode.
+confAUTO_REBUILD False OD Automatically rebuild
+ alias file if needed.
+confERROR_MODE (undefined) Oe Error message mode.
+confERROR_MESSAGE (undefined) OE Error message header/file.
+confSAVE_FROM_LINES False Of Save extra leading
+ From_ lines.
+confTEMP_FILE_MODE 0600 OF Temporary file mode.
+confDEF_GROUP_ID 1 Og Default group id.
+confMATCH_GECOS False OG Match GECOS field.
+confMAX_HOP 17 Oh Maximum hop count.
+confIGNORE_DOTS False Oi * Ignore dot as terminator
+ for incoming messages?
+confBIND_OPTS (empty) OI Default options for BIND.
+confMIME_FORMAT_ERRORS True Oj * Send error messages as MIME-
+ encapsulated messages per
+ RFC 1344.
+confFORWARD_PATH (undefined) OJ The colon-separated list of
+ places to search for .forward
+ files.
+confMCI_CACHE_SIZE 2 Ok Size of open connection cache.
+confMCI_CACHE_TIMEOUT 5m OK Open connection cache timeout.
+confUSE_ERRORS_TO False Ol * Use the Errors-To: header to
+ deliver error messages. This
+ should not be necessary because
+ of general acceptance of the
+ envelope/header distinction.
+confLOG_LEVEL 9 OL Log level.
+confME_TOO False Om Include sender in group
+ expansions.
+confCHECK_ALIASES True On Check RHS of aliases when
+ running newaliases.
+confOLD_STYLE_HEADERS True Oo * Assume that headers without
+ special chars are old style.
+confDAEMON_OPTIONS (undefined) OO SMTP daemon options.
+confPRIVACY_FLAGS authwarnings Op Privacy flags.
+confCOPY_ERRORS_TO (undefined) OP Address for additional copies
+ of all error messages.
+confQUEUE_FACTOR (undefined) Oq Slope of queue-only function
+confREAD_TIMEOUT (undefined) Or SMTP read timeouts.
+confSAFE_QUEUE True Os * Commit all messages to disk
+ before forking.
+confMESSAGE_TIMEOUT 5d/4h OT Timeout for messages before
+ sending error/warning message.
+confTIME_ZONE USE_SYSTEM Ot Time zone info -- can be
+ USE_SYSTEM to use the system's
+ idea, USE_TZ to use the user's
+ TZ envariable, or something
+ else to force that value.
+confDEF_USER_ID 1 Ou Default user id.
+confUSERDB_SPEC (undefined) OU User database specification.
+confFALLBACK_MX (undefined) OV Fallback MX host.
+confTRY_NULL_MX_LIST False Ow If we are the best MX for a
+ host and haven't made other
+ arrangements, try connecting
+ to the host directly; normally
+ this would be a config error.
+confQUEUE_LA 8 Ox Load average at which queue-only
+ function kicks in.
+confREFUSE_LA 12 OX Load average at which incoming
+ SMTP connections are refused.
+confWORK_RECIPIENT_FACTOR
+ (undefined) Oy Cost of each recipient.
+confSEPARATE_PROC False OY Run all deliveries in a
+ separate process.
+confWORK_CLASS_FACTOR (undefined) Oz Priority multiplier for class.
+confWORK_TIME_FACTOR (undefined) OZ Cost of each delivery attempt.
+confCW_FILE /etc/sendmail.cw Name of file used to get the
+ Fw local additions to the $=w
+ class.
+confSMTP_MAILER smtp - The mailer name used when
+ SMTP connectivity is required.
+ Either "smtp" or "esmtp".
+confLOCAL_MAILER local - The mailer name used when
+ local connectivity is required.
+ Almost always "local".
+confRELAY_MAILER relay - The default mailer name used
+ for relaying any mail (e.g.,
+ to a BITNET_RELAY, a
+ SMART_HOST, or whatever).
+ This can reasonably be "suucp"
+ if you are on a UUCP-connected
+ site.
+confDOMAIN_NAME (undefined) Dj If defined, sets $j.
+
+
++-----------+
+| HIERARCHY |
++-----------+
+
+Within this directory are several subdirectories, to wit:
+
+m4 General support routines. These are typically
+ very important and should not be changed without
+ very careful consideration.
+
+cf The configuration files themselves. They have
+ ".mc" suffixes, and must be run through m4 to
+ become complete. The resulting output should
+ have a ".cf" suffix.
+
+ostype Definitions describing a particular operating
+ system type. These should always be referenced
+ using the OSTYPE macro in the .mc file. Examples
+ include "bsd4.3", "bsd4.4", "sunos3.5", and
+ "sunos4.1".
+
+domain Definitions describing a particular domain, referenced
+ using the DOMAIN macro in the .mc file. These are
+ site dependent; for example, we contribute "cs.exposed.m4"
+ and "cs.hidden.m4" which both describe hosts in the
+ CS.Berkeley.EDU subdomain; the former displays the local
+ hostname (e.g., mammoth.CS.Berkeley.EDU), whereas the
+ latter does its best to hide the identity of the local
+ workstation inside the CS subdomain.
+
+mailer Descriptions of mailers. These are referenced using
+ the MAILER macro in the .mc file.
+
+sh Shell files used when building the .cf file from the
+ .mc file in the cf subdirectory.
+
+feature These hold special orthogonal features that you might
+ want to include. They should be referenced using
+ the FEATURE macro.
+
+hack Local hacks. These can be referenced using the HACK
+ macro. They shouldn't be of more than voyeuristic
+ interest outside the .Berkeley.EDU domain, but who knows?
+ We've all got our own peccadillos.
+
+siteconfig Site configuration -- e.g., tables of locally connected
+ UUCP sites.
+
+
++------------------------+
+| ADMINISTRATIVE DETAILS |
++------------------------+
+
+The following sections detail usage of certain internal parts of the
+sendmail.cf file. Read them carefully if you are trying to modify
+the current model. If you find the above descriptions adequate, these
+should be {boring, confusing, tedious, ridiculous} (pick one or more).
+
+RULESETS (* means built in to sendmail)
+
+ 0 * Parsing
+ 1 * Sender rewriting
+ 2 * Recipient rewriting
+ 3 * Canonicalization
+ 4 * Post cleanup
+ 5 * Local address rewrite (after aliasing)
+ 1x mailer rules (sender qualification)
+ 2x mailer rules (recipient qualification)
+ 3x mailer rules (sender header qualification)
+ 4x mailer rules (recipient header qualification)
+ 5x mailer subroutines (general)
+ 6x mailer subroutines (general)
+ 7x mailer subroutines (general)
+ 8x reserved
+ 90 Mailertable host stripping
+ 96 Bottom half of Ruleset 3 (ruleset 6 in old sendmail)
+ 97 Hook for recursive ruleset 0 call (ruleset 7 in old sendmail)
+ 98 Local part of ruleset 0 (ruleset 8 in old sendmail)
+
+
+MAILERS
+
+ 0 local, prog local and program mailers
+ 1 [e]smtp, relay SMTP channel
+ 2 uucp-* UNIX-to-UNIX Copy Program
+ 3 netnews Network News delivery
+ 4 fax Sam Leffler's FlexFAX software
+
+
+MACROS
+
+ A
+ B Bitnet Relay
+ C
+ D The local domain -- usually not needed
+ E
+ F FAX Relay
+ G
+ H mail Hub (for mail clusters)
+ I
+ J
+ K
+ L
+ M Masquerade (who I claim to be)
+ N
+ O
+ P
+ Q
+ R Relay (for unqualified names)
+ S Smart Host
+ T
+ U my UUCP name (if I have a UUCP connection)
+ V UUCP Relay (class V hosts)
+ W UUCP Relay (class W hosts)
+ X UUCP Relay (class X hosts)
+ Y UUCP Relay (all other hosts)
+ Z Version number
+
+
+CLASSES
+
+ A
+ B
+ C
+ D
+ E addresses that should not seem to come from $M
+ F hosts we forward for
+ G
+ H
+ I
+ J
+ K
+ L addresses that should not be forwarded to $R
+ M
+ N
+ O operators that indicate network operations (cannot be in local names)
+ P top level pseudo-domains: BITNET, FAX, UUCP, etc.
+ Q
+ R
+ S
+ T
+ U locally connected UUCP hosts
+ V UUCP hosts connected to relay $V
+ W UUCP hosts connected to relay $W
+ X UUCP hosts connected to relay $X
+ Y locally connected smart UUCP hosts
+ Z locally connected domain-ized UUCP hosts
+ . the class containing only a dot
+
+
+M4 DIVERSIONS
+
+ 1 Local host detection and resolution
+ 2 Local Ruleset 3 additions
+ 3 Local Ruleset 0 additions
+ 4 UUCP Ruleset 0 additions
+ 5 locally interpreted names (overrides $R)
+ 6 local configuration (at top of file)
+ 7 mailer definitions
+ 8
+ 9 special local rulesets (1 and 2)
diff --git a/usr.sbin/sendmail/cf/cf/Makefile b/usr.sbin/sendmail/cf/cf/Makefile
new file mode 100644
index 00000000000..f4be0a39879
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/Makefile
@@ -0,0 +1,69 @@
+# @(#)Makefile 8.5 (Berkeley) 12/1/93
+
+M4= m4
+CHMOD= chmod
+ROMODE= 444
+RM= rm -f
+
+.SUFFIXES: .mc .cf
+
+.mc.cf:
+ $(RM) $@
+ (cd ${.CURDIR} && $(M4) ${@:R}.mc > ${.OBJDIR}/$@)
+ $(CHMOD) $(ROMODE) $@
+
+ALL= ucbarpa.cf ucbvax.cf vangogh.cf \
+ chez.cf python.cf \
+ boat-anchor.cf chimera.cf pain.cf sun-lamp.cf trinity.cf \
+ clientproto.cf netbsd-proto.cf tcpproto.cf uucpproto.cf
+
+all: $(ALL)
+
+clean cleandir:
+ $(RM) $(ALL) core
+
+depend install:
+
+distribution:
+ install -c -o root -g wheel -m 444 netbsd-proto.cf \
+ ${DESTDIR}/etc/sendmail.cf
+
+# this is overkill, but....
+M4FILES=\
+ ../domain/Berkeley.m4 \
+ ../domain/cs.exposed.m4 \
+ ../domain/cs.hidden.m4 \
+ ../domain/eecs.hidden.m4 \
+ ../domain/s2k.m4 \
+ ../feature/allmasquerade.m4 \
+ ../feature/always_add_domain.m4 \
+ ../feature/bitdomain.m4 \
+ ../feature/domaintable.m4 \
+ ../feature/mailertable.m4 \
+ ../feature/nocanonify.m4 \
+ ../feature/nodns.m4 \
+ ../feature/notsticky.m4 \
+ ../feature/nouucp.m4 \
+ ../feature/nullclient.m4 \
+ ../feature/redirect.m4 \
+ ../feature/use_cw_file.m4 \
+ ../feature/uucpdomain.m4 \
+ ../hack/cssubdomain.m4 \
+ ../m4/cf.m4 \
+ ../m4/nullrelay.m4 \
+ ../m4/proto.m4 \
+ ../m4/version.m4 \
+ ../mailer/fax.m4 \
+ ../mailer/local.m4 \
+ ../mailer/smtp.m4 \
+ ../mailer/usenet.m4 \
+ ../mailer/uucp.m4 \
+ ../ostype/bsd4.4.m4 \
+ ../siteconfig/uucp.cogsci.m4 \
+ ../siteconfig/uucp.old.arpa.m4 \
+ ../siteconfig/uucp.ucbarpa.m4 \
+ ../siteconfig/uucp.ucbvax.m4 \
+
+$(ALL): $(M4FILES)
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/cf/cf/boat-anchor.mc b/usr.sbin/sendmail/cf/cf/boat-anchor.mc
new file mode 100644
index 00000000000..77f122b365a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/boat-anchor.mc
@@ -0,0 +1,47 @@
+divert(-1)
+#
+# Copyright (c) 1993 Adam Glass
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)boat-anchor.mc $Revision: 1.1.1.1 $')
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`UUCP_RELAY', ucbvax.Berkeley.EDU)dnl
+define(`BITNET_RELAY', mailhost.Berkeley.EDU)dnl
+define(`CSNET_RELAY', mailhost.Berkeley.EDU)dnl
+define(`LOCAL_RELAY', sun-lamp.CS.Berkeley.EDU)
+define(`MAIL_HUB', sun-lamp.CS.Berkeley.EDU)
+define(`confCHECKPOINT_INTERVAL', 4)dnl
diff --git a/usr.sbin/sendmail/cf/cf/chez.mc b/usr.sbin/sendmail/cf/cf/chez.mc
new file mode 100644
index 00000000000..13f951977f0
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/chez.mc
@@ -0,0 +1,44 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)chez.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(bsd4.4)dnl
+DOMAIN(cs.exposed)dnl
+define(`LOCAL_RELAY', vangogh.CS.Berkeley.EDU)dnl
+define(`MASQUERADE_NAME', vangogh.CS.Berkeley.EDU)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+Fw/etc/sendmail.cw
diff --git a/usr.sbin/sendmail/cf/cf/chimera.mc b/usr.sbin/sendmail/cf/cf/chimera.mc
new file mode 100644
index 00000000000..b86168caee3
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/chimera.mc
@@ -0,0 +1,48 @@
+divert(-1)
+#
+# Copyright (c) 1993, 1994, 1995 Adam Glass
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+#
+include(`../m4/cf.m4')
+VERSIONID(`@(#)pain.mc $Revision: 1.1.1.1 $')
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`MAIL_HUB', mail.netbsd.org)dnl
+define(`SMART_HOST', nobozo.cs.berkeley.edu)dnl
+define(`confCHECKPOINT_INTERVAL', 10)dnl
+define(`confAUTO_REBUILD', True)dnl
+define(`confMESSAGE_TIMEOUT', 3d/4h)dnl
+MASQUERADE_AS(netbsd.org)dnl
+LOCAL_USER(root)
diff --git a/usr.sbin/sendmail/cf/cf/clientproto.mc b/usr.sbin/sendmail/cf/cf/clientproto.mc
new file mode 100644
index 00000000000..902c1eb752e
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/clientproto.mc
@@ -0,0 +1,49 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+#
+# This the prototype for a "null client" -- that is, a client that
+# does nothing except forward all mail to a mail hub.
+#
+# To use this, you MUST use the nullclient feature with the name of
+# the mail hub as its argument. You MAY also define an OSTYPE to
+# define the location of the queue directories and the like.
+# Other than these, it should never contain any other lines.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)clientproto.mc 8.2 (Berkeley) 8/21/93')
+
+FEATURE(nullclient, mailhost.$m)
diff --git a/usr.sbin/sendmail/cf/cf/netbsd-proto.mc b/usr.sbin/sendmail/cf/cf/netbsd-proto.mc
new file mode 100644
index 00000000000..0a3d8496d36
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/netbsd-proto.mc
@@ -0,0 +1,50 @@
+divert(-1)
+#
+# Copyright (c) 1994 Adam Glass
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+#
+# This is the prototype file for a configuration that supports nothing
+# but basic SMTP connections via TCP.
+#
+# You may want to add an OSTYPE macro to get the location of various
+# support files for your operating system environment.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)netbsd-proto.mc $Revision: 1.1.1.1 $')
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+
diff --git a/usr.sbin/sendmail/cf/cf/pain.mc b/usr.sbin/sendmail/cf/cf/pain.mc
new file mode 100644
index 00000000000..f89e7c48240
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/pain.mc
@@ -0,0 +1,47 @@
+divert(-1)
+#
+# Copyright (c) 1993, 1994, 1995 Adam Glass
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)pain.mc $Revision: 1.1.1.1 $')
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`MAIL_HUB', mail.netbsd.org)
+define(`SMART_HOST', mail.netbsd.org)
+define(`confCHECKPOINT_INTERVAL', 10)dnl
+define(`confAUTO_REBUILD', True)dnl
+define(`confMESSAGE_TIMEOUT', 3d/4h)dnl
+Cwftp.netbsd.org
diff --git a/usr.sbin/sendmail/cf/cf/python.mc b/usr.sbin/sendmail/cf/cf/python.mc
new file mode 100644
index 00000000000..ac23e613138
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/python.mc
@@ -0,0 +1,52 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)python.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(bsd4.4)dnl
+DOMAIN(cs.exposed)dnl
+define(`LOCAL_RELAY', vangogh.CS.Berkeley.EDU)dnl
+define(`MASQUERADE_NAME', vangogh.CS.Berkeley.EDU)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+
+# accept mail sent to the domain head
+DDBostic.COM
+
+LOCAL_RULE_0
+# accept mail sent to the domain head
+R< @ $D . > : $* $@ $>7 $1 @here:... -> ...
+R$* $=O $* < @ $D . > $@ $>7 $1 $2 $3 ...@here -> ...
+R$* < @ $D . > $#local $: $1 user@here -> user
diff --git a/usr.sbin/sendmail/cf/cf/sun-lamp.mc b/usr.sbin/sendmail/cf/cf/sun-lamp.mc
new file mode 100644
index 00000000000..37286b01a2b
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sun-lamp.mc
@@ -0,0 +1,52 @@
+divert(-1)
+#
+# Copyright (c) 1993, 1994 Adam Glass
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sun-lamp.mc $Revision: 1.1.1.1 $')
+OSTYPE(bsd4.4)dnl
+MASQUERADE_AS(NetBSD.ORG)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`UUCP_RELAY', mailhost.Berkeley.EDU)dnl
+define(`BITNET_RELAY', mailhost.Berkeley.EDU)dnl
+define(`CSNET_RELAY', mailhost.Berkeley.EDU)dnl
+define(`confCHECKPOINT_INTERVAL', 10)dnl
+define(`confAUTO_REBUILD', True)dnl
+define(`confMESSAGE_TIMEOUT', 3d/4h)dnl
+Cw lamp.CS.Berkeley.EDU
+Cw mail.NetBSD.ORG
+Cw ftp.NetBSD.ORG
+Cw NetBSD.ORG
diff --git a/usr.sbin/sendmail/cf/cf/tcpproto.mc b/usr.sbin/sendmail/cf/cf/tcpproto.mc
new file mode 100644
index 00000000000..aa31ca152dc
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/tcpproto.mc
@@ -0,0 +1,50 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+#
+# This is the prototype file for a configuration that supports nothing
+# but basic SMTP connections via TCP.
+#
+# You may want to add an OSTYPE macro to get the location of various
+# support files for your operating system environment.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)tcpproto.mc 8.2 (Berkeley) 8/21/93')
+
+FEATURE(nouucp)
+
+MAILER(local)
+MAILER(smtp)
diff --git a/usr.sbin/sendmail/cf/cf/trinity.mc b/usr.sbin/sendmail/cf/cf/trinity.mc
new file mode 100644
index 00000000000..f27a86e7587
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/trinity.mc
@@ -0,0 +1,45 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`$Id: trinity.mc,v 1.1.1.1 1995/10/18 08:48:10 deraadt Exp $')
+OSTYPE(bsd4.4)dnl
+define(`UUCP_RELAY', life.ai.mit.edu)dnl
+define(`BITNET_RELAY', mitvma.mit.edu)dnl
+define(`LOCAL_RELAY', albert.gnu.ai.mit.edu)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`confCHECKPOINT_INTERVAL', 4)dnl
+define(`confAUTO_REBUILD', True)dnl
diff --git a/usr.sbin/sendmail/cf/cf/ucbarpa.mc b/usr.sbin/sendmail/cf/cf/ucbarpa.mc
new file mode 100644
index 00000000000..21f35fdaced
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/ucbarpa.mc
@@ -0,0 +1,43 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)ucbarpa.mc 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.exposed)dnl
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+MAILER(uucp)dnl
+SITECONFIG(uucp.ucbarpa, ucbarpa, U)
diff --git a/usr.sbin/sendmail/cf/cf/ucbvax.mc b/usr.sbin/sendmail/cf/cf/ucbvax.mc
new file mode 100644
index 00000000000..249368febaa
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/ucbvax.mc
@@ -0,0 +1,101 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)ucbvax.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(bsd4.4)
+DOMAIN(cs.hidden)
+FEATURE(notsticky)
+MAILER(local)
+MAILER(smtp)
+MAILER(uucp)
+undefine(`UUCP_RELAY')dnl
+DDBerkeley.EDU
+
+# names for which we act as a local forwarding agent
+CF CS
+FF/etc/sendmail.cw
+
+# local UUCP connections, and our local uucp name
+SITECONFIG(uucp.ucbvax, ucbvax, U)
+
+# remote UUCP connections, and the machine they are on
+SITECONFIG(uucp.ucbarpa, ucbarpa.Berkeley.EDU, W)
+
+SITECONFIG(uucp.cogsci, cogsci.Berkeley.EDU, X)
+
+LOCAL_RULE_3
+# map old UUCP names into Internet names
+UUCPSMTP(bellcore, bellcore.com)
+UUCPSMTP(decvax, decvax.dec.com)
+UUCPSMTP(decwrl, decwrl.dec.com)
+UUCPSMTP(hplabs, hplabs.hp.com)
+UUCPSMTP(lbl-csam, lbl-csam.arpa)
+UUCPSMTP(pur-ee, ecn.purdue.edu)
+UUCPSMTP(purdue, purdue.edu)
+UUCPSMTP(research, research.att.com)
+UUCPSMTP(sdcarl, sdcarl.ucsd.edu)
+UUCPSMTP(sdcsvax, sdcsvax.ucsd.edu)
+UUCPSMTP(ssyx, ssyx.ucsc.edu)
+UUCPSMTP(sun, sun.com)
+UUCPSMTP(ucdavis, ucdavis.ucdavis.edu)
+UUCPSMTP(ucivax, ics.uci.edu)
+UUCPSMTP(ucla-cs, cs.ucla.edu)
+UUCPSMTP(ucla-se, seas.ucla.edu)
+UUCPSMTP(ucsbcsl, ucsbcsl.ucsb.edu)
+UUCPSMTP(ucscc, c.ucsc.edu)
+UUCPSMTP(ucsd, ucsd.edu)
+UUCPSMTP(ucsfcgl, cgl.ucsf.edu)
+UUCPSMTP(unmvax, unmvax.cs.unm.edu)
+UUCPSMTP(uwvax, spool.cs.wisc.edu)
+
+LOCAL_RULE_0
+
+# make sure we handle the local domain as absolute
+R$* < @ $* $D > $* $: $1 < @ $2 $D . > $3
+
+# handle names we forward for as though they were local, so we will use UDB
+R< @ $=F . $D . > : $* $@ $>7 $2 @here:... -> ...
+R< @ $D . > : $* $@ $>7 $1 @here:... -> ...
+R$* $=O $* < @ $=F . $D . > $@ $>7 $1 $2 $3 ...@here -> ...
+R$* $=O $* < @ $D . > $@ $>7 $1 $2 $3 ...@here -> ...
+
+R$* < @ $=F . $D . > $#local $: $1 use UDB
+
+# handle local UUCP connections in the Berkeley.EDU domain
+R$+<@cnmat.$D . > $#uucp$@cnmat$:$1
+R$+<@cnmat.CS.$D . > $#uucp$@cnmat$:$1
+R$+<@craig.$D . > $#uucp$@craig$:$1
+R$+<@craig.CS.$D . > $#uucp$@craig$:$1
diff --git a/usr.sbin/sendmail/cf/cf/uucpproto.mc b/usr.sbin/sendmail/cf/cf/uucpproto.mc
new file mode 100644
index 00000000000..c460d76b3cd
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/uucpproto.mc
@@ -0,0 +1,49 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+#
+# This is the prototype for a configuration that only supports UUCP.
+#
+# You may want to add an OSTYPE macro to get the location of various
+# support files for your operating system environment.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)uucpproto.mc 8.3 (Berkeley) 8/21/93')
+
+FEATURE(nodns)dnl
+
+MAILER(local)dnl
+MAILER(uucp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/vangogh.mc b/usr.sbin/sendmail/cf/cf/vangogh.mc
new file mode 100644
index 00000000000..2406364c5a8
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/vangogh.mc
@@ -0,0 +1,44 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)vangogh.mc 8.2 (Berkeley) 1/26/94')
+DOMAIN(cs.exposed)dnl
+OSTYPE(bsd4.4)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`MCI_CACHE_SIZE', 5)
+Cw okeeffe.CS.Berkeley.EDU
+Cw python.CS.Berkeley.EDU
diff --git a/usr.sbin/sendmail/cf/domain/Berkeley.m4 b/usr.sbin/sendmail/cf/domain/Berkeley.m4
new file mode 100644
index 00000000000..4f572d6436a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/domain/Berkeley.m4
@@ -0,0 +1,42 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)Berkeley.m4 8.5 (Berkeley) 2/18/94')
+define(`UUCP_RELAY', `ucbvax.Berkeley.EDU')dnl
+define(`BITNET_RELAY', `CMSA.Berkeley.EDU')dnl
+define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward')dnl
+define(`confCW_FILE', `-o /etc/sendmail.cw')dnl
+FEATURE(redirect)dnl
+FEATURE(use_cw_file)dnl
diff --git a/usr.sbin/sendmail/cf/domain/cs.exposed.m4 b/usr.sbin/sendmail/cf/domain/cs.exposed.m4
new file mode 100644
index 00000000000..43c07becdb8
--- /dev/null
+++ b/usr.sbin/sendmail/cf/domain/cs.exposed.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)cs.exposed.m4 8.1 (Berkeley) 6/7/93')
+DOMAIN(Berkeley)dnl
+HACK(cssubdomain)dnl
+define(`confUSERDB_SPEC',
+ `/usr/sww/share/lib/users.cs.db,/usr/sww/share/lib/users.eecs.db')dnl
diff --git a/usr.sbin/sendmail/cf/domain/cs.hidden.m4 b/usr.sbin/sendmail/cf/domain/cs.hidden.m4
new file mode 100644
index 00000000000..3d9721af7a6
--- /dev/null
+++ b/usr.sbin/sendmail/cf/domain/cs.hidden.m4
@@ -0,0 +1,38 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)cs.hidden.m4 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.exposed)dnl
+MASQUERADE_AS(CS.Berkeley.EDU)dnl
diff --git a/usr.sbin/sendmail/cf/domain/eecs.hidden.m4 b/usr.sbin/sendmail/cf/domain/eecs.hidden.m4
new file mode 100644
index 00000000000..bbdc01afb1a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/domain/eecs.hidden.m4
@@ -0,0 +1,38 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)eecs.hidden.m4 8.1 (Berkeley) 6/7/93')
+DOMAIN(Berkeley)dnl
+MASQUERADE_AS(EECS.Berkeley.EDU)dnl
diff --git a/usr.sbin/sendmail/cf/domain/s2k.m4 b/usr.sbin/sendmail/cf/domain/s2k.m4
new file mode 100644
index 00000000000..25b931f5111
--- /dev/null
+++ b/usr.sbin/sendmail/cf/domain/s2k.m4
@@ -0,0 +1,38 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)s2k.m4 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.exposed)dnl
+MASQUERADE_AS(postgres.Berkeley.EDU)dnl
diff --git a/usr.sbin/sendmail/cf/feature/allmasquerade.m4 b/usr.sbin/sendmail/cf/feature/allmasquerade.m4
new file mode 100644
index 00000000000..c7cbffa78ea
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/allmasquerade.m4
@@ -0,0 +1,41 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)allmasquerade.m4 8.2 (Berkeley) 1/22/94')
+divert(-1)
+
+
+define(`_ALL_MASQUERADE_', 1)
diff --git a/usr.sbin/sendmail/cf/feature/always_add_domain.m4 b/usr.sbin/sendmail/cf/feature/always_add_domain.m4
new file mode 100644
index 00000000000..dd572c8130d
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/always_add_domain.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)always_add_domain.m4 8.1 (Berkeley) 6/7/93')
+divert(-1)
+
+define(`_ALWAYS_ADD_DOMAIN_', 1)
diff --git a/usr.sbin/sendmail/cf/feature/bitdomain.m4 b/usr.sbin/sendmail/cf/feature/bitdomain.m4
new file mode 100644
index 00000000000..85c8cf0017f
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/bitdomain.m4
@@ -0,0 +1,49 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)bitdomain.m4 8.6 (Berkeley) 2/19/94')
+divert(-1)
+
+
+PUSHDIVERT(6)
+Kbitdomain ifelse(_ARG_, `', `hash -o /etc/bitdomain', `_ARG_')
+POPDIVERT
+
+
+PUSHDIVERT(2)
+# handle BITNET mapping
+R$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3
+POPDIVERT
diff --git a/usr.sbin/sendmail/cf/feature/domaintable.m4 b/usr.sbin/sendmail/cf/feature/domaintable.m4
new file mode 100644
index 00000000000..bfad1bcecc4
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/domaintable.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)domaintable.m4 8.2 (Berkeley) 8/9/93')
+divert(-1)
+
+define(`DOMAIN_TABLE', ifelse(_ARG_, `', `hash -o /etc/domaintable', `_ARG_'))dnl
diff --git a/usr.sbin/sendmail/cf/feature/mailertable.m4 b/usr.sbin/sendmail/cf/feature/mailertable.m4
new file mode 100644
index 00000000000..fa399973bf7
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/mailertable.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)mailertable.m4 8.3 (Berkeley) 8/7/93')
+divert(-1)
+
+define(`MAILER_TABLE', ifelse(_ARG_, `', `hash -o /etc/mailertable', `_ARG_'))dnl
diff --git a/usr.sbin/sendmail/cf/feature/nocanonify.m4 b/usr.sbin/sendmail/cf/feature/nocanonify.m4
new file mode 100644
index 00000000000..0157e6b9e48
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/nocanonify.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)nocanonify.m4 8.1 (Berkeley) 6/7/93')
+divert(-1)
+
+define(`_NO_CANONIFY_', 1)
diff --git a/usr.sbin/sendmail/cf/feature/nodns.m4 b/usr.sbin/sendmail/cf/feature/nodns.m4
new file mode 100644
index 00000000000..465a5ae4653
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/nodns.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)nodns.m4 8.1 (Berkeley) 8/6/93')
+divert(-1)
+
+undefine(`confBIND_OPTS')dnl
diff --git a/usr.sbin/sendmail/cf/feature/notsticky.m4 b/usr.sbin/sendmail/cf/feature/notsticky.m4
new file mode 100644
index 00000000000..51189236717
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/notsticky.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)notsticky.m4 8.1 (Berkeley) 6/7/93')
+divert(-1)
+
+define(`_LOCAL_NOT_STICKY_', 1)
diff --git a/usr.sbin/sendmail/cf/feature/nouucp.m4 b/usr.sbin/sendmail/cf/feature/nouucp.m4
new file mode 100644
index 00000000000..8723437b3c7
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/nouucp.m4
@@ -0,0 +1,40 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)nouucp.m4 8.1 (Berkeley) 6/7/93')
+divert(-1)
+
+define(`_NO_UUCP_', 1)
diff --git a/usr.sbin/sendmail/cf/feature/nullclient.m4 b/usr.sbin/sendmail/cf/feature/nullclient.m4
new file mode 100644
index 00000000000..930f265c4b8
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/nullclient.m4
@@ -0,0 +1,61 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+ifdef(`SMTP_MAILER_FLAGS',,
+ `define(`SMTP_MAILER_FLAGS',
+ `ifdef(`_OLD_SENDMAIL_', `L', `')')')
+define(_NULL_CLIENT_ONLY_, `1')
+ifelse(_ARG_, `', `errprint(`Feature "nullclient" requires argument')',
+ `define(`MAIL_HUB', _ARG_)')
+POPDIVERT
+
+#
+# This is used only for relaying mail from a client to a hub when
+# that client does absolutely nothing else -- i.e., it is a "null
+# mailer". In this sense, it acts like the "R" option in Sun
+# sendmail.
+#
+
+VERSIONID(`@(#)nullclient.m4 8.2 (Berkeley) 8/21/93')
+
+PUSHDIVERT(7)
+############################################
+### Null Client Mailer specification ###
+############################################
+
+ifdef(`confRELAY_MAILER',,
+ `define(`confRELAY_MAILER', `nullclient')')dnl
+
+Mnullclient, P=[IPC], F=CONCAT(mDFMuXa, SMTP_MAILER_FLAGS), A=IPC $h
+POPDIVERT
diff --git a/usr.sbin/sendmail/cf/feature/redirect.m4 b/usr.sbin/sendmail/cf/feature/redirect.m4
new file mode 100644
index 00000000000..0f2199c9755
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/redirect.m4
@@ -0,0 +1,48 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)redirect.m4 8.2 (Berkeley) 12/27/93')
+divert(-1)
+
+
+PUSHDIVERT(3)
+# addresses sent to foo@host.REDIRECT will give a 551 error code
+R$* < @ $+ .REDIRECT. > $# error $@ NOUSER $: "551 User not local; please try " <$1@$2>
+POPDIVERT
+
+PUSHDIVERT(6)
+CPREDIRECT
+POPDIVERT
diff --git a/usr.sbin/sendmail/cf/feature/use_cw_file.m4 b/usr.sbin/sendmail/cf/feature/use_cw_file.m4
new file mode 100644
index 00000000000..33b5ad56ed0
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/use_cw_file.m4
@@ -0,0 +1,46 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)use_cw_file.m4 8.1 (Berkeley) 6/7/93')
+divert(-1)
+
+# if defined, the sendmail.cf will read the /etc/sendmail.cw file
+# to find alternate names for this host. Typically only used when
+# several hosts have been squashed into one another at high speed.
+
+define(`USE_CW_FILE', `')
+
+divert(0)
diff --git a/usr.sbin/sendmail/cf/feature/uucpdomain.m4 b/usr.sbin/sendmail/cf/feature/uucpdomain.m4
new file mode 100644
index 00000000000..77cc97bbe4a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/feature/uucpdomain.m4
@@ -0,0 +1,49 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+divert(0)
+VERSIONID(`@(#)uucpdomain.m4 8.6 (Berkeley) 2/19/94')
+divert(-1)
+
+
+PUSHDIVERT(6)
+Kuudomain ifelse(_ARG_, `', `hash -o /etc/uudomain', `_ARG_')
+POPDIVERT
+
+
+PUSHDIVERT(2)
+# handle UUCP mapping
+R$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3
+POPDIVERT
diff --git a/usr.sbin/sendmail/cf/hack/cssubdomain.m4 b/usr.sbin/sendmail/cf/hack/cssubdomain.m4
new file mode 100644
index 00000000000..4f270c05f06
--- /dev/null
+++ b/usr.sbin/sendmail/cf/hack/cssubdomain.m4
@@ -0,0 +1,44 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+VERSIONID(`@(#)cssubdomain.m4 8.1 (Berkeley) 6/7/93')
+
+divert(2)
+# find possible (old & new) versions of our name via short circuit hack
+# (this code should exist ONLY during the transition from .Berkeley.EDU
+# names to .CS.Berkeley.EDU names -- probably not more than a few months)
+R$* < @ $=w .CS.Berkeley.EDU > $* $: $1 < @ $j > $3
+R$* < @ $=w .Berkeley.EDU> $* $: $1 < @ $j > $3
+divert(0)
diff --git a/usr.sbin/sendmail/cf/m4/cf.m4 b/usr.sbin/sendmail/cf/m4/cf.m4
new file mode 100644
index 00000000000..528cbfffef9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/m4/cf.m4
@@ -0,0 +1,149 @@
+divert(0)dnl
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+
+######################################################################
+######################################################################
+#####
+##### SENDMAIL CONFIGURATION FILE
+#####
+define(`TEMPFILE', maketemp(/tmp/cfXXXXXX))dnl
+syscmd(sh ../sh/makeinfo.sh > TEMPFILE)dnl
+include(TEMPFILE)dnl
+syscmd(rm -f TEMPFILE)dnl
+#####
+######################################################################
+######################################################################
+
+divert(-1)
+
+changecom()
+undefine(`format')
+undefine(`hpux')
+ifdef(`pushdef', `',
+ `errprint(`You need a newer version of M4, at least as new as
+System V or GNU')
+ include(NoSuchFile)')
+define(`PUSHDIVERT', `pushdef(`__D__', divnum)divert($1)')
+define(`POPDIVERT', `divert(__D__)popdef(`__D__')')
+define(`OSTYPE', `PUSHDIVERT(-1)define(`_ARG_', $2)include(../ostype/$1.m4)POPDIVERT`'')
+define(`MAILER',
+`ifdef(`_MAILER_$1_', `dnl`'',
+`define(`_MAILER_$1_', `')PUSHDIVERT(7)include(../mailer/$1.m4)POPDIVERT`'')')
+define(`DOMAIN', `PUSHDIVERT(-1)define(`_ARG_', $2)include(../domain/$1.m4)POPDIVERT`'')
+define(`FEATURE', `PUSHDIVERT(-1)define(`_ARG_', $2)include(../feature/$1.m4)POPDIVERT`'')
+define(`HACK', `PUSHDIVERT(-1)define(`_ARG_', $2)include(../hack/$1.m4)POPDIVERT`'')
+define(`OLDSENDMAIL', `define(`_OLD_SENDMAIL_', `')')
+define(`VERSIONID', ``##### $1 #####'')
+define(`LOCAL_RULE_0', `divert(3)')
+define(`LOCAL_RULE_1',
+`divert(9)dnl
+#######################################
+### Ruleset 1 -- Sender Rewriting ###
+#######################################
+
+S1
+')
+define(`LOCAL_RULE_2',
+`divert(9)dnl
+##########################################
+### Ruleset 2 -- Recipient Rewriting ###
+##########################################
+
+S2
+')
+define(`LOCAL_RULE_3', `divert(2)')
+define(`LOCAL_CONFIG', `divert(6)')
+define(`LOCAL_NET_CONFIG', `define(`_LOCAL_RULES_', 1)divert(1)')
+define(`UUCPSMTP', `R DOL(*) < @ $1 .UUCP > DOL(*) DOL(1) < @ $2 > DOL(2)')
+define(`CONCAT', `$1$2$3$4$5$6$7')
+define(`DOL', ``$'$1')
+define(`SITECONFIG',
+`CONCAT(D, $3, $2)
+define(`_CLASS_$3_', `')dnl
+ifelse($3, U, Cw$2 $2.UUCP, `dnl')
+define(`SITE', `ifelse(CONCAT($'2`, $3), SU,
+ CONCAT(CY, $'1`),
+ CONCAT(C, $3, $'1`))')
+sinclude(../siteconfig/$1.m4)')
+define(`EXPOSED_USER', `PUSHDIVERT(5)CE$1
+POPDIVERT`'dnl')
+define(`LOCAL_USER', `PUSHDIVERT(5)CL$1
+POPDIVERT`'dnl')
+define(`MASQUERADE_AS', `define(`MASQUERADE_NAME', $1)')
+
+m4wrap(`include(`../m4/proto.m4')')
+
+# set up default values for options
+define(`confMAILER_NAME', ``MAILER-DAEMON'')
+define(`confFROM_LINE', `From $g $d')
+define(`confOPERATORS', `.:%@!^/[]')
+define(`confSMTP_LOGIN_MSG', `$j Sendmail $v/$Z ready at $b')
+define(`confSEVEN_BIT_INPUT', `False')
+define(`confALIAS_WAIT', `10')
+define(`confMIN_FREE_BLOCKS', `4')
+define(`confBLANK_SUB', `.')
+define(`confCON_EXPENSIVE', `False')
+define(`confCHECKPOINT_INTERVAL', `10')
+define(`confDELIVERY_MODE', `background')
+define(`confAUTO_REBUILD', `False')
+define(`confSAVE_FROM_LINES', `False')
+define(`confTEMP_FILE_MODE', `0600')
+define(`confMATCH_GECOS', `False')
+define(`confDEF_GROUP_ID', `1')
+define(`confMAX_HOP', `17')
+define(`confIGNORE_DOTS', `False')
+define(`confBIND_OPTS', `')
+define(`confMCI_CACHE_SIZE', `2')
+define(`confMCI_CACHE_TIMEOUT', `5m')
+define(`confUSE_ERRORS_TO', `False')
+define(`confLOG_LEVEL', `9')
+define(`confME_TOO', `False')
+define(`confCHECK_ALIASES', `True')
+define(`confOLD_STYLE_HEADERS', `True')
+define(`confPRIVACY_FLAGS', `authwarnings')
+define(`confSAFE_QUEUE', `True')
+define(`confMESSAGE_TIMEOUT', `5d/4h')
+define(`confTIME_ZONE', `USE_SYSTEM')
+define(`confDEF_USER_ID', `1')
+define(`confQUEUE_LA', `8')
+define(`confREFUSE_LA', `12')
+define(`confSEPARATE_PROC', `False')
+define(`confCW_FILE', `/etc/sendmail.cw')
+define(`confMIME_FORMAT_ERRORS', `True')
+define(`confTRY_NULL_MX_LIST', `False')
+
+divert(0)dnl
+VERSIONID(`@(#)cf.m4 8.4 (Berkeley) 12/24/93')
diff --git a/usr.sbin/sendmail/cf/m4/nullrelay.m4 b/usr.sbin/sendmail/cf/m4/nullrelay.m4
new file mode 100644
index 00000000000..c79d1797f47
--- /dev/null
+++ b/usr.sbin/sendmail/cf/m4/nullrelay.m4
@@ -0,0 +1,302 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+
+VERSIONID(`@(#)nullrelay.m4 8.5 (Berkeley) 2/1/94')
+
+#
+# This configuration applies only to relay-only hosts. They send
+# all mail to a hub without consideration of the address syntax
+# or semantics, except for adding the hub qualification to the
+# addresses.
+#
+# This is based on a prototype done by Bryan Costales of ICSI.
+#
+
+# hub host (to which all mail is sent)
+DH`'ifdef(`MAIL_HUB', MAIL_HUB,
+ `errprint(`MAIL_HUB not defined for nullclient feature')')
+
+# name from which everyone will appear to come
+DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME, MAIL_HUB)
+
+# route-addr separators
+C: : ,
+
+undivert(6)dnl
+
+######################
+# Special macros #
+######################
+
+# SMTP initial login message
+De`'confSMTP_LOGIN_MSG
+
+# UNIX initial From header format
+Dl`'confFROM_LINE
+
+# my name for error messages
+Dn`'confMAILER_NAME
+
+# delimiter (operator) characters
+Do`'confOPERATORS
+
+# format of a total name
+Dq<$g>
+include(`../m4/version.m4')
+
+###############
+# Options #
+###############
+
+# strip message body to 7 bits on input?
+O7`'confSEVEN_BIT_INPUT
+
+# no aliases here
+
+# substitution for space (blank) characters
+OB`'confBLANK_SUB
+
+# default delivery mode
+Od`'confDELIVERY_MODE
+
+# error message header/file
+ifdef(`confERROR_MESSAGE',
+ OE`'confERROR_MESSAGE,
+ #OE/etc/sendmail.oE)
+
+# error mode
+ifdef(`confERROR_MODE',
+ Oe`'confERROR_MODE,
+ #Oep)
+
+# save Unix-style "From_" lines at top of header?
+Of`'confSAVE_FROM_LINES
+
+# temporary file mode
+OF`'confTEMP_FILE_MODE
+
+# default GID
+Og`'confDEF_GROUP_ID
+
+# maximum hop count
+Oh`'confMAX_HOP
+
+# location of help file
+OH`'ifdef(`HELP_FILE', HELP_FILE, /usr/lib/sendmail.hf)
+
+# ignore dots as terminators in incoming messages?
+Oi`'confIGNORE_DOTS
+
+# Insist that the BIND name server be running to resolve names
+ifdef(`confBIND_OPTS',
+ OI`'confBIND_OPTS,
+ #OI)
+
+# deliver MIME-encapsulated error messages?
+Oj`'confMIME_FORMAT_ERRORS
+
+# open connection cache size
+Ok`'confMCI_CACHE_SIZE
+
+# open connection cache timeout
+OK`'confMCI_CACHE_TIMEOUT
+
+# use Errors-To: header?
+Ol`'confUSE_ERRORS_TO
+
+# log level
+OL`'confLOG_LEVEL
+
+# send to me too, even in an alias expansion?
+Om`'confME_TOO
+
+# default messages to old style headers if no special punctuation?
+Oo`'confOLD_STYLE_HEADERS
+
+# SMTP daemon options
+ifdef(`confDAEMON_OPTIONS',
+ OO`'confDAEMON_OPTIONS,
+ #OOPort=esmtp)
+
+# privacy flags
+Op`'confPRIVACY_FLAGS
+
+# who (if anyone) should get extra copies of error messages
+ifdef(`confCOPY_ERRORS_TO',
+ OP`'confCOPY_ERRORS_TO,
+ #OPPostmaster)
+
+# slope of queue-only function
+ifdef(`confQUEUE_FACTOR',
+ Oq`'confQUEUE_FACTOR,
+ #Oq600000)
+
+# queue directory
+OQ`'ifdef(`QUEUE_DIR', QUEUE_DIR, /var/spool/mqueue)
+
+# read timeout -- now OK per RFC 1123 section 5.3.2
+ifdef(`confREAD_TIMEOUT',
+ Or`'confREAD_TIMEOUT,
+ #Ordatablock=10m)
+
+# queue up everything before forking?
+Os`'confSAFE_QUEUE
+
+# status file
+OS`'ifdef(`STATUS_FILE', STATUS_FILE, /etc/sendmail.st)
+
+# default message timeout interval
+OT`'confMESSAGE_TIMEOUT
+
+# time zone handling:
+# if undefined, use system default
+# if defined but null, use TZ envariable passed in
+# if defined and non-null, use that info
+ifelse(confTIME_ZONE, `USE_SYSTEM', `#Ot',
+ confTIME_ZONE, `USE_TZ', `Ot',
+ `Ot`'confTIME_ZONE')
+
+# default UID
+Ou`'confDEF_USER_ID
+
+# deliver each queued job in a separate process?
+OY`'confSEPARATE_PROC
+
+# work class factor
+ifdef(`confWORK_CLASS_FACTOR',
+ Oz`'confWORK_CLASS_FACTOR,
+ #Oz1800)
+
+# work time factor
+ifdef(`confWORK_TIME_FACTOR',
+ OZ`'confWORK_TIME_FACTOR,
+ #OZ90000)
+
+###########################
+# Message precedences #
+###########################
+
+Pfirst-class=0
+Pspecial-delivery=100
+Plist=-30
+Pbulk=-60
+Pjunk=-100
+
+#####################
+# Trusted users #
+#####################
+
+Troot
+Tdaemon
+Tuucp
+
+#########################
+# Format of headers #
+#########################
+
+H?P?Return-Path: $g
+HReceived: $?sfrom $s $.$?_($_) $.by $j ($v/$Z)$?r with $r$. id $i$?u for $u$.; $b
+H?D?Resent-Date: $a
+H?D?Date: $a
+H?F?Resent-From: $q
+H?F?From: $q
+H?x?Full-Name: $x
+HSubject:
+# HPosted-Date: $a
+# H?l?Received-Date: $b
+H?M?Resent-Message-Id: <$t.$i@$j>
+H?M?Message-Id: <$t.$i@$j>
+#
+######################################################################
+######################################################################
+#####
+##### REWRITING RULES
+#####
+######################################################################
+######################################################################
+
+###########################################
+### Rulset 3 -- Name Canonicalization ###
+###########################################
+S3
+
+# handle null input and list syntax (translate to <@> special case)
+R$@ $@ <@>
+R$*:;$* $@ $1 :; <@>
+
+# basic textual canonicalization -- note RFC733 heuristic here
+R$*<$*>$*<$*>$* $2$3<$4>$5 strip multiple <> <>
+R$*<$*<$+>$*>$* <$3>$5 2-level <> nesting
+R$*<>$* $@ <@> MAIL FROM:<> case
+R$*<$+>$* $2 basic RFC821/822 parsing
+
+ifdef(`_NO_CANONIFY_', `dnl',
+`# eliminate local host if present
+R@ $=w $=: $+ $@ @ $M $2 $3 @thishost ...
+R@ $+ $@ @ $1 @somewhere ...
+
+R$+ @ $=w $@ $1 @ $M ...@thishost
+R$+ @ $+ $@ $1 @ $2 ...@somewhere
+
+R$=w ! $+ $@ $2 @ $M thishost!...
+R$+ ! $+ $@ $1 ! $2 @ $M somewhere ! ...
+
+R$+ % $=w $@ $1 @ $M ...%thishost
+R$+ % $+ $@ $1 @ $2 ...%somewhere
+
+R$+ $@ $1 @ $M unadorned user')
+
+
+######################################
+### Ruleset 0 -- Parse Address ###
+######################################
+
+S0
+
+R$*:;<@> $#error $@ USAGE $: "list:; syntax illegal for recipient addresses"
+
+# pass everything else to a relay host
+R$* $#_RELAY_ $@ $H $: $1
+
+#
+######################################################################
+######################################################################
+#####
+`##### MAILER DEFINITIONS'
+#####
+######################################################################
+######################################################################
+undivert(7)dnl
diff --git a/usr.sbin/sendmail/cf/m4/proto.m4 b/usr.sbin/sendmail/cf/m4/proto.m4
new file mode 100644
index 00000000000..284572988f9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/m4/proto.m4
@@ -0,0 +1,689 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+divert(0)
+
+VERSIONID(`@(#)proto.m4 8.45 (Berkeley) 3/4/94')
+
+MAILER(local)dnl
+
+ifdef(`_OLD_SENDMAIL_',
+`define(`_SET_95_', 5)dnl
+define(`_SET_96_', 6)dnl
+define(`_SET_97_', 7)dnl
+define(`_SET_98_', 8)dnl
+define(`confDOMAIN_NAME',
+ `ifdef(`NEED_DOMAIN', `$w.$d', `$w')')dnl',
+`# level 5 config file format
+V5
+define(`_SET_95_', 95)dnl
+define(`_SET_96_', 96)dnl
+define(`_SET_97_', 97)dnl
+define(`_SET_98_', 98)dnl')
+ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `smtp')')dnl
+ifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')dnl
+ifdef(`confRELAY_MAILER',,
+ `define(`confRELAY_MAILER',
+ `ifdef(`_MAILER_smtp_', `relay',
+ `ifdef(`_MAILER_uucp', `suucp', `unknown')')')')dnl
+define(`_SMTP_', `confSMTP_MAILER')dnl for readability only
+define(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only
+define(`_RELAY_', `confRELAY_MAILER')dnl for readability only
+
+##################
+# local info #
+##################
+
+Cwlocalhost
+ifdef(`USE_CW_FILE',
+`# file containing names of hosts for which we receive email
+Fw`'confCW_FILE',
+ `dnl')
+ifdef(`confDOMAIN_NAME', `
+# my official domain name
+Dj`'confDOMAIN_NAME',
+ `dnl')
+
+ifdef(`_NULL_CLIENT_ONLY_',
+`include(../m4/nullrelay.m4)m4exit',
+ `dnl')
+
+CP.
+
+ifdef(`UUCP_RELAY',
+`# UUCP relay host
+DY`'UUCP_RELAY
+CPUUCP
+
+')dnl
+ifdef(`BITNET_RELAY',
+`# BITNET relay host
+DB`'BITNET_RELAY
+CPBITNET
+
+')dnl
+ifdef(`FAX_RELAY',
+`# FAX relay host
+DF`'FAX_RELAY
+CPFAX
+
+')dnl
+# "Smart" relay host (may be null)
+DS`'ifdef(`SMART_HOST', SMART_HOST)
+
+ifdef(`MAILER_TABLE',
+`# Mailer table (overriding domains)
+Kmailertable MAILER_TABLE
+
+')dnl
+ifdef(`DOMAIN_TABLE',
+`# Domain table (adding domains)
+Kdomaintable DOMAIN_TABLE
+
+')dnl
+# who I send unqualified names to (null means deliver locally)
+DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
+
+# who gets all local email traffic ($R has precedence for unqualified names)
+DH`'ifdef(`MAIL_HUB', MAIL_HUB)
+
+# who I masquerade as (null for no masquerading)
+DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
+
+# class L: names that should be delivered locally, even if we have a relay
+# class E: names that should be exposed as from this host, even if we masquerade
+#CLroot
+CEroot
+undivert(5)dnl
+
+# operators that cannot be in local usernames (i.e., network indicators)
+CO @ % ifdef(`_NO_UUCP_', `', `!')
+
+# a class with just dot (for identifying canonical names)
+C..
+
+ifdef(`_OLD_SENDMAIL_', `dnl',
+`# dequoting map
+Kdequote dequote')
+
+undivert(6)dnl
+
+######################
+# Special macros #
+######################
+
+# SMTP initial login message
+De`'confSMTP_LOGIN_MSG
+
+# UNIX initial From header format
+Dl`'confFROM_LINE
+
+# my name for error messages
+Dn`'confMAILER_NAME
+
+# delimiter (operator) characters
+Do`'confOPERATORS
+
+# format of a total name
+Dq`'ifdef(`confFROM_HEADER', confFROM_HEADER,
+ ifdef(`_OLD_SENDMAIL_', `$g$?x ($x)$.', `$?x$x <$g>$|$g$.'))
+include(`../m4/version.m4')
+
+###############
+# Options #
+###############
+
+# strip message body to 7 bits on input?
+O7`'confSEVEN_BIT_INPUT
+
+# wait (in minutes) for alias file rebuild
+Oa`'confALIAS_WAIT
+
+# location of alias file
+OA`'ifdef(`ALIAS_FILE', `ALIAS_FILE', /etc/aliases)
+
+# minimum number of free blocks on filesystem
+Ob`'confMIN_FREE_BLOCKS
+
+# substitution for space (blank) characters
+OB`'confBLANK_SUB
+
+# avoid connecting to "expensive" mailers on initial submission?
+Oc`'confCON_EXPENSIVE
+
+# checkpoint queue runs after every N successful deliveries
+OC`'confCHECKPOINT_INTERVAL
+
+# default delivery mode
+Od`'confDELIVERY_MODE
+
+# automatically rebuild the alias database?
+OD`'confAUTO_REBUILD
+
+# error message header/file
+ifdef(`confERROR_MESSAGE',
+ OE`'confERROR_MESSAGE,
+ #OE/etc/sendmail.oE)
+
+# error mode
+ifdef(`confERROR_MODE',
+ Oe`'confERROR_MODE,
+ #Oep)
+
+# save Unix-style "From_" lines at top of header?
+Of`'confSAVE_FROM_LINES
+
+# temporary file mode
+OF`'confTEMP_FILE_MODE
+
+# match recipients against GECOS field?
+OG`'confMATCH_GECOS
+
+# default GID
+Og`'confDEF_GROUP_ID
+
+# maximum hop count
+Oh`'confMAX_HOP
+
+# location of help file
+OH`'ifdef(`HELP_FILE', HELP_FILE, /usr/lib/sendmail.hf)
+
+# ignore dots as terminators in incoming messages?
+Oi`'confIGNORE_DOTS
+
+# Insist that the BIND name server be running to resolve names
+ifdef(`confBIND_OPTS',
+ OI`'confBIND_OPTS,
+ #OI)
+
+# deliver MIME-encapsulated error messages?
+Oj`'confMIME_FORMAT_ERRORS
+
+# Forward file search path
+ifdef(`confFORWARD_PATH',
+ OJ`'confFORWARD_PATH,
+ #OJ/var/forward/$u:$z/.forward.$w:$z/.forward)
+
+# open connection cache size
+Ok`'confMCI_CACHE_SIZE
+
+# open connection cache timeout
+OK`'confMCI_CACHE_TIMEOUT
+
+# use Errors-To: header?
+Ol`'confUSE_ERRORS_TO
+
+# log level
+OL`'confLOG_LEVEL
+
+# send to me too, even in an alias expansion?
+Om`'confME_TOO
+
+# verify RHS in newaliases?
+On`'confCHECK_ALIASES
+
+# default messages to old style headers if no special punctuation?
+Oo`'confOLD_STYLE_HEADERS
+
+# SMTP daemon options
+ifdef(`confDAEMON_OPTIONS',
+ OO`'confDAEMON_OPTIONS,
+ #OOPort=esmtp)
+
+# privacy flags
+Op`'confPRIVACY_FLAGS
+
+# who (if anyone) should get extra copies of error messages
+ifdef(`confCOPY_ERRORS_TO',
+ OP`'confCOPY_ERRORS_TO,
+ #OPPostmaster)
+
+# slope of queue-only function
+ifdef(`confQUEUE_FACTOR',
+ Oq`'confQUEUE_FACTOR,
+ #Oq600000)
+
+# queue directory
+OQ`'ifdef(`QUEUE_DIR', QUEUE_DIR, /var/spool/mqueue)
+
+# read timeout -- now OK per RFC 1123 section 5.3.2
+ifdef(`confREAD_TIMEOUT',
+ Or`'confREAD_TIMEOUT,
+ #Ordatablock=10m)
+
+# queue up everything before forking?
+Os`'confSAFE_QUEUE
+
+# status file
+OS`'ifdef(`STATUS_FILE', STATUS_FILE, /etc/sendmail.st)
+
+# default message timeout interval
+OT`'confMESSAGE_TIMEOUT
+
+# time zone handling:
+# if undefined, use system default
+# if defined but null, use TZ envariable passed in
+# if defined and non-null, use that info
+ifelse(confTIME_ZONE, `USE_SYSTEM', `#Ot',
+ confTIME_ZONE, `USE_TZ', `Ot',
+ `Ot`'confTIME_ZONE')
+
+# default UID
+Ou`'confDEF_USER_ID
+
+# list of locations of user database file (null means no lookup)
+OU`'ifdef(`confUSERDB_SPEC', `confUSERDB_SPEC')
+
+# fallback MX host
+ifdef(`confFALLBACK_MX',
+ OV`'confFALLBACK_MX,
+ #OVfall.back.host.net)
+
+# if we are the best MX host for a site, try it directly instead of config err
+Ow`'confTRY_NULL_MX_LIST
+
+# load average at which we just queue messages
+Ox`'confQUEUE_LA
+
+# load average at which we refuse connections
+OX`'confREFUSE_LA
+
+# work recipient factor
+ifdef(`confWORK_RECIPIENT_FACTOR',
+ Oy`'confWORK_RECIPIENT_FACTOR,
+ #Oy30000)
+
+# deliver each queued job in a separate process?
+OY`'confSEPARATE_PROC
+
+# work class factor
+ifdef(`confWORK_CLASS_FACTOR',
+ Oz`'confWORK_CLASS_FACTOR,
+ #Oz1800)
+
+# work time factor
+ifdef(`confWORK_TIME_FACTOR',
+ OZ`'confWORK_TIME_FACTOR,
+ #OZ90000)
+
+###########################
+# Message precedences #
+###########################
+
+Pfirst-class=0
+Pspecial-delivery=100
+Plist=-30
+Pbulk=-60
+Pjunk=-100
+
+#####################
+# Trusted users #
+#####################
+
+Troot
+Tdaemon
+Tuucp
+
+#########################
+# Format of headers #
+#########################
+
+H?P?Return-Path: $g
+HReceived: $?sfrom $s $.$?_($?s$|from $.$_) $.by $j ($v/$Z)$?r with $r$. id $i$?u for $u$.; $b
+H?D?Resent-Date: $a
+H?D?Date: $a
+H?F?Resent-From: $q
+H?F?From: $q
+H?x?Full-Name: $x
+HSubject:
+# HPosted-Date: $a
+# H?l?Received-Date: $b
+H?M?Resent-Message-Id: <$t.$i@$j>
+H?M?Message-Id: <$t.$i@$j>
+#
+######################################################################
+######################################################################
+#####
+##### REWRITING RULES
+#####
+######################################################################
+######################################################################
+
+undivert(9)dnl
+
+###########################################
+### Rulset 3 -- Name Canonicalization ###
+###########################################
+S3
+
+# handle null input (translate to <@> special case)
+R$@ $@ <@>
+
+# basic textual canonicalization -- note RFC733 heuristic here
+R$*<$*>$*<$*>$* $2$3<$4>$5 strip multiple <> <>
+R$*<$*<$+>$*>$* <$3>$5 2-level <> nesting
+R$*<>$* $@ <@> MAIL FROM:<> case
+R$*<$+>$* $2 basic RFC821/822 parsing
+
+# handle list:; syntax as special case
+R$*:;$* $@ $1 :; <@>
+
+# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
+R@ $+ , $+ @ $1 : $2 change all "," to ":"
+
+# localize and dispose of route-based addresses
+R@ $+ : $+ $@ $>_SET_96_ < @$1 > : $2 handle <route-addr>
+
+# find focus for list syntax
+R $+ : $* ; @ $+ $@ $>_SET_96_ $1 : $2 ; < @ $3 > list syntax
+R $+ : $* ; $@ $1 : $2; list syntax
+
+# find focus for @ syntax addresses
+R$+ @ $+ $: $1 < @ $2 > focus on domain
+R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right
+R$+ < @ $+ > $@ $>_SET_96_ $1 < @ $2 > already canonical
+
+# do some sanity checking
+R$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs
+
+ifdef(`_NO_UUCP_', `dnl',
+`# convert old-style addresses to a domain-based address
+R$- ! $+ $@ $>_SET_96_ $2 < @ $1 .UUCP > resolve uucp names
+R$+ . $- ! $+ $@ $>_SET_96_ $3 < @ $1 . $2 > domain uucps
+R$+ ! $+ $@ $>_SET_96_ $2 < @ $1 .UUCP > uucp subdomains')
+
+# if we have % signs, take the rightmost one
+R$* % $* $1 @ $2 First make them all @s.
+R$* @ $* @ $* $1 % $2 @ $3 Undo all but the last.
+R$* @ $* $@ $>_SET_96_ $1 < @ $2 > Insert < > and finish
+
+# else we must be a local name
+
+
+################################################
+### Ruleset _SET_96_ -- bottom half of ruleset 3 ###
+################################################
+
+# At this point, everything should be in a "local_part<@domain>extra" format.
+S`'_SET_96_
+
+# handle special cases for local names
+R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all
+R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain
+ifdef(`_NO_UUCP_', `dnl',
+`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain')
+R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d]
+R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal
+R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr
+ifdef(`DOMAIN_TABLE', `
+# look up unqualified domains in the domain table
+R$* < @ $- > $* $: $1 < @ $(domaintable $2 $) > $3',
+`dnl')
+undivert(2)dnl
+
+ifdef(`_NO_UUCP_', `dnl',
+`ifdef(`UUCP_RELAY',
+`# pass UUCP addresses straight through
+R$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3',
+`# if really UUCP, handle it immediately
+ifdef(`_CLASS_U_',
+`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
+ifdef(`_CLASS_V_',
+`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
+ifdef(`_CLASS_W_',
+`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
+ifdef(`_CLASS_X_',
+`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
+ifdef(`_CLASS_Y_',
+`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
+
+# try UUCP traffic as a local address
+R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3
+ifdef(`_OLD_SENDMAIL_',
+`R$* < @ $+ . $+ . UUCP . > $* $@ $1 < @ $2 . $3 . > $4',
+`R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3')')
+')
+ifdef(`_NO_CANONIFY_', `dnl',
+`# pass to name server to make hostname canonical
+R$* < @ $* $~P > $* $: $1 < @ $[ $2 $3 $] > $4')
+
+# local host aliases and pseudo-domains are always canonical
+R$* < @ $=w > $* $: $1 < @ $2 . > $3
+R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4
+R$* < @ $* . . > $* $1 < @ $2 . > $3
+
+# if this is the local hostname, make sure we treat is as canonical
+R$* < @ $j > $* $: $1 < @ $j . > $2
+
+
+##################################################
+### Ruleset 4 -- Final Output Post-rewriting ###
+##################################################
+S4
+
+R$*<@> $@ $1 handle <> and list:;
+
+# strip trailing dot off possibly canonical name
+R$* < @ $+ . > $* $1 < @ $2 > $3
+
+# externalize local domain info
+R$* < $+ > $* $1 $2 $3 defocus
+R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical
+R@ $* $@ @ $1 ... and exit
+
+ifdef(`_NO_UUCP_', `dnl',
+`# UUCP must always be presented in old form
+R$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u')
+
+# delete duplicate local names
+R$+ % $=w @ $=w $1 @ $j u%host@host => u@host
+
+
+
+##############################################################
+### Ruleset _SET_97_ -- recanonicalize and call ruleset zero ###
+### (used for recursive calls) ###
+##############################################################
+
+S`'_SET_97_
+R$* $: $>3 $1
+R$* $@ $>0 $1
+
+
+######################################
+### Ruleset 0 -- Parse Address ###
+######################################
+
+S0
+
+R<@> $#_LOCAL_ $: <> special case error msgs
+R$* : $* ; $#error $@ USAGE $: "list:; syntax illegal for recipient addresses"
+R<@ $+> $#error $@ USAGE $: "user address required"
+R<$* : $* > $#error $@ USAGE $: "colon illegal in host name part"
+
+ifdef(`_MAILER_smtp_',
+`# handle numeric address spec
+R$* < @ [ $+ ] > $* $: $>_SET_98_ $1 < @ [ $2 ] > $3 numeric internet spec
+R$* < @ [ $+ ] > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 still numeric: send',
+ `dnl')
+
+# now delete the local info -- note $=O to find characters that cause forwarding
+R$* < @ > $* $@ $>_SET_97_ $1 user@ => user
+R< @ $=w . > : $* $@ $>_SET_97_ $2 @here:... -> ...
+R$* $=O $* < @ $=w . > $@ $>_SET_97_ $1 $2 $3 ...@here -> ...
+
+# handle local hacks
+R$* $: $>_SET_98_ $1
+
+# short circuit local delivery so forwarded email works
+ifdef(`_LOCAL_NOT_STICKY_',
+`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names
+R$+ < @ $=w . > $#_LOCAL_ $: $1 dispose directly',
+`R$+ < @ $=w . > $: $1 < @ $2 . @ $H > first try hub
+ifdef(`_OLD_SENDMAIL_',
+`R$+ < $+ @ $-:$+ > $# $3 $@ $4 $: $1 < $2 > yep ....
+R$+ < $+ @ $+ > $#relay $@ $3 $: $1 < $2 > yep ....
+R$+ < $+ @ > $#_LOCAL_ $: $1 nope, local address',
+`R$+ < $+ @ $+ > $#_LOCAL_ $: $1 yep ....
+R$+ < $+ @ > $#_LOCAL_ $: @ $1 nope, local address')')
+ifdef(`MAILER_TABLE',
+`
+# not local -- try mailer table lookup
+R$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name
+R< $+ . > $* $: < $1 > $2 strip trailing dot
+R< $+ > $* $: < $(mailertable $1 $) > $2 lookup
+R< $- : $+ > $* $# $1 $@ $2 $: $3 check -- resolved?
+R< $+ > $* $: $>90 <$1> $2 try domain',
+`dnl')
+undivert(4)dnl
+
+ifdef(`_NO_UUCP_', `dnl',
+`# resolve remotely connected UUCP links (if any)
+ifdef(`_CLASS_V_',
+`R$* < @ $=V . UUCP . > $* $: $>_SET_95_ < $V > $1 <@$2.UUCP.> $3',
+ `dnl')
+ifdef(`_CLASS_W_',
+`R$* < @ $=W . UUCP . > $* $: $>_SET_95_ < $W > $1 <@$2.UUCP.> $3',
+ `dnl')
+ifdef(`_CLASS_X_',
+`R$* < @ $=X . UUCP . > $* $: $>_SET_95_ < $X > $1 <@$2.UUCP.> $3',
+ `dnl')')
+
+# resolve fake top level domains by forwarding to other hosts
+ifdef(`BITNET_RELAY',
+`R$*<@$+.BITNET.>$* $: $>_SET_95_ < $B > $1 <@$2.BITNET.> $3 user@host.BITNET',
+ `dnl')
+ifdef(`_MAILER_pop_',
+`R$+ < @ POP. > $#pop $: $1 user@POP',
+ `dnl')
+ifdef(`_MAILER_fax_',
+`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX',
+`ifdef(`FAX_RELAY',
+`R$*<@$+.FAX.>$* $: $>_SET_95_ < $F > $1 <@$2.FAX.> $3 user@host.FAX',
+ `dnl')')
+
+ifdef(`UUCP_RELAY',
+`# forward non-local UUCP traffic to our UUCP relay
+R$*<@$*.UUCP.>$* $: $>_SET_95_ < $Y > $1 <@$2.UUCP.> $3 uucp mail',
+`ifdef(`_MAILER_uucp_',
+`# forward other UUCP traffic straight to UUCP
+R$* < @ $+ .UUCP. > $* $#uucp $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP',
+ `dnl')')
+ifdef(`_MAILER_usenet_', `
+# addresses sent to net.group.USENET will get forwarded to a newsgroup
+R$+ . USENET $#usenet $: $1',
+ `dnl')
+
+ifdef(`_LOCAL_RULES_',
+`# figure out what should stay in our local mail system
+undivert(1)', `dnl')
+
+# pass names that still have a host to a smarthost (if defined)
+R$* < @ $* > $* $: $>_SET_95_ < $S > $1 < @ $2 > $3 glue on smarthost name
+
+# deal with other remote names
+ifdef(`_MAILER_smtp_',
+`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain',
+`R$* < @$* > $* $#error $@NOHOST $: Unrecognized host name $2')
+
+ifdef(`_OLD_SENDMAIL_',
+`# forward remaining names to local relay, if any
+R$=L $#_LOCAL_ $: $1 special local names
+R$+ $: $>_SET_95_ < $R > $1 try relay
+R$+ $: $>_SET_95_ < $H > $1 try hub
+R$+ $#_LOCAL_ $: $1 no relay or hub: local',
+
+`# if this is quoted, strip the quotes and try again
+R$+ $: $(dequote $1 $) strip quotes
+R$+ $=O $+ $@ $>_SET_97_ $1 $2 $3 try again
+
+# handle locally delivered names
+R$=L $#_LOCAL_ $: @ $1 special local names
+R$+ $#_LOCAL_ $: $1 regular local names
+
+###########################################################################
+### Ruleset 5 -- special rewriting after aliases have been expanded ###
+### (new sendmail only) ###
+###########################################################################
+
+S5
+
+# see if we have a relay or a hub
+R$+ $: < $R > $1 try relay
+R< > $+ $: < $H > $1 try hub
+R< > $+ $@ $1 nope, give up
+R< $- : $+ > $+ $: $>_SET_95_ < $1 : $2 > $3 < @ $2 >
+R< $+ > $+ $@ $>_SET_95_ < $1 > $2 < @ $1 >')
+ifdef(`MAILER_TABLE',
+`
+
+###################################################################
+### Ruleset 90 -- try domain part of mailertable entry ###
+### (new sendmail only) ###
+###################################################################
+
+S90
+R$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
+R$* <$- : $+ > $* $# $2 $@ $3 $: $4 check -- resolved?
+R$* < . $+ > $* $@ $>90 $1 . <$2> $3 no -- strip & try again
+R$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "."
+R<$- : $+ > $* $# $1 $@ $2 $: $3 "." found?
+R< $* > $* $@ $2 no mailertable match',
+`dnl')
+
+###################################################################
+### Ruleset _SET_95_ -- canonify mailer:host syntax to triple ###
+###################################################################
+
+S`'_SET_95_
+R< > $* $@ $1 strip off null relay
+R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer
+R< $=w > $* $@ $2 delete local host
+R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer
+
+###################################################################
+### Ruleset _SET_98_ -- local part of ruleset zero (can be null) ###
+###################################################################
+
+S`'_SET_98_
+undivert(3)dnl
+#
+######################################################################
+######################################################################
+#####
+`##### MAILER DEFINITIONS'
+#####
+######################################################################
+######################################################################
+undivert(7)dnl
diff --git a/usr.sbin/sendmail/cf/m4/version.m4 b/usr.sbin/sendmail/cf/m4/version.m4
new file mode 100644
index 00000000000..d7abdd6ac44
--- /dev/null
+++ b/usr.sbin/sendmail/cf/m4/version.m4
@@ -0,0 +1,39 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+VERSIONID(`@(#)version.m4 8.6.12.1 (Berkeley) 3/28/95')
+#
+divert(0)
+# Configuration version number
+DZ8.6.12
diff --git a/usr.sbin/sendmail/cf/mailer/fax.m4 b/usr.sbin/sendmail/cf/mailer/fax.m4
new file mode 100644
index 00000000000..0c98a3bde19
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/fax.m4
@@ -0,0 +1,50 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This assumes you already have Sam Leffler's FAX software.
+#
+# 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.
+#
+
+ifdef(`FAX_MAILER_PATH',,
+ `define(`FAX_MAILER_PATH', /usr/local/lib/fax/mailfax)')
+ifdef(`FAX_MAILER_MAX',,
+ `define(`FAX_MAILER_MAX', 100000)')
+POPDIVERT
+####################################
+### FAX Mailer specification ###
+####################################
+
+VERSIONID(`@(#)fax.m4 8.2 (Berkeley) 1/24/94')
+
+Mfax, P=FAX_MAILER_PATH, F=DFMhu, S=14, R=24, M=FAX_MAILER_MAX,
+ A=mailfax $u $h $f
diff --git a/usr.sbin/sendmail/cf/mailer/local.m4 b/usr.sbin/sendmail/cf/mailer/local.m4
new file mode 100644
index 00000000000..24a820413cb
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/local.m4
@@ -0,0 +1,66 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+ifdef(`LOCAL_MAILER_FLAGS',, `define(`LOCAL_MAILER_FLAGS', `rmn')')
+ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /bin/mail)')
+ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', `mail -d $u')')
+ifdef(`LOCAL_SHELL_FLAGS',, `define(`LOCAL_SHELL_FLAGS', `eu')')
+ifdef(`LOCAL_SHELL_PATH',, `define(`LOCAL_SHELL_PATH', /bin/sh)')
+ifdef(`LOCAL_SHELL_ARGS',, `define(`LOCAL_SHELL_ARGS', `sh -c $u')')
+POPDIVERT
+
+##################################################
+### Local and Program Mailer specification ###
+##################################################
+
+VERSIONID(`@(#)local.m4 8.6 (Berkeley) 10/24/93')
+
+Mlocal, P=LOCAL_MAILER_PATH, F=CONCAT(`lsDFM', LOCAL_MAILER_FLAGS), S=10, R=20/40,
+ A=LOCAL_MAILER_ARGS
+Mprog, P=LOCAL_SHELL_PATH, F=CONCAT(`lsDFM', LOCAL_SHELL_FLAGS), S=10, R=20/40, D=$z:/,
+ A=LOCAL_SHELL_ARGS
+
+S10
+R<@> $n errors to mailer-daemon
+R$+ $: $>40 $1
+
+S20
+R$+ < @ $* > $: $1 strip host part
+
+S40
+ifdef(`_ALWAYS_ADD_DOMAIN_',
+`R$* < @ $* > $* $@ $1 < @ $2 > $3 already fully qualified
+R$* $: $1 @ $M add local qualification
+R$* @ $: $1 @ $j if $M not defined',
+`dnl')
diff --git a/usr.sbin/sendmail/cf/mailer/pop.m4 b/usr.sbin/sendmail/cf/mailer/pop.m4
new file mode 100644
index 00000000000..92bcff9e790
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/pop.m4
@@ -0,0 +1,53 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+ifdef(`POP_MAILER_PATH',, `define(`POP_MAILER_PATH', /usr/lib/mh/spop)')
+ifdef(`POP_MAILER_FLAGS',, `define(`POP_MAILER_FLAGS', `eu')')
+ifdef(`POP_MAILER_ARGS',, `define(`POP_MAILER_ARGS', `pop $u')')
+
+POPDIVERT
+
+####################################
+### POP Mailer specification ###
+####################################
+
+VERSIONID(`@(#)pop.m4 8.2 (Berkeley) 2/19/94')
+
+Mpop, P=POP_MAILER_PATH, F=CONCAT(`lsDFM', POP_MAILER_FLAGS), S=10, R=20/40,
+ A=POP_MAILER_ARGS
+
+LOCAL_CONFIG
+# POP mailer is a pseudo-domain
+CPPOP
diff --git a/usr.sbin/sendmail/cf/mailer/smtp.m4 b/usr.sbin/sendmail/cf/mailer/smtp.m4
new file mode 100644
index 00000000000..45efbd68a81
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/smtp.m4
@@ -0,0 +1,126 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+ifdef(`SMTP_MAILER_FLAGS',,
+ `define(`SMTP_MAILER_FLAGS',
+ `ifdef(`_OLD_SENDMAIL_', `L', `')')')
+POPDIVERT
+#####################################
+### SMTP Mailer specification ###
+#####################################
+
+VERSIONID(`@(#)smtp.m4 8.15 (Berkeley) 2/14/94')
+
+Msmtp, P=[IPC], F=CONCAT(mDFMuX, SMTP_MAILER_FLAGS), S=11/31, R=ifdef(`_ALL_MASQUERADE_', `11/31', `21'), E=\r\n,
+ ifdef(`_OLD_SENDMAIL_',, `L=990, ')ifdef(`SMTP_MAILER_MAX', `M=SMTP_MAILER_MAX, ')A=IPC $h
+Mesmtp, P=[IPC], F=CONCAT(mDFMuXa, SMTP_MAILER_FLAGS), S=11/31, R=ifdef(`_ALL_MASQUERADE_', `11/31', `21'), E=\r\n,
+ ifdef(`_OLD_SENDMAIL_',, `L=990, ')ifdef(`SMTP_MAILER_MAX', `M=SMTP_MAILER_MAX, ')A=IPC $h
+Mrelay, P=[IPC], F=CONCAT(mDFMuXa, SMTP_MAILER_FLAGS), S=11/31, R=61, E=\r\n,
+ ifdef(`_OLD_SENDMAIL_',, `L=2040, ')A=IPC $h
+
+#
+# envelope sender and masquerading recipient rewriting
+#
+S11
+R$+ $: $>51 $1 sender/recipient common
+R$* :; <@> $@ $1 :; list:; special case
+R$* $@ $>61 $1 qualify unqual'ed names
+
+
+#
+# header recipient rewriting if not masquerading recipients
+#
+S21
+
+# do sender/recipient common rewriting
+R$+ $: $>51 $1
+
+# unqualified names (e.g., "eric") are qualified by local host
+R$* < @ $* > $* $@ $1 < @ $2 > $3 already qualified
+R$+ $: $1 < @ $j > add local domain
+
+
+#
+# header sender and masquerading recipient rewriting
+#
+S31
+R$+ $: $>51 $1 sender/recipient common
+R$* :; <@> $@ $1 :; list:; special case
+
+# do special header rewriting
+R$* <@> $* $@ $1 <@> $2 pass null host through
+R< @ $* > $* $@ < @ $1 > $2 pass route-addr through
+R$=E < @ $=w . > $@ $1 < @ $2 > exposed user as is
+R$* < @ $=w . > $: $1 < @ $2 @ $M > masquerade as domain
+R$* < @ $+ @ > $@ $1 < @ $2 > in case $M undefined
+R$* < @ $+ @ $+ > $@ $1 < @ $3 > $M is defined -- use it
+R$* $@ $>61 $1 qualify unqual'ed names
+
+
+#
+# convert pseudo-domain addresses to real domain addresses
+#
+S51
+
+# pass <route-addr>s through
+R< @ $+ > $* $@ < @ $1 > $2 resolve <route-addr>
+
+# output fake domains as user%fake@relay
+ifdef(`BITNET_RELAY',
+`R$+ <@ $+ .BITNET. > $: $1 % $2 .BITNET < @ $B > user@host.BITNET
+R$+.BITNET <@ $+:$+ > $: $1 .BITNET < @ $3 > strip mailer: part',
+ `dnl')
+ifdef(`_NO_UUCP_', `dnl', `
+# do UUCP heuristics; note that these are shared with UUCP mailers
+R$+ < @ $+ .UUCP. > $: < $2 ! > $1 convert to UUCP form
+R$+ < @ $* > $* $@ $1 < @ $2 > $3 not UUCP form
+
+# leave these in .UUCP form to avoid further tampering
+R< $&h ! > $- ! $+ $@ $2 < @ $1 .UUCP. >
+R< $&h ! > $-.$+ ! $+ $@ $3 < @ $1.$2 >
+R< $&h ! > $+ $@ $1 < @ $&h .UUCP. >
+R< $+ ! > $+ $: $1 ! $2 < @ $Y >
+R$+ < @ > $: $1 < @ $j > in case $Y undefined
+R$+ < @ $+ : $+ > $: $1 < @ $3 > strip mailer: part')
+
+
+#
+# common sender and masquerading recipient rewriting
+#
+S61
+
+R$* < @ $* > $* $@ $1 < @ $2 > $3 already qualified
+R$=E $@ $1 < @ $j> show exposed names
+R$+ $: $1 < @ $M > user w/o host
+R$+ <@> $: $1 < @ $j > in case $M undefined
diff --git a/usr.sbin/sendmail/cf/mailer/usenet.m4 b/usr.sbin/sendmail/cf/mailer/usenet.m4
new file mode 100644
index 00000000000..fe6ee3071f8
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/usenet.m4
@@ -0,0 +1,47 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+ifdef(`USENET_MAILER_PATH',, `define(`USENET_MAILER_PATH', /usr/lib/news/inews)')
+ifdef(`USENET_MAILER_FLAGS',, `define(`USENET_MAILER_FLAGS', `rlsDFMmn')')
+ifdef(`USENET_MAILER_ARGS',, `define(`USENET_MAILER_ARGS', `inews -m -h -n')')
+POPDIVERT
+####################################
+### USENET Mailer specification ###
+####################################
+
+VERSIONID(`@(#)usenet.m4 8.3 (Berkeley) 1/24/94')
+
+Musenet, P=USENET_MAILER_PATH, F=USENET_MAILER_FLAGS, S=10, R=20,ifdef(`USENET_MAILER_MAX', ` M=USENET_MAILER_MAX,')
+ A=USENET_MAILER_ARGS $u
diff --git a/usr.sbin/sendmail/cf/mailer/uucp.m4 b/usr.sbin/sendmail/cf/mailer/uucp.m4
new file mode 100644
index 00000000000..dd7aa87ff18
--- /dev/null
+++ b/usr.sbin/sendmail/cf/mailer/uucp.m4
@@ -0,0 +1,172 @@
+PUSHDIVERT(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+
+ifdef(`UUCP_MAILER_PATH',, `define(`UUCP_MAILER_PATH', /usr/bin/uux)')
+ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -a$f -gC $h!rmail ($u)')')
+ifdef(`UUCP_MAILER_FLAGS',, `define(`UUCP_MAILER_FLAGS', `')')
+ifdef(`UUCP_MAX_SIZE',, `define(`UUCP_MAX_SIZE', 100000)')
+POPDIVERT
+#####################################
+### UUCP Mailer specification ###
+#####################################
+
+VERSIONID(`@(#)uucp.m4 8.16 (Berkeley) 4/14/94')
+
+#
+# There are innumerable variations on the UUCP mailer. It really
+# is rather absurd.
+#
+
+# old UUCP mailer (two names)
+Muucp, P=UUCP_MAILER_PATH, F=CONCAT(DFMhuU, UUCP_MAILER_FLAGS), S=12, R=22/42, M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS
+Muucp-old, P=UUCP_MAILER_PATH, F=CONCAT(DFMhuU, UUCP_MAILER_FLAGS), S=12, R=22/42, M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS
+
+# smart UUCP mailer (handles multiple addresses) (two names)
+Msuucp, P=UUCP_MAILER_PATH, F=CONCAT(mDFMhuU, UUCP_MAILER_FLAGS), S=12, R=22/42, M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS
+Muucp-new, P=UUCP_MAILER_PATH, F=CONCAT(mDFMhuU, UUCP_MAILER_FLAGS), S=12, R=22/42, M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS
+
+ifdef(`_MAILER_smtp_',
+`# domain-ized UUCP mailer
+Muucp-dom, P=UUCP_MAILER_PATH, F=CONCAT(mDFMhu, UUCP_MAILER_FLAGS), S=52/31, R=ifdef(`_ALL_MASQUERADE_', `11/31', `21'), M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS
+
+# domain-ized UUCP mailer with UUCP-style sender envelope
+Muucp-uudom, P=UUCP_MAILER_PATH, F=CONCAT(mDFMhu, UUCP_MAILER_FLAGS), S=72/31, R=ifdef(`_ALL_MASQUERADE_', `11/31', `21'), M=UUCP_MAX_SIZE,
+ A=UUCP_MAILER_ARGS')
+
+
+#
+# envelope and header sender rewriting
+#
+S12
+
+# handle error address as a special case
+R<@> $n errors to mailer-daemon
+
+# do not qualify list:; syntax
+R$* :; <@> $@ $1 :;
+
+R$* < @ $* . > $1 < @ $2 > strip trailing dots
+R$* < @ $=w > $1 strip local name
+R<@ $- . UUCP > : $+ $1 ! $2 convert to UUCP format
+R<@ $+ > : $+ $1 ! $2 convert to UUCP format
+R$* < @ $- . UUCP > $2 ! $1 convert to UUCP format
+R$* < @ $+ > $2 ! $1 convert to UUCP format
+R$&h ! $+ ! $+ $@ $1 ! $2 $h!...!user => ...!user
+R$&h ! $+ $@ $&h ! $1 $h!user => $h!user
+R$+ $: $U ! $1 prepend our name
+R! $+ $: $k ! $1 in case $U undefined
+
+#
+# envelope recipient rewriting
+#
+S22
+
+# don't touch list:; syntax
+R$* :; <@> $@ $1 :;
+
+R$* < @ $* . > $1 < @ $2 > strip trailing dots
+R$* < @ $j > $1 strip local name
+R<@ $- . UUCP > : $+ $1 ! $2 convert to UUCP format
+R<@ $+ > : $+ $1 ! $2 convert to UUCP format
+R$* < @ $- . UUCP > $2 ! $1 convert to UUCP format
+R$* < @ $+ > $2 ! $1 convert to UUCP format
+
+#
+# header recipient rewriting
+#
+S42
+
+# don't touch list:; syntax
+R$* :; <@> $@ $1 :;
+
+R$* < @ $* . > $1 < @ $2 > strip trailing dots
+R$* < @ $j > $1 strip local name
+R<@ $- . UUCP > : $+ $1 ! $2 convert to UUCP format
+R<@ $+ > : $+ $1 ! $2 convert to UUCP format
+R$* < @ $- . UUCP > $2 ! $1 convert to UUCP format
+R$* < @ $+ > $2 ! $1 convert to UUCP format
+R$&h ! $+ ! $+ $@ $1 ! $2 $h!...!user => ...!user
+R$&h ! $+ $@ $&h ! $1 $h!user => $h!user
+R$+ $: $U ! $1 prepend our name
+R! $+ $: $k ! $1 in case $U undefined
+
+
+ifdef(`_MAILER_smtp_',
+`#
+# envelope sender rewriting for uucp-dom mailer
+#
+S52
+
+# handle error address as a special case
+R<@> $n errors to mailer-daemon
+
+# pass everything to standard SMTP mailer rewriting
+R$* $@ $>11 $1
+
+#
+# envelope sender rewriting for uucp-uudom mailer
+#
+S72
+
+# handle error address as a special case
+R<@> $n errors to mailer-daemon
+
+# do not qualify list:; syntax
+R$* :; <@> $@ $1 :;
+
+R$* < @ $* . > $1 < @ $2 > strip trailing dots
+R$* < @ $=w > $1 strip local name
+R<@ $- . UUCP > : $+ $1 ! $2 convert to UUCP format
+R<@ $+ > : $+ $1 ! $2 convert to UUCP format
+R$* < @ $- . UUCP > $2 ! $1 convert to UUCP format
+R$* < @ $+ > $@ $2 ! $1 convert to UUCP format
+
+R$&h ! $+ ! $+ $@ $1 ! $2 $h!...!user => ...!user
+R$&h ! $+ $@ $&h ! $1 $h!user => $h!user
+R$+ $: $M ! $1 prepend masquerade name
+R! $+ $: $j ! $1 in case $M undefined')
+
+
+PUSHDIVERT(4)
+# resolve locally connected UUCP links
+R$* < @ $=Z . UUCP. > $* $#uucp-uudom $@ $2 $: $1 < @ $2 .UUCP. > $3
+R$* < @ $=Y . UUCP. > $* $#uucp-new $@ $2 $: $1 < @ $2 .UUCP. > $3
+R$* < @ $=U . UUCP. > $* $#uucp-old $@ $2 $: $1 < @ $2 .UUCP. > $3
+POPDIVERT
diff --git a/usr.sbin/sendmail/cf/ostype/bsd4.4.m4 b/usr.sbin/sendmail/cf/ostype/bsd4.4.m4
new file mode 100644
index 00000000000..1950528902b
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/bsd4.4.m4
@@ -0,0 +1,42 @@
+divert(-1)
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+#
+
+divert(0)
+VERSIONID(`@(#)bsd4.4.m4 8.2 (Berkeley) 2/10/94')
+define(`HELP_FILE', /usr/share/misc/sendmail.hf)dnl
+define(`STATUS_FILE', /var/log/sendmail.st)dnl
+define(`LOCAL_MAILER_PATH', /usr/libexec/mail.local)dnl
+define(`UUCP_MAILER_ARGS', `uux - -r -z -a$f $h!rmail ($u)')dnl
diff --git a/usr.sbin/sendmail/cf/sh/makeinfo.sh b/usr.sbin/sendmail/cf/sh/makeinfo.sh
new file mode 100644
index 00000000000..dd5044afe97
--- /dev/null
+++ b/usr.sbin/sendmail/cf/sh/makeinfo.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+#
+# Copyright (c) 1983 Eric P. Allman
+# 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.
+#
+# @(#)makeinfo.sh 8.4 (Berkeley) 3/4/94
+#
+
+usewhoami=0
+usehostname=0
+for p in `echo $PATH | sed 's/:/ /g'`
+do
+ if [ "x$p" = "x" ]
+ then
+ p="."
+ fi
+ if [ -f $p/whoami ]
+ then
+ usewhoami=1
+ if [ $usehostname -ne 0 ]
+ then
+ break;
+ fi
+ fi
+ if [ -f $p/hostname ]
+ then
+ usehostname=1
+ if [ $usewhoami -ne 0 ]
+ then
+ break;
+ fi
+ fi
+done
+if [ $usewhoami -ne 0 ]
+then
+ user=`whoami`
+else
+ user=$LOGNAME
+fi
+
+if [ $usehostname -ne 0 ]
+then
+ host=`hostname`
+else
+ host=`uname -n`
+fi
+echo '#####' built by $user@$host on `date`
+echo '#####' in `pwd` | sed 's/\/tmp_mnt//'
diff --git a/usr.sbin/sendmail/cf/siteconfig/uucp.cogsci.m4 b/usr.sbin/sendmail/cf/siteconfig/uucp.cogsci.m4
new file mode 100644
index 00000000000..33c71511781
--- /dev/null
+++ b/usr.sbin/sendmail/cf/siteconfig/uucp.cogsci.m4
@@ -0,0 +1,6 @@
+SITE(contessa)
+SITE(emind)
+SITE(hoptoad)
+SITE(nkainc)
+SITE(well)
+SITE(ferdy)
diff --git a/usr.sbin/sendmail/cf/siteconfig/uucp.old.arpa.m4 b/usr.sbin/sendmail/cf/siteconfig/uucp.old.arpa.m4
new file mode 100644
index 00000000000..81d5e9443d9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/siteconfig/uucp.old.arpa.m4
@@ -0,0 +1,4 @@
+SITE(endotsew)
+SITE(fateman)
+SITE(interlan)
+SITE(metron)
diff --git a/usr.sbin/sendmail/cf/siteconfig/uucp.ucbarpa.m4 b/usr.sbin/sendmail/cf/siteconfig/uucp.ucbarpa.m4
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/usr.sbin/sendmail/cf/siteconfig/uucp.ucbarpa.m4
@@ -0,0 +1 @@
+
diff --git a/usr.sbin/sendmail/cf/siteconfig/uucp.ucbvax.m4 b/usr.sbin/sendmail/cf/siteconfig/uucp.ucbvax.m4
new file mode 100644
index 00000000000..ee2c34f60d9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/siteconfig/uucp.ucbvax.m4
@@ -0,0 +1,73 @@
+SITE(Padova)
+SITE(Shasta)
+SITE(alice)
+SITE(allegra)
+SITE(amdcad)
+SITE(att)
+SITE(attunix)
+SITE(avsd)
+SITE(bellcore bellcor)
+SITE(calma)
+SITE(cithep)
+SITE(cnmat)
+SITE(craig)
+SITE(craylab)
+SITE(decusj)
+SITE(decvax, S)
+SITE(decwrl)
+SITE(dssovax)
+SITE(eagle)
+SITE(ecovax)
+SITE(floyd)
+SITE(franz)
+SITE(geoff)
+SITE(harpo)
+SITE(ho3e2)
+SITE(hpda)
+SITE(hplabs)
+SITE(ibmsupt ibmuupa ibmpa)
+SITE(iiasa70)
+SITE(imagen)
+SITE(isunix menlo70)
+SITE(kentmth)
+SITE(lbl-csam lbl-csa)
+SITE(lime)
+SITE(mothra)
+SITE(mseonyx)
+SITE(mtxinu)
+SITE(pixar)
+SITE(pur-ee)
+SITE(purdue)
+SITE(pwbd)
+SITE(sdcarl)
+SITE(sftig)
+SITE(sgi olympus)
+SITE(sii)
+SITE(srivisi)
+SITE(ssyx)
+SITE(sun)
+SITE(trwrb)
+SITE(twg)
+SITE(ucivax)
+SITE(ucla-se)
+SITE(ucla-cs)
+SITE(ucsbcsl ucsbhub)
+SITE(ucscc)
+SITE(ucsd)
+SITE(ucsfcgl)
+SITE(ucsfmis)
+SITE(ulysses)
+SITE(unisoft)
+SITE(unmvax)
+SITE(usenix)
+SITE(uw)
+SITE(uwvax)
+SITE(vax135)
+SITE(voder)
+SITE(wheps)
+SITE(whuxle)
+SITE(whuxlj)
+SITE(xicomp)
+SITE(xprin)
+SITE(zehntel)
+SITE(zilog)
diff --git a/usr.sbin/sendmail/contrib/README b/usr.sbin/sendmail/contrib/README
new file mode 100644
index 00000000000..dcf5c8fe7e0
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/README
@@ -0,0 +1,10 @@
+Everything in this directory (except this file) has been contributed.
+We will not fix bugs in these programs. Contact the original author
+for assistance.
+
+Some of these are patches to sendmail itself. You may need to take
+care -- some of the patches may be out of date with the latest release
+of sendmail. Also, the previous comment applies -- patches belong to
+the original author, not to me.
+
+Eric Allman, 26 May 1993
diff --git a/usr.sbin/sendmail/contrib/bitdomain.c b/usr.sbin/sendmail/contrib/bitdomain.c
new file mode 100644
index 00000000000..4fad7617549
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/bitdomain.c
@@ -0,0 +1,409 @@
+/*
+ * By John G. Myers, jgm+@cmu.edu
+ * Version 1.1
+ *
+ * Process a BITNET "internet.listing" file, producing output
+ * suitable for input to makemap.
+ *
+ * The input file can be obtained via anonymous FTP to bitnic.educom.edu.
+ * Change directory to "netinfo" and get the file internet.listing
+ * The file is updated monthly.
+ *
+ * Feed the output of this program to "makemap hash /etc/bitdomain.db"
+ * to create the table used by the "FEATURE(bitdomain)" config file macro.
+ * If your sendmail does not have the db library compiled in, you can instead
+ * use "makemap dbm /etc/bitdomain" and
+ * "FEATURE(bitdomain,`dbm -o /etc/bitdomain')"
+ *
+ * The bitdomain table should be rebuilt monthly.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+
+/* don't use sizeof because sizeof(long) is different on 64-bit machines */
+#define SHORTSIZE 2 /* size of a short (really, must be 2) */
+#define LONGSIZE 4 /* size of a long (really, must be 4) */
+
+typedef union
+{
+ HEADER qb1;
+ char qb2[PACKETSZ];
+} querybuf;
+
+extern int h_errno;
+extern char *malloc();
+extern char *optarg;
+extern int optind;
+
+char *lookup();
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "o:")) != EOF) {
+ switch (opt) {
+ case 'o':
+ if (!freopen(optarg, "w", stdout)) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "usage: %s [-o outfile] [internet.listing]\n",
+ argv[0]);
+ exit(1);
+ }
+ }
+
+ if (optind < argc) {
+ if (!freopen(argv[optind], "r", stdin)) {
+ perror(argv[optind]);
+ exit(1);
+ }
+ }
+ readfile(stdin);
+ finish();
+ exit(0);
+}
+
+/*
+ * Parse and process an input file
+ */
+readfile(infile)
+FILE *infile;
+{
+ int skippingheader = 1;
+ char buf[1024], *node, *hostname, *p;
+
+ while (fgets(buf, sizeof(buf), infile)) {
+ for (p = buf; *p && isspace(*p); p++);
+ if (!*p) {
+ skippingheader = 0;
+ continue;
+ }
+ if (skippingheader) continue;
+
+ node = p;
+ for (; *p && !isspace(*p); p++) {
+ if (isupper(*p)) *p = tolower(*p);
+ }
+ if (!*p) {
+ fprintf(stderr, "%-8s: no domain name in input file\n", node);
+ continue;
+ }
+ *p++ = '\0';
+
+ for (; *p && isspace(*p); p++) ;
+ if (!*p) {
+ fprintf(stderr, "%-8s no domain name in input file\n", node);
+ continue;
+ }
+
+ hostname = p;
+ for (; *p && !isspace(*p); p++) {
+ if (isupper(*p)) *p = tolower(*p);
+ }
+ *p = '\0';
+
+ /* Chop off any trailing .bitnet */
+ if (strlen(hostname) > 7 &&
+ !strcmp(hostname+strlen(hostname)-7, ".bitnet")) {
+ hostname[strlen(hostname)-7] = '\0';
+ }
+ entry(node, hostname, sizeof(buf)-(hostname - buf));
+ }
+}
+
+/*
+ * Process a single entry in the input file.
+ * The entry tells us that "node" expands to "domain".
+ * "domain" can either be a domain name or a bitnet node name
+ * The buffer pointed to by "domain" may be overwritten--it
+ * is of size "domainlen".
+ */
+entry(node, domain, domainlen)
+char *node;
+char *domain;
+char *domainlen;
+{
+ char *otherdomain, *p, *err;
+
+ /* See if we have any remembered information about this node */
+ otherdomain = lookup(node);
+
+ if (otherdomain && strchr(otherdomain, '.')) {
+ /* We already have a domain for this node */
+ if (!strchr(domain, '.')) {
+ /*
+ * This entry is an Eric Thomas FOO.BITNET kludge.
+ * He doesn't want LISTSERV to do transitive closures, so we
+ * do them instead. Give the the domain expansion for "node"
+ * (which is in "otherdomian") to FOO (which is in "domain")
+ * if "domain" doesn't have a domain expansion already.
+ */
+ p = lookup(domain);
+ if (!p || !index(p, '.')) remember(domain, otherdomain);
+ }
+ }
+ else {
+ if (!strchr(domain, '.') || valhost(domain, domainlen)) {
+ remember(node, domain);
+ if (otherdomain) {
+ /*
+ * We previously mapped the node "node" to the node
+ * "otherdomain". If "otherdomain" doesn't already
+ * have a domain expansion, give it the expansion "domain".
+ */
+ p = lookup(otherdomain);
+ if (!p || !index(p, '.')) remember(otherdomain, domain);
+ }
+ }
+ else {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ err = "not registered in DNS";
+ break;
+
+ case TRY_AGAIN:
+ err = "temporary DNS lookup failure";
+ break;
+
+ case NO_RECOVERY:
+ err = "non-recoverable nameserver error";
+ break;
+
+ case NO_DATA:
+ err = "registered in DNS, but not mailable";
+ break;
+
+ default:
+ err = "unknown nameserver error";
+ break;
+ }
+
+ fprintf(stderr, "%-8s %s %s\n", node, domain, err);
+ }
+ }
+}
+
+/*
+ * Validate whether the mail domain "host" is registered in the DNS.
+ * If "host" is a CNAME, it is expanded in-place if the expansion fits
+ * into the buffer of size "hbsize". Returns nonzero if it is, zero
+ * if it is not. A BIND error code is left in h_errno.
+ */
+int
+valhost(host, hbsize)
+ char *host;
+ int hbsize;
+{
+ register u_char *eom, *ap;
+ register int n;
+ HEADER *hp;
+ querybuf answer;
+ int ancount, qdcount;
+ int ret;
+ int type;
+ int qtype;
+ char nbuf[1024];
+
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return (0);
+
+ _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
+ _res.retrans = 30;
+ _res.retry = 10;
+
+ qtype = T_ANY;
+
+ for (;;) {
+ h_errno = NO_DATA;
+ ret = res_querydomain(host, "", C_IN, qtype,
+ &answer, sizeof(answer));
+ if (ret <= 0)
+ {
+ if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
+ {
+ /* the name server seems to be down */
+ h_errno = TRY_AGAIN;
+ return 0;
+ }
+
+ if (h_errno != HOST_NOT_FOUND)
+ {
+ /* might have another type of interest */
+ if (qtype == T_ANY)
+ {
+ qtype = T_A;
+ continue;
+ }
+ else if (qtype == T_A)
+ {
+ qtype = T_MX;
+ continue;
+ }
+ }
+
+ /* otherwise, no record */
+ return 0;
+ }
+
+ /*
+ ** This might be a bogus match. Search for A, MX, or
+ ** CNAME records.
+ */
+
+ hp = (HEADER *) &answer;
+ ap = (u_char *) &answer + sizeof(HEADER);
+ eom = (u_char *) &answer + ret;
+
+ /* skip question part of response -- we know what we asked */
+ for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
+ {
+ if ((ret = dn_skipname(ap, eom)) < 0)
+ {
+ return 0; /* ???XXX??? */
+ }
+ }
+
+ for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
+ {
+ n = dn_expand((u_char *) &answer, eom, ap,
+ (u_char *) nbuf, sizeof nbuf);
+ if (n < 0)
+ break;
+ ap += n;
+ GETSHORT(type, ap);
+ ap += SHORTSIZE + LONGSIZE;
+ GETSHORT(n, ap);
+ switch (type)
+ {
+ case T_MX:
+ case T_A:
+ return 1;
+
+ case T_CNAME:
+ /* value points at name */
+ if ((ret = dn_expand((u_char *)&answer,
+ eom, ap, (u_char *)nbuf, sizeof(nbuf))) < 0)
+ break;
+ if (strlen(nbuf) < hbsize) {
+ (void)strcpy(host, nbuf);
+ }
+ return 1;
+
+ default:
+ /* not a record of interest */
+ continue;
+ }
+ }
+
+ /*
+ ** If this was a T_ANY query, we may have the info but
+ ** need an explicit query. Try T_A, then T_MX.
+ */
+
+ if (qtype == T_ANY)
+ qtype = T_A;
+ else if (qtype == T_A)
+ qtype = T_MX;
+ else
+ return 0;
+ }
+}
+
+struct entry {
+ struct entry *next;
+ char *node;
+ char *domain;
+};
+struct entry *firstentry;
+
+/*
+ * Find any remembered information about "node"
+ */
+char *lookup(node)
+char *node;
+{
+ struct entry *p;
+
+ for (p = firstentry; p; p = p->next) {
+ if (!strcmp(node, p->node)) {
+ return p->domain;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Mark the node "node" as equivalent to "domain". "domain" can either
+ * be a bitnet node or a domain name--if it is the latter, the mapping
+ * will be written to stdout.
+ */
+remember(node, domain)
+char *node;
+char *domain;
+{
+ struct entry *p;
+
+ if (strchr(domain, '.')) {
+ fprintf(stdout, "%-8s %s\n", node, domain);
+ }
+
+ for (p = firstentry; p; p = p->next) {
+ if (!strcmp(node, p->node)) {
+ p->domain = malloc(strlen(domain)+1);
+ if (!p->domain) {
+ goto outofmemory;
+ }
+ strcpy(p->domain, domain);
+ return;
+ }
+ }
+
+ p = (struct entry *)malloc(sizeof(struct entry));
+ if (!p) goto outofmemory;
+
+ p->next = firstentry;
+ firstentry = p;
+ p->node = malloc(strlen(node)+1);
+ p->domain = malloc(strlen(domain)+1);
+ if (!p->node || !p->domain) goto outofmemory;
+ strcpy(p->node, node);
+ strcpy(p->domain, domain);
+ return;
+
+ outofmemory:
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+}
+
+/*
+ * Walk through the database, looking for any cases where we know
+ * node FOO is equivalent to node BAR and node BAR has a domain name.
+ * For those cases, give FOO the same domain name as BAR.
+ */
+finish()
+{
+ struct entry *p;
+ char *domain;
+
+ for (p = firstentry; p; p = p->next) {
+ if (!strchr(p->domain, '.') && (domain = lookup(p->domain))) {
+ remember(p->node, domain);
+ }
+ }
+}
+
diff --git a/usr.sbin/sendmail/contrib/converting.sun.configs b/usr.sbin/sendmail/contrib/converting.sun.configs
new file mode 100644
index 00000000000..0fcd9196730
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/converting.sun.configs
@@ -0,0 +1,446 @@
+
+ Converting Standard Sun Config
+ Files to Sendmail Version 8
+
+ Rick McCarty
+ Texas Instruments Inc.
+ Latest Update: 08/25/93 - RJMc
+
+This document details the changes necessary to continue using your
+current SunOS sendmail.cf with sendmail version 8. In the longer term,
+it is recommended that one move to using an m4 based configuration such
+as those shipped with sendmail, but if you're like me and have made
+enough modifications to your .cf file that you'd rather put that task
+off until later, here's the sum total of my experience to get you to
+version 8 with minimal pain. I'll cover .cf as well as build issues.
+
+Some background - as many are surely aware, Sun has some "special"
+features in the sendmail they ship ($%x, %y LHS lookup, NIS alias DB
+search, etc.). (Some of those features can be had in alternative forms
+in IDA sendmail, but v8 has picked up some IDA capabilities as well as
+new ones, making it IMHO a most desirable version to go to.) What I
+will explain below includes v8 functional "equivalences" to these Sun
+sendmail features.
+
+So with that out of the way, let's begin.
+
+First, some assumptions:
+
+ 1) I'm going to assume you've got sendmail version 8.6 or
+ later in hand - if not, grab it from ftp.cs.berkeley.edu
+ in the ucb/sendmail directory. There are bugs in earlier
+ versions which affect some of the needed functionality.
+
+ 2) Second, I'm going to detail this based upon the
+ "sendmail.main.cf" configuration. (BTW, if you attempt
+ to move to using an m4 generated config in the future,
+ MAIL_HUB is the feature which should provide similar
+ functionality).
+
+ In general, the changes will be similar for a subsidiary
+ file, but since we (my TI group) funnel all non-local mail
+ through our mailhost, we're not as interested in getting v8
+ to run on such systems and I haven't tried it.
+
+ 3) You're using DNS and sendmail.mx. If you're not, you ought
+ to be, even if you're also running it along with NIS (which
+ we do - except for gethostbyxxx() lookups, which I'll be
+ talking about later). I would imagine you could get things
+ running OK without DNS support, but I haven't tried it myself.
+
+ 4) You're not mounting /var/spool/mail from other systems.
+ I haven't found a v8 feature to guarantee this will work
+ correctly. Anyway, in the past, we've tried doing that
+ here and found it to be a rather "ugly" feature, though
+ Sun ostensibly supports it ("R" option). Perhaps v8
+ will one day have a similar feature, but for now, bottom
+ line, I would recommend against it.
+
+ 5) You're not on Solaris or using NIS+. I'm on 4.1.3. I've
+ looked at Solaris briefly and have noted that things are
+ pretty much similar there except that they've moved some
+ things into the /etc/mail directory. I'd guess the
+ executables aren't functionally all that different from
+ what they had before - the configs are roughly the same.
+ So I'd bet most of what I say in here will apply to
+ Solaris.
+
+OK, let's configure our sendmail.cf! I'll just go from the top down...
+
+ VARIOUS DECLARATIONS
+
+1) For v8, you need to define your .cf as AT LEAST a version level 4
+ configuration. Add the following line:
+
+ V4
+
+ There are some issues regarding certain predefined macros - $w, $j, and
+ $m. With a V4 configuration:
+
+ $w is defined to be the hostname, which will usually be fully
+ qualified (i.e. "firefly.add.itg.ti.com").
+
+ $j should have the same value as $w.
+
+ $m will be predefined as the domain portion of $w
+ (ex. "add.itg.ti.com").
+
+ One note about this - if your configuration relies on the "w" macro to
+ be the "simple" hostname (as mine does)...
+
+ If the configuration version is 5 or larger:
+
+ $w is supposed to be the "simple" name (ex. "firefly")
+
+ $j should be the fully qualified name (i.e. "firefly.add.itg.ti.com")
+
+ $m will be predefined as the domain portion of $j
+ (ex. "add.itg.ti.com").
+
+ I have not experimented with the various combinations, so I cannot
+ guarantee you that the above definitions will always come out as
+ expected. Bottom line: if your sendmail.cf depends on $w being the
+ simple hostname, test it carefully or define the name explicitly,
+ for example:
+
+ Dwfirefly
+
+2) To replace the Sun's "%y" feature, we must use a hostname mapping
+ feature in v8. If you want to do similar lookups with v8, you need
+ to define the following map (we'll go over the rules that use this
+ map later):
+
+ Khostlookup host -f -m -a.
+
+ This will define a "lookup only" map that is otherwise the same as
+ sendmail version 8's built-in "host" map (see the "Sendmail
+ Installation and Operation Guide" for details on this map.).
+
+ An important note: Whether or not these lookups will be done via
+ NIS is a function of what gethostbyxxx() functions you link into
+ your sendmail. DO NOT redefine your host mapping to use NIS
+ explicitly within sendmail - there can be unexpected behaviour if
+ you do so (if you do any canonicalization in your .cf, you can get
+ incorrect results, for one thing).
+
+ For example, DO NOT TRY:
+
+ Khost nis -f -a. hosts.byname
+
+3) If you're doing reverse alias mapping as done in ruleset 22, instead of:
+
+ DZmail.byaddr
+
+ you'll need to declare the following:
+
+ Kaliasrev nis -f -N mail.byaddr
+
+4) If you are doing any other NIS map lookups, you'll need to define the
+ map as done in the below example. I have a "mailhosts" map, which I
+ use to distinguish between local and non-local hosts. Look at the
+ sendmail doc for details on this stuff.
+
+ Kmailhosts nis -f -m -a. mailhosts
+
+5) You might wish to add the following line to support Errors-To: headers.
+ I don't.
+
+ Ol
+
+6) Comment out/remove the following line:
+
+ OR
+
+ The R option means something different under v8 - check the documentation
+ if you're interested in using it.
+
+7) If you're running NIS and have a separate alias map, BELOW the
+ following line where the alias file is declared:
+
+ OA/etc/aliases
+
+ ADD the following:
+
+ OAnis:mail.aliases
+
+ This will set things up so v8 will look at the local alias DB first,
+ then the NIS map, just as Sun sendmail does.
+
+8) Though you don't have to, I'd suggest changing:
+
+ OT3d
+
+ to use v8's warning feature, which allows a warning message to be
+ sent if a message cannot be delivered within a specified period.
+ I use:
+
+ OT5d/4h
+
+ which says - bounce after 5 days, warn after 4 hours.
+
+9) I set the following option to be explicit about how I want DNS
+ handled:
+
+ OI +DNSRCH +DEFNAMES
+
+10) The following line:
+
+ T root daemon uucp
+
+ may be deleted, though it will be ignored if you leave it around.
+
+11) It would probably be good to change the version macro value (which
+ shows up in "Received:" headers) so no one debugging mail problems
+ gets the wrong idea about what config you're running under. Look
+ for something like:
+
+ DVSMI-4.1
+
+ Mine, for example is:
+
+ DVADD-HUB-2.1
+
+ RULESETS
+
+1) In ruleset 3, BELOW this rule:
+
+ # basic textual canonicalization
+ R$*<$+>$* $2 basic RFC822 parsing
+
+
+I add the following rule to remove a trailing dot in the domain spec so
+it won't interfere with v8 mapping features, etc. (Having a trailing dot is
+not RFC-compliant anyway.):
+
+ R$+. $1
+
+2) Because ruleset 5 is special in v8, I rename it to S95 and also change
+ all RHS expressions containing ">5" to use ">95" instead. In v8,
+ 5 is executed against addresses which resolve to the local mailer and
+ are not an alias. If you don't change S5 to something else, you might
+ get a surprise!
+
+3) If you're doing any lookups via the generalized NIS "$%x/$!x"
+ mechanisms (such as with the mailhost map I referred to earlier) it's
+ done differently under v8. For example:
+
+ DMmailhosts
+ ...
+ R$*<@$%M.uucp>$* $#ether $@$2 $:$1<@$2>$3
+
+ takes a different map definition and two rules under version 8:
+
+ Kmailhosts nis -f -m -a. mailhosts
+ ...
+ R$*<@$+.uucp>$* $: $1<@$(mailhosts $2 $).uucp>$3
+ R$*<@$+..uucp>$* $#ether $@$2 $:$1<@$2>$3
+
+4) Sun has a special case of the "$%x" feature for host lookups - "%y" is
+ automagically defined to do an NIS "hosts.byname" search with no other
+ definition, as done in the below example:
+
+ R$*<@$%y.LOCAL>$* $#ether $@$2 $:$1<@$2>$3
+
+ (Sun does this in more than one place. But the above syntax is almost
+ identical in each - mostly a case of changing names to protect the
+ innocent.)
+
+ In version 8, the predefined "host" map can be used to do essentially
+ the same thing. (However, whether or not it does an NIS lookup is
+ a function of what gethostbyxxx() functions are linked in.)
+
+ Recall the map definition I mentioned earlier in the DECLARATIONS
+ section:
+
+ Khostlookup host -f -m -a.
+
+ Here's where we will use it. It will take two rules:
+
+ R$*<@$+.LOCAL>$* $: $1<@$(hostlookup $2 $).LOCAL>$3
+ R$*<@$+..LOCAL>$* $#ether $@$2 $:$1<@$2>$3
+
+ Note that this is almost verbatim the same change as was used in the
+ previous "mailhosts" example.
+
+5) Although Sun's default configs don't do this, because I mentioned
+ canonicalization earlier, it deserves an example, as it's illustrative
+ of the functional difference in the map definitions I discussed before.
+ This stuff is also convered in the "Sendmail Installation and Operation
+ Guide".
+
+ Remember the built-in "host" map definition? As you'll recall, unlike
+ the "hostlookup" map we defined, "host" will actually CHANGE the
+ hostname in addition to appending a dot. "hostlookup" only appends a
+ dot if the name is found and doesn't change it otherwise. Anyway,
+ here's the example:
+
+ R$*<@$+>$* $: $1<@$(host $2 $)>$3 canonicalize
+ R$*<@$+.>$* $1<@$2>$3 remove trailing dot
+
+ Using the above, say you had input of:
+
+ joe<@tilde>
+
+ OR
+
+ joe<@[128.247.160.56]>
+
+ Assuming "tilde" or the IP address is found, it might be
+ canonicalized as:
+
+ joe<@tilde.csc.ti.com>
+
+6) As another instance of the NIS lookup feature, with a slightly
+ different twist, Sun implements reverse alias mapping in ruleset 22
+ with the below:
+
+ DZmail.byaddr
+ ...
+ R$-<@$-> $:$>3${Z$1@$2$} invert aliases
+
+ To use this feature under v8, change the above rule a (remember to
+ define the alias map as I showed earlier):
+
+ R$-<@$-> $:$>3$(aliasrev $1@$2 $) invert aliases
+
+
+ MAILER DEFINITIONS
+
+1) Where "TCP" is defined in the "P=" and "A=" parameters of mailers, I
+ changed it to "IPC". Version 8 will accept "TCP", but "IPC" is
+ preferred.
+
+2) On all IPC mailers, I also defined "E=\r\n" and added an "L=1000" as
+ in the below example:
+
+ Mether, P=[IPC], F=mDFMuCX, S=11, R=21, L=1000, E=\r\n, A=IPC $h
+
+ The "E=\r\n" will save you headaches interoperating with such things as
+ VMS TCP products.
+
+ The "L=1000" is for RFC821 compatibility. Not strictly necessary.
+
+ I also removed the "s" (strip quotes) mailer flag Sun puts in for
+ these mailers. Stripping quotes violates protocols, which say
+ clearly that you can't touch the local-part (left hand side of
+ the @) until you are on the delivering host.
+
+NOW. If I haven't left anything out, you should be able to run through
+your Sun sendmail.cf file and convert it to run under v8.
+
+ BUILD ISSUES
+
+Some important notes on building v8 on SunOS:
+
+Makefile
+
+The default makefile in the version 8 source (src) directory assumes the
+new Berkeley make. Unless you want to go to the trouble of building it,
+you can use your regular make, but you need to use a different makefile.
+You can use "Makefile.dist" or "Makefile.SunOS" in the src directory. I
+made changes to get it to build so it is as compatible as possible with
+the file/directory locations Sun uses. Here are some relevant sections
+out of my makefile:
+
+ CC=gcc
+
+ # use O=-O (usual) or O=-g (debugging)
+ O= -O
+
+ # define the database mechanisms available for map & alias lookups:
+ # -DNDBM -- use new DBM
+ # -DNEWDB -- use new Berkeley DB
+ # -DNDBM -DNEWDB -DYPCOMPAT -- use both plus YP compatility
+ # -DNIS -- include client NIS support
+ # The really old (V7) DBM library is no longer supported.
+ # See READ_ME for a description of how these flags interact.
+ #DBMDEF= -DNDBM -DNEWDB
+ DBMDEF= -DNDBM -DNIS
+
+ # environment definitions (e.g., -D_AIX3)
+ ENVDEF=
+
+ # see also conf.h for additional compilation flags
+
+ # library directories
+ LIBDIRS=-L/usr/local/lib
+
+ # libraries required on your system
+ #LIBS= -ldb -ldbm
+ LIBS= -ldbm -lresolv
+
+ # location of sendmail binary (usually /usr/sbin or /usr/lib)
+ BINDIR= ${DESTDIR}/usr/lib
+
+ # location of sendmail.st file (usually /var/log or /usr/lib)
+ STDIR= ${DESTDIR}/etc
+
+ # location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+ HFDIR= ${DESTDIR}/usr/lib
+
+For the resolver library, you can use the one shipped with Sun if you
+want. But I'd recommend using another version of the resolver library
+(such as the one with Bind 4.8.3 or 4.9). Sun's resolver stuff (at
+least with 4.1.x) is quite old - I believe it is of 4.3.1 vintage. (Do
+you get the impression I don't TRUST what Sun ships with their systems?)
+
+If you want NIS host lookup while maintaining DNS capability, you might
+take a look at resolv+, which has NIS capable gethostbyxxx() functions
+in it. My recommendation, however, is to avoid doing NIS host lookups
+in sendmail altogether, and to use a "pure" version of the resolver
+library.
+
+There are probably no situations (at least I think so) where it makes
+any sense to link in Sun's NIS gethostbyxxx() functions from libc.
+You could, I guess do it (I haven't tried it) and wind up with a
+sendmail equivalent to the non-mx version Sun ships. You'd need to
+insure that NAMED_BIND is not defined in the build. (If you do
+this and have the "-b" DNS passthru option set in NIS, remember that
+while you have some DNS functionality you'll not have any MX support.
+(This, IMO, is what makes this a non-optimal choice.)
+
+ INSTALLATION/TESTING ISSUES
+
+The sendmail.hf file in the src directory should replace the one currently
+in /usr/lib. You also might choose to edit it a bit to "localize" what it
+says.
+
+The sendmail executable goes, of course, in /usr/lib in place of the current
+one. What I did was create a subdirectory in /usr/lib and put all of the
+Sun sendmail stuff in there. I named the v8 sendmail executable to be
+sendmail.v8.mx and then symbolically linked it to sendmail.
+
+One other thing. If you use address test mode, keep in mind that
+Version 8 is like IDA in that it does not automatically execute ruleset
+3 first. So say you're playing around with things testing addresses and
+you're used to things like:
+
+ 0 jimbob@good.old.boy.com
+
+under v8 you need to say instead:
+
+ 3,0 jimbob@good.old.boy.com
+
+ INTEROPERABILITY ISSUES YOU MIGHT ENCOUNTER
+
+Be aware that sendmail v8 issues a multi-line SMTP welcome (220)
+response upon a client connection. Most systems in your network should
+handle it OK, but there are some that choke on it, because whoever wrote
+the clients assumed only a single line. THIS IS NOT SENDMAIL's FAULT.
+A multi-line 220 response is perfectly valid. A likely place you'll
+encounter this problem is with non-Un*x SMTP clients. If you do run
+into it, you should report it to the vendor.
+
+A final note about version 8 - if you follow the above configuration
+scenario, you'll notice it doesn't like to get envelope sender
+addresses it doesn't know how to get back to. Sun sendmail would take
+anything, even though it might not be able to bounce the message back
+should something happen downstream. So if another sendmail on a host
+that's not locally known is trying to pump mail through your v8 host,
+the ENVELOPE sender it gives had better be fully qualified. This is
+a GREAT thing, because it helps clear up problems we've had with not
+being able to get things back to the sender, resulting in an
+overburdened postmaster.
+
+I hope this helps those running Sun sendmail feel more at ease with moving
+on to v8. It's really worth going to.
diff --git a/usr.sbin/sendmail/contrib/expn.pl b/usr.sbin/sendmail/contrib/expn.pl
new file mode 100644
index 00000000000..a08f8d7e979
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/expn.pl
@@ -0,0 +1,1365 @@
+#!/usr/local/bin/perl
+'di ';
+'ds 00 \\"';
+'ig00 ';
+#
+# THIS PROGRAM IS ITS OWN MANUAL PAGE. INSTALL IN man & bin.
+#
+
+# hardcoded constants, should work fine for BSD-based systems
+$AF_INET = 2;
+$SOCK_STREAM = 1;
+$sockaddr = 'S n a4 x8';
+
+# system requirements:
+# must have 'nslookup' and 'hostname' programs.
+
+# Header: /home/muir/bin/RCS/expn,v 3.6 1994/02/23 22:26:19 muir Exp muir
+
+# TODO:
+# less magic should apply to command-line addresses
+# less magic should apply to local addresses
+# add magic to deal with cross-domain cnames
+
+# Checklist: (hard addresses)
+# 250 Kimmo Suominen <"|/usr/local/mh/lib/slocal -user kim"@grendel.tac.nyc.ny.us>
+# harry@hofmann.cs.Berkeley.EDU -> harry@tenet (.berkeley.edu) [dead]
+# bks@cs.berkeley.edu -> shiva.CS (.berkeley.edu) [dead]
+# dan@tc.cornell.edu -> brown@tiberius (.tc.cornell.edu)
+
+#############################################################################
+#
+# Copyright (c) 1993 David Muir Sharnoff
+# 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 David Muir Sharnoff.
+# 4. The name of David Sharnoff may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE DAVID MUIR SHARNOFF ``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 DAVID MUIR SHARNOFF 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.
+#
+# This copyright notice derrived from material copyrighted by the Regents
+# of the University of California.
+#
+# Contributions accepted.
+#
+#############################################################################
+
+# overall structure:
+# in an effort to not trace each address individually, but rather
+# ask each server in turn a whole bunch of questions, addresses to
+# be expanded are queued up.
+#
+# This means that all account w.r.t. an address must be stored in
+# various arrays. Generally these arrays are indexed by the
+# string "$addr *** $server" where $addr is the address to be
+# expanded "foo" or maybe "foo@bar" and $server is the hostname
+# of the SMTP server to contact.
+#
+
+# important global variables:
+#
+# @hosts : list of servers still to be contacted
+# $server : name of the current we are currently looking at
+# @users = $users{@hosts[0]} : addresses to expand at this server
+# $u = $users[0] : the current address being expanded
+# $names{"$users[0] *** $server"} : the 'name' associated with the address
+# $mxbacktrace{"$users[0] *** $server"} : record of mx expansion
+# $mx_secondary{$server} : other mx relays at the same priority
+# $domainify_fallback{"$users[0] *** $server"} : alternative names to try
+# instead of $server if $server doesn't work
+# $temporary_redirect{"$users[0] *** $server"} : when trying alternates,
+# temporarily channel all tries along current path
+# $giveup{$server} : do not bother expanding addresses at $server
+# $verbose : -v
+# $watch : -w
+# $vw : -v or -w
+# $debug : -d
+# $valid : -a
+# $levels : -1
+# S : the socket connection to $server
+
+$have_nslookup = 1; # we have the nslookup program
+$port = 'smtp';
+$av0 = $0;
+$0 = "$av0 - running hostname";
+$ENV{'PATH'} .= ":/usr/etc" unless $ENV{'PATH'} =~ m,/usr/etc,;
+chop($hostname = `hostname`);
+select(STDERR);
+
+$usage = "Usage: $av0 [-1avwd] user[@host] [user2[host2] ...]";
+$0 = "$av0 - parsing args";
+for $a (@ARGV) {
+ die $usage if $a eq "-";
+ while ($a =~ s/^(-.*)([1avwd])/$1/) {
+ eval '$'."flag_$2 += 1";
+ }
+ next if $a eq "-";
+ die $usage if $a =~ /^-/;
+ &expn(&parse($a,$hostname,undef,1));
+}
+$verbose = $flag_v;
+$watch = $flag_w;
+$vw = $flag_v + $flag_w;
+$debug = $flag_d;
+$valid = $flag_a;
+$levels = $flag_1;
+
+die $usage unless @hosts;
+if ($valid) {
+ if ($valid == 1) {
+ $validRequirement = 0.8;
+ } elsif ($valid == 2) {
+ $validRequirement = 1.0;
+ } elsif ($valid == 3) {
+ $validRequirement = 0.9;
+ } else {
+ $validRequirement = (1 - (1/($valid-3)));
+ print "validRequirement = $validRequirement\n" if $debug;
+ }
+}
+
+$0 = "$av0 - building local socket";
+($name,$aliases,$proto) = getprotobyname('tcp');
+($name,$aliases,$port) = getservbyname($port,'tcp')
+ unless $port =~ /^\d+/;
+($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);
+$this = pack($sockaddr, $AF_INET, 0, $thisaddr);
+
+HOST:
+while (@hosts) {
+ $server = shift(@hosts);
+ @users = split(' ',$users{$server});
+ delete $users{$server};
+
+ # is this server already known to be bad?
+ $0 = "$av0 - looking up $server";
+ if ($giveup{$server}) {
+ &giveup('mx domainify',$giveup{$server});
+ next;
+ }
+
+ # do we already have an mx record for this host?
+ next HOST if &mxredirect($server,*users);
+
+ # look it up, or try for an mx.
+ $0 = "$av0 - gethostbyname($server)";
+
+ ($name,$aliases,$type,$len,$thataddr) = gethostbyname($server);
+ # if we can't get an A record, try for an MX record.
+ unless($thataddr) {
+ &mxlookup(1,$server,"$server: could not resolve name",*users);
+ next HOST;
+ }
+
+ # get a connection, or look for an mx
+ $0 = "$av0 - socket to $server";
+ $that = pack($sockaddr, $AF_INET, $port, $thataddr);
+ socket(S, $AF_INET, $SOCK_STREAM, $proto)
+ || die "socket: $!";
+ $0 = "$av0 - bind to $server";
+ bind(S, $this)
+ || die "bind $hostname,0: $!";
+ $0 = "$av0 - connect to $server";
+ print "debug = $debug server = $server\n" if $debug > 8;
+ if (! connect(S, $that) || ($debug == 10 && $server =~ /relay\d.UU.NET$/i)) {
+ $0 = "$av0 - $server: could not connect: $!\n";
+ $emsg = $!;
+ unless (&mxlookup(0,$server,"$server: could not connect: $!",*users)) {
+ &giveup('mx',"$server: Could not connect: $emsg");
+ }
+ next HOST;
+ }
+ select((select(S),$| = 1)[0]); # don't buffer output to S
+
+ # read the greeting
+ $0 = "$av0 - talking to $server";
+ &alarm("greeting with $server",'');
+ while(<S>) {
+ alarm(0);
+ print if $watch;
+ if (/^(\d+)([- ])/) {
+ if ($1 != 220) {
+ $0 = "$av0 - bad numeric responce from $server";
+ &alarm("giving up after bet responce from $server",'');
+ &read_response($2,$watch);
+ alarm(0);
+ print STDERR "$server: NOT 220 greeting: $_"
+ if ($debug || $vw);
+ if (&mxlookup(0,$server,"$server: did not respond with a 220 greeting",*users)) {
+ close(S);
+ next HOST;
+ }
+ }
+ last if ($2 eq " ");
+ } else {
+ $0 = "$av0 - bad responce from $server";
+ print STDERR "$server: NOT 220 greeting: $_"
+ if ($debug || $vw);
+ unless (&mxlookup(0,$server,"$server: did not respond with SMTP codes",*users)) {
+ &giveup('',"$server: did not talk SMTP");
+ }
+ close(S);
+ next HOST;
+ }
+ &alarm("greeting with $server",'');
+ }
+ alarm(0);
+
+ # if this causes problems, remove it
+ $0 = "$av0 - sending helo to $server";
+ &alarm("sending helo to $server","");
+ &ps("helo $hostname");
+ while(<S>) {
+ print if $watch;
+ last if /^\d+ /;
+ }
+ alarm(0);
+
+ # try the users, one by one
+ USER:
+ while(@users) {
+ $u = shift(@users);
+ $0 = "$av0 - expanding $u [\@$server]";
+
+ # do we already have a name for this user?
+ $oldname = $names{"$u *** $server"};
+
+ print &compact($u,$server)." ->\n" if ($verbose && ! $valid);
+ if ($valid) {
+ #
+ # when running with -a, we delay taking any action
+ # on the results of our query until we have looked
+ # at the complete output. @toFinal stores expansions
+ # that will be final if we take them. @toExpn stores
+ # expnansions that are not final. @isValid keeps
+ # track of our ability to send mail to each of the
+ # expansions.
+ #
+ @isValid = ();
+ @toFinal = ();
+ @toExpn = ();
+ }
+
+ ($ecode,@expansion) = &expn_vrfy($u,$server);
+ if ($ecode) {
+ &giveup('',$ecode,$u);
+ last USER;
+ }
+
+ for $s (@expansion) {
+ $s =~ s/[\n\r]//g;
+ $0 = "$av0 - parsing $server: $s";
+
+ $skipwatch = $watch;
+
+ if ($s =~ /^[25]51([- ]).*<(.+)>/) {
+ print "$s" if $watch;
+ print "(pretending 250$1<$2>)" if ($debug && $watch);
+ print "\n" if $watch;
+ $s = "250$1<$2>";
+ $skipwatch = 0;
+ }
+
+ if ($s =~ /^250([- ])(.+)/) {
+ print "$s\n" if $skipwatch;
+ ($done,$addr) = ($1,$2);
+ ($newhost, $newaddr, $newname) = &parse($addr,$server,$oldname, $#expansion == 0);
+ print "($newhost, $newaddr, $newname) = &parse($addr, $server, $oldname)\n" if $debug;
+ if (! $newhost) {
+ # no expansion is possible w/o a new server to call
+ if ($valid) {
+ push(@isValid, &validAddr($newaddr));
+ push(@toFinal,$newaddr,$server,$newname);
+ } else {
+ &verbose(&final($newaddr,$server,$newname));
+ }
+ } else {
+ $newmxhost = &mx($newhost,$newaddr);
+ print "$newmxhost = &mx($newhost)\n"
+ if ($debug && $newhost ne $newmxhost);
+ $0 = "$av0 - parsing $newaddr [@$newmxhost]";
+ print "levels = $levels, level{$u *** $server} = ".$level{"$u *** $server"}."\n" if ($debug > 1);
+ # If the new server is the current one,
+ # it would have expanded things for us
+ # if it could have. Mx records must be
+ # followed to compare server names.
+ # We are also done if the recursion
+ # count has been exceeded.
+ if (&trhost($newmxhost) eq &trhost($server) || ($levels && $level{"$u *** $server"} >= $levels)) {
+ if ($valid) {
+ push(@isValid, &validAddr($newaddr));
+ push(@toFinal,$newaddr,$newmxhost,$newname);
+ } else {
+ &verbose(&final($newaddr,$newmxhost,$newname));
+ }
+ } else {
+ # more work to do...
+ if ($valid) {
+ push(@isValid, &validAddr($newaddr));
+ push(@toExpn,$newmxhost,$newaddr,$newname,$level{"$u *** $server"});
+ } else {
+ &verbose(&expn($newmxhost,$newaddr,$newname,$level{"$u *** $server"}));
+ }
+ }
+ }
+ last if ($done eq " ");
+ next;
+ }
+ # 550 is a known code... Should the be
+ # included in -a output? Might be a bug
+ # here. Does it matter? Can assume that
+ # there won't be UNKNOWN USER responces
+ # mixed with valid users?
+ if ($s =~ /^(550)([- ])/) {
+ if ($valid) {
+ print STDERR "\@$server:$u ($oldname) USER UNKNOWN\n";
+ } else {
+ &verbose(&final($u,$server,$oldname,"USER UNKNOWN"));
+ }
+ last if ($2 eq " ");
+ next;
+ }
+ # 553 is a known code...
+ if ($s =~ /^(553)([- ])/) {
+ if ($valid) {
+ print STDERR "\@$server:$u ($oldname) USER AMBIGUOUS\n";
+ } else {
+ &verbose(&final($u,$server,$oldname,"USER AMBIGUOUS"));
+ }
+ last if ($2 eq " ");
+ next;
+ }
+ # 252 is a known code...
+ if ($s =~ /^(252)([- ])/) {
+ if ($valid) {
+ print STDERR "\@$server:$u ($oldname) REFUSED TO VRFY\n";
+ } else {
+ &verbose(&final($u,$server,$oldname,"REFUSED TO VRFY"));
+ }
+ last if ($2 eq " ");
+ next;
+ }
+ &giveup('',"$server: did not grok '$s'",$u);
+ last USER;
+ }
+
+ if ($valid) {
+ #
+ # now we decide if we are going to take these
+ # expansions or roll them back.
+ #
+ $avgValid = &average(@isValid);
+ print "avgValid = $avgValid\n" if $debug;
+ if ($avgValid >= $validRequirement) {
+ print &compact($u,$server)." ->\n" if $verbose;
+ while (@toExpn) {
+ &verbose(&expn(splice(@toExpn,0,4)));
+ }
+ while (@toFinal) {
+ &verbose(&final(splice(@toFinal,0,3)));
+ }
+ } else {
+ print "Tossing some valid to avoid invalid ".&compact($u,$server)."\n" if ($avgValid > 0.0 && ($vw || $debug));
+ print &compact($u,$server)." ->\n" if $verbose;
+ &verbose(&final($u,$server,$newname));
+ }
+ }
+ }
+
+ &alarm("sending 'quit' to $server",'');
+ $0 = "$av0 - sending 'quit' to $server";
+ &ps("quit");
+ while(<S>) {
+ print if $watch;
+ last if /^\d+ /;
+ }
+ close(S);
+ alarm(0);
+}
+
+$0 = "$av0 - printing final results";
+print "----------\n" if $vw;
+select(STDOUT);
+for $f (sort @final) {
+ print "$f\n";
+}
+unlink("/tmp/expn$$");
+exit(0);
+
+
+# abandon all attempts deliver to $server
+# register the current addresses as the final ones
+sub giveup
+{
+ local($redirect_okay,$reason,$user) = @_;
+ local($us,@so,$nh,@remaining_users);
+
+ $0 = "$av0 - giving up on $server: $reason";
+ #
+ # add back a user if we gave up in the middle
+ #
+ push(@users,$user) if $user;
+ #
+ # don't bother with this system anymore
+ #
+ unless ($giveup{$server}) {
+ $giveup{$server} = $reason;
+ print STDERR "$reason\n";
+ }
+ print "Giveup!!! redirect okay = $redirect_okay; $reason\n" if $debug;
+ #
+ # Wait!
+ # Before giving up, see if there is a chance that
+ # there is another host to redirect to!
+ # (Kids, don't do this at home! Hacking is a dangerous
+ # crime and you could end up behind bars.)
+ #
+ for $u (@users) {
+ if ($redirect_okay =~ /\bmx\b/) {
+ next if &try_fallback('mx',$u,*server,
+ *mx_secondary,
+ *already_mx_fellback);
+ }
+ if ($redirect_okay =~ /\bdomainify\b/) {
+ next if &try_fallback('domainify',$u,*server,
+ *domainify_fallback,
+ *already_domainify_fellback);
+ }
+ push(@remaining_users,$u);
+ }
+ @users = @remaining_users;
+ for $u (@users) {
+ print &compact($u,$server)." ->\n" if ($verbose && $valid && $u);
+ &verbose(&final($u,$server,$names{"$u *** $server"},$reason));
+ }
+}
+#
+# This routine is used only within &giveup. It checks to
+# see if we really have to giveup or if there is a second
+# chance because we did something before that can be
+# backtracked.
+#
+# %fallback{"$user *** $host"} tracks what is able to fallback
+# %fellback{"$user *** $host"} tracks what has fallen back
+#
+# If there is a valid backtrack, then queue up the new possibility
+#
+sub try_fallback
+{
+ local($method,$user,*host,*fall_table,*fellback) = @_;
+ local($us,$fallhost,$oldhost,$ft,$i);
+
+ if ($debug > 8) {
+ print "Fallback table $method:\n";
+ for $i (sort keys %fall_table) {
+ print "\t'$i'\t\t'$fall_table{$i}'\n";
+ }
+ print "Fellback table $method:\n";
+ for $i (sort keys %fellback) {
+ print "\t'$i'\t\t'$fellback{$i}'\n";
+ }
+ print "U: $user H: $host\n";
+ }
+
+ $us = "$user *** $host";
+ if (defined $fellback{$us}) {
+ #
+ # Undo a previous fallback so that we can try again
+ # Nest fallbacks are avoided because they could
+ # lead to infinite loops
+ #
+ $fallhost = $fellback{$us};
+ print "Already $method fell back from $us -> \n" if $debug;
+ $us = "$user *** $fallhost";
+ $oldhost = $fallhost;
+ } elsif (($method eq 'mx') && (defined $mxbacktrace{$us}) && (defined $mx_secondary{$mxbacktrace{$us}})) {
+ print "Fallback an MX expansion $us -> \n" if $debug;
+ $oldhost = $mxbacktrace{$us};
+ } else {
+ print "Oldhost($host, $us) = " if $debug;
+ $oldhost = $host;
+ }
+ print "$oldhost\n" if $debug;
+ if (((defined $fall_table{$us}) && ($ft = $us)) || ((defined $fall_table{$oldhost}) && ($ft = $oldhost))) {
+ print "$method Fallback = ".$fall_table{$ft}."\n" if $debug;
+ local(@so,$newhost);
+ @so = split(' ',$fall_table{$ft});
+ $newhost = shift(@so);
+ print "Falling back ($method) $us -> $newhost (from $oldhost)\n" if $debug;
+ if ($method eq 'mx') {
+ if (! defined ($mxbacktrace{"$user *** $newhost"})) {
+ if (defined $mxbacktrace{"$user *** $oldhost"}) {
+ print "resetting oldhost $oldhost to the original: " if $debug;
+ $oldhost = $mxbacktrace{"$user *** $oldhost"};
+ print "$oldhost\n" if $debug;
+ }
+ $mxbacktrace{"$user *** $newhost"} = $oldhost;
+ print "mxbacktrace $user *** $newhost -> $oldhost\n" if $debug;
+ }
+ $mx{&trhost($oldhost)} = $newhost;
+ } else {
+ $temporary_redirect{$us} = $newhost;
+ }
+ if (@so) {
+ print "Can still $method $us: @so\n" if $debug;
+ $fall_table{$ft} = join(' ',@so);
+ } else {
+ print "No more fallbacks for $us\n" if $debug;
+ delete $fall_table{$ft};
+ }
+ if (defined $create_host_backtrack{$us}) {
+ $create_host_backtrack{"$user *** $newhost"}
+ = $create_host_backtrack{$us};
+ }
+ $fellback{"$user *** $newhost"} = $oldhost;
+ &expn($newhost,$user,$names{$us},$level{$us});
+ return 1;
+ }
+ delete $temporary_redirect{$us};
+ $host = $oldhost;
+ return 0;
+}
+# return 1 if you could send mail to the address as is.
+sub validAddr
+{
+ local($addr) = @_;
+ $res = &do_validAddr($addr);
+ print "validAddr($addr) = $res\n" if $debug;
+ $res;
+}
+sub do_validAddr
+{
+ local($addr) = @_;
+ local($urx) = "[-A-Za-z_.0-9+]+";
+
+ # \u
+ return 0 if ($addr =~ /^\\/);
+ # ?@h
+ return 1 if ($addr =~ /.\@$urx$/);
+ # @h:?
+ return 1 if ($addr =~ /^\@$urx\:./);
+ # h!u
+ return 1 if ($addr =~ /^$urx!./);
+ # u
+ return 1 if ($addr =~ /^$urx$/);
+ # ?
+ print "validAddr($addr) = ???\n" if $debug;
+ return 0;
+}
+# Some systems use expn and vrfy interchangeably. Some only
+# implement one or the other. Some check expn against mailing
+# lists and vrfy against users. It doesn't appear to be
+# consistent.
+#
+# So, what do we do? We try everything!
+#
+#
+# Ranking of result codes: good: 250, 251/551, 252, 550, anything else
+#
+# Ranking of inputs: best: user@host.domain, okay: user
+#
+# Return value: $error_string, @responces_from_server
+sub expn_vrfy
+{
+ local($u,$server) = @_;
+ local(@c) = ('expn', 'vrfy');
+ local(@try_u) = $u;
+ local(@ret,$code);
+
+ if (($u =~ /(.+)@(.+)/) && (&trhost($2) eq &trhost($server))) {
+ push(@try_u,$1);
+ }
+
+ TRY:
+ for $c (@c) {
+ for $try_u (@try_u) {
+ &alarm("$c'ing $try_u on $server",'',$u);
+ &ps("$c $try_u");
+ alarm(0);
+ $s = <S>;
+ if ($s eq '') {
+ return "$server: lost connection";
+ }
+ if ($s !~ /^(\d+)([- ])/) {
+ return "$server: garbled reply to '$c $try_u'";
+ }
+ if ($1 == 250) {
+ $code = 250;
+ @ret = ("",$s);
+ push(@ret,&read_response($2,$debug));
+ return @ret;
+ }
+ if ($1 == 551 || $1 == 251) {
+ $code = $1;
+ @ret = ("",$s);
+ push(@ret,&read_response($2,$debug));
+ next;
+ }
+ if ($1 == 252 && ($code == 0 || $code == 550)) {
+ $code = 252;
+ @ret = ("",$s);
+ push(@ret,&read_response($2,$watch));
+ next;
+ }
+ if ($1 == 550 && $code == 0) {
+ $code = 550;
+ @ret = ("",$s);
+ push(@ret,&read_response($2,$watch));
+ next;
+ }
+ &read_response($2,$watch);
+ }
+ }
+ return "$server: expn/vrfy not implemented" unless @ret;
+ return @ret;
+}
+# sometimes the old parse routine (now parse2) didn't
+# reject funky addresses.
+sub parse
+{
+ local($oldaddr,$server,$oldname,$one_to_one) = @_;
+ local($newhost, $newaddr, $newname, $um) = &parse2($oldaddr,$server,$oldname,$one_to_one);
+ if ($newaddr =~ m,^["/],) {
+ return (undef, $oldaddr, $newname) if $valid;
+ return (undef, $um, $newname);
+ }
+ return ($newhost, $newaddr, $newname);
+}
+
+# returns ($new_smtp_server,$new_address,$new_name)
+# given a responce from a SMTP server ($newaddr), the
+# current host ($server), the old "name" and a flag that
+# indicates if it is being called during the initial
+# command line parsing ($parsing_args)
+sub parse2
+{
+ local($newaddr,$context_host,$old_name,$parsing_args) = @_;
+ local(@names) = $old_name;
+ local($urx) = "[-A-Za-z_.0-9+]+";
+ local($unmangle);
+
+ #
+ # first, separate out the address part.
+ #
+
+ #
+ # [NAME] <ADDR [(NAME)]>
+ # [NAME] <[(NAME)] ADDR
+ # ADDR [(NAME)]
+ # (NAME) ADDR
+ # [(NAME)] <ADDR>
+ #
+ if ($newaddr =~ /^\<(.*)\>$/) {
+ print "<A:$1>\n" if $debug;
+ $newaddr = &trim($1);
+ print "na = $newaddr\n" if $debug;
+ }
+ if ($newaddr =~ /^([^\<\>]*)\<([^\<\>]*)\>([^\<\>]*)$/) {
+ # address has a < > pair in it.
+ print "N:$1 <A:$2> N:$3\n" if $debug;
+ $newaddr = &trim($2);
+ unshift(@names, &trim($3,$1));
+ print "na = $newaddr\n" if $debug;
+ }
+ if ($newaddr =~ /^([^\(\)]*)\(([^\(\)]*)\)([^\(\)]*)$/) {
+ # address has a ( ) pair in it.
+ print "A:$1 (N:$2) A:$3\n" if $debug;
+ unshift(@names,&trim($2));
+ local($f,$l) = (&trim($1),&trim($3));
+ if (($f && $l) || !($f || $l)) {
+ # address looks like:
+ # foo (bar) baz or (bar)
+ # not allowed!
+ print STDERR "Could not parse $newaddr\n" if $vw;
+ return(undef,$newaddr,&firstname(@names));
+ }
+ $newaddr = $f if $f;
+ $newaddr = $l if $l;
+ print "newaddr now = $newaddr\n" if $debug;
+ }
+ #
+ # @foo:bar
+ # j%k@l
+ # a@b
+ # b!a
+ # a
+ #
+ $unmangle = $newaddr;
+ if ($newaddr =~ /^\@($urx)\:(.+)$/) {
+ print "(\@:)" if $debug;
+ # this is a bit of a cheat, but it seems necessary
+ return (&domainify($1,$context_host,$2),$2,&firstname(@names),$unmangle);
+ }
+ if ($newaddr =~ /^(.+)\@($urx)$/) {
+ print "(\@)" if $debug;
+ return (&domainify($2,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle);
+ }
+ if ($parsing_args) {
+ if ($newaddr =~ /^($urx)\!(.+)$/) {
+ return (&domainify($1,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle);
+ }
+ if ($newaddr =~ /^($urx)$/) {
+ return ($context_host,$newaddr,&firstname(@names),$unmangle);
+ }
+ print STDERR "Could not parse $newaddr\n";
+ }
+ print "(?)" if $debug;
+ return(undef,$newaddr,&firstname(@names),$unmangle);
+}
+# return $u (@$server) unless $u includes reference to $server
+sub compact
+{
+ local($u, $server) = @_;
+ local($se) = $server;
+ local($sp);
+ $se =~ s/(\W)/\\$1/g;
+ $sp = " (\@$server)";
+ if ($u !~ /$se/i) {
+ return "$u$sp";
+ }
+ return $u;
+}
+# remove empty (spaces don't count) members from an array
+sub trim
+{
+ local(@v) = @_;
+ local($v,@r);
+ for $v (@v) {
+ $v =~ s/^\s+//;
+ $v =~ s/\s+$//;
+ push(@r,$v) if ($v =~ /\S/);
+ }
+ return(@r);
+}
+# using the host part of an address, and the server name, add the
+# servers' domain to the address if it doesn't already have a
+# domain. Since this sometimes failes, save a back reference so
+# it can be unrolled.
+sub domainify
+{
+ local($host,$domain_host,$u) = @_;
+ local($domain,$newhost);
+
+ # cut of trailing dots
+ $host =~ s/\.$//;
+ $domain_host =~ s/\.$//;
+
+ if ($domain_host !~ /\./) {
+ #
+ # domain host isn't, keep $host whatever it is
+ #
+ print "domainify($host,$domain_host) = $host\n" if $debug;
+ return $host;
+ }
+
+ #
+ # There are several weird situtations that need to be
+ # accounted for. They have to do with domain relay hosts.
+ #
+ # Examples:
+ # host server "right answer"
+ #
+ # shiva.cs cs.berkeley.edu shiva.cs.berkeley.edu
+ # shiva cs.berkeley.edu shiva.cs.berekley.edu
+ # cumulus reed.edu @reed.edu:cumulus.uucp
+ # tiberius tc.cornell.edu tiberius.tc.cornell.edu
+ #
+ # The first try must always be to cut the domain part out of
+ # the server and tack it onto the host.
+ #
+ # A reasonable second try is to tack the whole server part onto
+ # the host and for each possible repeated element, eliminate
+ # just that part.
+ #
+ # These extra "guesses" get put into the %domainify_fallback
+ # array. They will be used to give addresses a second chance
+ # in the &giveup routine
+ #
+
+ local(%fallback);
+
+ local($long);
+ $long = "$host $domain_host";
+ $long =~ tr/A-Z/a-z/;
+ print "long = $long\n" if $debug;
+ if ($long =~ s/^([^ ]+\.)([^ ]+) \2(\.[^ ]+\.[^ ]+)/$1$2$3/) {
+ # matches shiva.cs cs.berkeley.edu and returns shiva.cs.berkeley.edu
+ print "condensed fallback $host $domain_host -> $long\n" if $debug;
+ $fallback{$long} = 9;
+ }
+
+ local($fh);
+ $fh = $domain_host;
+ while ($fh =~ /\./) {
+ print "FALLBACK $host.$fh = 1\n" if $debug > 7;
+ $fallback{"$host.$fh"} = 1;
+ $fh =~ s/^[^\.]+\.//;
+ }
+
+ $fallback{"$host.$domain_host"} = 2;
+
+ ($domain = $domain_host) =~ s/^[^\.]+//;
+ $fallback{"$host$domain"} = 6
+ if ($domain =~ /\./);
+
+ if ($host =~ /\./) {
+ #
+ # Host is already okay, but let's look for multiple
+ # interpretations
+ #
+ print "domainify($host,$domain_host) = $host\n" if $debug;
+ delete $fallback{$host};
+ $domainify_fallback{"$u *** $host"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback;
+ return $host;
+ }
+
+ $domain = ".$domain_host"
+ if ($domain !~ /\..*\./);
+ $newhost = "$host$domain";
+
+ $create_host_backtrack{"$u *** $newhost"} = $domain_host;
+ print "domainify($host,$domain_host) = $newhost\n" if $debug;
+ delete $fallback{$newhost};
+ $domainify_fallback{"$u *** $newhost"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback;
+ if ($debug) {
+ print "fallback = ";
+ print $domainify_fallback{"$u *** $newhost"}
+ if defined($domainify_fallback{"$u *** $newhost"});
+ print "\n";
+ }
+ return $newhost;
+}
+# return the first non-empty element of an array
+sub firstname
+{
+ local(@names) = @_;
+ local($n);
+ while(@names) {
+ $n = shift(@names);
+ return $n if $n =~ /\S/;
+ }
+ return undef;
+}
+# queue up more addresses to expand
+sub expn
+{
+ local($host,$addr,$name,$level) = @_;
+ if ($host) {
+ $host = &trhost($host);
+
+ if (($debug > 3) || (defined $giveup{$host})) {
+ unshift(@hosts,$host) unless $users{$host};
+ } else {
+ push(@hosts,$host) unless $users{$host};
+ }
+ $users{$host} .= " $addr";
+ $names{"$addr *** $host"} = $name;
+ $level{"$addr *** $host"} = $level + 1;
+ print "expn($host,$addr,$name)\n" if $debug;
+ return "\t$addr\n";
+ } else {
+ return &final($addr,'NONE',$name);
+ }
+}
+# compute the numerical average value of an array
+sub average
+{
+ local(@e) = @_;
+ return 0 unless @e;
+ local($e,$sum);
+ for $e (@e) {
+ $sum += $e;
+ }
+ $sum / @e;
+}
+# print to the server (also to stdout, if -w)
+sub ps
+{
+ local($p) = @_;
+ print ">>> $p\n" if $watch;
+ print S "$p\n";
+}
+# return case-adjusted name for a host (for comparison purposes)
+sub trhost
+{
+ # treat foo.bar as an alias for Foo.BAR
+ local($host) = @_;
+ local($trhost) = $host;
+ $trhost =~ tr/A-Z/a-z/;
+ if ($trhost{$trhost}) {
+ $host = $trhost{$trhost};
+ } else {
+ $trhost{$trhost} = $host;
+ }
+ $trhost{$trhost};
+}
+# re-queue users if an mx record dictates a redirect
+# don't allow a user to be redirected more than once
+sub mxredirect
+{
+ local($server,*users) = @_;
+ local($u,$nserver,@still_there);
+
+ $nserver = &mx($server);
+
+ if (&trhost($nserver) ne &trhost($server)) {
+ $0 = "$av0 - mx redirect $server -> $nserver\n";
+ for $u (@users) {
+ if (defined $mxbacktrace{"$u *** $nserver"}) {
+ push(@still_there,$u);
+ } else {
+ $mxbacktrace{"$u *** $nserver"} = $server;
+ print "mxbacktrace{$u *** $nserver} = $server\n"
+ if ($debug > 1);
+ &expn($nserver,$u,$names{"$u *** $server"});
+ }
+ }
+ @users = @still_there;
+ if (! @users) {
+ return $nserver;
+ } else {
+ return undef;
+ }
+ }
+ return undef;
+}
+# follow mx records, return a hostname
+# also follow temporary redirections comming from &domainify and
+# &mxlookup
+sub mx
+{
+ local($h,$u) = @_;
+
+ for (;;) {
+ if (defined $mx{&trhost($h)} && $h ne $mx{&trhost($h)}) {
+ $0 = "$av0 - mx expand $h";
+ $h = $mx{&trhost($h)};
+ return $h;
+ }
+ if ($u) {
+ if (defined $temporary_redirect{"$u *** $h"}) {
+ $0 = "$av0 - internal redirect $h";
+ print "Temporary redirect taken $u *** $h -> " if $debug;
+ $h = $temporary_redirect{"$u *** $h"};
+ print "$h\n" if $debug;
+ next;
+ }
+ $htr = &trhost($h);
+ if (defined $temporary_redirect{"$u *** $htr"}) {
+ $0 = "$av0 - internal redirect $h";
+ print "temporary redirect taken $u *** $h -> " if $debug;
+ $h = $temporary_redirect{"$u *** $htr"};
+ print "$h\n" if $debug;
+ next;
+ }
+ }
+ return $h;
+ }
+}
+# look up mx records with the name server.
+# re-queue expansion requests if possible
+# optionally give up on this host.
+sub mxlookup
+{
+ local($lastchance,$server,$giveup,*users) = @_;
+ local(*T);
+ local(*NSLOOKUP);
+ local($nh, $pref,$cpref);
+ local($o0) = $0;
+ local($nserver);
+ local($name,$aliases,$type,$len,$thataddr);
+ local(%fallback);
+
+ return 1 if &mxredirect($server,*users);
+
+ if ((defined $mx{$server}) || (! $have_nslookup)) {
+ return 0 unless $lastchance;
+ &giveup('mx domainify',$giveup);
+ return 0;
+ }
+
+ $0 = "$av0 - nslookup of $server";
+ open(T,">/tmp/expn$$") || die "open > /tmp/expn$$: $!\n";
+ print T "set querytype=MX\n";
+ print T "$server\n";
+ close(T);
+ $cpref = 1.0E12;
+ undef $nserver;
+ open(NSLOOKUP,"nslookup < /tmp/expn$$ 2>&1 |") || die "open nslookup: $!";
+ while(<NSLOOKUP>) {
+ print if ($debug > 2);
+ if (/mail exchanger = ([-A-Za-z_.0-9+]+)/) {
+ $nh = $1;
+ if (/preference = (\d+)/) {
+ $pref = $1;
+ if ($pref < $cpref) {
+ $nserver = $nh;
+ $cpref = $pref;
+ } elsif ($pref) {
+ $fallback{$pref} .= " $nh";
+ }
+ }
+ }
+ if (/Non-existent domain/) {
+ #
+ # These addresss are hosed. Kaput! Dead!
+ # However, if we created the address in the
+ # first place then there is a chance of
+ # salvation.
+ #
+ 1 while(<NSLOOKUP>);
+ close(NSLOOKUP);
+ return 0 unless $lastchance;
+ &giveup('domainify',"$server: Non-existent domain",undef,1);
+ return 0;
+ }
+
+ }
+ close(NSLOOKUP);
+ unlink("/tmp/expn$$");
+ unless ($nserver) {
+ $0 = "$o0 - finished mxlookup";
+ return 0 unless $lastchance;
+ &giveup('mx domainify',"$server: Could not resolve address");
+ return 0;
+ }
+
+ # provide fallbacks in case $nserver doesn't work out
+ if (defined $fallback{$cpref}) {
+# for $u (@users) {
+# print "mx_secondary{$u *** $nserver} = ".$fallback{$cpref}."\n"
+# if $debug;
+# $mx_secondary{"$u *** $nserver"} = $fallback{$cpref};
+# }
+ $mx_secondary{$server} = $fallback{$cpref};
+ }
+
+ $0 = "$av0 - gethostbyname($nserver)";
+ ($name,$aliases,$type,$len,$thataddr) = gethostbyname($nserver);
+
+ unless ($thataddr) {
+ $0 = $o0;
+ return 0 unless $lastchance;
+ &giveup('mx domainify',"$nserver: could not resolve address");
+ return 0;
+ }
+ print "MX($server) = $nserver\n" if $debug;
+ print "$server -> $nserver\n" if $vw && !$debug;
+ $mx{&trhost($server)} = $nserver;
+ # redeploy the users
+ unless (&mxredirect($server,*users)) {
+ return 0 unless $lastchance;
+ &giveup('mx domainify',"$nserver: only one level of mx redirect allowed");
+ return 0;
+ }
+ $0 = "$o0 - finished mxlookup";
+ return 1;
+}
+# if mx expansion did not help to resolve an address
+# (ie: foo@bar became @baz:foo@bar, then undo the
+# expansion).
+# this is only used by &final
+sub mxunroll
+{
+ local(*host,*addr) = @_;
+ local($r) = 0;
+ print "looking for mxbacktrace{$addr *** $host}\n"
+ if ($debug > 1);
+ while (defined $mxbacktrace{"$addr *** $host"}) {
+ print "Unrolling MX expnasion: \@$host:$addr -> "
+ if ($debug || $verbose);
+ $host = $mxbacktrace{"$addr *** $host"};
+ print "\@$host:$addr\n"
+ if ($debug || $verbose);
+ $r = 1;
+ }
+ return 1 if $r;
+ $addr = "\@$host:$addr"
+ if ($host =~ /\./);
+ return 0;
+}
+# register a completed expnasion. Make the final address as
+# simple as possible.
+sub final
+{
+ local($addr,$host,$name,$error) = @_;
+ local($he);
+ local($hb,$hr);
+ local($au,$ah);
+
+ if ($error =~ /Non-existent domain/) {
+ #
+ # If we created the domain, then let's undo the
+ # damage...
+ #
+ if (defined $create_host_backtrack{"$addr *** $host"}) {
+ while (defined $create_host_backtrack{"$addr *** $host"}) {
+ print "Un&domainifying($host) = " if $debug;
+ $host = $create_host_backtrack{"$addr *** $host"};
+ print "$host\n" if $debug;
+ }
+ $error = "$host: could not locate";
+ } else {
+ #
+ # If we only want valid addresses, toss out
+ # bad host names.
+ #
+ if ($valid) {
+ print STDERR "\@$host:$addr ($name) Non-existent domain\n";
+ return "";
+ }
+ }
+ }
+
+ MXUNWIND: {
+ $0 = "$av0 - final parsing of \@$host:$addr";
+ ($he = $host) =~ s/(\W)/\\$1/g;
+ if ($addr !~ /@/) {
+ # addr does not contain any host
+ $addr = "$addr@$host";
+ } elsif ($addr !~ /$he/i) {
+ # if host part really something else, use the something
+ # else.
+ if ($addr =~ m/(.*)\@([^\@]+)$/) {
+ ($au,$ah) = ($1,$2);
+ print "au = $au ah = $ah\n" if $debug;
+ if (defined $temporary_redirect{"$addr *** $ah"}) {
+ $addr = "$au\@".$temporary_redirect{"$addr *** $ah"};
+ print "Rewrite! to $addr\n" if $debug;
+ next MXUNWIND;
+ }
+ }
+ # addr does not contain full host
+ if ($valid) {
+ if ($host =~ /^([^\.]+)(\..+)$/) {
+ # host part has a . in it - foo.bar
+ ($hb, $hr) = ($1, $2);
+ if ($addr =~ /\@([^\.\@]+)$/ && ($1 eq $hb)) {
+ # addr part has not .
+ # and matches beginning of
+ # host part -- tack on a
+ # domain name.
+ $addr .= $hr;
+ } else {
+ &mxunroll(*host,*addr)
+ && redo MXUNWIND;
+ }
+ } else {
+ &mxunroll(*host,*addr)
+ && redo MXUNWIND;
+ }
+ } else {
+ $addr = "${addr}[\@$host]"
+ if ($host =~ /\./);
+ }
+ }
+ }
+ $name = "$name " if $name;
+ $error = " $error" if $error;
+ if ($valid) {
+ push(@final,"$name<$addr>");
+ } else {
+ push(@final,"$name<$addr>$error");
+ }
+ "\t$name<$addr>$error\n";
+}
+
+sub alarm
+{
+ local($alarm_action,$alarm_redirect,$alarm_user) = @_;
+ alarm(3600);
+ $SIG{ALRM} = 'handle_alarm';
+}
+# this involves one GREAT hack.
+# the "next HOST" has to unwind the stack!
+sub handle_alarm
+{
+ &giveup($alarm_redirect,"Timed out during $alarm_action",$alarm_user);
+ next HOST;
+}
+
+# read the rest of the current smtp daemon's responce (and toss it away)
+sub read_response
+{
+ local($done,$watch) = @_;
+ local(@resp);
+ print $s if $watch;
+ while(($done eq "-") && ($s = <S>) && ($s =~ /^\d+([- ])/)) {
+ print $s if $watch;
+ $done = $1;
+ push(@resp,$s);
+ }
+ return @resp;
+}
+# print args if verbose. Return them in any case
+sub verbose
+{
+ local(@tp) = @_;
+ print "@tp" if $verbose;
+}
+# to pass perl -w:
+@tp;
+$flag_a;
+$flag_d;
+$flag_1;
+%already_domainify_fellback;
+%already_mx_fellback;
+&handle_alarm;
+################### BEGIN PERL/TROFF TRANSITION
+.00;
+
+'di \\ " finish diversion--previous line must be blank
+.nr nl 0-1 \\ " fake up transition to first page again
+.nr % 0 \\ " start at page 1
+.\\"'; __END__
+.\" ############## END PERL/TROFF TRANSITION
+.TH EXPN 1 "March 11, 1993"
+.AT 3
+.SH NAME
+expn \- recursively expand mail aliases
+.SH SYNOPSIS
+.B expn
+.RI [ -a ]
+.RI [ -v ]
+.RI [ -w ]
+.RI [ -d ]
+.RI [ -1 ]
+.IR user [@ hostname ]
+.RI [ user [@ hostname ]]...
+.SH DESCRIPTION
+.B expn
+will use the SMTP
+.B expn
+and
+.B vrfy
+commands to expand mail aliases.
+It will first look up the addresses you provide on the command line.
+If those expand into addresses on other systems, it will
+connect to the other systems and expand again. It will keep
+doing this until no further expansion is possible.
+.SH OPTIONS
+The default output of
+.B expn
+can contain many lines which are not valid
+email addresses. With the
+.I -aa
+flag, only expansions that result in legal addresses
+are used. Since many mailing lists have an illegal
+address or two, the single
+.IR -a ,
+address, flag specifies that a few illegal addresses can
+be mixed into the results. More
+.I -a
+flags vary the ratio. Read the source to track down
+the formula. With the
+.I -a
+option, you should be able to construct a new mailing
+list out of an existing one.
+.LP
+If you wish to limit the number of levels deep that
+.B expn
+will recurse as it traces addresses, use the
+.I -1
+option. For each
+.I -1
+another level will be traversed. So,
+.I -111
+will traverse no more than three levels deep.
+.LP
+The normal mode of operation for
+.B expn
+is to do all of its work silently.
+The following options make it more verbose.
+It is not necessary to make it verbose to see what it is
+doing because as it works, it changes its
+.BR argv [0]
+variable to reflect its current activity.
+To see how it is expanding things, the
+.IR -v ,
+verbose, flag will cause
+.B expn
+to show each address before
+and after translation as it works.
+The
+.IR -w ,
+watch, flag will cause
+.B expn
+to show you its conversations with the mail daemons.
+Finally, the
+.IR -d ,
+debug, flag will expose many of the inner workings so that
+it is possible to eliminate bugs.
+.SH ENVIRONMENT
+No enviroment variables are used.
+.SH FILES
+.PD 0
+.B /tmp/expn$$
+.B temporary file used as input to
+.BR nslookup .
+.SH SEE ALSO
+.BR aliases (5),
+.BR sendmail (8),
+.BR nslookup (8),
+RFC 823, and RFC 1123.
+.SH BUGS
+Not all mail daemons will implement
+.B expn
+or
+.BR vrfy .
+It is not possible to verify addresses that are served
+by such daemons.
+.LP
+When attempting to connect to a system to verify an address,
+.B expn
+only tries one IP address. Most mail daemons
+will try harder.
+.LP
+It is assumed that you are running domain names and that
+the
+.BR nslookup (8)
+program is available. If not,
+.B expn
+will not be able to verify many addresses. It will also pause
+for a long time unless you change the code where it says
+.I $have_nslookup = 1
+to read
+.I $have_nslookup =
+.IR 0 .
+.LP
+Lastly,
+.B expn
+does not handle every valid address. If you have an example,
+please submit a bug report.
+.SH CREDITS
+In 1986 or so, Jon Broome wrote a program of the same name
+that did about the same thing. It has since suffered bit rot
+and Jon Broome has dropped off the face of the earth!
+(Jon, if you are out there, drop me a line)
+.SH AVAILABILITY
+The latest version of
+.B expn
+is available through anonymous ftp to
+.IR idiom.berkeley.ca.us .
+.SH AUTHOR
+.I David Muir Sharnoff\ \ \ \ <muir@idiom.berkeley.ca.us>
diff --git a/usr.sbin/sendmail/contrib/mh.patch b/usr.sbin/sendmail/contrib/mh.patch
new file mode 100644
index 00000000000..7b23a5b71dd
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/mh.patch
@@ -0,0 +1,193 @@
+Message-Id: <199309031900.OAA19417@ignatz.acs.depaul.edu>
+To: bug-mh@ics.uci.edu
+cc: mh-users@ics.uci.edu, eric@cs.berkeley.edu
+Subject: MH-6.8.1/Sendmail 8.X (MH patch) updated
+Date: Fri, 03 Sep 1993 14:00:46 -0500
+From: Dave Nelson <dcn@ignatz.acs.depaul.edu>
+
+
+ This patch will fix the "X-auth..." warnings from the newer
+Sendmails (8.X) while continuing to work with the old sendmails.
+
+ I think the following patch will make everyone happy.
+
+ 1) Anybody with MH-6.8.1 can install this. It doesn't matter
+ what version of sendmail you're running. It doesn't matter
+ if you're not running sendmail (but it won't fix anything
+ for you).
+
+ 2) No configuration file hacks. If the -client switch is
+ absent (the default), the new sendmails will get an EHLO
+ using what LocalName() returns as the hostname. On my systems,
+ this returns the FQDN. If the EHLO fails with a result between
+ 500 and 599 and the -client switch is not set, we give up on
+ sending EHLO/HELO and just go deliver the mail.
+
+ 3) No new configuration options.
+
+ 4) Retains the undocumented -client switch. One warning: it
+ is possible using the -client switch to cause the old sendmails
+ to return "I refuse to talk to myself". You could do this under
+ the old code as well. This will happen if you claim to be the
+ same system as the sendmail you're sending to is running on.
+ That's pointless, but possible. If you do this, just like under
+ the old code, you will get an error.
+
+ 5) If you're running a site with both old and new sendmails, you only
+ have to build MH once. The code's the same; works with them
+ both.
+
+ If you decide to install this, make sure that you look the patch
+over and that you agree with what it is doing. It works for me, but I
+can't test it on every possible combination. Make sure that it works
+before you really install it for your users, if any. No promises.
+
+ To install this, save this to a file in the mts/sendmail directory.
+Feed it to patch. Patch will ignore the non-patch stuff. You should have
+"mts sendmail/smtp" in your configuration file. This works with old and
+new sendmails. Using "mts sendmail" will cause the new sendmails to
+print an "X-auth..." warning about who owns the process piping the mail
+message. I don't know of anyway of getting rid of these.
+
+ mh-config (if necessary), make, make inst-all.
+
+
+I hope this helps people.
+
+/dcn
+
+Dave Nelson
+Academic Computer Services
+DePaul University, Chicago
+
+*** smail.c Fri Sep 3 11:58:05 1993
+--- smail.c Fri Sep 3 11:57:27 1993
+***************
+*** 239,261 ****
+ return RP_RPLY;
+ }
+
+! if (client && *client) {
+! doingEHLO = 1;
+! result = smtalk (SM_HELO, "EHLO %s", client);
+! doingEHLO = 0;
+
+! if (500 <= result && result <= 599)
+ result = smtalk (SM_HELO, "HELO %s", client);
+!
+! switch (result) {
+ case 250:
+! break;
+
+ default:
+ (void) sm_end (NOTOK);
+ return RP_RPLY;
+ }
+ }
+
+ #ifndef ZMAILER
+ if (onex)
+--- 239,276 ----
+ return RP_RPLY;
+ }
+
+! doingEHLO = 1;
+! result = smtalk (SM_HELO, "EHLO %s",
+! (client && *client) ? client : LocalName());
+! doingEHLO = 0;
+!
+! switch (result)
+! {
+! case 250:
+! break;
+
+! default:
+! if (!(500 <= result && result <= 599))
+! {
+! (void) sm_end (NOTOK);
+! return RP_RPLY;
+! }
+!
+! if (client && *client)
+! {
+ result = smtalk (SM_HELO, "HELO %s", client);
+! switch (result)
+! {
+ case 250:
+! break;
+
+ default:
+ (void) sm_end (NOTOK);
+ return RP_RPLY;
++ }
+ }
+ }
++
+
+ #ifndef ZMAILER
+ if (onex)
+***************
+*** 357,380 ****
+ return RP_RPLY;
+ }
+
+! if (client && *client) {
+! doingEHLO = 1;
+! result = smtalk (SM_HELO, "EHLO %s", client);
+! doingEHLO = 0;
+
+! if (500 <= result && result <= 599)
+ result = smtalk (SM_HELO, "HELO %s", client);
+!
+! switch (result) {
+! case 250:
+ break;
+
+! default:
+ (void) sm_end (NOTOK);
+ return RP_RPLY;
+ }
+ }
+!
+ send_options: ;
+ if (watch && EHLOset ("XVRB"))
+ (void) smtalk (SM_HELO, "VERB on");
+--- 372,409 ----
+ return RP_RPLY;
+ }
+
+! doingEHLO = 1;
+! result = smtalk (SM_HELO, "EHLO %s",
+! (client && *client) ? client : LocalName());
+! doingEHLO = 0;
+!
+! switch (result)
+! {
+! case 250:
+! break;
+!
+! default:
+! if (!(500 <= result && result <= 599))
+! {
+! (void) sm_end (NOTOK);
+! return RP_RPLY;
+! }
+
+! if (client && *client)
+! {
+ result = smtalk (SM_HELO, "HELO %s", client);
+! switch (result)
+! {
+! case 250:
+ break;
+
+! default:
+ (void) sm_end (NOTOK);
+ return RP_RPLY;
++ }
+ }
+ }
+!
+ send_options: ;
+ if (watch && EHLOset ("XVRB"))
+ (void) smtalk (SM_HELO, "VERB on");
diff --git a/usr.sbin/sendmail/contrib/mmuegel b/usr.sbin/sendmail/contrib/mmuegel
new file mode 100644
index 00000000000..6db4a45189c
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/mmuegel
@@ -0,0 +1,2079 @@
+From: "Michael S. Muegel" <mmuegel@cssun6.corp.mot.com>
+Message-Id: <199307280818.AA08111@cssun6.corp.mot.com>
+Subject: Re: contributed software
+To: eric@cs.berkeley.edu (Eric Allman)
+Date: Wed, 28 Jul 1993 03:18:02 -0500 (CDT)
+In-Reply-To: <199307221853.LAA04266@mastodon.CS.Berkeley.EDU> from "Eric Allman" at Jul 22, 93 11:53:47 am
+X-Mailer: ELM [version 2.4 PL22]
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+Content-Length: 69132
+
+OK. Here is a new shell archive.
+
+Cheers,
+-Mike
+
+---- Cut Here and feed the following to sh ----
+#!/bin/sh
+# This is a shell archive (produced by shar 3.49)
+# To extract the files from this archive, save it to a file, remove
+# everything above the "!/bin/sh" line above, and type "sh file_name".
+#
+# made 07/28/1993 08:13 UTC by mmuegel@mot.com (Michael S. Muegel)
+# Source directory /home/ustart/NeXT/src/mail-tools/dist/foo
+#
+# existing files will NOT be overwritten unless -c is specified
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 4308 -r--r--r-- README
+# 12339 -r--r--r-- libs/date.pl
+# 3198 -r--r--r-- libs/elapsed.pl
+# 4356 -r--r--r-- libs/mail.pl
+# 6908 -r--r--r-- libs/mqueue.pl
+# 7024 -r--r--r-- libs/newgetopts.pl
+# 4687 -r--r--r-- libs/strings1.pl
+# 1609 -r--r--r-- libs/timespec.pl
+# 5212 -r--r--r-- man/cqueue.1
+# 2078 -r--r--r-- man/postclip.1
+# 6647 -r-xr-xr-x src/cqueue
+# 1836 -r-xr-xr-x src/postclip
+#
+# ============= README ==============
+if test -f 'README' -a X"$1" != X"-c"; then
+ echo 'x - skipping README (File already exists)'
+else
+echo 'x - extracting README (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'README' &&
+-------------------------------------------------------------------------------
+Document Revision Control Information:
+X mmuegel
+X /usr/local/ustart/src/mail-tools/dist/foo/README,v
+X 1.1 of 1993/07/28 08:12:53
+-------------------------------------------------------------------------------
+X
+1. Introduction
+---------------
+X
+These tools may be of use to those sites using sendmail. Both are written in
+Perl. Our site, Mot.COM, receives a ton of mail being a top-level domain
+gateway. We have over 24 domains under us. Needless to say, we must have
+a robust mail system or my head, and others, would be on the chopping block.
+X
+2. Description
+--------------
+X
+The first tool, cqueue, checks the sendmail queue for problems. We use
+it to flag problems with subdomain mail servers (and even our own servers
+once in a while ;-). We run it via a cron job every hour during the day.
+You may find this too frequent, however.
+X
+The other program, postclip, is used to "filter" non-deliverable NDNs that
+get sent to our Postmaster account now and then. This ensures privacy of
+e-mail and helps avoid disk problems from huge NDNs. It is different than
+a brute force "just keep the header" approach because it tries hard to keep
+other parts of the message that look like non-delivery information.
+X
+Both have been used for some time at our site with no problems. Everything
+you need should be in this distribution: source, manual pages, and support
+libs. See the manual pages for a complete description of each tool.
+X
+3. Installation
+---------------
+X
+No fancy Makefile simply because these tools are all under a large
+hierarchy at my site. Installation should be a snap, however. Install
+the nroff(1) man(5) manual pages from the man subdirectory to the
+appropriate directory on your system. This might be something like
+/usr/local/man/man1.
+X
+Next, install all of the Perl libraries located in the lib subdirectory
+to your Perl library area. /usr/local/lib/perl is a good bet. The person
+who installed Perl at your site will be able to tell you for sure.
+X
+Finally, you need to install the programs. Note that cqueue wants to
+run setuid root by default. This is because the sendmail queue is normally
+only readable by root or some special group. In order to let any user
+run this suidperl is used. suidperl allows a Perl program to run with the
+privileges of another user.
+X
+You will have to edit both the cqueue and postclip programs to change
+the #! line at the top of each. Just change the pathname to whatever is
+appropriate on your system. Note that Larry Wall's fixin program from
+the Camel book can also be used to do this. It is very handy. It changes
+#! lines by looking at your PATH.
+X
+If you do not have suidperl on your system change the #! line in cqueue
+to reference perl instead of suidperl.
+X
+You may also wish to change some constants in cqueue. $DEF_QUEUE should be
+changed to your queue directory if it is not /usr/spool/mqueue. $DEF_TIME
+could be changed easy enough also. It is the time spec for the time duration
+after which a mail message will be reported on if the -a option has not been
+specified. See the manual page for more information and the format of this
+constant (same as the -t argument). Then again, neither of these has to
+be changed. Command line options are there to override their default
+values.
+X
+After you have edited the programs as necessary, all that remains is to
+install them to some executable directory. Install postclip mode 555
+and cqueue mode 4555 with owner root (if using suidperl) or mode 555
+(if not using suidperl).
+X
+4. Gripes, Comments, Etc
+------------------------
+X
+If you start using either of these let me know. I have other mail tools I
+will likely post in the future if these prove useful. Also, if you think
+something is just plain dumb/wrong/stupid let me know!
+X
+Cheers,
+-Mike
+X
+--
++----------------------------------------------------------------------------+
+| Michael S. Muegel | Internet E-Mail: mmuegel@mot.com |
+| UNIX Applications Startup Group | Moto Dist E-Mail: X10090 |
+| Corporate Information Office | Voice: (708) 576-0507 |
+| Motorola | Fax: (708) 576-4153 |
++----------------------------------------------------------------------------+
+SHAR_EOF
+chmod 0444 README ||
+echo 'restore of README failed'
+Wc_c="`wc -c < 'README'`"
+test 4308 -eq "$Wc_c" ||
+ echo 'README: original size 4308, current size' "$Wc_c"
+fi
+# ============= libs/date.pl ==============
+if test ! -d 'libs'; then
+ echo 'x - creating directory libs'
+ mkdir 'libs'
+fi
+if test -f 'libs/date.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/date.pl (File already exists)'
+else
+echo 'x - extracting libs/date.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/date.pl' &&
+;#
+;# Name
+;# date.pl - Perl emulation of (the output side of) date(1)
+;#
+;# Synopsis
+;# require "date.pl";
+;# $Date = &date(time);
+;# $Date = &date(time, $format);
+;#
+;# Description
+;# This package implements the output formatting functions of date(1) in
+;# Perl. The format options are based on those supported by Ultrix 4.0
+;# plus a couple of additions from SunOS 4.1.1 and elsewhere:
+;#
+;# %a abbreviated weekday name - Sun to Sat
+;# %A full weekday name - Sunday to Saturday
+;# %b abbreviated month name - Jan to Dec
+;# %B full month name - January to December
+;# %c date and time in local format [+]
+;# %C date and time in long local format [+]
+;# %d day of month - 01 to 31
+;# %D date as mm/dd/yy
+;# %e day of month (space padded) - ` 1' to `31'
+;# %E day of month (with suffix: 1st, 2nd, 3rd...)
+;# %f month of year (space padded) - ` 1' to `12'
+;# %h abbreviated month name - Jan to Dec
+;# %H hour - 00 to 23
+;# %i hour (space padded) - ` 1' to `12'
+;# %I hour - 01 to 12
+;# %j day of the year (Julian date) - 001 to 366
+;# %k hour (space padded) - ` 0' to `23'
+;# %l date in ls(1) format
+;# %m month of year - 01 to 12
+;# %M minute - 00 to 59
+;# %n insert a newline character
+;# %p ante-meridiem or post-meridiem indicator (AM or PM)
+;# %r time in AM/PM notation
+;# %R time as HH:MM
+;# %S second - 00 to 59
+;# %t insert a tab character
+;# %T time as HH:MM:SS
+;# %u date/time in date(1) required format
+;# %U week number, Sunday as first day of week - 00 to 53
+;# %V date-time in SysV touch format (mmddHHMMyy)
+;# %w day of week - 0 (Sunday) to 6
+;# %W week number, Monday as first day of week - 00 to 53
+;# %x date in local format [+]
+;# %X time in local format [+]
+;# %y last 2 digits of year - 00 to 99
+;# %Y all 4 digits of year ~ 1700 to 2000 odd ?
+;# %z time zone from TZ environment variable w/ a trailing space
+;# %Z time zone from TZ environment variable
+;# %% insert a `%' character
+;# %+ insert a `+' character
+;#
+;# [+]: These may need adjustment to fit local conventions, see below.
+;#
+;# For the sake of compatibility, a leading `+' in the format
+;# specificaiton is removed if present.
+;#
+;# Remarks
+;# This is version 3.4 of date.pl
+;#
+;# An extension of `ctime.pl' by Waldemar Kebsch (kebsch.pad@nixpbe.UUCP),
+;# as modified by Marion Hakanson (hakanson@ogicse.ogi.edu).
+;#
+;# Unlike date(1), unknown format tags are silently replaced by "".
+;#
+;# defaultTZ is a blatant hack, but I wanted to be able to get date(1)
+;# like behaviour by default and there does'nt seem to be an easy (read
+;# portable) way to get the local TZ name back...
+;#
+;# For a cheap date, try...
+;#
+;# #!/usr/local/bin/perl
+;# require "date.pl";
+;# exit print (&date(time, shift @ARGV) . "\n") ? 0 : 1;
+;#
+;# This package is redistributable under the same terms as apply to
+;# the Perl 4.0 release. See the COPYING file in your Perl kit for
+;# more information.
+;#
+;# Please send any bug reports or comments to tmcgonigal@gallium.com
+;#
+;# Modification History
+;# Nmemonic Version Date Who
+;#
+;# NONE 1.0 02feb91 Terry McGonigal (tmcgonigal@gallium.com)
+;# Created from ctime.pl
+;#
+;# NONE 2.0 07feb91 tmcgonigal
+;# Added some of Marion Hakanson (hakanson@ogicse.ogi.edu)'s ctime.pl
+;# TZ handling changes.
+;#
+;# NONE 2.1 09feb91 tmcgonigal
+;# Corrected week number calculations.
+;#
+;# NONE 2.2 21oct91 tmcgonigal
+;# Added ls(1) date format, `%l'.
+;#
+;# NONE 2.3 06nov91 tmcgonigal
+;# Added SysV touch(1) date-time format, `%V' (pretty thin as
+;# mnemonics go, I know, but `t' and `T' were both gone already!)
+;#
+;# NONE 2.4 05jan92 tmcgonigal
+;# Corrected slight (cosmetic) problem with %V replacment string
+;#
+;# NONE 3.0 09jul92 tmcgonigal
+;# Fixed a couple of problems with &ls as pointed out by
+;# Thomas Richter (richter@ki1.chemie.fu-berlin.de), thanks Thomas!
+;# Also added a couple of SunOS 4.1.1 strftime-ish formats, %i and %k
+;# for space padded hours (` 1' to `12' and ` 0' to `23' respectivly),
+;# and %C for locale long date/time format. Changed &ampmH to take a
+;# pad char parameter to make to evaled code for %i and %k simpler.
+;# Added %E for suffixed day-of-month (ie 1st, 3rd, 4th etc).
+;#
+;# NONE 3.1 16jul92 tmcgonigal
+;# Added `%u' format to generate date/time in date(1) required
+;# format (ie '%y%m%d%H%M.%S').
+;#
+;# NONE 3.2 23jan93 tmcgonigal
+;# Added `%f' format to generate space padded month numbers, added
+;# `%E' to the header comments, it seems to have been left out (and
+;# I'm sure I wanted to use it at some point in the past...).
+;#
+;# NONE 3.3 03feb93 tmcgonigal
+;# Corrected some problems with AM/PM handling pointed out by
+;# Michael S. Muegel (mmuegel@mot.com). Thanks Michael, I hope
+;# this is the behaviour you were looking for, it seems more
+;# correct to me...
+;#
+;# NONE 3.4 26jul93 tmcgonigal
+;# Incorporated some fixes provided by DaviD W. Sanderson
+;# (dws@ssec.wisc.edu): February was spelled incorrectly and
+;# &wkno() was always using the current year while calculating
+;# week numbers, regardless of year implied by the time value
+;# passed to &date(). DaviD also contributed an improved &date()
+;# test script, thanks DaviD, I appreciate the effort. Finally,
+;# changed my mailling address from @gvc.com to @gallium.com
+;# to reflect, well, my new address!
+;#
+;# SccsId = "%W% %E%"
+;#
+require 'timelocal.pl';
+package date;
+X
+# Months of the year
+@MoY = ('January', 'February', 'March', 'April', 'May', 'June',
+X 'July', 'August', 'September','October', 'November', 'December');
+X
+# days of the week
+@DoW = ('Sunday', 'Monday', 'Tuesday', 'Wednesday',
+X 'Thursday', 'Friday', 'Saturday');
+X
+# CUSTOMIZE - defaults
+$defaultTZ = 'CST'; # time zone (hack!)
+$defaultFMT = '%a %h %e %T %z%Y'; # format (ala date(1))
+X
+# CUSTOMIZE - `local' formats
+$locTF = '%T'; # time (as HH:MM:SS)
+$locDF = '%D'; # date (as mm/dd/yy)
+$locDTF = '%a %b %d %T %Y'; # date/time (as dow mon dd HH:MM:SS yyyy)
+$locLDTF = '%i:%M:%S %p %A %B %E %Y'; # long date/time (as HH:MM:SS a/p day month dom yyyy)
+X
+# Time zone info
+$TZ; # wkno needs this info too
+X
+# define the known format tags as associative keys with their associated
+# replacement strings as values. Each replacement string should be
+# an eval-able expresion assigning a value to $rep. These expressions are
+# eval-ed, then the value of $rep is substituted into the supplied
+# format (if any).
+%Tags = ( '%a', q|($rep = $DoW[$wday])=~ s/^(...).*/\1/|, # abbr. weekday name - Sun to Sat
+X '%A', q|$rep = $DoW[$wday]|, # full weekday name - Sunday to Saturday
+X '%b', q|($rep = $MoY[$mon]) =~ s/^(...).*/\1/|, # abbr. month name - Jan to Dec
+X '%B', q|$rep = $MoY[$mon]|, # full month name - January to December
+X '%c', q|$rep = $locDTF; 1|, # date/time in local format
+X '%C', q|$rep = $locLDTF; 1|, # date/time in local long format
+X '%d', q|$rep = &date'pad($mday, 2, "0")|, # day of month - 01 to 31
+X '%D', q|$rep = '%m/%d/%y'|, # date as mm/dd/yy
+X '%e', q|$rep = &date'pad($mday, 2, " ")|, # day of month (space padded) ` 1' to `31'
+X '%E', q|$rep = &date'dsuf($mday)|, # day of month (w/suffix) `1st' to `31st'
+X '%f', q|$rep = &date'pad($mon+1, 2, " ")|, # month of year (space padded) ` 1' to `12'
+X '%h', q|$rep = '%b'|, # abbr. month name (same as %b)
+X '%H', q|$rep = &date'pad($hour, 2, "0")|, # hour - 00 to 23
+X '%i', q|$rep = &date'ampmH($hour, " ")|, # hour (space padded ` 1' to `12'
+X '%I', q|$rep = &date'ampmH($hour, "0")|, # hour - 01 to 12
+X '%j', q|$rep = &date'pad($yday+1, 3, "0")|, # Julian date 001 - 366
+X '%k', q|$rep = &date'pad($hour, 2, " ")|, # hour (space padded) ` 0' to `23'
+X '%l', q|$rep = '%b %d ' . &date'ls($year)|, # ls(1) style date
+X '%m', q|$rep = &date'pad($mon+1, 2, "0")|, # month of year - 01 to 12
+X '%M', q|$rep = &date'pad($min, 2, "0")|, # minute - 00 to 59
+X '%n', q|$rep = "\n"|, # insert a newline
+X '%p', q|$rep = &date'ampmD($hour)|, # insert `AM' or `PM'
+X '%r', q|$rep = '%I:%M:%S %p'|, # time in AM/PM notation
+X '%R', q|$rep = '%H:%M'|, # time as HH:MM
+X '%S', q|$rep = &date'pad($sec, 2, "0")|, # second - 00 to 59
+X '%t', q|$rep = "\t"|, # insert a tab
+X '%T', q|$rep = '%H:%M:%S'|, # time as HH:MM:SS
+X '%u', q|$rep = '%y%m%d%H%M.%S'|, # daaate/time in date(1) required format
+X '%U', q|$rep = &date'wkno($year, $yday, 0)|, # week number (weeks start on Sun) - 00 to 53
+X '%V', q|$rep = '%m%d%H%M%y'|, # SysV touch(1) date-time format (mmddHHMMyy)
+X '%w', q|$rep = $wday; 1|, # day of week - Sunday = 0
+X '%W', q|$rep = &date'wkno($year, $yday, 1)|, # week number (weeks start on Mon) - 00 to 53
+X '%x', q|$rep = $locDF; 1|, # date in local format
+X '%X', q|$rep = $locTF; 1|, # time in local format
+X '%y', q|($rep = $year) =~ s/..(..)/\1/|, # last 2 digits of year - 00 to 99
+X '%Y', q|$rep = "$year"; 1|, # full year ~ 1700 to 2000 odd
+X '%z', q|$rep = $TZ eq "" ? "" : "$TZ "|, # time zone from TZ env var (w/trail. space)
+X '%Z', q|$rep = $TZ; 1|, # time zone from TZ env. var.
+X '%%', q|$rep = '%'; $adv=1|, # insert a `%'
+X '%+', q|$rep = '+'| # insert a `+'
+);
+X
+sub main'date {
+X local($time, $format) = @_;
+X local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
+X local($pos, $tag, $rep, $adv) = (0, "", "", 0);
+X
+X # default to date/ctime format or strip leading `+'...
+X if ($format eq "") {
+X $format = $defaultFMT;
+X } elsif ($format =~ /^\+/) {
+X $format = $';
+X }
+X
+X # Use local time if can't find a TZ in the environment
+X $TZ = defined($ENV{'TZ'}) ? $ENV{'TZ'} : $defaultTZ;
+X ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
+X &gettime ($TZ, $time);
+X
+X # Hack to deal with 'PST8PDT' format of TZ
+X # Note that this can't deal with all the esoteric forms, but it
+X # does recognize the most common: [:]STDoff[DST[off][,rule]]
+X if ($TZ =~ /^([^:\d+\-,]{3,})([+-]?\d{1,2}(:\d{1,2}){0,2})([^\d+\-,]{3,})?/) {
+X $TZ = $isdst ? $4 : $1;
+X }
+X
+X # watch out in 2070...
+X $year += ($year < 70) ? 2000 : 1900;
+X
+X # now loop throught the supplied format looking for tags...
+X while (($pos = index ($format, '%')) != -1) {
+X
+X # grab the format tag
+X $tag = substr($format, $pos, 2);
+X $adv = 0; # for `%%' processing
+X
+X # do we have a replacement string?
+X if (defined $Tags{$tag}) {
+X
+X # trap dead evals...
+X if (! eval $Tags{$tag}) {
+X print STDERR "date.pl: internal error: eval for $tag failed: $@\n";
+X return "";
+X }
+X } else {
+X $rep = "";
+X }
+X
+X # do the substitution
+X substr ($format, $pos, 2) =~ s/$tag/$rep/;
+X $pos++ if ($adv);
+X }
+X
+X $format;
+}
+X
+# dsuf - add `st', `nd', `rd', `th' to a date (ie 1st, 22nd, 29th)
+sub dsuf {
+X local ($mday) = @_;
+X
+X return $mday . 'st' if ($mday =~ m/.*1$/);
+X return $mday . 'nd' if ($mday =~ m/.*2$/);
+X return $mday . 'rd' if ($mday =~ m/.*3$/);
+X return $mday . 'th';
+}
+X
+# weekno - figure out week number
+sub wkno {
+X local ($year, $yday, $firstweekday) = @_;
+X local ($jan1, @jan1, $wks);
+X
+X # figure out the `time' value for January 1 of the given year
+X $jan1 = &maketime ($TZ, 0, 0, 0, 1, 0, $year-1900);
+X
+X # figure out what day of the week January 1 was
+X @jan1= &gettime ($TZ, $jan1);
+X
+X # and calculate the week number
+X $wks = (($yday + ($jan1[6] - $firstweekday)) + 1)/ 7;
+X $wks += (($wks - int($wks) > 0.0) ? 1 : 0);
+X
+X # supply zero padding
+X &pad (int($wks), 2, "0");
+}
+X
+# ampmH - figure out am/pm (1 - 12) mode hour value, padded with $p (0 or ' ')
+sub ampmH { local ($h, $p) = @_; &pad($h>12 ? $h-12 : ($h ? $h : 12), 2, $p); }
+X
+# ampmD - figure out am/pm designator
+sub ampmD { shift @_ >= 12 ? "PM" : "AM"; }
+X
+# gettime - get the time via {local,gmt}time
+sub gettime { ((shift @_) eq 'GMT') ? gmtime(shift @_) : localtime(shift @_); }
+X
+# maketime - make a time via time{local,gmt}
+sub maketime { ((shift @_) eq 'GMT') ? &main'timegm(@_) : &main'timelocal(@_); }
+X
+# ls - generate the time/year portion of an ls(1) style date
+sub ls {
+X return ((&gettime ($TZ, time))[5] == @_[0]) ? "%R" : " %Y";
+}
+X
+# pad - pad $in with leading $pad until lenght $len
+sub pad {
+X local ($in, $len, $pad) = @_;
+X local ($out) = "$in";
+X
+X $out = $pad . $out until (length ($out) == $len);
+X return $out;
+}
+X
+1;
+SHAR_EOF
+chmod 0444 libs/date.pl ||
+echo 'restore of libs/date.pl failed'
+Wc_c="`wc -c < 'libs/date.pl'`"
+test 12339 -eq "$Wc_c" ||
+ echo 'libs/date.pl: original size 12339, current size' "$Wc_c"
+fi
+# ============= libs/elapsed.pl ==============
+if test -f 'libs/elapsed.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/elapsed.pl (File already exists)'
+else
+echo 'x - extracting libs/elapsed.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/elapsed.pl' &&
+;# NAME
+;# elapsed.pl - convert seconds to elapsed time format
+;#
+;# AUTHOR
+;# Michael S. Muegel <mmuegel@mot.com>
+;#
+;# RCS INFORMATION
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/elapsed.pl,v
+;# 1.1 of 1993/07/28 08:07:19
+X
+package elapsed;
+X
+# Time field types
+$DAYS = 1;
+$HOURS = 2;
+$MINUTES = 3;
+$SECONDS = 4;
+X
+# The array contains four records each with four fields. The fields are,
+# in order:
+#
+# Type Specifies what kind of time field this is. Once of
+# $DAYS, $HOURS, $MINUTES, or $SECONDS.
+#
+# Multiplier Specifies what time field this is via the minimum
+# number of seconds this time field may specify. For
+# example, the minutes field would be non-zero
+# when there are 60 or more seconds.
+#
+# Separator How to separate this time field from the next
+# *greater* field.
+#
+# Format sprintf() format specifier on how to print this
+# time field.
+@MULT_AND_SEPS = ($DAYS, 60 * 60 * 24, "+", "%d",
+X $HOURS, 60 * 60, ":", "%d",
+X $MINUTES, 60, ":", "%02d",
+X $SECONDS, 1, "", "%02d"
+X );
+X
+;###############################################################################
+;# Seconds_To_Elapsed
+;#
+;# Coverts a seconds count to form [d+]h:mm:ss. If $Collapse
+;# is true then the result is compacted somewhat. The string returned
+;# will be of the form [d+][[h:]mm]:ss.
+;#
+;# Arguments:
+;# $Seconds, $Collapse
+;#
+;# Examples:
+;# &Seconds_To_Elapsed (0, 0) -> 0:00:00
+;# &Seconds_To_Elapsed (0, 1) -> :00
+;#
+;# &Seconds_To_Elapsed (119, 0) -> 0:01:59
+;# &Seconds_To_Elapsed (119, 1) -> 01:59
+;#
+;# &Seconds_To_Elapsed (3601, 0) -> 1:00:01
+;# &Seconds_To_Elapsed (3601, 1) -> 1:00:01
+;#
+;# &Seconds_To_Elapsed (86401, 0) -> 1+0:00:01
+;# &Seconds_To_Elapsed (86401, 1) -> 1+:01
+;#
+;# Returns:
+;# $Elapsed
+;###############################################################################
+sub main'Seconds_To_Elapsed
+{
+X local ($Seconds, $Collapse) = @_;
+X local ($Type, $Multiplier, @Multipliers, $Separator, $DHMS_Used,
+X $Elapsed, @Mult_And_Seps, $Print_Field);
+X
+X $Multiplier = 1;
+X @Mult_And_Seps = @MULT_AND_SEPS;
+X
+X # Keep subtracting the number of seconds corresponding to a time field
+X # from the number of seconds passed to the function.
+X while (1)
+X {
+X ($Type, $Multiplier, $Separator, $Format) = splice (@Mult_And_Seps, 0, 4);
+X last if (! $Multiplier);
+X $Seconds -= $DHMS_Used * $Multiplier
+X if ($DHMS_Used = int ($Seconds / $Multiplier));
+X
+X # Figure out if we should print this field
+X if ($Type == $DAYS)
+X {
+X $Print_Field = $DHMS_Used;
+X }
+X
+X elsif ($Collapse)
+X {
+X if ($Type == $HOURS)
+X {
+X $Print_Field = $DHMS_Used;
+X }
+X elsif ($Type == $MINUTES)
+X {
+X $Print_Field = $DHMS_Used || $Printed_Field {$HOURS};
+X }
+X else
+X {
+X $Format = ":%02d"
+X if (! $Printed_Field {$MINUTES});
+X $Print_Field = 1;
+X };
+X }
+X
+X else
+X {
+X $Print_Field = 1;
+X };
+X
+X $Printed_Field {$Type} = $Print_Field;
+X $Elapsed .= sprintf ("$Format%s", $DHMS_Used, $Separator)
+X if ($Print_Field);
+X };
+X
+X return ($Elapsed);
+};
+X
+1;
+SHAR_EOF
+chmod 0444 libs/elapsed.pl ||
+echo 'restore of libs/elapsed.pl failed'
+Wc_c="`wc -c < 'libs/elapsed.pl'`"
+test 3198 -eq "$Wc_c" ||
+ echo 'libs/elapsed.pl: original size 3198, current size' "$Wc_c"
+fi
+# ============= libs/mail.pl ==============
+if test -f 'libs/mail.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/mail.pl (File already exists)'
+else
+echo 'x - extracting libs/mail.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/mail.pl' &&
+;# NAME
+;# mail.pl - perl function(s) to handle mail processing
+;#
+;# AUTHOR
+;# Michael S. Muegel (mmuegel@mot.com)
+;#
+;# RCS INFORMATION
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/mail.pl,v 1.1 1993/07/28 08:07:19 mmuegel Exp
+X
+package mail;
+X
+# Mailer statement to eval. $Users, $Subject, and $Verbose are substituted
+# via eval
+$BIN_MAILER = "/usr/ucb/mail \$Verbose -s '\$Subject' \$Users";
+X
+# Sendmail command to use when $Use_Sendmail is true.
+$SENDMAIL = '/usr/lib/sendmail $Verbose $Users';
+X
+;###############################################################################
+;# Send_Mail
+;#
+;# Sends $Message to $Users with a subject of $Subject. If $Message_Is_File
+;# is true then $Message is assumed to be a filename pointing to the mail
+;# message. This is a new option and thus the backwards-compatible hack.
+;# $Users should be a space separated list of mail-ids.
+;#
+;# If everything went OK $Status will be 1 and $Error_Msg can be ignored;
+;# otherwise, $Status will be 0 and $Error_Msg will contain an error message.
+;#
+;# If $Use_Sendmail is 1 then sendmail is used to send the message. Normally
+;# a mailer such as Mail is used. By specifiying this you can include
+;# headers in addition to text in either $Message or $Message_Is_File.
+;# If either $Message or $Message_Is_File contain a Subject: header then
+;# $Subject is ignored; otherwise, a Subject: header is automatically created.
+;# Similar to the Subject: header, if a To: header does not exist one
+;# is automatically created from the $Users argument. The mail is still
+;# sent, however, to the recipients listed in $Users. This is keeping with
+;# normal sendmail usage (header vs. envelope).
+;#
+;# In both bin mailer and sendmail modes $Verbose will turn on verbose mode
+;# (normally just sendmail verbose mode output).
+;#
+;# Arguments:
+;# $Users, $Subject, $Message, $Message_Is_File, $Verbose, $Use_Sendmail
+;#
+;# Returns:
+;# $Status, $Error_Msg
+;###############################################################################
+sub main'Send_Mail
+{
+X local ($Users, $Subject, $Message, $Message_Is_File, $Verbose,
+X $Use_Sendmail) = @_;
+X local ($BIN_MAILER_HANDLE, $Mailer_Command, $Header_Found, %Header_Map,
+X $Header_Extra, $Mailer);
+X
+X # If the message is contained in a file read it in so we can have one
+X # consistent interface
+X if ($Message_Is_File)
+X {
+X undef $/;
+X $Message_Is_File = 0;
+X open (Message) || return (0, "error reading $Message: $!");
+X $Message = <Message>;
+X close (Message);
+X };
+X
+X # If sendmail mode see if we need to add some headers
+X if ($Use_Sendmail)
+X {
+X # Determine if a header block is included in the message and what headers
+X # are there
+X foreach (split (/\n/, $Message))
+X {
+X last if ($_ eq "");
+X $Header_Found = $Header_Map {$1} = 1 if (/^([A-Z]\S*): /);
+X };
+X
+X # Add some headers?
+X if (! $Header_Map {"To"})
+X {
+X $Header_Extra .= "To: " . join (", ", $Users) . "\n";
+X };
+X if (($Subject ne "") && (! $Header_Map {"Subject"}))
+X {
+X $Header_Extra .= "Subject: $Subject\n";
+X };
+X
+X # Add the required blank line between header/body if there where no
+X # headers to begin with
+X if ($Header_Found)
+X {
+X $Message = "$Header_Extra$Message";
+X }
+X else
+X {
+X $Message = "$Header_Extra\n$Message";
+X };
+X };
+X
+X # Get a string that is the mail command
+X $Verbose = ($Verbose) ? "-v" : "";
+X $Mailer = ($Use_Sendmail) ? $SENDMAIL : $BIN_MAILER;
+X eval "\$Mailer = \"$Mailer\"";
+X return (0, "error setting \$Mailer: $@") if ($@);
+X
+X # need to catch SIGPIPE in case the $Mailer call fails
+X $SIG {'PIPE'} = "mail'Cleanup";
+X
+X # Open mailer
+X return (0, "can not open mail program: $Mailer") if (! open (MAILER, "| $Mailer"));
+X
+X # Send off the mail!
+X print MAILER $Message;
+X close (MAILER);
+X return (0, "error running mail program: $Mailer") if ($?);
+X
+X # Everything must have went AOK
+X return (1);
+};
+X
+;###############################################################################
+;# Cleanup
+;#
+;# Simply here so we can catch SIGPIPE and not exit.
+;#
+;# Globals:
+;# None
+;#
+;# Arguments:
+;# None
+;#
+;# Returns:
+;# Nothing exciting
+;###############################################################################
+sub Cleanup
+{
+};
+X
+1;
+SHAR_EOF
+chmod 0444 libs/mail.pl ||
+echo 'restore of libs/mail.pl failed'
+Wc_c="`wc -c < 'libs/mail.pl'`"
+test 4356 -eq "$Wc_c" ||
+ echo 'libs/mail.pl: original size 4356, current size' "$Wc_c"
+fi
+# ============= libs/mqueue.pl ==============
+if test -f 'libs/mqueue.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/mqueue.pl (File already exists)'
+else
+echo 'x - extracting libs/mqueue.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/mqueue.pl' &&
+;# NAME
+;# mqueue.pl - functions to work with the sendmail queue
+;#
+;# DESCRIPTION
+;# Both Get_Queue_IDs and Parse_Control_File are available to get
+;# information about the sendmail queue. The cqueue program is a good
+;# example of how these functions work.
+;#
+;# AUTHOR
+;# Michael S. Muegel (mmuegel@mot.com)
+;#
+;# RCS INFORMATION
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/mqueue.pl,v
+;# 1.1 of 1993/07/28 08:07:19
+X
+package mqueue;
+X
+;###############################################################################
+;# Get_Queue_IDs
+;#
+;# Will figure out the queue IDs in $Queue that have both control and data
+;# files. They are returned in @Valid_IDs. Those IDs that have a
+;# control file and no data file are saved to the array globbed by
+;# *Missing_Control_IDs. Likewise, those IDs that have a data file and no
+;# control file are saved to the array globbed by *Missing_Data_IDs.
+;#
+;# If $Skip_Locked is true they a message that has a lock file is skipped
+;# and will not show up in any of the arrays.
+;#
+;# If everything went AOK then $Status is 1; otherwise, $Status is 0 and
+;# $Msg tells what went wrong.
+;#
+;# Globals:
+;# None
+;#
+;# Arguments:
+;# $Queue, $Skip_Locked, *Missing_Control_IDs, *Missing_Data_IDs
+;#
+;# Returns:
+;# $Status, $Msg, @Valid_IDs
+;###############################################################################
+sub main'Get_Queue_IDs
+{
+X local ($Queue, $Skip_Locked, *Missing_Control_IDs,
+X *Missing_Data_IDs) = @_;
+X local (*QUEUE, @Files, %Lock_IDs, %Data_IDs, %Control_IDs, $_);
+X
+X # Make sure that the * argument @arrays ar empty
+X @Missing_Control_IDs = @Missing_Data_IDs = ();
+X
+X # Save each data, lock, and queue file in @Files
+X opendir (QUEUE, $Queue) || return (0, "error getting directory listing of $Queue");
+X @Files = grep (/^(df|lf|qf)/, readdir (QUEUE));
+X closedir (QUEUE);
+X
+X # Create indexed list of data and control files. IF $Skip_Locked is true
+X # then skip either if there is a lock file present.
+X if ($Skip_Locked)
+X {
+X grep ((s/^lf//) && ($Lock_IDs {$_} = 1), @Files);
+X grep ((s/^df//) && (! $Lock_IDs {$_}) && ($Data_IDs {$_} = 1), @Files);
+X grep ((s/^qf//) && (! $Lock_IDs {$_}) && ($Control_IDs {$_} = 1), @Files);
+X }
+X else
+X {
+X grep ((s/^df//) && ($Data_IDs {$_} = 1), @Files);
+X grep ((s/^qf//) && ($Control_IDs {$_} = 1), @Files);
+X };
+X
+X # Find missing control and data files and remove them from the lists of each
+X @Missing_Control_IDs = sort (grep ((! $Control_IDs {$_}) && (delete $Data_IDs {$_}), keys (%Data_IDs)));
+X @Missing_Data_IDs = sort (grep ((! $Data_IDs {$_} && (delete $Control_IDs {$_})), keys (%Control_IDs)));
+X
+X
+X # Return the IDs in an appartently random order
+X return (1, "", keys (%Control_IDs));
+};
+X
+X
+;###############################################################################
+;# Parse_Control_File
+;#
+;# Will pase a sendmail queue control file for useful information. See the
+;# Sendmail Installtion and Operation Guide (SMM:07) for a complete
+;# explanation of each field.
+;#
+;# The following globbed variables are set (or cleared) by this function:
+;#
+;# $Sender The sender's address.
+;#
+;# @Recipients One or more addresses for the recipient of the mail.
+;#
+;# @Errors_To One or more addresses for addresses to which mail
+;# delivery errors should be sent.
+;#
+;# $Creation_Time The job creation time in time(3) format. That is,
+;# seconds since 00:00:00 GMT 1/1/70.
+;#
+;# $Priority An integer representing the current message priority.
+;# This is used to order the queue. Higher numbers mean
+;# lower priorities.
+;#
+;# $Status_Message The status of the mail message. It can contain any
+;# text.
+;#
+;# @Headers Message headers unparsed but in their original order.
+;# Headers that span multiple lines are not mucked with,
+;# embedded \ns will be evident.
+;#
+;# In all e-mail addresses bounding <> pairs are stripped.
+;#
+;# If everything went AOK then $Status is 1. If the message with queue ID
+;# $Queue_ID just does not exist anymore -1 is returned. This is very
+;# possible and should be allowed for. Otherwise, $Status is 0 and $Msg
+;# tells what went wrong.
+;#
+;# Globals:
+;# None
+;#
+;# Arguments:
+;# $Queue, $Queue_ID, *Sender, *Recipients, *Errors_To, *Creation_Time,
+;# *Priority, *Status_Message, *Headers
+;#
+;# Returns:
+;# $Status, $Msg
+;###############################################################################
+sub main'Parse_Control_File
+{
+X local ($Queue, $Queue_ID, *Sender, *Recipients, *Errors_To, *Creation_Time,
+X *Priority, *Status_Message, *Headers) = @_;
+X local (*Control, $_, $Not_Empty);
+X
+X # Required variables and the associated control. If empty at the end of
+X # parsing we return a bad status.
+X @REQUIRED_INFO = ('$Creation_Time', 'T', '$Sender', 'S', '@Recipients', 'R',
+X '$Priority', 'P');
+X
+X # Open up the control file for read
+X $Control = "$Queue/qf$Queue_ID";
+X if (! open (Control))
+X {
+X return (-1) if ((-x $Queue) && (! -f "$Queue/qf$Queue_ID") &&
+X (! -f "$Queue/df$Queue_ID"));
+X return (0, "error opening $Control for read: $!");
+X };
+X
+X # Reset the globbed variables just in case
+X $Sender = $Creation_Time = $Priority = $Status_Message = "";
+X @Recipients = @Errors_To = @Headers = ();
+X
+X # Look for a few things in the control file
+X READ: while (<Control>)
+X {
+X $Not_Empty = 1;
+X chop;
+X
+X PARSE:
+X {
+X if (/^T(\d+)$/)
+X {
+X $Creation_Time = $1;
+X }
+X elsif (/^S(<)?([^>]+)/)
+X {
+X $Sender = $2;
+X }
+X elsif (/^R(<)?([^>]+)/)
+X {
+X push (@Recipients, $2);
+X }
+X elsif (/^E(<)?([^>]+)/)
+X {
+X push (@Errors_To, $2);
+X }
+X elsif (/^M(.*)/)
+X {
+X $Status_Message = $1;
+X }
+X elsif (/^P(\d+)$/)
+X {
+X $Priority = $1;
+X }
+X elsif (/^H(.*)/)
+X {
+X $Header = $1;
+X while (<Control>)
+X {
+X chop;
+X last if (/^[A-Z]/);
+X $Header .= "\n$_";
+X };
+X push (@Headers, $Header);
+X redo PARSE if ($_);
+X last if (eof);
+X };
+X };
+X };
+X
+X # If the file was empty scream bloody murder
+X return (0, "empty control file") if (! $Not_Empty);
+X
+X # Yell if we could not find a required field
+X while (($Var, $Control) = splice (@REQUIRED_INFO, 0, 2))
+X {
+X eval "return (0, 'required control field $Control not found')
+X if (! $Var)";
+X return (0, "error checking \$Var: $@") if ($@);
+X };
+X
+X # Everything went AOK
+X return (1);
+};
+X
+1;
+SHAR_EOF
+chmod 0444 libs/mqueue.pl ||
+echo 'restore of libs/mqueue.pl failed'
+Wc_c="`wc -c < 'libs/mqueue.pl'`"
+test 6908 -eq "$Wc_c" ||
+ echo 'libs/mqueue.pl: original size 6908, current size' "$Wc_c"
+fi
+# ============= libs/newgetopts.pl ==============
+if test -f 'libs/newgetopts.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/newgetopts.pl (File already exists)'
+else
+echo 'x - extracting libs/newgetopts.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/newgetopts.pl' &&
+;# NAME
+;# newgetopts.pl - a better newgetopt (which is a better getopts which is
+;# a better getopt ;-)
+;#
+;# AUTHOR
+;# Mike Muegel (mmuegel@mot.com)
+;#
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/newgetopts.pl,v 1.1 1993/07/28 08:07:19 mmuegel Exp
+X
+;###############################################################################
+;# New_Getopts
+;#
+;# Does not care about order of switches, options, and arguments like
+;# getopts.pl. Thus all non-switches/options will be kept in ARGV even if they
+;# are not at the end. If $Pass_Invalid is set all unkown options will be
+;# passed back to the caller by keeping them in @ARGV. This is useful when
+;# parsing a command line for your script while ignoring options that you
+;# may pass to another script. If this is set New_Getopts tries to maintain
+;# the switch clustering on the unkown switches.
+;#
+;# Accepts the special argument -usage to print the Usage string. Also accepts
+;# the special option -version which prints the contents of the string
+;# $VERSION. $VERSION may or may not have an embeded \n in it. If -usage
+;# or -version are specified a status of -1 is returned. Note that the usage
+;# option is only accepted if the usage string is not null.
+;#
+;# $Switches is just like the formal arguemnt of getopts.pl. $Usage is a usage
+;# string with or without a trailing \n. *Switch_To_Order is an optional
+;# pointer to the name of an associative array which will contain a mapping of
+;# switch names to the order in which (if at all) the argument was entered.
+;#
+;# For example, if @ARGV contains -v, -x, test:
+;#
+;# $Switch_To_Order {"v"} = 1;
+;# $Switch_To_Order {"x"} = 2;
+;#
+;# Note that in the case of multiple occurances of an option $Switch_To_Order
+;# will store each occurance of the argument via a string that emulates
+;# an array. This is done by using join ($;, ...). You can retrieve the
+;# array by using split (/$;/, ...).
+;#
+;# *Split_ARGV is an optional pointer to an array which will conatin the
+;# original switches along with their values. For the example used above
+;# Split_ARGV would contain:
+;#
+;# @Split_ARGV = ("v", "", "x", "test");
+;#
+;# Another exciting ;-) feature that newgetopts has. Along with creating the
+;# normal $opt_ scalars for the last value of an argument the list @opt_ is
+;# created. It is an array which contains all the values of arguments to the
+;# basename of the variable. They are stored in the order which they occured
+;# on the command line starting with $[. Note that blank arguments are stored
+;# as "". Along with providing support for multiple options on the command
+;# line this also provides a method of counting the number of times an option
+;# was specified via $#opt_.
+;#
+;# Automatically resets all $opt_, @opt_, %Switch_To_Order, and @Split_ARGV
+;# variables so that New_Getopts may be called more than once from within
+;# the same program. Thus, if $opt_v is set upon entry to New_Getopts and
+;# -v is not in @ARGV $opt_v will not be set upon exit.
+;#
+;# Arguments:
+;# $Switches, $Usage, $Pass_Invalid, *Switch_To_Order, *Split_ARGV
+;#
+;# Returns:
+;# -1, 0, or 1 depending on status (printed Usage/Version, OK, not OK)
+;###############################################################################
+sub New_Getopts
+{
+X local($taint_argumentative, $Usage, $Pass_Invalid, *Switch_To_Order,
+X *Split_ARGV) = @_;
+X local(@args,$_,$first,$rest,$errs, @leftovers, @current_leftovers,
+X %Switch_Found);
+X local($[, $*, $Script_Name, $argumentative);
+X
+X # Untaint the argument cluster so that we can use this with taintperl
+X $taint_argumentative =~ /^(.*)$/;
+X $argumentative = $1;
+X
+X # Clear anything that might still be set from a previous New_Getopts
+X # call.
+X @Split_ARGV = ();
+X
+X # Get the basename of the calling script
+X ($Script_Name = $0) =~ s/.*\///;
+X
+X # Make Usage have a trailing \n
+X $Usage .= "\n" if ($Usage !~ /\n$/);
+X
+X @args = split( / */, $argumentative );
+X
+X # Clear anything that might still be set from a previous New_Getopts call.
+X foreach $first (@args)
+X {
+X next if ($first eq ":");
+X delete $Switch_Found {$first};
+X delete $Switch_To_Order {$first};
+X eval "undef \@opt_$first; undef \$opt_$first;";
+X };
+X
+X while (@ARGV)
+X {
+X # Let usage through
+X if (($ARGV[0] eq "-usage") && ($Usage ne "\n"))
+X {
+X print $Usage;
+X exit (-1);
+X }
+X
+X elsif ($ARGV[0] eq "-version")
+X {
+X if ($VERSION)
+X {
+X print $VERSION;
+X print "\n" if ($VERSION !~ /\n$/);
+X }
+X else
+X {
+X warn "${Script_Name}: no version information available, sorry\n";
+X }
+X exit (-1);
+X }
+X
+X elsif (($_ = $ARGV[0]) =~ /^-(.)(.*)/)
+X {
+X ($first,$rest) = ($1,$2);
+X $pos = index($argumentative,$first);
+X
+X $Switch_To_Order {$first} = join ($;, split (/$;/, $Switch_To_Order {$first}), ++$Order);
+X
+X if($pos >= $[)
+X {
+X if($args[$pos+1] eq ':')
+X {
+X shift(@ARGV);
+X if($rest eq '')
+X {
+X $rest = shift(@ARGV);
+X }
+X
+X eval "\$opt_$first = \$rest;";
+X eval "push (\@opt_$first, \$rest);";
+X push (@Split_ARGV, $first, $rest);
+X }
+X else
+X {
+X eval "\$opt_$first = 1";
+X eval "push (\@opt_$first, '');";
+X push (@Split_ARGV, $first, "");
+X
+X if($rest eq '')
+X {
+X shift(@ARGV);
+X }
+X else
+X {
+X $ARGV[0] = "-$rest";
+X }
+X }
+X }
+X
+X else
+X {
+X # Save any other switches if $Pass_Valid
+X if ($Pass_Invalid)
+X {
+X push (@current_leftovers, $first);
+X }
+X else
+X {
+X warn "${Script_Name}: unknown option: $first\n";
+X ++$errs;
+X };
+X if($rest ne '')
+X {
+X $ARGV[0] = "-$rest";
+X }
+X else
+X {
+X shift(@ARGV);
+X }
+X }
+X }
+X
+X else
+X {
+X push (@leftovers, shift (@ARGV));
+X };
+X
+X # Save any other switches if $Pass_Valid
+X if ((@current_leftovers) && ($rest eq ''))
+X {
+X push (@leftovers, "-" . join ("", @current_leftovers));
+X @current_leftovers = ();
+X };
+X };
+X
+X # Automatically print Usage if a warning was given
+X @ARGV = @leftovers;
+X if ($errs != 0)
+X {
+X warn $Usage;
+X return (0);
+X }
+X else
+X {
+X return (1);
+X }
+X
+}
+X
+1;
+SHAR_EOF
+chmod 0444 libs/newgetopts.pl ||
+echo 'restore of libs/newgetopts.pl failed'
+Wc_c="`wc -c < 'libs/newgetopts.pl'`"
+test 7024 -eq "$Wc_c" ||
+ echo 'libs/newgetopts.pl: original size 7024, current size' "$Wc_c"
+fi
+# ============= libs/strings1.pl ==============
+if test -f 'libs/strings1.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/strings1.pl (File already exists)'
+else
+echo 'x - extracting libs/strings1.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/strings1.pl' &&
+;# NAME
+;# strings1.pl - FUN with strings #1
+;#
+;# NOTES
+;# I wrote Format_Text_Block when I just started programming Perl so
+;# it is probably not very Perlish code. Center is more like it :-).
+;#
+;# AUTHOR
+;# Michael S. Muegel (mmuegel@mot.com)
+;#
+;# RCS INFORMATION
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/strings1.pl,v 1.1 1993/07/28 08:07:19 mmuegel Exp
+X
+package strings1;
+X
+;###############################################################################;# Center
+;#
+;# Center $Text assuming the output should be $Columns wide. $Text can span
+;# multiple lines, of course :-). Lines within $Text that contain only
+;# whitespace are not centered and are instead collapsed. This may save time
+;# when printing them later.
+;#
+;# Arguments:
+;# $Text, $Columns
+;#
+;# Returns:
+;# $Centered_Text
+;###############################################################################
+sub main'Center
+{
+X local ($_, $Columns) = @_;
+X local ($*) = 1;
+X
+X s@^(.*)$@" " x (($Columns - length ($1)) / 2) . $1@eg;
+X s/^[\t ]*$//g;
+X return ($_);
+};
+X
+;###############################################################################
+;# Format_Text_Block
+;#
+;# Formats a text string to be printed to the display or other similar device.
+;# Text in $String will be fomratted such that the following hold:
+;#
+;# + $String contains the (possibly) multi-line text to print. It is
+;# automatically word-wrapped to fit in $Columns.
+;#
+;# + \n'd are maintained and are not folded.
+;#
+;# + $Offset is pre-pended before each separate line of text.
+;#
+;# + If $Offset_Once is $TRUE $Offset will only appear on the first line.
+;# All other lines will be indented to match the amount of whitespace of
+;# $Offset.
+;#
+;# + If $Bullet_Indent is $TRUE $Offset will only be applied to the begining
+;# of lines as they occured in the original $String. Lines that are created
+;# by this routine will always be indented by blank spaces.
+;#
+;# + If $Columns is 0 no word-wrap is done. This might be useful to still
+;# to offset each line in a buffer.
+;#
+;# + If $Split_Expr is supplied the string is split on it. If not supplied
+;# the string is split on " \t\/\-\,\." by default.
+;#
+;# + If $Offset_Blank is $TRUE then empty lines will have $Offset pre-pended
+;# to them. Otherwise, they will still empty.
+;#
+;# This is a realy workhorse routine that I use in many places because of its
+;# veratility.
+;#
+;# Arguments:
+;# $String, $Offset, $Offset_Once, $Bullet_Indent, $Columns, $Split_Expr,
+;# $Offset_Blank
+;#
+;# Returns:
+;# $Buffer
+;###############################################################################
+sub main'Format_Text_Block
+{
+X local ($String, $Real_Offset, $Offset_Once, $Bullet_Indent, $Columns,
+X $Split_Expr, $Offset_Blank) = @_;
+X
+X local ($New_Line, $Line, $Chars_Per_Line, $Space_Offset, $Buffer,
+X $Next_New_Line, $Num_Lines, $Num_Offsets, $Offset);
+X local ($*) = 0;
+X local ($BLANK_TAG) = "__FORMAT_BLANK__";
+X local ($Blank_Offset) = $Real_Offset if ($Offset_Blank);
+X
+X # What should we split on?
+X $Split_Expr = " \\t\\/\\-\\,\\." if (! $Split_Expr);
+X
+X # Pre-process the string - convert blank lines to __FORMAT_BLANK__ sequence
+X $String =~ s/\n\n/\n$BLANK_TAG\n/g;
+X $String =~ s/^\n/$BLANK_TAG\n/g;
+X $String =~ s/\n$/\n$BLANK_TAG/g;
+X
+X # If bad $Columns/$Offset combo or no $Columns make a VERRRYYY wide $Column
+X $Offset = $Real_Offset;
+X $Chars_Per_Line = 16000 if (($Chars_Per_Line = $Columns - length ($Offset)) <= 0);
+X $Space_Offset = " " x length ($Offset);
+X
+X # Get a buffer
+X foreach $Line (split ("\n", $String))
+X {
+X $Offset = $Real_Offset if ($Bullet_Indent);
+X
+X # Find where to split the line
+X if ($Line ne $BLANK_TAG)
+X {
+X $New_Line = "";
+X while ($Line =~ /^([$Split_Expr]*)([^$Split_Expr]+)/)
+X {
+X if (length ("$New_Line$&") >= $Chars_Per_Line)
+X {
+X $Next_New_Line = $+;
+X $New_Line = "$Offset$New_Line$1";
+X $Buffer .= "\n" if ($Num_Lines++);
+X $Buffer .= $New_Line;
+X $Offset = $Space_Offset if (($Offset) && ($Offset_Once));
+X $New_Line = $Next_New_Line;
+X ++$Num_Lines;
+X }
+X else
+X {
+X $New_Line .= $&;
+X };
+X $Line = $';
+X };
+X
+X $Buffer .= "\n" if ($Num_Lines++);
+X $Buffer .= "$Offset$New_Line$Line";
+X $Offset = $Space_Offset if (($Offset) && ($Offset_Once));
+X }
+X
+X else
+X {
+X $Buffer .= "\n$Blank_Offset";
+X };
+X };
+X
+X return ($Buffer);
+X
+};
+X
+1;
+SHAR_EOF
+chmod 0444 libs/strings1.pl ||
+echo 'restore of libs/strings1.pl failed'
+Wc_c="`wc -c < 'libs/strings1.pl'`"
+test 4687 -eq "$Wc_c" ||
+ echo 'libs/strings1.pl: original size 4687, current size' "$Wc_c"
+fi
+# ============= libs/timespec.pl ==============
+if test -f 'libs/timespec.pl' -a X"$1" != X"-c"; then
+ echo 'x - skipping libs/timespec.pl (File already exists)'
+else
+echo 'x - extracting libs/timespec.pl (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'libs/timespec.pl' &&
+;# NAME
+;# timespec.pl - convert a pre-defined time specifyer to seconds
+;#
+;# AUTHOR
+;# Michael S. Muegel (mmuegel@mot.com)
+;#
+;# RCS INFORMATION
+;# mmuegel
+;# /usr/local/ustart/src/mail-tools/dist/foo/libs/timespec.pl,v 1.1 1993/07/28 08:07:19 mmuegel Exp
+X
+package timespec;
+X
+%TIME_SPEC_TO_SECONDS = ("s", 1,
+X "m", 60,
+X "h", 60 * 60,
+X "d", 60 * 60 * 24
+X );
+X
+$VALID_TIME_SPEC_EXPR = "[" . join ("", keys (%TIME_SPEC_TO_SECONDS)) . "]";
+X
+;###############################################################################
+;# Time_Spec_To_Seconds
+;#
+;# Converts a string of the form:
+;#
+;# (<number>(s|m|h|d))+
+;#
+;# to seconds. The second part of the time spec specifies seconds, minutes,
+;# hours, or days, respectfully. The first part is the number of those untis.
+;# There can be any number of such specifiers. As an example, 1h30m means 1
+;# hour and 30 minutes.
+;#
+;# If the parsing went OK then $Status is 1, $Msg is undefined, and $Seconds
+;# is $Time_Spec converted to seconds. If something went wrong then $Status
+;# is 0 and $Msg explains what went wrong.
+;#
+;# Arguments:
+;# $Time_Spec
+;#
+;# Returns:
+;# $Status, $Msg, $Seconds
+;###############################################################################
+sub main'Time_Spec_To_Seconds
+{
+X $Time_Spec = $_[0];
+X
+X $Seconds = 0;
+X while ($Time_Spec =~ /^(\d+)($VALID_TIME_SPEC_EXPR)/)
+X {
+X $Seconds += $1 * $TIME_SPEC_TO_SECONDS {$2};
+X $Time_Spec = $';
+X };
+X
+X return (0, "error parsing time spec: $Time_Spec") if ($Time_Spec ne "");
+X return (1, "", $Seconds);
+X
+};
+X
+X
+1;
+SHAR_EOF
+chmod 0444 libs/timespec.pl ||
+echo 'restore of libs/timespec.pl failed'
+Wc_c="`wc -c < 'libs/timespec.pl'`"
+test 1609 -eq "$Wc_c" ||
+ echo 'libs/timespec.pl: original size 1609, current size' "$Wc_c"
+fi
+# ============= man/cqueue.1 ==============
+if test ! -d 'man'; then
+ echo 'x - creating directory man'
+ mkdir 'man'
+fi
+if test -f 'man/cqueue.1' -a X"$1" != X"-c"; then
+ echo 'x - skipping man/cqueue.1 (File already exists)'
+else
+echo 'x - extracting man/cqueue.1 (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'man/cqueue.1' &&
+.TH CQUEUE 1L
+\"
+\" mmuegel
+\" /usr/local/ustart/src/mail-tools/dist/foo/man/cqueue.1,v 1.1 1993/07/28 08:08:25 mmuegel Exp
+\"
+.ds mp \fBcqueue\fR
+.de IB
+.IP \(bu 2
+..
+.SH NAME
+\*(mp - check sendmail queue for problems
+.SH SYNOPSIS
+.IP \*(mp 7
+[ \fB-abdms\fR ] [ \fB-q\fR \fIqueue-dir\fI ] [ \fB-t\fR \fItime\fR ]
+[ \fB-u\fR \fIusers\fR ] [ \fB-w\fR \fIwidth\fR ]
+.SH DESCRIPTION
+Reports on problems in the sendmail queue. With no options this simply
+means listing messages that have been in the queue longer than a default
+period along with a summary of queue mail by host and status message.
+.SH OPTIONS
+.IP \fB-a\fR 14
+Report on all messages in the queue. This is equivalent to saying \fB-t\fR 0s.
+You may like this command so much that you use it as a replacement for
+\fBmqueue\fR. For example:
+.sp 1
+.RS
+.RS
+\fBalias mqueue cqueue -a\fR
+.RE
+.RE
+.IP \fB-b\fR 14
+Also report on bogus queue files. Those are files that
+have data files and no control files or vice versa.
+.IP \fB-d\fR
+Print a detailed report of mail messages that have been queued longer than
+the specified or default time. Information that is presented includes:
+.RS
+.RS
+.IB
+Sendmail queue identifier.
+.IB
+Date the message was first queued.
+.IB
+Sender of the message.
+.IB
+One or more recipients of the message.
+.IB
+An optional status of the message. This usually indicates why the message
+has not been delivered.
+.RE
+.RE
+.IP \fB-m\fR 14
+Mail off the results if any problems were found.
+Normaly results are printed to stdout. If this option
+is specified they are mailed to one or more users. Results
+are not printed to stdout in this case. Results are \fBonly\fR
+mailed if \*(mp found something wrong.
+.IP "\fB-q\fR \fIqueue-dir\fI"
+The sendmail mail queue directory. Default is \fB/usr/spool/mqueue\fR or
+some other site configured value.
+.IP "\fB-t\fR \fItime\fR"
+List messages that have been in the queue longer than
+\fItime\fR. Time should of the form:
+.sp 1
+.RS
+.RS
+(<number>(s|m|h|d))+
+.sp 1
+.RE
+.RE
+.RS 14
+The second portion of the above definition
+specifies seconds, minutes, hours, or
+days, respectfully. The first portion is the number of
+those units. There can be any number of such specifiers.
+As an example, 1h30m means 1 hour and 30 minutes.
+.sp 1
+The default is 2 hours.
+.RE
+.IP \fB-s\fR 14
+Print a summary of messages that have been queued longer than
+the specified or default time. Two separate types of summaries are printed.
+The first summarizes the queue messages by destination host. The host name
+is gleaned from the recipient addresses for each message.
+Thus the actual host names for this summary should be taken with a grain
+of salt since ruleset 0 has not been applied to the address the host was
+taken from nor were MX records consulted. It would be possible to add
+this; however, the execution time of the script would increase
+dramatically. The second summary is by status message.
+.IP "\fB-u\fR \fIusers\fR"
+Specify list of users to send a mail report to other than
+the invoker. This option is only valid when \fB-m\fR has been
+specified. Multiple recipients may be separated by spaces.
+.IP "\fB-w\fR \fIwidth\fR"
+Specify the page width to which the output should tailored. \fIwidth\fR
+should be an integer representing some character position. The default is
+80 or some other site configured value. Output is folded neatly to match
+\fIwidth\fR.
+.SH EXAMPLES
+.nf
+% \fBdate\fR
+Tue Jan 19 12:07:20 CST 1993
+X
+% \fBcqueue -t 21h45m -w 70\fR
+X
+Summary of messages in queue longer than 21:45:00 by destination
+host:
+X
+X Number of
+X Messages Destination Host
+X --------- ----------------
+X 2 cigseg.rtsg.mot.com
+X 1 mnesouth.corp.mot.com
+X ---------
+X 3
+X
+Summary of messages in queue longer than 21:45:00 by status message:
+X
+X Number of
+X Messages Status Message
+X --------- --------------
+X 1 Deferred: Connection refused by mnesouth.corp.mot.com
+X 2 Deferred: Host Name Lookup Failure
+X ---------
+X 3
+X
+Detail of messages in queue longer than 21:45:00 sorted by creation
+date:
+X
+X ID: AA20573
+X Date: 02:09:27 PM 01/18/93
+X Sender: melrose-place-owner@ferkel.ucsb.edu
+X Recipient: pbaker@cigseg.rtsg.mot.com
+X Status: Deferred: Host Name Lookup Failure
+X
+X ID: AA20757
+X Date: 02:11:30 PM 01/18/93
+X Sender: 90210-owner@ferkel.ucsb.edu
+X Recipient: pbaker@cigseg.rtsg.mot.com
+X Status: Deferred: Host Name Lookup Failure
+X
+X ID: AA21110
+X Date: 02:17:01 PM 01/18/93
+X Sender: rd_lap_wg@mdd.comm.mot.com
+X Recipient: jim_mathis@mnesouth.corp.mot.com
+X Status: Deferred: Connection refused by mnesouth.corp.mot.com
+.fi
+.SH AUTHOR
+.nf
+Michael S. Muegel (mmuegel@mot.com)
+UNIX Applications Startup Group
+Corporate Information Office, Schaumburg, IL
+Motorola, Inc.
+.fi
+.SH COPYRIGHT NOTICE
+Copyright 1993, Motorola, Inc.
+.sp 1
+Permission to use, copy, modify and distribute without charge this
+software, documentation, etc. is granted, provided that this
+comment and the author's name is retained. The author nor Motorola assume any
+responsibility for problems resulting from the use of this software.
+.SH SEE ALSO
+.nf
+\fBsendmail(8)\fR
+\fISendmail Installation and Operation Guide\fR.
+.fi
+SHAR_EOF
+chmod 0444 man/cqueue.1 ||
+echo 'restore of man/cqueue.1 failed'
+Wc_c="`wc -c < 'man/cqueue.1'`"
+test 5212 -eq "$Wc_c" ||
+ echo 'man/cqueue.1: original size 5212, current size' "$Wc_c"
+fi
+# ============= man/postclip.1 ==============
+if test -f 'man/postclip.1' -a X"$1" != X"-c"; then
+ echo 'x - skipping man/postclip.1 (File already exists)'
+else
+echo 'x - extracting man/postclip.1 (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'man/postclip.1' &&
+.TH POSTCLIP 1L
+\"
+\" mmuegel
+\" /usr/local/ustart/src/mail-tools/dist/foo/man/postclip.1,v 1.1 1993/07/28 08:08:25 mmuegel Exp
+\"
+.ds mp \fBpostclip\fR
+.SH NAME
+\*(mp - send only the headers to Postmaster
+.SH SYNOPSIS
+\*(mp [ \fB-v\fR ] [ \fIto\fR ... ]
+.SH DESCRIPTION
+\*(mp will forward non-delivery reports to a postmaster after deleting the body
+of the message. This keeps bounced mail private and helps to avoid disk space problems. \*(mp tries its best to keep as much of the header trail as possible.
+Hopefully only the original body of the message will be filtered. Only messages
+that have a subject that begins with 'Returned mail:' are filtered. This
+ensures that other mail is not accidently mucked with. Finally, note that
+\fBsendmail\fR is used to deliver the message after it has been (possibly)
+filtered. All of the original headers will remain intact.
+.sp 1
+You can use this with any \fBsendmail\fR by modifying the Postmaster alias.
+If you use IDA \fBsendmail\fR you could add the following to <machine>.m4:
+.sp 1
+.RS
+define(POSTMASTERBOUNCE, mailer-errors)
+.RE
+.sp 1
+In the aliases file, add a line similar to the following:
+.sp 1
+.RS
+mailer-errors: "|/usr/local/bin/postclip postmaster"
+.RE
+.SH OPTIONS
+.IP \fB-v\fR
+Be verbose about delivery. Probably only useful when debugging \*(mp.
+.IP \fIto\fR
+A list of one or more e-mail ids to send the modified
+Postmaster messages to. If none are specified postmaster
+is used.
+.SH AUTHOR
+.nf
+Michael S. Muegel (mmuegel@mot.com)
+UNIX Applications Startup Group
+Corporate Information Office, Schaumburg, IL
+Motorola, Inc.
+.fi
+.SH CREDITS
+The original idea to filter Postmaster mail was taken from a script by
+Christopher Davis <ckd@eff.org>.
+.SH COPYRIGHT NOTICE
+Copyright 1992, Motorola, Inc.
+.sp 1
+Permission to use, copy, modify and distribute without charge this
+software, documentation, etc. is granted, provided that this
+comment and the author's name is retained. The author nor Motorola assume any
+responsibility for problems resulting from the use of this software.
+.SH SEE ALSO
+.nf
+\fBsendmail(8)\fR
+.fi
+SHAR_EOF
+chmod 0444 man/postclip.1 ||
+echo 'restore of man/postclip.1 failed'
+Wc_c="`wc -c < 'man/postclip.1'`"
+test 2078 -eq "$Wc_c" ||
+ echo 'man/postclip.1: original size 2078, current size' "$Wc_c"
+fi
+# ============= src/cqueue ==============
+if test ! -d 'src'; then
+ echo 'x - creating directory src'
+ mkdir 'src'
+fi
+if test -f 'src/cqueue' -a X"$1" != X"-c"; then
+ echo 'x - skipping src/cqueue (File already exists)'
+else
+echo 'x - extracting src/cqueue (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'src/cqueue' &&
+#!/usr/local/ustart/bin/suidperl
+X
+# NAME
+# cqueue - check sendmail queue for problems
+#
+# SYNOPSIS
+# Type cqueue -usage
+#
+# AUTHOR
+# Michael S. Muegel <mmuegel@mot.com>
+#
+# RCS INFORMATION
+# mmuegel
+# /usr/local/ustart/src/mail-tools/dist/foo/src/cqueue,v 1.1 1993/07/28 08:09:02 mmuegel Exp
+X
+# So that date.pl does not yell (Domain/OS version does a ``)
+$ENV{'PATH'} = "";
+X
+# A better getopts routine
+require "newgetopts.pl";
+require "timespec.pl";
+require "mail.pl";
+require "date.pl";
+require "mqueue.pl";
+require "strings1.pl";
+require "elapsed.pl";
+X
+($Script_Name = $0) =~ s/.*\///;
+X
+# Some defaults you may want to change
+$DEF_TIME = "2h";
+$DEF_QUEUE = "/usr/spool/mqueue";
+$DEF_COLUMNS = 80;
+$DATE_FORMAT = "%r %D";
+X
+# Constants that probably should not be changed
+$USAGE = "Usage: $Script_Name [ -abdms ] [ -q queue-dir ] [ -t time ] [ -u user ] [ -w width ]\n";
+$VERSION = "${Script_Name} by mmuegel; 1.1 of 1993/07/28 08:09:02";
+$SWITCHES = "abdmst:u:q:w:";
+$SPLIT_EXPR = '\s,\.@!%:';
+$ADDR_PART_EXPR = '[^!@%]+';
+X
+# Let getopts parse for switches
+$Status = &New_Getopts ($SWITCHES, $USAGE);
+exit (0) if ($Status == -1);
+exit (1) if (! $Status);
+X
+# Check args
+die "${Script_Name}: -u only valid with -m\n" if (($opt_u) && (! $opt_m));
+die "${Script_Name}: -a not valid with -t option\n" if ($opt_a && $opt_t);
+$opt_u = getlogin || (getpwuid ($<))[0] || $ENV{"USER"} || die "${Script_Name}: can not determine who you are!\n" if (! $opt_u);
+X
+# Set defaults
+$opt_t = "0s" if ($opt_a);
+$opt_t = $DEF_TIME if ($opt_t eq "");
+$opt_w = $DEF_COLUMNS if ($opt_w eq "");
+$opt_q = $DEF_QUEUE if ($opt_q eq "");
+$opt_s = $opt_d = 1 if (! ($opt_s || $opt_d));
+X
+# Untaint the users to mail to
+$opt_u =~ /^(.*)$/;
+$Users = $1;
+X
+# Convert time option to seconds and seconds to elapsed form
+die "${Script_Name}: $Msg\n" if (! (($Status, $Msg, $Seconds) = &Time_Spec_To_Seconds ($opt_t))[0]);
+$Elapsed = &Seconds_To_Elapsed ($Seconds, 1);
+$Time_Info = " longer than $Elapsed" if ($Seconds);
+X
+# Get the current time
+$Current_Time = time;
+$Current_Date = &date ($Current_Time, $DATE_FORMAT);
+X
+($Status, $Msg, @Queue_IDs) = &Get_Queue_IDs ($opt_q, 1, @Missing_Control_IDs,
+X @Missing_Data_IDs);
+die "$Script_Name: $Msg\n" if (! $Status);
+X
+# Yell about missing data/control files?
+if ($opt_b)
+{
+X
+X $Report = "\nMessages missing control files:\n\n " .
+X join ("\n ", @Missing_Control_IDs) .
+X "\n"
+X if (@Missing_Control_IDs);
+X
+X $Report .= "\nMessages missing data files:\n\n " .
+X join ("\n ", @Missing_Data_IDs) .
+X "\n"
+X if (@Missing_Data_IDs);
+};
+X
+# See if any mail messages are older than $Seconds
+foreach $Queue_ID (@Queue_IDs)
+{
+X # Get lots of info about this sendmail message via the control file
+X ($Status, $Msg) = &Parse_Control_File ($opt_q, $Queue_ID, *Sender,
+X *Recipients, *Errors_To, *Creation_Time, *Priority, *Status_Message,
+X *Headers);
+X next if ($Status == -1);
+X if (! $Status)
+X {
+X warn "$Script_Name: $Queue_ID: $Msg\n";
+X next;
+X };
+X
+X # Report on message if it is older than $Seconds
+X if ($Current_Time - $Creation_Time >= $Seconds)
+X {
+X # Build summary by host information. Keep track of each host destination
+X # encountered.
+X if ($opt_s)
+X {
+X %Host_Map = ();
+X foreach (@Recipients)
+X {
+X if ((/@($ADDR_PART_EXPR)$/) || (/($ADDR_PART_EXPR)!$ADDR_PART_EXPR$/))
+X {
+X ($Host = $1) =~ tr/A-Z/a-z/;
+X $Host_Map {$Host} = 1;
+X }
+X else
+X {
+X warn "$Script_Name: could not find host part from $_; contact author\n";
+X };
+X };
+X
+X # For each unique target host add to its stats
+X grep ($Host_Queued {$_}++, keys (%Host_Map));
+X
+X # Build summary by message information.
+X $Message_Queued {$Status_Message}++ if ($Status_Message);
+X };
+X
+X # Build long report information for this creation time (there may be
+X # more than one message created at the same time)
+X if ($opt_d)
+X {
+X $Creation_Date = &date ($Creation_Time, $DATE_FORMAT);
+X $Recipient_Info = &Format_Text_Block (join (", ", @Recipients),
+X " Recipient: ", 1, 0, $opt_w, $SPLIT_EXPR);
+X $Time_To_Report {$Creation_Time} .= <<"EOS";
+X
+X ID: $Queue_ID
+X Date: $Creation_Date
+X Sender: $Sender
+$Recipient_Info
+EOS
+X
+X # Add the status message if available to long report
+X if ($Status_Message)
+X {
+X $Time_To_Report {$Creation_Time} .= &Format_Text_Block ($Status_Message,
+X " Status: ", 1, 0, $opt_w, $SPLIT_EXPR) . "\n";
+X };
+X };
+X };
+X
+};
+X
+# Add the summary report by target host?
+if ($opt_s)
+{
+X foreach $Host (sort (keys (%Host_Queued)))
+X {
+X $Host_Report .= &Format_Text_Block ($Host,
+X sprintf (" %-9d ", $Host_Queued{$Host}), 1, 0, $opt_w,
+X $SPLIT_EXPR) . "\n";
+X $Num_Hosts += $Host_Queued{$Host};
+X };
+X if ($Host_Report)
+X {
+X chop ($Host_Report);
+X $Report .= &Format_Text_Block("\nSummary of messages in queue$Time_Info by destination host:\n", "", 0, 0, $opt_w);
+X
+X $Report .= <<"EOS";
+X
+X Number of
+X Messages Destination Host
+X --------- ----------------
+$Host_Report
+X ---------
+X $Num_Hosts
+EOS
+X };
+};
+X
+# Add the summary by message report?
+if ($opt_s)
+{
+X foreach $Message (sort (keys (%Message_Queued)))
+X {
+X $Message_Report .= &Format_Text_Block ($Message,
+X sprintf (" %-9d ", $Message_Queued{$Message}), 1, 0, $opt_w,
+X $SPLIT_EXPR) . "\n";
+X $Num_Messages += $Message_Queued{$Message};
+X };
+X if ($Message_Report)
+X {
+X chop ($Message_Report);
+X $Report .= &Format_Text_Block ("\nSummary of messages in queue$Time_Info by status message:\n", "", 0, 0, $opt_w);
+X
+X $Report .= <<"EOS";
+X
+X Number of
+X Messages Status Message
+X --------- --------------
+$Message_Report
+X ---------
+X $Num_Messages
+EOS
+X };
+};
+X
+# Add the detailed message reports?
+if ($opt_d)
+{
+X foreach $Time (sort { $a <=> $b} (keys (%Time_To_Report)))
+X {
+X $Report .= &Format_Text_Block ("\nDetail of messages in queue$Time_Info sorted by creation date:\n","", 0, 0, $opt_w) if (! $Detailed_Header++);
+X $Report .= $Time_To_Report {$Time};
+X };
+};
+X
+# Now mail or print the report
+if ($Report)
+{
+X $Report .= "\n";
+X if ($opt_m)
+X {
+X ($Status, $Msg) = &Send_Mail ($Users, "sendmail queue report for $Current_Date", $Report, 0);
+X die "${Script_Name}: $Msg" if (! $Status);
+X }
+X
+X else
+X {
+X print $Report;
+X };
+X
+};
+X
+# I am outta here...
+exit (0);
+SHAR_EOF
+chmod 0555 src/cqueue ||
+echo 'restore of src/cqueue failed'
+Wc_c="`wc -c < 'src/cqueue'`"
+test 6647 -eq "$Wc_c" ||
+ echo 'src/cqueue: original size 6647, current size' "$Wc_c"
+fi
+# ============= src/postclip ==============
+if test -f 'src/postclip' -a X"$1" != X"-c"; then
+ echo 'x - skipping src/postclip (File already exists)'
+else
+echo 'x - extracting src/postclip (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'src/postclip' &&
+#!/usr/local/bin/perl
+X
+# NAME
+# postclip - send only the headers to Postmaster
+#
+# SYNOPSIS
+# postclip [ -v ] [ to ... ]
+#
+# AUTHOR
+# Michael S. Muegel <mmuegel@mot.com>
+#
+# RCS INFORMATION
+# /usr/local/ustart/src/mail-tools/dist/foo/src/postclip,v
+# 1.1 of 1993/07/28 08:09:02
+X
+# We use this to send off the mail
+require "newgetopts.pl";
+require "mail.pl";
+X
+# Get the basename of the script
+($Script_Name = $0) =~ s/.*\///;
+X
+# Some famous constants
+$USAGE = "Usage: $Script_Name [ -v ] [ to ... ]\n";
+$VERSION = "${Script_Name} by mmuegel; 1.1 of 1993/07/28 08:09:02";
+$SWITCHES = "v";
+X
+# Let getopts parse for switches
+$Status = &New_Getopts ($SWITCHES, $USAGE);
+exit (0) if ($Status == -1);
+exit (1) if (! $Status);
+X
+# Who should we send the modified mail to?
+@ARGV = ("postmaster") if (! @ARGV);
+$Users = join (" ", @ARGV);
+@ARGV = ();
+X
+# Suck in the original header and save a few interesting lines
+while (<>)
+{
+X $Buffer .= $_ if (! /^From /);
+X $Subject = $1 if (/^Subject:\s+(.*)$/);
+X $From = $1 if (/^From:\s+(.*)$/);
+X last if (/^$/);
+};
+X
+# Do not filter the message unless it has a subject and the subject indicates
+# it is an NDN
+if ($Subject && ($Subject =~ /^returned mail/i))
+{
+X # Slurp input by paragraph. Keep track of the last time we saw what
+X # appeared to be NDN text. We keep this.
+X $/ = "\n\n";
+X $* = 1;
+X while (<>)
+X {
+X push (@Paragraphs, $_);
+X $Last_Error_Para = $#Paragraphs
+X if (/unsent message follows/i || /was not delivered because/);
+X };
+X
+X # Now save the NDN text into $Buffer
+X $Buffer .= join ("", @Paragraphs [0..$Last_Error_Para]);
+}
+X
+else
+{
+X undef $/;
+X $Buffer .= <>;
+};
+X
+# Send off the (possibly) modified mail
+($Status, $Msg) = &Send_Mail ($Users, "", $Buffer, 0, $opt_v, 1);
+die "$Script_Name: $Msg\n" if (! $Status);
+SHAR_EOF
+chmod 0555 src/postclip ||
+echo 'restore of src/postclip failed'
+Wc_c="`wc -c < 'src/postclip'`"
+test 1836 -eq "$Wc_c" ||
+ echo 'src/postclip: original size 1836, current size' "$Wc_c"
+fi
+exit 0
+
+--
++----------------------------------------------------------------------------+
+| Michael S. Muegel | Internet E-Mail: mmuegel@mot.com |
+| UNIX Applications Startup Group | Moto Dist E-Mail: X10090 |
+| Corporate Information Office | Voice: (708) 576-0507 |
+| Motorola | Fax: (708) 576-4153 |
++----------------------------------------------------------------------------+
+
+ "I'm disturbed, I'm depressed, I'm inadequate -- I've got it all!"
+ -- George from _Seinfeld_
diff --git a/usr.sbin/sendmail/contrib/oldbind.compat.c b/usr.sbin/sendmail/contrib/oldbind.compat.c
new file mode 100644
index 00000000000..1621a7ba5e8
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/oldbind.compat.c
@@ -0,0 +1,79 @@
+/*
+** OLDBIND.COMPAT.C
+**
+** Very old systems do not have res_query(), res_querydomain() or
+** res_search(), so emulate them here.
+**
+** You really ought to be upgrading to a newer version of BIND
+** (4.8.2 or later) rather than be using this.
+**
+** J.R. Oldroyd <jr@inset.com>
+*/
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+typedef union
+{
+ HEADER qb1;
+ char qb2[PACKETSZ];
+} querybuf;
+
+res_query(dname, class, type, data, datalen)
+ char * dname;
+ int class;
+ int type;
+ char * data;
+ int datalen;
+{
+ int n;
+ querybuf buf;
+
+ n = res_mkquery(QUERY, dname, class, type, (char *) NULL, 0,
+ NULL, (char *) &buf, sizeof buf);
+ n = res_send((char *)&buf, n, data, datalen);
+
+ return n;
+}
+
+res_querydomain(host, dname, class, type, data, datalen)
+ char * host;
+ char * dname;
+ int class;
+ int type;
+ char * data;
+ int datalen;
+{
+ int n;
+ querybuf buf;
+ char dbuf[256];
+
+ strcpy(dbuf, host);
+ if (dbuf[strlen(dbuf)-1] != '.')
+ strcat(dbuf, ".");
+ strcat(dbuf, dname);
+ n = res_mkquery(QUERY, dbuf, class, type, (char *) NULL, 0,
+ NULL, (char *)&buf, sizeof buf);
+ n = res_send((char *) &buf, n, data, datalen);
+
+ return n;
+}
+
+res_search(dname, class, type, data, datalen)
+ char * dname;
+ int class;
+ int type;
+ char * data;
+ int datalen;
+{
+ int n;
+ querybuf buf;
+
+ n = res_mkquery(QUERY, dname, class, type, (char *)NULL, 0,
+ NULL, (char *) &buf, sizeof buf);
+ n = res_send((char *) &buf, n, data, datalen);
+
+ return n;
+}
diff --git a/usr.sbin/sendmail/contrib/rcpt-streaming b/usr.sbin/sendmail/contrib/rcpt-streaming
new file mode 100644
index 00000000000..a43af6d43f4
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/rcpt-streaming
@@ -0,0 +1,305 @@
+Message-ID: <wgKo1lW00WBw46OU8k@andrew.cmu.edu>
+Date: Sun, 1 Aug 1993 00:02:57 -0400 (EDT)
+From: John Gardiner Myers <jgm+@CMU.EDU>
+To: sendmail@cs.berkeley.edu
+Subject: contrib/rcpt-streaming
+Beak: Is
+
+This patch implements "RCPT streaming" in sendmail version 8. This
+patch is not an official part of sendmail. Please report all problems
+with this patch to jgm+@cmu.edu.
+
+RCPT streming avoids network round trips by sending all RCPT commands
+for a single SMTP transaction together. Sendmail then waits for all
+the replies, matching them up with the apropriate addresses.
+
+Apply to the sendmail src directory (your line numbers may vary) and
+compile with -DRCPTSTREAM
+
+diff -cr ./src/deliver.c /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/deliver.c
+*** ./src/deliver.c Thu Jul 22 14:28:19 1993
+--- /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/deliver.c Fri Jul 30 21:11:16 1993
+***************
+*** 1334,1339 ****
+--- 1334,1354 ----
+ register int i;
+
+ /* send the recipient list */
++ #ifdef RCPTSTREAM
++ /***********************************************************************
++ *
++ * RCPT streaming code by John G Myers, jgm+@cmu.edu
++ * This is not supported by the maintainer of sendmail.
++ * Report all bugs concerning RCPT streaming to jgm+@cmu.edu
++ *
++ ***********************************************************************
++ */
++ for (to = tochain; to != NULL; to = to->q_tchain)
++ {
++ smtpstreammessage("RCPT To:<%s>", m, mci,
++ to->q_user);
++ }
++ #endif
+ tobuf[0] = '\0';
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ {
+diff -cr ./src/usersmtp.c /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/usersmtp.c
+*** ./src/usersmtp.c Mon Jul 19 23:50:43 1993
+--- /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/usersmtp.c Fri Jul 30 21:12:00 1993
+***************
+*** 44,49 ****
+--- 44,61 ----
+
+ # include <sysexits.h>
+ # include <errno.h>
++ #ifdef RCPTSTREAM
++ /***********************************************************************
++ *
++ * RCPT streaming code by John G Myers, jgm+@cmu.edu
++ * This is not supported by the maintainer of sendmail.
++ * Report all bugs concerning RCPT streaming to jgm+@cmu.edu
++ *
++ ***********************************************************************
++ */
++ # include <sys/types.h>
++ # include <sys/time.h>
++ #endif
+
+ # ifdef SMTP
+
+***************
+*** 62,67 ****
+--- 74,87 ----
+ char SmtpError[MAXLINE] = ""; /* save failure error messages */
+ int SmtpPid; /* pid of mailer */
+
++ #ifdef RCPTSTREAM
++ char *SmtpStreamBuf; /* buffer for streaming output */
++ int SmtpStreamBufSize = 0; /* allocated size of buffer */
++ char *SmtpStreamStart; /* pointer to text not yet written */
++ int SmtpStreamLen = 0; /* # chars not yet written */
++ #endif
++
++
+ #ifdef __STDC__
+ extern smtpmessage(char *f, MAILER *m, MCI *mci, ...);
+ #endif
+***************
+*** 404,410 ****
+--- 424,434 ----
+ {
+ register int r;
+
++ #ifdef RCPTSTREAM
++ sprintf(SmtpMsgBuffer, "RCPT To:<%s>", to->q_user);
++ #else
+ smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
++ #endif
+
+ SmtpPhase = mci->mci_phase = "client RCPT";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+***************
+*** 667,672 ****
+--- 694,703 ----
+ bool firstline = TRUE;
+ char junkbuf[MAXLINE];
+
++ #ifdef RCPTSTREAM
++ extern char MsgBuf[]; /* err.c */
++ #endif
++
+ if (mci->mci_out != NULL)
+ (void) fflush(mci->mci_out);
+
+***************
+*** 682,687 ****
+--- 713,755 ----
+ register char *p;
+ extern time_t curtime();
+
++ #ifdef RCPTSTREAM
++ if (SmtpStreamLen > 0) {
++ int outfd;
++
++ outfd = fileno(mci->mci_out);
++
++ nonblock(outfd, TRUE);
++ r = write(outfd, SmtpStreamStart, SmtpStreamLen);
++ nonblock(outfd, FALSE);
++ if (r == -1 && errno != EAGAIN
++ #ifdef EWOULDBLOCK
++ && errno != EWOULDBLOCK
++ #endif
++ ) {
++
++ mci->mci_errno = errno;
++ message("451 streamreply: write error to %s",
++ mci->mci_host);
++
++ /* if debugging, pause so we can see state */
++ if (tTd(18, 100))
++ pause();
++ # ifdef LOG
++ if (LogLevel > 0)
++ syslog(LOG_INFO, "%s", &MsgBuf[4]);
++ # endif /* LOG */
++ /* stop trying to write output */
++ SmtpStreamLen = 0;
++ continue;
++ }
++ if (r > 0) {
++ SmtpStreamStart += r;
++ SmtpStreamLen -= r;
++ }
++ }
++ #endif /* RCPTSTREAM */
++
+ /* actually do the read */
+ if (e->e_xfp != NULL)
+ (void) fflush(e->e_xfp); /* for debugging */
+***************
+*** 792,797 ****
+--- 860,937 ----
+
+ return (r);
+ }
++
++ #ifdef RCPTSTREAM
++ /*
++ ** SMTPSTREAMMESSAGE -- buffer message to be streamed to server
++ **
++ ** Parameters:
++ ** f -- format
++ ** m -- the mailer to control formatting.
++ ** a, b, c -- parameters
++ **
++ ** Returns:
++ ** none.
++ **
++ ** Side Effects:
++ ** stores message in SmtpStreamBuf
++ */
++
++ /*VARARGS1*/
++ #ifdef __STDC__
++ smtpstreammessage(char *f, MAILER *m, MCI *mci, ...)
++ #else
++ smtpstreammessage(f, m, mci, va_alist)
++ char *f;
++ MAILER *m;
++ MCI *mci;
++ va_dcl
++ #endif
++ {
++ VA_LOCAL_DECL
++ int len;
++
++ VA_START(mci);
++ (void) vsprintf(SmtpMsgBuffer, f, ap);
++ VA_END;
++
++ if (tTd(18, 1) || Verbose)
++ nmessage(">>> %s", SmtpMsgBuffer);
++ if (TrafficLogFile != NULL)
++ fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer);
++
++ if (mci->mci_out == NULL) {
++ if (tTd(18, 1)) printf("smtpstreammessage: NULL mci_out\n");
++ return;
++ }
++
++ strcat(SmtpMsgBuffer, m == NULL ? "\r\n" : m->m_eol);
++ len = strlen(SmtpMsgBuffer);
++
++ if (SmtpStreamLen == 0) {
++ if (SmtpStreamBufSize == 0) {
++ SmtpStreamBufSize = MAXLINE;
++ SmtpStreamBuf = xalloc(SmtpStreamBufSize);
++ }
++ SmtpStreamStart = SmtpStreamBuf;
++ }
++
++ if (SmtpStreamBufSize - SmtpStreamLen < len + 1) {
++ int start = SmtpStreamStart - SmtpStreamBuf;
++ SmtpStreamBufSize += MAXLINE;
++ SmtpStreamBuf = realloc(SmtpStreamBuf, SmtpStreamBufSize);
++ if (!SmtpStreamBuf) {
++ syserr("Out of memory!!");
++ abort();
++ /* exit(EX_UNAVAILABLE); */
++ }
++ SmtpStreamStart = SmtpStreamBuf + start;
++ }
++
++ strcpy(SmtpStreamBuf + SmtpStreamLen, SmtpMsgBuffer);
++ SmtpStreamLen += len;
++ }
++ #endif /* RCPTSTREAM */
+ /*
+ ** SMTPMESSAGE -- send message to server
+ **
+Only in /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src: usersmtp.c~
+diff -cr ./src/util.c /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/util.c
+*** ./src/util.c Mon Jul 19 23:50:45 1993
+--- /afs/andrew.cmu.edu/system/src/local/../host/oldsmail/016/src/util.c Mon Jul 26 17:17:10 1993
+***************
+*** 1034,1039 ****
+--- 1034,1091 ----
+ return (FALSE);
+ return (TRUE);
+ }
++
++ #ifdef RCPTSTREAM
++ /***********************************************************************
++ *
++ * RCPT streaming code by John G Myers, jgm+@cmu.edu
++ * This is not supported by the maintainer of sendmail.
++ * Report all bugs concerning RCPT streaming to jgm+@cmu.edu
++ *
++ ***********************************************************************
++ */
++
++ #include <fcntl.h>
++
++ /*
++ ** NONBLOCK -- set or clear non-blocking mode on file descriptor
++ **
++ ** Parameters:
++ ** fd -- the file descriptor
++ ** mode -- TRUE to set non-blocking mode
++ ** FALSE to clear non-blocking mode
++ **
++ ** Returns:
++ ** none
++ **
++ ** Side Effects:
++ ** modifies nonblocking status of fd
++ */
++
++ nonblock(fd, mode)
++ int fd;
++ bool mode;
++ {
++ int flags;
++
++ flags = fcntl(fd, F_GETFL, 0);
++ if (mode) {
++ #ifdef FNONBIO
++ flags |= FNONBIO;
++ #else
++ flags |= O_NDELAY;
++ #endif
++ }
++ else {
++ #ifdef FNONBIO
++ flags &= ~FNONBIO;
++ #else
++ flags &= ~O_NDELAY;
++ #endif
++ }
++ fcntl(fd, F_SETFL, flags);
++ }
++ #endif
+ /*
+ ** STRCONTAINEDIN -- tell if one string is contained in another
+ **
diff --git a/usr.sbin/sendmail/contrib/xla/README b/usr.sbin/sendmail/contrib/xla/README
new file mode 100644
index 00000000000..a72fd03c832
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/xla/README
@@ -0,0 +1,207 @@
+ XLA - Extended Load Average design for Sendmail R6
+ --------------------------------------------------
+
+ Christophe Wolfhugel - Herve Schauer Consultants
+ wolf@grasp.insa-lyon.fr, wolf@hsc-sec.fr
+
+
+WARNING: this extension is supplied as a contribution to Sendmail.
+Should you have trouble, questions, please contact me directly, and
+*not* the Sendmail development team.
+
+
+ABSTRACT
+
+Sendmail currently furnishes a limitation mecanism which is based on
+the system load average, when available. Experience has prooven that
+this was not sufficiant for some particular situations, for example
+if you have slow and/or overloaded links. This can easily cause both
+system and network congestions with Sendmail having to handle a large
+number of simultaneous sessions on the same overloaded link, causing
+most of the SMTP sessions to timeout after a long time. The system
+load average is also generally too slow to react when your system
+gets a burst of incoming or outgoing SMTP sessions which on some
+stations can easily cause system unavailabilities.
+
+The extended load average module has been designed in order to furnish
+a way of limitation the load generated by Sendmail to both your
+system and your network. This design can be used either alone or as
+complementary to the system load average if your system supports it.
+
+Limitation is based on the number of incoming/outgoing SMTP sessions,
+and remote hosts are classified in classes. The system administrator
+will define a maximum number of incoming SMTP sessions as well as
+a maximum total (incoming + outgoing) sessions for each class of
+hosts. A class can be either an individual machine or a network.
+
+When the limit is reached for a given class, all incoming SMTP
+connections will be politely refused. When the limit is reached for
+all classes, the SMTP connections will be refused by the system
+(which one could consider as less politely :)).
+On outgoing mail, messages will be queued for delayed processing.
+
+The extended load average parameters are given in the Sendmail
+configuration file, and when not present, Sendmail behaves the
+usual way.
+
+
+COMPILATION
+
+Copy the xla.c module in the src sub-directory, edit the Makefile
+in order to define XLA (-DXLA). Also add the xla.[co] module name
+in the list of files so that it gets compiled.
+
+Regenerate sendmail by removing all objects, or at least those
+containing references to XLA (this list may vary, so use grep to
+get the module list). This will generate a new sendmail executable
+containing the xla code.
+
+Debugging level 59 has been assigned to this module and when used
+it provides some output (sendmail -d59.x). Please check the source
+code to see which levels are supported.
+
+
+CONFIGURATION
+
+The extended average uses a new set of configuration lines in the
+sendmail.cf file. All newly introduced line begin with the letter L
+(capital L).
+
+Before detailling the syntax, first an example (this can be placed
+at any section of the sendmail.cf file, note that the order is
+important). Fields are separated by (one or more) tabs/spaces.
+
+# File name used to store the counters
+L/etc/sendmail.la
+# Classes definition
+# Lname #queue #reject
+L*.insa-lyon.fr 8 3
+L*.univ-lyon1.fr 6 4
+L* 15 16
+
+The first line defines the working file which will be used in order
+to have the occurences of Sendmail read and update the counters. The
+format of this file is described in the "Design" section.
+This line is mandatory and the specified file must be absolute (ie
+begin with a slash).
+
+Then you can specify one or more classes. The last class (*) is also
+mandatory and should be in last position as the first match will stop
+the search and if there is no match the behavior of Sendmail is unknown.
+
+Each class has three fields separated by one or more tabs/spaces.
+
+L{mask} {queue_#} {refuse_#}
+
+The {mask} is a simple mask. It can be either an explicit host name
+(like grasp.insa-lyon.fr) or a mask starting with "*." or just "*".
+No other variants are allowed.
+
+Lgrasp.insa-lyon.fr will match exactely any session to/from this host.
+
+L*.insa-lyon.fr will match any session to/from any machine in the
+ insa-lyon.fr domain as well as from the machine
+ named "insa-lyon.fr" if it exists.
+
+L* will match any session, and thus should also be
+ last in the list to act as a catchup line.
+
+The {queue_#} is the maximum number of SMTP sessions in the given class
+for both incoming and outgoing messages. The {refuse_#} indicates when
+to refuse incoming messages for this class. The interaction between
+those counters is somewhat subtle. It seems logical that a standard
+configuration has {queue_#} >= {refuse_#}, and in fact in most
+configurations they can be equal (that's why what I use in my environment).
+Thus, this is not mandatory. If {queue_#} < {refuse_#} outgoing messages
+will be lower priority than incoming messages and once a class gets loaded
+the outgoing messages are blocked first.
+
+I use very low values in some situations, for example I have a customer
+connected to the Internet via a 9600 bps line, they also have internal
+users sending burst of messages (10, 20 small messages coming in just
+one or two seconds). Both situations were unsupportable. The line is
+too slow to handle many simultaneous connections and the mail server
+does not have the ressources to handle such a heavy load (it's a 12 Megs
+Sun 3 also doing Usenet news).
+
+I have defined following section in the configuration file, and experience
+shows the benefits for everyone. Fake domain for the example: customer.fr.
+
+L/etc/sendmail.la
+L*.customer.fr 8 8
+L* 3 3
+
+This means that there might not be more than 8 simultaneous SMTP sessions
+between the mail server and any other internal host. This is to protect
+the station from heavy loads like users (or applications !) sending
+several tenths of messages in just a few seconds).
+No more than 3 SMTP sessions are authorized with any other host, this is
+to save the load of the slow 9600 line to the Internet.
+
+Drawback is that is you have 3 * 2 Megs sessions established from/to the
+outside, all your mail will be held until one slot gets available, on
+a 9600 bps line just make your counts, il blocks your line during over
+one hour.
+
+
+DESIGN
+
+Sendmail will analyze the "L" lines in the configuration file during
+startup (or read the initialized structure from the frozen file).
+When started in daemon mode (and only there), any existing working file
+will be cleared and a new one is created. Each class gets a record in
+the sendmail.la work file. The size of this record is a short integer
+(generally two bytes) and represents the count of active sessions in
+the given class. Read/Write operations in this file are done in
+one operation (as anyway the size is far below one disk sector). The
+file is locked with Sendmail's lockfile() function priori to any
+access.
+
+Handling incoming SMTP sessions.
+
+There is interaction is two points in the Sendmail source code. First
+on the listen system call: if all slots in all classes are in use,
+a listen(0) is done so that the system rejects any incoming SMTP session.
+This avois to fork and then reject the connexion.
+
+If there are some free slots, nothing better than accepting the
+connection, then forking can be done. The child process then checks if
+the adequate class is full or not. If full, it rejects the connection
+with a "421 Too many sessions" diagnostic to the sender (which should
+then appear when the remote users do a mailq). If the treshold {reject_#}
+is not reached, the connection is accepted and the counter is sendmail.la
+is updated.
+
+Handling outgoing SMTP sessions.
+
+As soon as Sendmail needs to connect to a distant host, the adequate class
+is checked against {queue_#} and if no slots are available, the message is
+queued for further processing.
+
+Sendmail's connection caching.
+
+Sendmail-R6 introduces a new design: connection caching, ie several SMTP
+sessions can be opened at the same time. This could cause some problems
+when sending mail, as after having a few connections opened, all slots
+could be in use and generate a partial delivery of the message. In
+order to deal with this, xla.c uses following design "for a given
+sendmail process, only the first connection in a given class is counted".
+This can be done because sendmail does not do parralel message sending
+on the different channels.
+
+End of connection.
+
+As soon as a connection is closed, the counters will be automatically
+updated.
+
+
+
+Please look at the code to understand of all this works. Comments,
+suggestions, questions welcome.
+
+
+
+ Christophe Wolfhugel
+ Herve Schauer Consultants
+ Paris, France
+ May 23, 1993
diff --git a/usr.sbin/sendmail/contrib/xla/xla.c b/usr.sbin/sendmail/contrib/xla/xla.c
new file mode 100644
index 00000000000..627d383676b
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/xla/xla.c
@@ -0,0 +1,532 @@
+/*
+ * (C) Copyright 1993-94, Herve Schauer Consultants
+ *
+ * This module written by Christophe.Wolfhugel@hsc-sec.fr
+ * is to be used under the same conditions and terms (and absence
+ * or warranties) than the other modules of the Sendmail package.
+ *
+ * ABSOLUTELY NO WARRANTY. USE AT YOUR OWN RISKS.
+ *
+ * Version: 940417, applied a patch from Paul Graham <pjg@acsu.buffalo.edu>
+ * (lockfile syntax in xla.c did not reflect anymore the
+ * new one used by sendmail, now fine).
+ *
+ */
+
+
+#ifdef XLA
+
+#ifndef MAXLARULES
+# define MAXLARULES 20
+#endif
+
+# include "sendmail.h"
+
+typedef struct {
+ short queue; /* # of connexions to have queueing */
+ short reject; /* # of conn. to reject */
+ short num; /* # of increments this process */
+ char *mask; /* Mask (domain) */
+ } XLARULE;
+
+char *XlaFname; /* Work file name */
+char XlaHostName[1024]; /* Temporary */
+int XlaNext; /* # of XlaRules */
+pid_t XlaPid; /* Pid updating the tables */
+XLARULE XlaRules[MAXLARULES]; /* The rules themselves */
+short XlaCtr[MAXLARULES]; /* Counter (for work file only) */
+
+extern bool lockfile();
+
+/*
+** XLAMATCH -- Matches a fnmatch like expression.
+**
+** Parameters:
+** mask -- mask to match the string too;
+** name -- string.
+**
+** Mask can either be a plain string or a simplified fnmatch like mask:
+** *.string or string.*
+** No other alternatives are accepted.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+XlaMatch(mask, name)
+ char *mask, *name;
+{
+ int l1, l2;
+
+ l1 = strlen(mask); l2 = strlen(name);
+ if (l1 == 1 && mask[0] == '*') return(TRUE);
+ if (mask[0] == '*' && mask[1] == '.') {
+ if (l2 < (l1 - 2)) return(FALSE);
+ if (strcasecmp(&mask[2], name) == 0) return(TRUE);
+ if (strcasecmp(&mask[1], name + l2 - l1 + 1) == 0) return(TRUE);
+ return(FALSE);
+ }
+ if (l1 < 3) return(FALSE);
+ if (mask[l1 -1] == '*') {
+ if (l2 < l1 - 1) return(FALSE);
+ if (strncasecmp(mask, name, l1 - 1) == 0) return(TRUE);
+ return(FALSE);
+ }
+ if (strcasecmp(mask, name) == 0) return(TRUE);
+ return(FALSE);
+}
+
+/*
+** XLAZERO -- Zeroes the used variables
+**
+** Just initializes some variables, called once at sendmail
+** startup.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+xla_zero()
+{
+ if (tTd(59, 1)) {
+ printf("xla_zero\n");
+ }
+ XlaFname = NULL;
+ XlaNext = 0;
+ XlaPid = 0;
+ memset((char *) &XlaRules[0], 0, sizeof(XLARULE) * MAXLARULES);
+}
+
+
+/*
+** XLAINIT -- initialized extended load average stuff
+**
+** This routine handles the L lines appearing in the configuration
+** file.
+**
+** L/etc/sendmail.la indicates the working file
+** Lmask #1 #2 Xtended LA to apply to mask
+** #1 = Queueing # of connections
+** #2 = Reject connections.
+**
+** Parameters:
+** line -- the cf file line to parse.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Builds several internal tables.
+*/
+
+xla_init(line)
+ char *line;
+{
+ char *s;
+
+ if (tTd(59, 1)) {
+ printf("xla_init line: %s\n", line);
+ }
+ if (XlaFname == NULL && *line == '/') { /* Work file name */
+ XlaFname = newstr(line);
+ if (tTd(59, 10))
+ printf("xla_init: fname = %s\n", XlaFname);
+ return;
+ }
+ if (XlaNext == MAXLARULES) {
+ syserr("too many xla rules defined (%d max)", MAXLARULES);
+ return;
+ }
+ s = strtok(line, " \t");
+ if (s == NULL) {
+ syserr("xla: line unparseable");
+ return;
+ }
+ XlaRules[XlaNext].mask = newstr(s);
+ s = strtok(NULL, " \t");
+ if (s == NULL) {
+ syserr("xla: line unparseable");
+ return;
+ }
+ XlaRules[XlaNext].queue = atoi(s);
+ s = strtok(NULL, " \t");
+ if (s == NULL) {
+ syserr("xla: line unparseable");
+ return;
+ }
+ XlaRules[XlaNext].reject = atoi(s);
+ if (tTd(59, 10))
+ printf("xla_init: rule #%d = %s q=%d r=%d\n", XlaNext,
+ XlaRules[XlaNext].mask,
+ XlaRules[XlaNext].queue, XlaRules[XlaNext].reject);
+ XlaNext++;
+}
+
+
+/*
+** XLACREATEFILE -- Create the working file
+**
+** Tries to create the working file, called each time sendmail is
+** invoked with the -bd option.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Creates the working file (sendmail.la) and zeroes it.
+*/
+
+xla_create_file()
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_create_file:\n");
+ if (XlaFname == NULL) return;
+ fd = open(XlaFname, O_RDWR|O_CREAT, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_create_file: open failed");
+ return;
+ }
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_create_file: can't set lock");
+ return;
+ }
+ if (ftruncate(fd, 0) == -1) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_create_file: can't truncate XlaFname");
+ return;
+ }
+ if (write(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ XlaFname == NULL;
+ syserr("xla_create_file: can't write XlaFname");
+ }
+ close(fd);
+}
+
+
+/*
+** XLASMTPOK -- Checks if all slots are in use
+**
+** Check is there are still some slots available for an SMTP
+** connection.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** TRUE -- slots are available;
+** FALSE -- no more slots.
+**
+** Side Effects:
+** Reads a file, uses a lock and updates sendmail.la if a slot
+** is free for use.
+*/
+
+bool
+xla_smtp_ok()
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_smtp_ok:\n");
+ if (XlaFname == NULL) return(TRUE);
+ fd = open(XlaFname, O_RDWR, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_smtp_ok: open failed");
+ return(TRUE);
+ }
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_smtp_ok: can't set lock");
+ return(TRUE);
+ }
+ if (read(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_smtp_ok: can't read XlaFname");
+ return(TRUE);
+ }
+ close(fd);
+ for (i = 0; i < XlaNext; i++) {
+ if (XlaCtr[i] < XlaRules[i].reject)
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+/*
+** XLAHOSTOK -- Can we accept a connection from this host
+**
+** Check the quota for the indicated host
+**
+** Parameters:
+** name -- host name or IP# (string)
+**
+** Returns:
+** TRUE -- we can accept the connection;
+** FALSE -- we must refuse the connection.1
+**
+** Side Effects:
+** Reads and writes a file, uses a lock and still updates
+** sendmail.la is a slot gets assigned.
+*/
+
+bool
+xla_host_ok(name)
+ char *name;
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_host_ok:\n");
+ if (XlaFname == NULL) return(TRUE);
+ fd = open(XlaFname, O_RDWR, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_host_ok: open failed");
+ return(TRUE);
+ }
+ XlaPid = getpid();
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_host_ok: can't set lock");
+ return(TRUE);
+ }
+ if (read(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_smtp_ok: can't read XlaFname");
+ return(TRUE);
+ }
+ strncpy(XlaHostName, name, sizeof(XlaHostName) -1);
+ XlaHostName[sizeof(XlaHostName) -1] = 0;
+ i = strlen(name) - 1;
+ if (i >= 0 && XlaHostName[i] == '.') XlaHostName[i] = 0;
+ for (i = 0; i < XlaNext; i++) {
+ if (XlaMatch(XlaRules[i].mask, XlaHostName)) {
+ if (XlaCtr[i] < XlaRules[i].reject) {
+ if (XlaRules[i].num++ == 0) {
+ XlaCtr[i]++;
+ lseek(fd, i*sizeof(XlaCtr[i]), SEEK_SET);
+ if (write(fd, &XlaCtr[i], sizeof(XlaCtr[i])) != sizeof(XlaCtr[i]))
+ XlaFname = NULL;
+ }
+ close(fd);
+ return(TRUE);
+ }
+ close(fd);
+ return(FALSE);
+ }
+ }
+ close(fd);
+ return(TRUE);
+}
+
+/*
+** XLANOQUEUEOK -- Can we sent this message to the remote host
+**
+** Check if we can send to the remote host
+**
+** Parameters:
+** name -- host name or IP# (string)
+**
+** Returns:
+** TRUE -- we can send the message to the remote site;
+** FALSE -- we can't connect the remote host, queue.
+**
+** Side Effects:
+** Reads and writes a file, uses a lock.
+** And still updates the sendmail.la file.
+*/
+
+bool
+xla_noqueue_ok(name)
+ char *name;
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_noqueue_ok:\n");
+ if (XlaFname == NULL) return(TRUE);
+ fd = open(XlaFname, O_RDWR, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_noqueue_ok: open failed");
+ return(TRUE);
+ }
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_noqueue_ok: can't set lock");
+ return(TRUE);
+ }
+ XlaPid = getpid();
+ if (read(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_noqueue_ok: can't read XlaFname");
+ return(TRUE);
+ }
+ strncpy(XlaHostName, name, sizeof(XlaHostName) -1);
+ XlaHostName[sizeof(XlaHostName) -1] = 0;
+ i = strlen(name) - 1;
+ if (i >= 0 && XlaHostName[i] == '.') XlaHostName[i] = 0;
+ for (i = 0; i < XlaNext; i++) {
+ if (XlaMatch(XlaRules[i].mask, XlaHostName)) {
+ if (XlaCtr[i] < XlaRules[i].queue) {
+ if (XlaRules[i].num++ == 0) {
+ XlaCtr[i]++;
+ lseek(fd, i*sizeof(XlaCtr[i]), SEEK_SET);
+ if (write(fd, &XlaCtr[i], sizeof(XlaCtr[i])) != sizeof(XlaCtr[i]))
+ XlaFname = NULL;
+ }
+ close(fd);
+ return(TRUE);
+ }
+ close(fd);
+ return(FALSE);
+ }
+ }
+ close(fd);
+ return(TRUE);
+}
+
+
+/*
+** XLAHOSTEND -- Notice that a connection is terminated.
+**
+** Updates the counters to reflect the end of an SMTP session
+** (in or outgoing).
+**
+** Parameters:
+** name -- host name or IP# (string)
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Reads and writes a file, uses a lock.
+** And still updates sendmail.la.
+*/
+
+xla_host_end(name)
+ char *name;
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_host_end:\n");
+ if (XlaFname == NULL || XlaPid != getpid()) return;
+ fd = open(XlaFname, O_RDWR, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_host_end: open failed");
+ return;
+ }
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_host_end: can't set lock");
+ return;
+ }
+ if (read(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_host_end: can't read XlaFname");
+ return(TRUE);
+ }
+ strncpy(XlaHostName, name, sizeof(XlaHostName) -1);
+ XlaHostName[sizeof(XlaHostName) -1] = 0;
+ i = strlen(name) - 1;
+ if (i >= 0 && XlaHostName[i] == '.') XlaHostName[i] = 0;
+ for (i = 0; i < XlaNext; i++) {
+ if (XlaMatch(XlaRules[i].mask, XlaHostName)) {
+ if (XlaRules[i].num > 0 && XlaRules[i].num-- == 1) {
+ if (XlaCtr[i]) XlaCtr[i]--;
+ lseek(fd, i*sizeof(XlaCtr[i]), SEEK_SET);
+ if (write(fd, &XlaCtr[i], sizeof(XlaCtr[i]))
+ != sizeof(XlaCtr[i]))
+ XlaFname = NULL;
+ }
+ close(fd);
+ return;
+ }
+ }
+ close(fd);
+}
+
+/*
+** XLAALLEND -- Mark all connections as closed.
+**
+** Generally due to an emergency exit.
+**
+** Parameters:
+** name -- host name or IP# (string)
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Reads and writes a file, uses a lock.
+** And guess what: updates sendmail.la.
+*/
+
+xla_all_end()
+{
+ int fd, i;
+
+ if (tTd(59, 1))
+ printf("xla_all_end:\n");
+ if (XlaFname == NULL || XlaPid != getpid()) return;
+ fd = open(XlaFname, O_RDWR, 0644);
+ if (fd == -1) {
+ XlaFname = NULL;
+ syserr("xla_all_end: open failed");
+ return;
+ }
+ if (!lockfile(fd, XlaFname, NULL, LOCK_EX)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_all_end: can't set lock");
+ return;
+ }
+ if (read(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ close(fd);
+ XlaFname = NULL;
+ syserr("xla_all_end: can't read XlaFname");
+ return(TRUE);
+ }
+ for (i = 0; i < XlaNext; i++) {
+ if (XlaCtr[i] > 0 && XlaRules[i].num > 0) {
+ XlaCtr[i]--; XlaRules[i].num = 0;
+ }
+ }
+ lseek(fd, 0, SEEK_SET);
+ if (write(fd, XlaCtr, sizeof(XlaCtr)) != sizeof(XlaCtr)) {
+ XlaFname = NULL;
+ }
+ close(fd);
+}
+#endif /* XLA */
diff --git a/usr.sbin/sendmail/doc/changes/Makefile b/usr.sbin/sendmail/doc/changes/Makefile
new file mode 100644
index 00000000000..46447c2e534
--- /dev/null
+++ b/usr.sbin/sendmail/doc/changes/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.1 (Berkeley) 4/13/94
+
+DIR= smm/09.sendmail
+SRCS= changes.me
+MACROS= -me
+
+all: changes.ps
+
+changes.ps: ${SRCS}
+ rm -f ${.TARGET}
+ ${PIC} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/sendmail/doc/changes/changes.me b/usr.sbin/sendmail/doc/changes/changes.me
new file mode 100644
index 00000000000..0b91ed0d438
--- /dev/null
+++ b/usr.sbin/sendmail/doc/changes/changes.me
@@ -0,0 +1,997 @@
+.\" Copyright (c) 1994 Eric P. Allman
+.\" Copyright (c) 1988, 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.
+.\"
+.\" @(#)changes.me 8.1 (Berkeley) 4/13/94
+.\"
+.\" ditroff -me -Pxx changes.me
+.eh '%''Changes in Sendmail Version 8'
+.oh 'Changes in Sendmail Version 8''%'
+.nr si 3n
+.if n .ls 2
+.+c
+.(l C
+.sz 14
+Changes in Sendmail Version 8*
+.sz
+.sp
+Eric Allman
+.sp 0.5
+.i
+University of California, Berkeley
+Mammoth Project
+.)l
+.(f
+*An earlier version of this paper was printed in the
+Proceedings of the 1994 AUUG Queensland Summer Technical Conference,
+Gateway Hotel, Brisbane, March 1994.
+.)f
+.sp
+.(l F
+.ce
+ABSTRACT
+.sp \n(psu
+Version 8 of
+.i sendmail
+includes a number of major changes from previous versions.
+This paper gives a very short history of
+.i sendmail ,
+a summary of the major differences between version 5
+(the last publically available version)
+and version 8,
+and some discussion of future directions.
+.)l
+.sp 2
+.pp
+In 1987, the author stopped major work on
+.i sendmail
+due to other time committments,
+only to return to active work in 1991.
+This paper explores why work resumed
+and what changes have been made.
+.pp
+Section 1 gives a short history of
+.i sendmail
+through version 5 and the motivation behind working on version 8.
+Section 2 has
+a rather detailed description of what has changed
+between version 5 and version 8.
+The paper finishes off with some thoughts
+about what still needs to be done.
+.sh 1 "HISTORY"
+.pp
+As discussed elsewhere,
+[Allman83a, Allman83b, Allman&Amos85]
+sendmail has existed in various forms since 1980.
+It was released under the name
+.i delivermail
+in 4BSD and 4.1BSD, and as
+.i sendmail
+in 4.2BSD.
+.\"4.0BSD delivermail 1.10
+.\"4.1BSD delivermail 1.10
+.\"4.2BSD sendmail 4.12
+.\"4.3BSD sendmail 5.52
+It quickly became the dominant mail system for networked UNIX systems.
+.pp
+Prior the release of 4.3BSD in November 1986,
+the author had left the University for private industry,
+but continued to do some work on
+.i sendmail
+with activity slowly trailing off
+until effectively stopping after February 1987.
+There was minimal support done by many people for several years,
+until July of 1991 when the original author,
+who had returned the University,
+started active work on it again.
+.pp
+There were several reasons for renewed work on
+.i sendmail .
+There was a desire at Berkeley to convert to a subdomained structure
+so that individuals were identified by their subdomain
+rather than by their individual workstation;
+although possible in the old code, there were some problems,
+and the author was the obvious person to address them.
+The Computer Systems Research Group (CSRG),
+the group that produced the Berkeley Software Distributions,
+was working on 4.4BSD,
+and wanted an update to the mail system.
+Bryan Costales was working on a book on
+.i sendmail
+that was being reviewed by the author,
+which encouraged him to make some revisions.
+And the author wanted to try to unify some of the disparate versions of
+.i sendmail
+that had been permitted to proliferate.
+.pp
+During the 1987\-91 fallow period,
+many vendors and outside volunteers
+had produced variants of
+.i sendmail .
+Perhaps the best known is the IDA version
+[IDA87].
+Originally intended to be a new set of configuration files,
+IDA expanded into a fairly large set of patches for the code.
+Originally produced in Sweden,
+IDA development passed to the University of Illinois,
+and was widely used by the fairly large set of people
+who prefer to get and compile their own source code
+rather than use vendor-supplied binaries.
+.pp
+In about the same time frame,
+attempts were made to clean up and extend the Simple Mail Transport Protocol
+(SMTP)
+[RFC821].
+This involved clarifications of some ambiguities in the protocol,
+and correction of some problem areas
+[RFC1123],
+as well as extensions for additional functionality
+(dubbed Extended Simple Mail Transport Protocol, or ESMTP)
+[RFC1425, RFC1426, RFC1427]
+and a richer set of semantics in the body of messages
+(the Multipurpose Internet Mail Extensions, a.k.a. MIME)
+[RFC1521, RFC1344].
+Neither the IDA group nor most vendors
+were modifying
+.i sendmail
+to conform to these new standards.
+It seemed clear that these were ``good things''
+that should be encouraged.
+However, since no one was working on a publically available version of
+.i sendmail
+with these updates,
+they were unlikely to be widely deployed any time in the near future.
+.pp
+There are, of course, other mail transport agents available,
+such as
+.i MMDF
+.\"[ref],
+.i zmailer
+.\"[ref],
+.i smail
+.\"[ref],
+and
+.i PP
+.\"[ref].
+However, none of these seemed to be gaining the prominence of
+.i sendmail ;
+it appeared that most companies would not convert to another
+mail transport agent any time in the forseeable future.
+However, they might be persuaded to convert to a newer version of
+.i sendmail .
+.pp
+All of these convinced the author
+to work on a updated version of
+.i sendmail
+for public distribution.
+.pp
+The new version of
+.i sendmail
+is referred to as version eight (V8).
+Versions six and seven were skipped
+because of an agreement
+that all files in 4.4BSD would be numbered as
+.q 8.1 .
+Rather than have an external version number
+that differed from the file version numbers,
+.i sendmail
+just jumped directly to V8.
+.sh 1 "CHANGES IN VERSION EIGHT"
+.pp
+The following is a summary of the changes between the last commonly
+available version of sendmail from Berkeley (5.67) and the latest
+version (8.6.6).
+.pp
+Many of these are ideas that had been tried in IDA,
+but many of them were generalized in V8.
+.sh 2 "Performance Enhancements"
+.pp
+Instead of closing SMTP connections immediately, open connections are
+cached for possible future use. There is a limit to the number of
+simultaneous open connections and the idle time of any individual
+connection.
+.pp
+This is of best help during queue processing (since there is the
+potential of many different messages going to one site), although
+it can also help when processing MX records which aren't handled
+by MX Piggybacking.
+.pp
+If two hosts with different names in a single message happen to
+have the same set of MX hosts, they can be sent in the same
+transaction. Version 8 notices this and tries to batch the messages.
+.pp
+For example, if two sites ``foo.com'' and ``bar.com'' are both
+served by UUNET, they will have the same set of MX hosts and will
+be sent in one transaction. UUNET will then split the message
+and send it to the two individual hosts.
+.sh 2 "RFC 1123 Changes"
+.pp
+A number of changes have been made to make sendmail ``conditionally
+compliant'' (that is, it satisfies all of the MUST clauses and most
+but not all of the SHOULD clauses in RFC 1123).
+.pp
+The major areas of change are (numbers are RFC 1123 section numbers):
+.nr ii 0.75i
+.ip \(sc5.2.7
+Response to RCPT command is fast. Previously, sendmail
+expanded all aliases as far as it could \*- this could
+take a very long time, particularly if there were
+name server delays. Version 8 only checks for the
+existence of an alias and does the expansion later.
+It does still do a DNS lookup if there is an explicit host name
+in the RCPT command,
+but this time is bounded.
+.ip \(sc5.2.8
+Numeric IP addresses are logged in Received: lines.
+This helps tracing spoofed messages.
+.ip \(sc5.2.17
+Self domain literal is properly handled. Previously,
+if someone sent to user@[1.2.3.4], where 1.2.3.4 is
+your IP address, the mail would probably be rejected
+with a ``configuration error''.
+Version 8 can handle these addresses.
+.ip \(sc5.3.2
+Better control over individual timeouts. RFC 821 specified
+no timeouts. Older versions of sendmail had a single
+timeout, typically set to two hours. Version 8 allows
+the configuration file to set timeouts for various
+SMTP commands individually.
+.ip \(sc5.3.3
+Error messages are sent as From:<>. This was urged by
+RFC 821 and reiterated by RFC 1123, but older versions
+of sendmail never really did it properly. Version 8
+does. However, some systems cannot handle this
+perfectly legal address; if necessary, you can create
+a special mailer that uses the `g' flag to disable this.
+.ip \(sc5.3.3
+Error messages are never sent to <>. Previously,
+sendmail was happy to send responses-to-responses which
+sometimes resulted in responses-to-responses-to-responses
+which resulted in .... you get the idea.
+.ip \(sc5.3.3
+Route-addrs (the ugly ``<@hosta,@hostb:user@hostc>''
+syntax) are pruned. RFC 821 urged the use of this
+bletcherous syntax. RFC 1123 has seen the light and
+officially deprecates them, further urging that you
+eliminate all but ``user@hostc'' should you receive
+one of these things. Version 8 is slightly more generous
+than the standards suggest; instead of stripping off all
+the route addressees, it only strips hosts off up to
+the one before the last one known to DNS, thus allowing
+you to have pseudo-hosts such as foo.BITNET. The `R'
+option will turn this off.
+.lp
+The areas in which sendmail is not ``unconditionally compliant'' are:
+.ip \(sc5.2.6
+Sendmail does do header munging.
+.ip \(sc5.2.10
+Sendmail doesn't always use the exact SMTP message
+text from RFC 821. This is a rather silly requirement.
+.ip \(sc5.3.1.1
+Sendmail doesn't guarantee only one connect for each
+host on queue runs. Connection caching gives you most
+of this, but it does not provide a guarantee.
+.ip \(sc5.3.1.1
+Sendmail doesn't always provide an adequate limit
+on concurrency. That is, there can be several
+independent sendmails running at once. My feeling
+is that doing an absolute limit would be a mistake
+(it might result in lost mail). However, if you use
+the XLA contributed software, most of this will be
+guaranteed (but I don't guarantee the guarantee).
+.sh 2 "Extended SMTP Support
+.pp
+Version 8 includes both sending and receiving support for Extended
+SMTP support as defined by RFC 1425 (basic) and RFC 1427 (SIZE);
+and limited support for RFC 1426 (BODY).
+The body support is minimal because the
+.q 8BITMIME
+body type is not currently advertised.
+Although such a body type will be accepted,
+it will not be correctly converted to 7 bits
+if speaking to a non-8-bit-MIME aware SMTP server.
+.pp
+.i Sendmail
+tries to speak ESMTP if you have the `a' flag set
+in the flags for the mailer descriptor,
+or if the other end advertises the fact that it speaks ESMTP.
+This is a non-standard advertisement:
+.i sendmail
+announces
+.q "ESMTP spoken here"
+during the initial connection message,
+and client sendmails search for this message.
+This creates some problems for some PC-based mailers,
+which do not understand two-line greeting messages
+as required by RFC 821.
+.sh 2 "Eight-Bit Clean
+.pp
+Previous versions of sendmail used the 0200 bit for quoting. This
+version avoids that use.
+However, you can set option `7' to get seven bit stripping
+for compatibility with RFC 821,
+which is a 7-bit protocol.
+This option says ``strip to 7 bits on input''.
+.pp
+Individual mailers can still produce seven bit out put using the
+`7' mailer flag.
+This flag says ``strip to 7 bits on output''.
+.sh 2 "User Database"
+.pp
+The User Database (UDB) is an as-yet experimental attempt to provide
+unified large-site name support.
+We are installing it at Berkeley;
+future versions may show significant modifications.
+Briefly, UDB contains a database that is intended to contain
+all the per-user information for your workgroup,
+such as people's full names, their .plan information,
+their outgoing mail name, and their mail drop.
+.pp
+The user database allows you to map both incoming and outgoing
+addresses, much like IDA. However, the interface is still
+better with IDA;
+in particular, the alias file with incoming/outgoing marks
+provides better locality of information.
+.sh 2 "Improved BIND Support"
+.pp
+The BIND support, particularly for MX records, had a number of
+annoying ``features'' which have been removed in this release. In
+particular, these more tightly bind (pun intended) the name server
+to sendmail, so that the name server resolution rules are incorporated
+directly into sendmail.
+.pp
+The major change has been that the $[ ... $] operator didn't fully
+qualify names that were in DNS as A or MX records. Version 8 does
+this qualification.
+.pp
+This has proven to be an annoyance in Sun shops,
+who often still run without BIND support.
+However, it is really critical that this be supported,
+since MX records are mandatory.
+In SunOS you can choose either MX support or NIS support,
+but not both.
+This is fixed in Solaris,
+and some
+.i sendmail
+support to allow this in SunOS should be forthcoming in a future release.
+.sh 2 "Keyed Files"
+.pp
+Generalized keyed files is an idea taken directly from IDA sendmail
+(albeit with a completely different implementation).
+They can be useful on large sites.
+.pp
+Version 8 includes the following built-in map classes:
+.ip dbm
+Support for the ndbm(3) library.
+.ip hash
+Support for the ``Hash'' type from the new Berkeley db(3) library.
+this library provides substantially better database support
+than ndbm(3),
+including in-memory caching,
+arbitrarily long keys and values,
+and better disk utilization.
+.ip btree
+Support for the ``B-Tree'' type from the new Berkeley db(3) library.
+B-Trees provide better clustering than Hashed files
+if you are fetching lots of records that have similar keys,
+such as searching a dictionary for words beginning with ``detr''.
+.ip nis
+Support for NIS (a.k.a. YP) maps.
+NIS+ is not supported in this version.
+.ip host
+Support for DNS lookups.
+.ip dequote
+A ``pseudo-map'' (that is, once that does not have any external data)
+that allows a configuration file to break apart a quoted string
+in the address.
+This is necessary primarily for DECnet addresses,
+which often have quoted addresses that need to be unwrapped on gateways.
+.sh 2 "Multi-Word Classes & Macros in Classes"
+.pp
+Classes can now be multiple words. For example,
+.(b
+CShofmann.CS.Berkeley.EDU
+.)b
+allows you to match the entire string ``hofmann.CS.Berkeley.EDU''
+using the single construct ``$=S''.
+.pp
+Class definitions are now allowed to include macros \*- for example:
+.(b
+Cw$k
+.)b
+is legal.
+.sh 2 "IDENT Protocol Support"
+.pp
+The IDENT protocol as defined in RFC 1413 [RFC1413] is supported.
+However, many systems have a TCP/IP bug that renders this useless,
+and the feature must be turned off.
+Roughly, if one of these system receives a
+.q "No route to host"
+message (ICMP message ICMP_UNREACH_HOST) on
+.i any
+connection, all connections to that host are closed.
+Some firewalls return this error if you try to connect
+to the IDENT port,
+so you can't receive email from these hosts on these systems.
+It's possible that if the firewall used a more specific message
+(such as ICMP_UNREACH_PROTOCOL, ICMP_UNREACH_PORT or ICMP_UNREACH_NET_PROHIB)
+it would work, but this hasn't been verified.
+.pp
+IDENT protocol support cannot be used on
+4.3BSD,
+Apollo DomainOS,
+Apple A/UX,
+ConvexOS,
+Data General DG/UX,
+HP-UX,
+Sequent Dynix,
+or
+Ultrix.
+It seems to work on
+4.4BSD,
+IBM AIX 3.x,
+OSF/1,
+SGI IRIX,
+Solaris,
+and
+SunOS.
+.sh 2 "Separate Envelope/Header Processing
+.pp
+Since the From: line is passed in separately from the envelope
+sender, these have both been made visible; the $g macro is set to
+the envelope sender during processing of mailer argument vectors
+and the header sender during processing of headers.
+.pp
+It is also possible to specify separate per-mailer envelope and
+header processing. The SenderRWSet and RecipientRWset arguments
+for mailers can be specified as ``envelope/header'' to give different
+rewritings for envelope versus header addresses.
+.sh 2 "Owner-List Propagates to Envelope
+.pp
+When an alias has an associated owner-list name, that alias is used
+to change the envelope sender address. This will cause downstream
+errors to be returned to that owner.
+.pp
+Some people find this confusing
+because the envelope sender is what appears in the first
+``From_'' line in UNIX messages
+(that is, the line beginning ``From<space>''
+instead of ``From:'';
+the latter is the header from, which
+.i does
+indicate the sender of the message).
+In previous versions,
+.i sendmail
+has tried to avoid changing the envelope sender
+for back compatibility with UNIX convention;
+at this point that back compatibility is creating too many problems,
+and it is necessary to move forward into the 1980s.
+.sh 2 "Command Line Flags"
+.pp
+The
+.b \-B
+flag has been added to pass in body type information.
+.pp
+The
+.b \-p
+flag has been added to pass in protocol information
+that was previously passed in by defining the
+.b $r
+and
+.b $s
+macros.
+.pp
+The
+.b \-X
+flag has been added to allow logging of all protocol in and
+out of sendmail for debugging.
+You can set
+.q "\-X filename"
+and a complete transcript will be logged in that file.
+This gets big fast: the option is only for debugging.
+.pp
+The
+.b \-q
+flag can limit limit a queue run to specific recipients,
+senders, or queue ids using \-qRsubstring, \-qSsubstring, or
+\-qIsubstring respectively.
+.sh 2 "New Configuration Line Types
+.pp
+The `T' (Trusted users) configuration line has been deleted. It
+will still be accepted but will be ignored.
+.pp
+The `K' line has been added to declare database maps.
+.pp
+The `V' line has been added to declare the configuration version
+level.
+.pp
+The `M' (mailer) line takes a D= field to specify execution
+directory.
+.sh 2 "New and Extended Options"
+.pp
+Several new options have been added, many to support new features,
+others to allow tuning that was previously available only by
+recompiling. Briefly:
+.nr ii 0.5i
+.ip A
+The alias file specification can now be a list of alias files.
+Also, the configuration can specify a class of file.
+For example, to search the NIS aliases, use
+.q OAnis:mail.aliases .
+.ip b
+Insist on a minimum number of disk blocks.
+.ip C
+Delivery checkpoint interval. Checkpoint the queue (to avoid
+duplicate deliveries) every C addresses.
+.ip E
+Default error message. This message (or the contents of the
+indicated file) are prepended to error messages.
+.ip G
+Enable GECOS matching. If you can't find a local user name
+and this option is enabled, do a sequential scan of the passwd
+file to match against full names. Previously a compile option.
+.ip h
+Maximum hop count. Previously this was compiled in.
+.ip I
+This option has been extended to allow setting of resolver parameters.
+.ip j
+Send errors in MIME-encapsulated format.
+.ip J
+Forward file path. Where to search for .forward files \*- defaults
+to $HOME/.forward.
+.ip k
+Connection cache size. The total number of connections that will
+be kept open at any time.
+.ip K
+Connection cache lifetime. The amount of time any connection
+will be permitted to sit idle.
+.ip l
+Enable Errors-To: header. These headers violate RFC 1123;
+this option is included to provide back compatibility with
+old versions of sendmail.
+.ip O
+Incoming daemon options (e.g., use alternate SMTP port).
+.ip p
+Privacy options. These can be used to make your SMTP server
+less friendly.
+.ip r
+This option has been extended to allow finer grained control
+over timeouts.
+For example, you can set the timeout for SMTP commands individually.
+.ip R
+Don't prune route-addrs. Normally, if version 8 sees an address
+like "<@hostA,@hostB:user@hostC>, sendmail will try to strip off
+as much as it can (up to user@hostC) as suggested by RFC 1123.
+This option disables that behaviour.
+.ip T
+The
+.q "Return To Sender"
+timeout has been extended
+to allow specification of a warning message interval,
+typically something on the order of four hours.
+If a message cannot be delivered in that interval,
+a warning message is sent back to the sender
+but the message continues to be tried.
+.ip U
+User database spec. This is still experimental.
+.ip V
+Fallback ``MX'' host. This can be thought of as an MX host
+that applies to all addresses that has a very high preference
+value (that is, use it only if everything else fails).
+.ip w
+If set, assume that if you are the best MX host for a host,
+you should send directly to that host. This is intended
+for compatibility with UIUC sendmail, and may have some
+use on firewalls.
+.ip 7
+Do not run eight bit clean. Technically, you have to assert
+this option to be RFC 821 compatible.
+.sh 2 "New Mailer Definitions"
+.ip L=
+Set the allowable line length. In V5, the L mailer flag implied
+a line length limit of 990 characters; this is now settable to
+an arbitrary value.
+.ip F=a
+Try to use ESMTP. It will fall back to SMTP if the initial
+EHLO packet is rejected.
+.ip F=b
+Ensure a blank line at the end of messages. Useful on the
+*file* mailer.
+.ip F=c
+Strip all comments from addresses; this should only be used as
+a last resort when dealing with cranky mailers.
+.ip F=g
+Never use the null sender as the envelope sender, even when
+running SMTP. This violates RFC 1123.
+.ip F=7
+Strip all output to this mailer to 7 bits.
+.ip F=L
+Used to set the line limit to 990 bytes for SMTP compatibility.
+It now does that only if the L= keyletter is not specified.
+This flag is obsolete and should not be used.
+.sh 2 "New or Changed Pre-Defined Macros"
+.ip $k
+UUCP node name from uname(2).
+.ip $m
+Domain part of our full hostname.
+.ip $_
+RFC 1413-provided sender address.
+.ip $w
+Previously was sometimes the full domain name, sometimes
+just the first word. Now guaranteed to be the first word
+of the domain name (i.e., the host name).
+.ip $j
+Previously had to be defined \*- it is now predefined to be
+the full domain name, if that can be determined. That is,
+it is equivalent to $w.$m.
+.sh 2 "New and Changed Classes"
+.ip $=k
+Initialized to contain $k.
+.ip $=w
+Now includes
+.q [1.2.3.4]
+(where 1.2.3.4 is your IP address)
+to allow the configuration file to recognize your own IP address.
+.sh 2 "New Rewriting Tokens"
+.pp
+The
+.b $&
+construct has been adopted from IDA to defer macro evaluation.
+Normally, macros in rulesets are bound when the rule is first parsed
+during startup.
+Some macros change during processing and are uninteresting during startup.
+However, that macro can be referenced using
+.q $&x
+to defer the evaulation of
+$x
+until the rule is processed.
+.pp
+The tokens
+.b $(
+and
+.b $)
+have been added to allow specification of map rewriting.
+.pp
+Version 8 allows
+.b $@
+on the Left Hand Side of an `R' line to match
+zero tokens.
+This is intended to be used to match the null input.
+.sh 2 "Bigger Defaults
+.pp
+Version 8 allows up to 100 rulesets instead of 30. It is recommended
+that rulesets 0\-9 be reserved for sendmail's dedicated use in future
+releases.
+.pp
+The total number of MX records that can be used has been raised to
+20.
+.pp
+The number of queued messages that can be handled at one time has
+been raised from 600 to 1000.
+.sh 2 "Different Default Tuning Parameters
+.pp
+Version 8 has changed the default parameters for tuning queue costs
+to make the number of recipients more important than the size of
+the message (for small messages). This is reasonable if you are
+connected with reasonably fast links.
+.sh 2 "Auto-Quoting in Addresses
+.pp
+Previously, the ``Full Name <email address>'' syntax would generate
+incorrect protocol output if ``Full Name'' had special characters
+such as dot. This version puts quotes around such names.
+.sh 2 "Symbolic Names On Error Mailer
+.pp
+Several names have been built in to the $@ portion of the $#error
+mailer. For example:
+.(b
+$#error $@NOHOST $: Host unknown
+.)b
+Prints the indicated message
+and sets the exit status of
+.i sendmail
+to
+.sm EX_NOHOST .
+.sh 2 "New Built-In Mailers"
+.pp
+Two new mailers, *file* and *include*, are included to define options
+when mailing to a file or a :include: file respectively. Previously
+these were overloaded on the local mailer.
+.sh 2 "SMTP VRFY Doesn't Expand
+.pp
+Previous versions of sendmail treated VRFY and EXPN the same. In
+this version, VRFY doesn't expand aliases or follow .forward files.
+.pp
+As an optimization, if you run with your default delivery mode
+being queue-only, the RCPT command will also not chase aliases and
+\&.forward files.
+It will chase them when it processes the queue.
+This speeds up RCPT processing.
+.sh 2 "[IPC] Mailers Allow Multiple Hosts
+.pp
+When an address resolves to a mailer that has ``[IPC]'' as its
+``Path'', the $@ part (host name) can be a colon-separated list of
+hosts instead of a single hostname. This asks sendmail to search
+the list for the first entry that is available exactly as though
+it were an MX record. The intent is to route internal traffic
+through internal networks without publishing an MX record to the
+net. MX expansion is still done on the individual items.
+.sh 2 "Aliases Extended"
+.pp
+The implementation has been merged with maps. Among other things,
+this supports multiple alias files and NIS-based aliases. For
+example:
+.(b
+OA/etc/aliases,nis:mail.aliases
+.)b
+will search first the local database
+.q /etc/aliases
+followed by the NIS map
+
+.sh 2 "Portability and Security Enhancements
+.pp
+A number of internal changes have been made to enhance portability.
+.pp
+Several fixes have been made to increase the paranoia factor.
+.pp
+In particular, the permissions required for .forward and :include:
+files have been tightened up considerably. V5 would pretty much
+read any file it could get to as root, which exposed some security
+holes. V8 insists that all directories leading up to the .forward
+or :include: file be searchable ("x" permission) by the controlling
+user" (defined below), that the file itself be readable by the
+controlling user, and that .forward files be owned by the user
+who is being forwarded to or root.
+.pp
+The "controlling user" is the user on whose behalf the mail is
+being delivered. For example, if you mail to "user1" then the
+controlling user for ~user1/.forward and any mailers invoked
+by that .forward file, including :include: files.
+.pp
+Previously, anyone who had a home directory could create a .forward
+could forward to a program. Now, sendmail checks to make sure
+that they have an "approved shell", that is, a shell listed in
+the /etc/shells file.
+.sh 2 "Miscellaneous Fixes and Enhancements"
+.pp
+A number of small bugs having to do with things like backslash-escaped
+quotes inside of comments have been fixed.
+.pp
+The fixed size limit on header lines
+(such as
+.q To:
+and
+.q Cc: )
+has been eliminated;
+those buffers are dynamically allocated now.
+.pp
+Sendmail writes a /etc/sendmail.pid file with the current process id
+and the current invocation flags.
+.pp
+Two people using the same program (e.g., submit) are considered
+"different" so that duplicate elimination doesn't delete one of
+them. For example, two people forwarding their email to
+|submit will be treated as two recipients.
+.pp
+The mailstats program prints mailer names and gets the location of
+the sendmail.st file from /etc/sendmail.cf.
+.pp
+Many minor bugs have been fixed, such as handling of backslashes
+inside of quotes.
+.pp
+A hook has been added to allow rewriting of local addresses after
+aliasing.
+.sh 1 "FUTURE WORK"
+.pp
+The previous section describes
+.i sendmail
+as of version 8.6.6.
+There is still much to be done.
+Some high points are described below.
+This list is by no means exhaustive.
+.sh 2 "Full MIME Support"
+.pp
+Currently
+.i sendmail
+only supports seven bit MIME messages.
+Although it can pass eight bit MIME messages,
+it cannot advertise that fact because the standards say
+that the mail agent must be able to do 8- to 7-bit conversion
+to have full 8-bit support.
+This requires far more extensive modification of the message body
+than is currently supported.
+.pp
+The best way to do this would be to support the general concept
+of an external
+``message filter''
+that could do arbitrary modifications of the message.
+This would allow MIME conversion as well as such things as
+automatic encryption of messages sent over external links.
+This is probably an extremely non-trivial change.
+.sh 2 "Service Switch Abstraction"
+.pp
+Most modern systems include some concept of a
+.q "service switch"
+\*- for example, to look up host names you can try
+DNS, NIS, NIS+, text tables, NetInfo,
+or other services in some arbitrary order.
+This is currently very clumsy in
+.i sendmail ,
+with only limited control of the services provided.
+.sh 2 "More Control of Local Addresses"
+.pp
+Currently some addresses are declared as
+.q local
+and are handled specially \*-
+for example, they may have .forward files,
+may be translated into program calls or file deliveries,
+and so forth.
+These should be broken out into separate flags
+to allow the local system administrator
+to have more fine-grained control over operations.
+.sh 2 "More Run-Time Configuration Options"
+.pp
+There are many options that are configured at compile time,
+such as the method of file locking
+and the use of the IDENT protocol
+[RFC1413].
+These should be transfered to run time
+by adding new options.
+.pp
+Similarly, some options are currently overloaded,
+that is, a single option controls more than one thing.
+These should probably be broken out into separate options.
+.pp
+This implies that options will change from single characters
+to words.
+.sh 2 "More Configuration Control Over Errors"
+.pp
+Currently,
+the configuration file can generate an error message during parsing.
+However,
+it cannot tweak other operations,
+such as issuing a warning message to the system postmaster.
+Similarly,
+some errors should not be triggered if they are in aliases
+during an alias file rebuild,
+but should be triggered if that alias is actually used.
+.sh 2 "Long Term Host State"
+.pp
+Currently,
+.i sendmail
+only remembers host status during a single queue run.
+This should be converted to long term status
+stored on disk
+so it can be shared between instantiations of
+.i sendmail .
+Entries will have to be timestamped
+so they can time out.
+This will allow
+.i sendmail
+to implement exponential backoff on queue runs
+on a per-host basis.
+.sh 2 "Connection Control"
+.pp
+Modern networks have different types of connectivity
+than the past.
+In particular, the rising prominence of dialup IP
+has created certain challenges for automated servers.
+It is not uncommon to try to make a connection to a host
+and have it fail, even though if you tried again it would succeed.
+The connection management could be a bit cleverer
+to try to adapt to such situations.
+.sh 2 "Other Caching"
+.pp
+When you do an MX record lookup,
+the name server automatically returns the IP addresses
+of the associated MX servers.
+This information is currently ignored,
+and another query is done to get this information.
+It should be cached to avoid excess name server traffic.
+.sh 1 "REFERENCES"
+.ip [Allman83a]
+.q "Sendmail \*- An Internetwork Mail Router."
+E. Allman.
+In
+.ul
+Unix Programmers's Manual,
+4.2 Berkeley Software Distribution,
+volume 2C.
+August 1983.
+.ip [Allman83b]
+.q "Mail Systems and Addressing in 4.2BSD."
+E. Allman
+In
+.ul
+UNICOM Conference Proceedings.
+San Diego, California.
+January 1983.
+.ip [Allman&Amos85]
+``Sendmail Revisited.''
+E. Allman and M. Amos.
+In
+.ul
+Usenix Summer 1985 Conference Proceedings.
+Portland, Oregon.
+June 1985.
+.ip [IDA87]
+.ul 3
+Electronic Mail Addressing in Theory and Practice
+with the IDA Sendmail Enhancement Kit
+(or The Postmaster's Last Will and Testament).
+Lennart Lo\*:vstrand.
+Department of Computer and Information Science,
+University of Linko\*:ping,
+Sweden,
+Report no. LiTH-IDA-Ex-8715.
+May 1987.
+.ip [RFC821]
+.ul
+Simple Mail Transport Protocol.
+J. Postel.
+August 1982.
+.ip [RFC1123]
+.ul
+Requirements for Internet Hosts \*- Application and Support.
+Internet Engineering Task Force,
+R. Braden, Editor.
+October 1989.
+.ip [RFC1344]
+.ul
+Implications of MIME for Internet Mail Gateways.
+N. Borenstein.
+June 1992.
+.ip [RFC1413]
+.ul
+Identification Protocol.
+M. St. Johns.
+February 1993.
+.ip [RFC1425]
+.ul
+SMTP Service Extensions.
+J. Klensin, N. Freed, M. Rose, E. Stefferud, and D. Crocker.
+February 1993.
+.ip [RFC1426]
+.ul
+SMTP Service Extension for 8bit-MIMEtransport.
+J. Klensin, N. Freed, M. Rose, E. Stefferud, and D. Crocker.
+February 1993.
+.ip [RFC1427]
+.ul
+SMTP Service Extension for Message Size Declaration.
+J. Klensin, N. Freed, and K. Moore.
+February 1993.
+.ip [RFC1521]
+.ul 3
+MIME (Multipurpose Internet Mail Extensions) Part One:
+Mechanisms for Specifying and Describing
+the Format of Internet Message Bodies.
+N. Borenstein and N. Freed.
+September 1993.
diff --git a/usr.sbin/sendmail/doc/intro/Makefile b/usr.sbin/sendmail/doc/intro/Makefile
new file mode 100644
index 00000000000..939cd6c17eb
--- /dev/null
+++ b/usr.sbin/sendmail/doc/intro/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.2 (Berkeley) 2/28/94
+
+DIR= smm/09.sendmail
+SRCS= intro.me
+MACROS= -me
+
+all: intro.ps
+
+intro.ps: ${SRCS}
+ rm -f ${.TARGET}
+ ${PIC} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/sendmail/doc/intro/intro.me b/usr.sbin/sendmail/doc/intro/intro.me
new file mode 100644
index 00000000000..0406bb1fdd6
--- /dev/null
+++ b/usr.sbin/sendmail/doc/intro/intro.me
@@ -0,0 +1,1478 @@
+.\" Copyright (c) 1983 Eric P. Allman
+.\" 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.
+.\"
+.\" @(#)intro.me 8.2 (Berkeley) 11/27/93
+.\"
+.\" pic -Pxx intro.me | ditroff -me -Pxx
+.eh 'SMM:9-%''SENDMAIL \*- An Internetwork Mail Router'
+.oh 'SENDMAIL \*- An Internetwork Mail Router''SMM:9-%'
+.nr si 3n
+.if n .ls 2
+.+c
+.(l C
+.sz 14
+SENDMAIL \*- An Internetwork Mail Router
+.sz
+.sp
+Eric Allman*
+.sp 0.5
+.i
+University of California, Berkeley
+Mammoth Project
+.)l
+.sp
+.(l F
+.ce
+ABSTRACT
+.sp \n(psu
+Routing mail through a heterogenous internet presents many new
+problems. Among the worst of these is that of address mapping.
+Historically, this has been handled on an
+.i "ad hoc"
+basis. However,
+this approach has become unmanageable as internets grow.
+.sp \n(psu
+Sendmail acts a unified "post office" to which all mail can be
+submitted. Address interpretation is controlled by a production
+system, which can parse both domain-based addressing and old-style
+.i "ad hoc"
+addresses.
+The production system is powerful
+enough to rewrite addresses in the message header to conform to the
+standards of a number of common target networks, including old
+(NCP/RFC733) Arpanet, new (TCP/RFC822) Arpanet, UUCP, and Phonenet.
+Sendmail also implements an SMTP server, message
+queueing, and aliasing.
+.)l
+.sp 2
+.(f
+*A considerable part of this work
+was done while under the employ
+of the INGRES Project
+at the University of California at Berkeley
+and at Britton Lee.
+.)f
+.pp
+.i Sendmail
+implements a general internetwork mail routing facility,
+featuring aliasing and forwarding,
+automatic routing to network gateways,
+and flexible configuration.
+.pp
+In a simple network,
+each node has an address,
+and resources can be identified
+with a host-resource pair;
+in particular,
+the mail system can refer to users
+using a host-username pair.
+Host names and numbers have to be administered by a central authority,
+but usernames can be assigned locally to each host.
+.pp
+In an internet,
+multiple networks with different characterstics
+and managements
+must communicate.
+In particular,
+the syntax and semantics of resource identification change.
+Certain special cases can be handled trivially
+by
+.i "ad hoc"
+techniques,
+such as
+providing network names that appear local to hosts
+on other networks,
+as with the Ethernet at Xerox PARC.
+However, the general case is extremely complex.
+For example,
+some networks require point-to-point routing,
+which simplifies the database update problem
+since only adjacent hosts must be entered
+into the system tables,
+while others use end-to-end addressing.
+Some networks use a left-associative syntax
+and others use a right-associative syntax,
+causing ambiguity in mixed addresses.
+.pp
+Internet standards seek to eliminate these problems.
+Initially, these proposed expanding the address pairs
+to address triples,
+consisting of
+{network, host, resource}
+triples.
+Network numbers must be universally agreed upon,
+and hosts can be assigned locally
+on each network.
+The user-level presentation was quickly expanded
+to address domains,
+comprised of a local resource identification
+and a hierarchical domain specification
+with a common static root.
+The domain technique
+separates the issue of physical versus logical addressing.
+For example,
+an address of the form
+.q "eric@a.cc.berkeley.arpa"
+describes only the logical
+organization of the address space.
+.pp
+.i Sendmail
+is intended to help bridge the gap
+between the totally
+.i "ad hoc"
+world
+of networks that know nothing of each other
+and the clean, tightly-coupled world
+of unique network numbers.
+It can accept old arbitrary address syntaxes,
+resolving ambiguities using heuristics
+specified by the system administrator,
+as well as domain-based addressing.
+It helps guide the conversion of message formats
+between disparate networks.
+In short,
+.i sendmail
+is designed to assist a graceful transition
+to consistent internetwork addressing schemes.
+.sp
+.pp
+Section 1 discusses the design goals for
+.i sendmail .
+Section 2 gives an overview of the basic functions of the system.
+In section 3,
+details of usage are discussed.
+Section 4 compares
+.i sendmail
+to other internet mail routers,
+and an evaluation of
+.i sendmail
+is given in section 5,
+including future plans.
+.sh 1 "DESIGN GOALS"
+.pp
+Design goals for
+.i sendmail
+include:
+.np
+Compatibility with the existing mail programs,
+including Bell version 6 mail,
+Bell version 7 mail
+[UNIX83],
+Berkeley
+.i Mail
+[Shoens79],
+BerkNet mail
+[Schmidt79],
+and hopefully UUCP mail
+[Nowitz78a, Nowitz78b].
+ARPANET mail
+[Crocker77a, Postel77]
+was also required.
+.np
+Reliability, in the sense of guaranteeing
+that every message is correctly delivered
+or at least brought to the attention of a human
+for correct disposal;
+no message should ever be completely lost.
+This goal was considered essential
+because of the emphasis on mail in our environment.
+It has turned out to be one of the hardest goals to satisfy,
+especially in the face of the many anomalous message formats
+produced by various ARPANET sites.
+For example,
+certain sites generate improperly formated addresses,
+occasionally
+causing error-message loops.
+Some hosts use blanks in names,
+causing problems with
+UNIX mail programs that assume that an address
+is one word.
+The semantics of some fields
+are interpreted slightly differently
+by different sites.
+In summary,
+the obscure features of the ARPANET mail protocol
+really
+.i are
+used and
+are difficult to support,
+but must be supported.
+.np
+Existing software to do actual delivery
+should be used whenever possible.
+This goal derives as much from political and practical considerations
+as technical.
+.np
+Easy expansion to
+fairly complex environments,
+including multiple
+connections to a single network type
+(such as with multiple UUCP or Ether nets
+[Metcalfe76]).
+This goal requires consideration of the contents of an address
+as well as its syntax
+in order to determine which gateway to use.
+For example,
+the ARPANET is bringing up the
+TCP protocol to replace the old NCP protocol.
+No host at Berkeley runs both TCP and NCP,
+so it is necessary to look at the ARPANET host name
+to determine whether to route mail to an NCP gateway
+or a TCP gateway.
+.np
+Configuration should not be compiled into the code.
+A single compiled program should be able to run as is at any site
+(barring such basic changes as the CPU type or the operating system).
+We have found this seemingly unimportant goal
+to be critical in real life.
+Besides the simple problems that occur when any program gets recompiled
+in a different environment,
+many sites like to
+.q fiddle
+with anything that they will be recompiling anyway.
+.np
+.i Sendmail
+must be able to let various groups maintain their own mailing lists,
+and let individuals specify their own forwarding,
+without modifying the system alias file.
+.np
+Each user should be able to specify which mailer to execute
+to process mail being delivered for him.
+This feature allows users who are using specialized mailers
+that use a different format to build their environment
+without changing the system,
+and facilitates specialized functions
+(such as returning an
+.q "I am on vacation"
+message).
+.np
+Network traffic should be minimized
+by batching addresses to a single host where possible,
+without assistance from the user.
+.pp
+These goals motivated the architecture illustrated in figure 1.
+.(z
+.hl
+.ie t \
+\{\
+.ie !"\*(.T"" \
+\{\
+.PS
+boxht = 0.5i
+boxwid = 1.0i
+
+ down
+S: [
+ right
+ S1: box "sender1"
+ move
+ box "sender2"
+ move
+ S3: box "sender3"
+ ]
+ arrow
+SM: box "sendmail" wid 2i ht boxht
+ arrow
+M: [
+ right
+ M1: box "mailer1"
+ move
+ box "mailer2"
+ move
+ M3: box "mailer3"
+ ]
+
+ arrow from S.S1.s to 1/2 between SM.nw and SM.n
+ arrow from S.S3.s to 1/2 between SM.n and SM.ne
+
+ arrow from 1/2 between SM.sw and SM.s to M.M1.n
+ arrow from 1/2 between SM.s and SM.se to M.M3.n
+.PE
+.\}
+.el \
+. sp 18
+.\}
+.el \{\
+.(c
++---------+ +---------+ +---------+
+| sender1 | | sender2 | | sender3 |
++---------+ +---------+ +---------+
+ | | |
+ +----------+ + +----------+
+ | | |
+ v v v
+ +-------------+
+ | sendmail |
+ +-------------+
+ | | |
+ +----------+ + +----------+
+ | | |
+ v v v
++---------+ +---------+ +---------+
+| mailer1 | | mailer2 | | mailer3 |
++---------+ +---------+ +---------+
+.)c
+.\}
+
+.ce
+Figure 1 \*- Sendmail System Structure.
+.hl
+.)z
+The user interacts with a mail generating and sending program.
+When the mail is created,
+the generator calls
+.i sendmail ,
+which routes the message to the correct mailer(s).
+Since some of the senders may be network servers
+and some of the mailers may be network clients,
+.i sendmail
+may be used as an internet mail gateway.
+.sh 1 "OVERVIEW"
+.sh 2 "System Organization"
+.pp
+.i Sendmail
+neither interfaces with the user
+nor does actual mail delivery.
+Rather,
+it collects a message
+generated by a user interface program (UIP)
+such as Berkeley
+.i Mail ,
+MS
+[Crocker77b],
+or MH
+[Borden79],
+edits the message as required by the destination network,
+and calls appropriate mailers
+to do mail delivery or queueing for network transmission\**.
+.(f
+\**except when mailing to a file,
+when
+.i sendmail
+does the delivery directly.
+.)f
+This discipline allows the insertion of new mailers
+at minimum cost.
+In this sense
+.i sendmail
+resembles the Message Processing Module (MPM)
+of [Postel79b].
+.sh 2 "Interfaces to the Outside World"
+.pp
+There are three ways
+.i sendmail
+can communicate with the outside world,
+both in receiving and in sending mail.
+These are using the conventional UNIX
+argument vector/return status,
+speaking SMTP over a pair of UNIX pipes,
+and speaking SMTP over an interprocess(or) channel.
+.sh 3 "Argument vector/exit status"
+.pp
+This technique is the standard UNIX method
+for communicating with the process.
+A list of recipients is sent in the argument vector,
+and the message body is sent on the standard input.
+Anything that the mailer prints
+is simply collected and sent back to the sender
+if there were any problems.
+The exit status from the mailer is collected
+after the message is sent,
+and a diagnostic is printed if appropriate.
+.sh 3 "SMTP over pipes"
+.pp
+The SMTP protocol
+[Postel82]
+can be used to run an interactive lock-step interface
+with the mailer.
+A subprocess is still created,
+but no recipient addresses are passed to the mailer
+via the argument list.
+Instead, they are passed one at a time
+in commands sent to the processes standard input.
+Anything appearing on the standard output
+must be a reply code
+in a special format.
+.sh 3 "SMTP over an IPC connection"
+.pp
+This technique is similar to the previous technique,
+except that it uses a 4.2bsd IPC channel
+[UNIX83].
+This method is exceptionally flexible
+in that the mailer need not reside
+on the same machine.
+It is normally used to connect to a sendmail process
+on another machine.
+.sh 2 "Operational Description"
+.pp
+When a sender wants to send a message,
+it issues a request to
+.i sendmail
+using one of the three methods described above.
+.i Sendmail
+operates in two distinct phases.
+In the first phase,
+it collects and stores the message.
+In the second phase,
+message delivery occurs.
+If there were errors during processing
+during the second phase,
+.i sendmail
+creates and returns a new message describing the error
+and/or returns an status code
+telling what went wrong.
+.sh 3 "Argument processing and address parsing"
+.pp
+If
+.i sendmail
+is called using one of the two subprocess techniques,
+the arguments
+are first scanned
+and option specifications are processed.
+Recipient addresses are then collected,
+either from the command line
+or from the SMTP
+RCPT command,
+and a list of recipients is created.
+Aliases are expanded at this step,
+including mailing lists.
+As much validation as possible of the addresses
+is done at this step:
+syntax is checked, and local addresses are verified,
+but detailed checking of host names and addresses
+is deferred until delivery.
+Forwarding is also performed
+as the local addresses are verified.
+.pp
+.i Sendmail
+appends each address
+to the recipient list after parsing.
+When a name is aliased or forwarded,
+the old name is retained in the list,
+and a flag is set that tells the delivery phase
+to ignore this recipient.
+This list is kept free from duplicates,
+preventing alias loops
+and duplicate messages deliverd to the same recipient,
+as might occur if a person is in two groups.
+.sh 3 "Message collection"
+.pp
+.i Sendmail
+then collects the message.
+The message should have a header at the beginning.
+No formatting requirements are imposed on the message
+except that they must be lines of text
+(i.e., binary data is not allowed).
+The header is parsed and stored in memory,
+and the body of the message is saved
+in a temporary file.
+.pp
+To simplify the program interface,
+the message is collected even if no addresses were valid.
+The message will be returned with an error.
+.sh 3 "Message delivery"
+.pp
+For each unique mailer and host in the recipient list,
+.i sendmail
+calls the appropriate mailer.
+Each mailer invocation sends to all users receiving the message on one host.
+Mailers that only accept one recipient at a time
+are handled properly.
+.pp
+The message is sent to the mailer
+using one of the same three interfaces
+used to submit a message to sendmail.
+Each copy of the message is
+prepended by a customized header.
+The mailer status code is caught and checked,
+and a suitable error message given as appropriate.
+The exit code must conform to a system standard
+or a generic message
+(\c
+.q "Service unavailable" )
+is given.
+.sh 3 "Queueing for retransmission"
+.pp
+If the mailer returned an status that
+indicated that it might be able to handle the mail later,
+.i sendmail
+will queue the mail and try again later.
+.sh 3 "Return to sender"
+.pp
+If errors occur during processing,
+.i sendmail
+returns the message to the sender for retransmission.
+The letter can be mailed back
+or written in the file
+.q dead.letter
+in the sender's home directory\**.
+.(f
+\**Obviously, if the site giving the error is not the originating
+site, the only reasonable option is to mail back to the sender.
+Also, there are many more error disposition options,
+but they only effect the error message \*- the
+.q "return to sender"
+function is always handled in one of these two ways.
+.)f
+.sh 2 "Message Header Editing"
+.pp
+Certain editing of the message header
+occurs automatically.
+Header lines can be inserted
+under control of the configuration file.
+Some lines can be merged;
+for example,
+a
+.q From:
+line and a
+.q Full-name:
+line can be merged under certain circumstances.
+.sh 2 "Configuration File"
+.pp
+Almost all configuration information is read at runtime
+from an ASCII file,
+encoding
+macro definitions
+(defining the value of macros used internally),
+header declarations
+(telling sendmail the format of header lines that it will process specially,
+i.e., lines that it will add or reformat),
+mailer definitions
+(giving information such as the location and characteristics
+of each mailer),
+and address rewriting rules
+(a limited production system to rewrite addresses
+which is used to parse and rewrite the addresses).
+.pp
+To improve performance when reading the configuration file,
+a memory image can be provided.
+This provides a
+.q compiled
+form of the configuration file.
+.sh 1 "USAGE AND IMPLEMENTATION"
+.sh 2 "Arguments"
+.pp
+Arguments may be flags and addresses.
+Flags set various processing options.
+Following flag arguments,
+address arguments may be given,
+unless we are running in SMTP mode.
+Addresses follow the syntax in RFC822
+[Crocker82]
+for ARPANET
+address formats.
+In brief, the format is:
+.np
+Anything in parentheses is thrown away
+(as a comment).
+.np
+Anything in angle brackets (\c
+.q "<\|>" )
+is preferred
+over anything else.
+This rule implements the ARPANET standard that addresses of the form
+.(b
+user name <machine-address>
+.)b
+will send to the electronic
+.q machine-address
+rather than the human
+.q "user name."
+.np
+Double quotes
+(\ "\ )
+quote phrases;
+backslashes quote characters.
+Backslashes are more powerful
+in that they will cause otherwise equivalent phrases
+to compare differently \*- for example,
+.i user
+and
+.i
+"user"
+.r
+are equivalent,
+but
+.i \euser
+is different from either of them.
+.pp
+Parentheses, angle brackets, and double quotes
+must be properly balanced and nested.
+The rewriting rules control remaining parsing\**.
+.(f
+\**Disclaimer: Some special processing is done
+after rewriting local names; see below.
+.)f
+.sh 2 "Mail to Files and Programs"
+.pp
+Files and programs are legitimate message recipients.
+Files provide archival storage of messages,
+useful for project administration and history.
+Programs are useful as recipients in a variety of situations,
+for example,
+to maintain a public repository of systems messages
+(such as the Berkeley
+.i msgs
+program,
+or the MARS system
+[Sattley78]).
+.pp
+Any address passing through the initial parsing algorithm
+as a local address
+(i.e, not appearing to be a valid address for another mailer)
+is scanned for two special cases.
+If prefixed by a vertical bar (\c
+.q \^|\^ )
+the rest of the address is processed as a shell command.
+If the user name begins with a slash mark (\c
+.q /\^ )
+the name is used as a file name,
+instead of a login name.
+.pp
+Files that have setuid or setgid bits set
+but no execute bits set
+have those bits honored if
+.i sendmail
+is running as root.
+.sh 2 "Aliasing, Forwarding, Inclusion"
+.pp
+.i Sendmail
+reroutes mail three ways.
+Aliasing applies system wide.
+Forwarding allows each user to reroute incoming mail
+destined for that account.
+Inclusion directs
+.i sendmail
+to read a file for a list of addresses,
+and is normally used
+in conjunction with aliasing.
+.sh 3 "Aliasing"
+.pp
+Aliasing maps names to address lists using a system-wide file.
+This file is indexed to speed access.
+Only names that parse as local
+are allowed as aliases;
+this guarantees a unique key
+(since there are no nicknames for the local host).
+.sh 3 "Forwarding"
+.pp
+After aliasing,
+recipients that are local and valid
+are checked for the existence of a
+.q .forward
+file in their home directory.
+If it exists,
+the message is
+.i not
+sent to that user,
+but rather to the list of users in that file.
+Often
+this list will contain only one address,
+and the feature will be used for network mail forwarding.
+.pp
+Forwarding also permits a user to specify a private incoming mailer.
+For example,
+forwarding to:
+.(b
+"\^|\|/usr/local/newmail myname"
+.)b
+will use a different incoming mailer.
+.sh 3 "Inclusion"
+.pp
+Inclusion is specified in RFC 733 [Crocker77a] syntax:
+.(b
+:Include: pathname
+.)b
+An address of this form reads the file specified by
+.i pathname
+and sends to all users listed in that file.
+.pp
+The intent is
+.i not
+to support direct use of this feature,
+but rather to use this as a subset of aliasing.
+For example,
+an alias of the form:
+.(b
+project: :include:/usr/project/userlist
+.)b
+is a method of letting a project maintain a mailing list
+without interaction with the system administration,
+even if the alias file is protected.
+.pp
+It is not necessary to rebuild the index on the alias database
+when a :include: list is changed.
+.sh 2 "Message Collection"
+.pp
+Once all recipient addresses are parsed and verified,
+the message is collected.
+The message comes in two parts:
+a message header and a message body,
+separated by a blank line.
+.pp
+The header is formatted as a series of lines
+of the form
+.(b
+ field-name: field-value
+.)b
+Field-value can be split across lines by starting the following
+lines with a space or a tab.
+Some header fields have special internal meaning,
+and have appropriate special processing.
+Other headers are simply passed through.
+Some header fields may be added automatically,
+such as time stamps.
+.pp
+The body is a series of text lines.
+It is completely uninterpreted and untouched,
+except that lines beginning with a dot
+have the dot doubled
+when transmitted over an SMTP channel.
+This extra dot is stripped by the receiver.
+.sh 2 "Message Delivery"
+.pp
+The send queue is ordered by receiving host
+before transmission
+to implement message batching.
+Each address is marked as it is sent
+so rescanning the list is safe.
+An argument list is built as the scan proceeds.
+Mail to files is detected during the scan of the send list.
+The interface to the mailer
+is performed using one of the techniques
+described in section 2.2.
+.pp
+After a connection is established,
+.i sendmail
+makes the per-mailer changes to the header
+and sends the result to the mailer.
+If any mail is rejected by the mailer,
+a flag is set to invoke the return-to-sender function
+after all delivery completes.
+.sh 2 "Queued Messages"
+.pp
+If the mailer returns a
+.q "temporary failure"
+exit status,
+the message is queued.
+A control file is used to describe the recipients to be sent to
+and various other parameters.
+This control file is formatted as a series of lines,
+each describing a sender,
+a recipient,
+the time of submission,
+or some other salient parameter of the message.
+The header of the message is stored
+in the control file,
+so that the associated data file in the queue
+is just the temporary file that was originally collected.
+.sh 2 "Configuration"
+.pp
+Configuration is controlled primarily by a configuration file
+read at startup.
+.i Sendmail
+should not need to be recomplied except
+.np
+To change operating systems
+(V6, V7/32V, 4BSD).
+.np
+To remove or insert the DBM
+(UNIX database)
+library.
+.np
+To change ARPANET reply codes.
+.np
+To add headers fields requiring special processing.
+.lp
+Adding mailers or changing parsing
+(i.e., rewriting)
+or routing information
+does not require recompilation.
+.pp
+If the mail is being sent by a local user,
+and the file
+.q .mailcf
+exists in the sender's home directory,
+that file is read as a configuration file
+after the system configuration file.
+The primary use of this feature is to add header lines.
+.pp
+The configuration file encodes macro definitions,
+header definitions,
+mailer definitions,
+rewriting rules,
+and options.
+.sh 3 Macros
+.pp
+Macros can be used in three ways.
+Certain macros transmit
+unstructured textual information
+into the mail system,
+such as the name
+.i sendmail
+will use to identify itself in error messages.
+Other macros transmit information from
+.i sendmail
+to the configuration file
+for use in creating other fields
+(such as argument vectors to mailers);
+e.g., the name of the sender,
+and the host and user
+of the recipient.
+Other macros are unused internally,
+and can be used as shorthand in the configuration file.
+.sh 3 "Header declarations"
+.pp
+Header declarations inform
+.i sendmail
+of the format of known header lines.
+Knowledge of a few header lines
+is built into
+.i sendmail ,
+such as the
+.q From:
+and
+.q Date:
+lines.
+.pp
+Most configured headers
+will be automatically inserted
+in the outgoing message
+if they don't exist in the incoming message.
+Certain headers are suppressed by some mailers.
+.sh 3 "Mailer declarations"
+.pp
+Mailer declarations tell
+.i sendmail
+of the various mailers available to it.
+The definition specifies the internal name of the mailer,
+the pathname of the program to call,
+some flags associated with the mailer,
+and an argument vector to be used on the call;
+this vector is macro-expanded before use.
+.sh 3 "Address rewriting rules"
+.pp
+The heart of address parsing in
+.i sendmail
+is a set of rewriting rules.
+These are an ordered list of pattern-replacement rules,
+(somewhat like a production system,
+except that order is critical),
+which are applied to each address.
+The address is rewritten textually until it is either rewritten
+into a special canonical form
+(i.e.,
+a (mailer, host, user)
+3-tuple,
+such as {arpanet, usc-isif, postel}
+representing the address
+.q "postel@usc-isif" ),
+or it falls off the end.
+When a pattern matches,
+the rule is reapplied until it fails.
+.pp
+The configuration file also supports the editing of addresses
+into different formats.
+For example,
+an address of the form:
+.(b
+ucsfcgl!tef
+.)b
+might be mapped into:
+.(b
+tef@ucsfcgl.UUCP
+.)b
+to conform to the domain syntax.
+Translations can also be done in the other direction.
+.sh 3 "Option setting"
+.pp
+There are several options that can be set
+from the configuration file.
+These include the pathnames of various support files,
+timeouts,
+default modes,
+etc.
+.sh 1 "COMPARISON WITH OTHER MAILERS"
+.sh 2 "Delivermail"
+.pp
+.i Sendmail
+is an outgrowth of
+.i delivermail .
+The primary differences are:
+.np
+Configuration information is not compiled in.
+This change simplifies many of the problems
+of moving to other machines.
+It also allows easy debugging of new mailers.
+.np
+Address parsing is more flexible.
+For example,
+.i delivermail
+only supported one gateway to any network,
+whereas
+.i sendmail
+can be sensitive to host names
+and reroute to different gateways.
+.np
+Forwarding and
+:include:
+features eliminate the requirement that the system alias file
+be writable by any user
+(or that an update program be written,
+or that the system administration make all changes).
+.np
+.i Sendmail
+supports message batching across networks
+when a message is being sent to multiple recipients.
+.np
+A mail queue is provided in
+.i sendmail.
+Mail that cannot be delivered immediately
+but can potentially be delivered later
+is stored in this queue for a later retry.
+The queue also provides a buffer against system crashes;
+after the message has been collected
+it may be reliably redelivered
+even if the system crashes during the initial delivery.
+.np
+.i Sendmail
+uses the networking support provided by 4.2BSD
+to provide a direct interface networks such as the ARPANET
+and/or Ethernet
+using SMTP (the Simple Mail Transfer Protocol)
+over a TCP/IP connection.
+.sh 2 "MMDF"
+.pp
+MMDF
+[Crocker79]
+spans a wider problem set than
+.i sendmail .
+For example,
+the domain of
+MMDF includes a
+.q "phone network"
+mailer, whereas
+.i sendmail
+calls on preexisting mailers in most cases.
+.pp
+MMDF and
+.i sendmail
+both support aliasing,
+customized mailers,
+message batching,
+automatic forwarding to gateways,
+queueing,
+and retransmission.
+MMDF supports two-stage timeout,
+which
+.i sendmail
+does not support.
+.pp
+The configuration for MMDF
+is compiled into the code\**.
+.(f
+\**Dynamic configuration tables are currently being considered
+for MMDF;
+allowing the installer to select either compiled
+or dynamic tables.
+.)f
+.pp
+Since MMDF does not consider backwards compatibility
+as a design goal,
+the address parsing is simpler but much less flexible.
+.pp
+It is somewhat harder to integrate a new channel\**
+.(f
+\**The MMDF equivalent of a
+.i sendmail
+.q mailer.
+.)f
+into MMDF.
+In particular,
+MMDF must know the location and format
+of host tables for all channels,
+and the channel must speak a special protocol.
+This allows MMDF to do additional verification
+(such as verifying host names)
+at submission time.
+.pp
+MMDF strictly separates the submission and delivery phases.
+Although
+.i sendmail
+has the concept of each of these stages,
+they are integrated into one program,
+whereas in MMDF they are split into two programs.
+.sh 2 "Message Processing Module"
+.pp
+The Message Processing Module (MPM)
+discussed by Postel [Postel79b]
+matches
+.i sendmail
+closely in terms of its basic architecture.
+However,
+like MMDF,
+the MPM includes the network interface software
+as part of its domain.
+.pp
+MPM also postulates a duplex channel to the receiver,
+as does MMDF,
+thus allowing simpler handling of errors
+by the mailer
+than is possible in
+.i sendmail .
+When a message queued by
+.i sendmail
+is sent,
+any errors must be returned to the sender
+by the mailer itself.
+Both MPM and MMDF mailers
+can return an immediate error response,
+and a single error processor can create an appropriate response.
+.pp
+MPM prefers passing the message as a structured object,
+with type-length-value tuples\**.
+.(f
+\**This is similar to the NBS standard.
+.)f
+Such a convention requires a much higher degree of cooperation
+between mailers than is required by
+.i sendmail .
+MPM also assumes a universally agreed upon internet name space
+(with each address in the form of a net-host-user tuple),
+which
+.i sendmail
+does not.
+.sh 1 "EVALUATIONS AND FUTURE PLANS"
+.pp
+.i Sendmail
+is designed to work in a nonhomogeneous environment.
+Every attempt is made to avoid imposing unnecessary constraints
+on the underlying mailers.
+This goal has driven much of the design.
+One of the major problems
+has been the lack of a uniform address space,
+as postulated in [Postel79a]
+and [Postel79b].
+.pp
+A nonuniform address space implies that a path will be specified
+in all addresses,
+either explicitly (as part of the address)
+or implicitly
+(as with implied forwarding to gateways).
+This restriction has the unpleasant effect of making replying to messages
+exceedingly difficult,
+since there is no one
+.q address
+for any person,
+but only a way to get there from wherever you are.
+.pp
+Interfacing to mail programs
+that were not initially intended to be applied
+in an internet environment
+has been amazingly successful,
+and has reduced the job to a manageable task.
+.pp
+.i Sendmail
+has knowledge of a few difficult environments
+built in.
+It generates ARPANET FTP/SMTP compatible error messages
+(prepended with three-digit numbers
+[Neigus73, Postel74, Postel82])
+as necessary,
+optionally generates UNIX-style
+.q From
+lines on the front of messages for some mailers,
+and knows how to parse the same lines on input.
+Also,
+error handling has an option customized for BerkNet.
+.pp
+The decision to avoid doing any type of delivery where possible
+(even, or perhaps especially, local delivery)
+has turned out to be a good idea.
+Even with local delivery,
+there are issues of the location of the mailbox,
+the format of the mailbox,
+the locking protocol used,
+etc.,
+that are best decided by other programs.
+One surprisingly major annoyance in many internet mailers
+is that the location and format of local mail is built in.
+The feeling seems to be that local mail is so common
+that it should be efficient.
+This feeling is not born out by
+our experience;
+on the contrary,
+the location and format of mailboxes seems to vary widely
+from system to system.
+.pp
+The ability to automatically generate a response to incoming mail
+(by forwarding mail to a program)
+seems useful
+(\c
+.q "I am on vacation until late August...." )
+but can create problems
+such as forwarding loops
+(two people on vacation whose programs send notes back and forth,
+for instance)
+if these programs are not well written.
+A program could be written to do standard tasks correctly,
+but this would solve the general case.
+.pp
+It might be desirable to implement some form of load limiting.
+I am unaware of any mail system that addresses this problem,
+nor am I aware of any reasonable solution at this time.
+.pp
+The configuration file is currently practically inscrutable;
+considerable convenience could be realized
+with a higher-level format.
+.pp
+It seems clear that common protocols will be changing soon
+to accommodate changing requirements and environments.
+These changes will include modifications to the message header
+(e.g., [NBS80])
+or to the body of the message itself
+(such as for multimedia messages
+[Postel80]).
+Experience indicates that
+these changes should be relatively trivial to integrate
+into the existing system.
+.pp
+In tightly coupled environments,
+it would be nice to have a name server
+such as Grapvine
+[Birrell82]
+integrated into the mail system.
+This would allow a site such as
+.q Berkeley
+to appear as a single host,
+rather than as a collection of hosts,
+and would allow people to move transparently among machines
+without having to change their addresses.
+Such a facility
+would require an automatically updated database
+and some method of resolving conflicts.
+Ideally this would be effective even without
+all hosts being under
+a single management.
+However,
+it is not clear whether this feature
+should be integrated into the
+aliasing facility
+or should be considered a
+.q "value added"
+feature outside
+.i sendmail
+itself.
+.pp
+As a more interesting case,
+the CSNET name server
+[Solomon81]
+provides an facility that goes beyond a single
+tightly-coupled environment.
+Such a facility would normally exist outside of
+.i sendmail
+however.
+.sh 0 "ACKNOWLEDGEMENTS"
+.pp
+Thanks are due to Kurt Shoens for his continual cheerful
+assistance and good advice,
+Bill Joy for pointing me in the correct direction
+(over and over),
+and Mark Horton for more advice,
+prodding,
+and many of the good ideas.
+Kurt and Eric Schmidt are to be credited
+for using
+.i delivermail
+as a server for their programs
+(\c
+.i Mail
+and BerkNet respectively)
+before any sane person should have,
+and making the necessary modifications
+promptly and happily.
+Eric gave me considerable advice about the perils
+of network software which saved me an unknown
+amount of work and grief.
+Mark did the original implementation of the DBM version
+of aliasing, installed the VFORK code,
+wrote the current version of
+.i rmail ,
+and was the person who really convinced me
+to put the work into
+.i delivermail
+to turn it into
+.i sendmail .
+Kurt deserves accolades for using
+.i sendmail
+when I was myself afraid to take the risk;
+how a person can continue to be so enthusiastic
+in the face of so much bitter reality is beyond me.
+.pp
+Kurt,
+Mark,
+Kirk McKusick,
+Marvin Solomon,
+and many others have reviewed this paper,
+giving considerable useful advice.
+.pp
+Special thanks are reserved for Mike Stonebraker at Berkeley
+and Bob Epstein at Britton-Lee,
+who both knowingly allowed me to put so much work into this
+project
+when there were so many other things I really should
+have been working on.
+.+c
+.ce
+REFERENCES
+.nr ii 1.5i
+.ip [Birrell82]
+Birrell, A. D.,
+Levin, R.,
+Needham, R. M.,
+and
+Schroeder, M. D.,
+.q "Grapevine: An Exercise in Distributed Computing."
+In
+.ul
+Comm. A.C.M. 25,
+4,
+April 82.
+.ip [Borden79]
+Borden, S.,
+Gaines, R. S.,
+and
+Shapiro, N. Z.,
+.ul
+The MH Message Handling System: Users' Manual.
+R-2367-PAF.
+Rand Corporation.
+October 1979.
+.ip [Crocker77a]
+Crocker, D. H.,
+Vittal, J. J.,
+Pogran, K. T.,
+and
+Henderson, D. A. Jr.,
+.ul
+Standard for the Format of ARPA Network Text Messages.
+RFC 733,
+NIC 41952.
+In [Feinler78].
+November 1977.
+.ip [Crocker77b]
+Crocker, D. H.,
+.ul
+Framework and Functions of the MS Personal Message System.
+R-2134-ARPA,
+Rand Corporation,
+Santa Monica, California.
+1977.
+.ip [Crocker79]
+Crocker, D. H.,
+Szurkowski, E. S.,
+and
+Farber, D. J.,
+.ul
+An Internetwork Memo Distribution Facility \*- MMDF.
+6th Data Communication Symposium,
+Asilomar.
+November 1979.
+.ip [Crocker82]
+Crocker, D. H.,
+.ul
+Standard for the Format of Arpa Internet Text Messages.
+RFC 822.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1982.
+.ip [Metcalfe76]
+Metcalfe, R.,
+and
+Boggs, D.,
+.q "Ethernet: Distributed Packet Switching for Local Computer Networks" ,
+.ul
+Communications of the ACM 19,
+7.
+July 1976.
+.ip [Feinler78]
+Feinler, E.,
+and
+Postel, J.
+(eds.),
+.ul
+ARPANET Protocol Handbook.
+NIC 7104,
+Network Information Center,
+SRI International,
+Menlo Park, California.
+1978.
+.ip [NBS80]
+National Bureau of Standards,
+.ul
+Specification of a Draft Message Format Standard.
+Report No. ICST/CBOS 80-2.
+October 1980.
+.ip [Neigus73]
+Neigus, N.,
+.ul
+File Transfer Protocol for the ARPA Network.
+RFC 542, NIC 17759.
+In [Feinler78].
+August, 1973.
+.ip [Nowitz78a]
+Nowitz, D. A.,
+and
+Lesk, M. E.,
+.ul
+A Dial-Up Network of UNIX Systems.
+Bell Laboratories.
+In
+UNIX Programmer's Manual, Seventh Edition,
+Volume 2.
+August, 1978.
+.ip [Nowitz78b]
+Nowitz, D. A.,
+.ul
+Uucp Implementation Description.
+Bell Laboratories.
+In
+UNIX Programmer's Manual, Seventh Edition,
+Volume 2.
+October, 1978.
+.ip [Postel74]
+Postel, J.,
+and
+Neigus, N.,
+Revised FTP Reply Codes.
+RFC 640, NIC 30843.
+In [Feinler78].
+June, 1974.
+.ip [Postel77]
+Postel, J.,
+.ul
+Mail Protocol.
+NIC 29588.
+In [Feinler78].
+November 1977.
+.ip [Postel79a]
+Postel, J.,
+.ul
+Internet Message Protocol.
+RFC 753,
+IEN 85.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+March 1979.
+.ip [Postel79b]
+Postel, J. B.,
+.ul
+An Internetwork Message Structure.
+In
+.ul
+Proceedings of the Sixth Data Communications Symposium,
+IEEE.
+New York.
+November 1979.
+.ip [Postel80]
+Postel, J. B.,
+.ul
+A Structured Format for Transmission of Multi-Media Documents.
+RFC 767.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1980.
+.ip [Postel82]
+Postel, J. B.,
+.ul
+Simple Mail Transfer Protocol.
+RFC821
+(obsoleting RFC788).
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1982.
+.ip [Schmidt79]
+Schmidt, E.,
+.ul
+An Introduction to the Berkeley Network.
+University of California, Berkeley California.
+1979.
+.ip [Shoens79]
+Shoens, K.,
+.ul
+Mail Reference Manual.
+University of California, Berkeley.
+In UNIX Programmer's Manual,
+Seventh Edition,
+Volume 2C.
+December 1979.
+.ip [Sluizer81]
+Sluizer, S.,
+and
+Postel, J. B.,
+.ul
+Mail Transfer Protocol.
+RFC 780.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+May 1981.
+.ip [Solomon81]
+Solomon, M., Landweber, L., and Neuhengen, D.,
+.q "The Design of the CSNET Name Server."
+CS-DN-2,
+University of Wisconsin, Madison.
+November 1981.
+.ip [Su82]
+Su, Zaw-Sing,
+and
+Postel, Jon,
+.ul
+The Domain Naming Convention for Internet User Applications.
+RFC819.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1982.
+.ip [UNIX83]
+.ul
+The UNIX Programmer's Manual, Seventh Edition,
+Virtual VAX-11 Version,
+Volume 1.
+Bell Laboratories,
+modified by the University of California,
+Berkeley, California.
+March, 1983.
diff --git a/usr.sbin/sendmail/doc/op/Makefile b/usr.sbin/sendmail/doc/op/Makefile
new file mode 100644
index 00000000000..e8f791a4959
--- /dev/null
+++ b/usr.sbin/sendmail/doc/op/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.2 (Berkeley) 2/28/94
+
+DIR= smm/08.sendmailop
+SRCS= op.me
+MACROS= -me
+
+all: op.ps
+
+op.ps: ${SRCS}
+ rm -f ${.TARGET}
+ ${PIC} ${SRCS} | ${EQN} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/sendmail/doc/op/op.me b/usr.sbin/sendmail/doc/op/op.me
new file mode 100644
index 00000000000..9678d14c1fe
--- /dev/null
+++ b/usr.sbin/sendmail/doc/op/op.me
@@ -0,0 +1,6921 @@
+.\" Copyright (c) 1983 Eric P. Allman
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)op.me 8.36 (Berkeley) 4/14/94
+.\"
+.\" eqn op.me | pic | troff -me
+.eh 'SMM:08-%''Sendmail Installation and Operation Guide'
+.oh 'Sendmail Installation and Operation Guide''SMM:08-%'
+.\" SD is lib if sendmail is installed in /usr/lib, sbin if in /usr/sbin
+.ds SD sbin
+.\" SB is bin if newaliases/mailq are installed in /usr/bin, ucb if in /usr/ucb
+.ds SB bin
+.nr si 3n
+.de $0
+.(x
+.in \\$3u*3n
+.ti -3n
+\\$2. \\$1
+.)x
+..
+.de $C
+.(x
+.in 0
+\\$1 \\$2. \\$3
+.)x
+..
+.sc
+.+c
+.(l C
+.sz 16
+.b SENDMAIL
+.sz 12
+.sp
+.b "INSTALLATION AND OPERATION GUIDE"
+.sz 10
+.sp
+.r
+Eric Allman
+University of California, Berkeley
+Mammoth Project
+eric@CS.Berkeley.EDU
+.sp
+Version 8.36
+.sp
+For Sendmail Version 8.6
+.)l
+.sp 2
+.pp
+.i Sendmail
+implements a general purpose internetwork mail routing facility
+under the UNIX*
+.(f
+*UNIX is a trademark of Unix Systems Laboratories.
+.)f
+operating system.
+It is not tied to any one transport protocol \*-
+its function may be likened to a crossbar switch,
+relaying messages from one domain into another.
+In the process,
+it can do a limited amount of message header editing
+to put the message into a format that is appropriate
+for the receiving domain.
+All of this is done under the control of a configuration file.
+.pp
+Due to the requirements of flexibility
+for
+.i sendmail ,
+the configuration file can seem somewhat unapproachable.
+However, there are only a few basic configurations
+for most sites,
+for which standard configuration files have been supplied.
+Most other configurations
+can be built by adjusting an existing configuration files
+incrementally.
+.pp
+.i Sendmail
+is based on
+RFC822 (Internet Mail Format Protocol),
+RFC821 (Simple Mail Transport Protocol),
+RFC1123 (Internet Host Requirements),
+and
+RFC1425 (SMTP Service Extensions).
+However, since
+.i sendmail
+is designed to work in a wider world,
+in many cases it can be configured to exceed these protocols.
+These cases are described herein.
+.pp
+Although
+.i sendmail
+is intended to run
+without the need for monitoring,
+it has a number of features
+that may be used to monitor or adjust the operation
+under unusual circumstances.
+These features are described.
+.pp
+Section one describes how to do a basic
+.i sendmail
+installation.
+Section two
+explains the day-to-day information you should know
+to maintain your mail system.
+If you have a relatively normal site,
+these two sections should contain sufficient information
+for you to install
+.i sendmail
+and keep it happy.
+Section three
+describes some parameters that may be safely tweaked.
+Section four
+has information regarding the command line arguments.
+Section five
+contains the nitty-gritty information about the configuration
+file.
+This section is for masochists
+and people who must write their own configuration file.
+Section six
+describes configuration that can be done at compile time.
+Section seven
+gives a brief description of differences
+in this version of
+.i sendmail .
+The appendixes give a brief
+but detailed explanation of a number of features
+not described in the rest of the paper.
+.bp 7
+.sh 1 "BASIC INSTALLATION"
+.pp
+There are two basic steps to installing
+.i sendmail .
+The hard part is to build the configuration table.
+This is a file that
+.i sendmail
+reads when it starts up
+that describes the mailers it knows about,
+how to parse addresses,
+how to rewrite the message header,
+and the settings of various options.
+Although the configuration table is quite complex,
+a configuration can usually be built
+by adjusting an existing off-the-shelf configuration.
+The second part is actually doing the installation,
+i.e., creating the necessary files, etc.
+.pp
+The remainder of this section will describe the installation of
+.i sendmail
+assuming you can use one of the existing configurations
+and that the standard installation parameters are acceptable.
+All pathnames and examples
+are given from the root of the
+.i sendmail
+subtree,
+normally
+.i /usr/src/usr.\*(SD/sendmail
+on 4.4BSD.
+.pp
+If you are loading this off the tape,
+continue with the next section.
+If you have a running binary already on your system,
+you should probably skip to section 1.2.
+.sh 2 "Compiling Sendmail"
+.pp
+All
+.i sendmail
+source is in the
+.i src
+subdirectory.
+If you are running on a 4.4BSD system,
+compile by typing
+.q make .
+On other systems, you may have to make some other adjustments.
+.sh 3 "Old versions of make"
+.pp
+If you are not running the new version of
+.b make
+you will probably have to use
+.(b
+make \-f Makefile.dist
+.)b
+This file does not assume several new syntaxes,
+including the
+.q +=
+syntax in macro definition
+and the
+.q ".include"
+syntax.
+.sh 3 "Compilation flags"
+.pp
+.i Sendmail
+supports two different formats
+for the
+.i aliases
+database.
+These formats are:
+.nr ii 1i
+.ip NDBM
+The ``new DBM'' format,
+available on nearly all systems around today.
+This was the preferred format prior to 4.4BSD.
+It allows such complex things as multiple databases
+and closing a currently open database.
+.ip NEWDB
+The new database package from Berkeley.
+If you have this, use it.
+It allows
+long records,
+multiple open databases,
+real in-memory caching,
+and so forth.
+You can define this in conjunction with one of the other two;
+if you do,
+old databases are read,
+but when a new database is created it will be in NEWDB format.
+As a nasty hack,
+if you have NEWDB, NDBM, and NIS defined,
+and if the file
+.i /var/yp/Makefile
+exists and is readable,
+.i sendmail
+will create both new and old versions of the alias file
+during a
+.i newalias
+command.
+This is required because the Sun NIS/YP system
+reads the DBM version of the alias file.
+It's ugly as sin,
+but it works.
+.lp
+If neither of these are defined,
+.i sendmail
+reads the alias file into memory on every invocation.
+This can be slow and should be avoided.
+.pp
+System V based systems can define
+SYSTEM5
+to make several small adjustments.
+This changes the handling of timezones
+and uses the much less efficient
+.i lockf
+call in preference to
+.i flock .
+These can be specified separately using the compilation flags
+SYS5TZ
+and
+LOCKF
+respectively.
+.pp
+If you don't have the
+.i unsetenv
+routine in your system library, define the UNSETENV compilation flag.
+.pp
+You may also have to define the compilation variable LA_TYPE
+to describe how your load average is computed.
+This and other flags are detailed in section 6.1.
+.sh 3 "Compilation and installation"
+.pp
+After making the local system configuration described above,
+You should be able to compile and install the system.
+Compilation can be performed using
+.q make\**
+.(f
+\**where you may have to replace
+.q make
+with
+.q "make \-f Makefile.dist"
+as appropriate.
+.)f
+in the
+.b sendmail/src
+directory.
+You may be able to install using
+.(b
+make install
+.)b
+This should install the binary in
+/usr/\*(SD
+and create links from
+/usr/\*(SB/newaliases
+and
+/usr/\*(SB/mailq
+to
+/usr/\*(SD/sendmail.
+On 4.4BSD systems it will also format and install man pages.
+.sh 2 "Configuration Files"
+.pp
+.i Sendmail
+cannot operate without a configuration file.
+The configuration defines the mail systems understood at this site,
+how to access them,
+how to forward email to remote mail systems,
+and a number of tuning parameters.
+This configuration file is detailed
+in the later portion of this document.
+.pp
+The
+.i sendmail
+configuration can be daunting at first.
+The world is complex,
+and the mail configuration reflects that.
+The distribution includes an m4-based configuration package
+that hides a lot of the complexity.
+.pp
+These configuration files are simpler than old versions
+largely because the world has become simpler;
+in particular,
+text-based host files are officially eliminated,
+obviating the need to
+.q hide
+hosts behind a registered internet gateway.
+.pp
+These files also assume that most of your neighbors
+use domain-based UUCP addressing;
+that is,
+instead of naming hosts as
+.q host!user
+they will use
+.q host.domain!user .
+The configuration files can be customized to work around this,
+but it is more complex.
+.pp
+I haven't tested these yet on an isolated LAN environment
+with a single UUCP connection to the outside world.
+If you are in such an environment,
+please send comments to
+sendmail@CS.Berkeley.EDU.
+.pp
+Our configuration files are processed by
+.i m4
+to facilitate local customization;
+the directory
+.i cf
+of the
+.i sendmail
+distribution directory
+contains the source files.
+This directory contains several subdirectories:
+.nr ii 1i
+.ip cf
+Both site-dependent and site-independent descriptions of hosts.
+These can be literal host names
+(e.g.,
+.q ucbvax.mc )
+when the hosts are gateways
+or more general descriptions
+(such as
+.q "tcpproto.mc"
+as a general description of an SMTP-connected host
+or
+.q "uucpproto.mc"
+as a general description of a UUCP-connected host).
+Files ending
+.b \&.mc
+(``Master Configuration'')
+are the input descriptions;
+the output is in the corresponding
+.b \&.cf
+file.
+The general structure of these files is described below.
+.ip domain
+Site-dependent subdomain descriptions.
+These are tied to the way your organization wants to do addressing.
+For example,
+.b domain/cs.exposed.m4
+is our description for hosts in the CS.Berkeley.EDU subdomain
+that want their individual hostname to be externally visible;
+.b domain/cs.hidden.m4
+is the same except that the hostname is hidden
+(everything looks like it comes from CS.Berkeley.EDU).
+These are referenced using the
+.sm DOMAIN
+.b m4
+macro in the
+.b \&.mc
+file.
+.ip feature
+Definitions of specific features that some particular host in your site
+might want.
+These are referenced using the
+.sm FEATURE
+.b m4
+macro.
+An example feature is
+use_cw_file
+(which tells
+.i sendmail
+to read an /etc/sendmail.cw file on startup
+to find the set of local names).
+.ip hack
+Local hacks, referenced using the
+.sm HACK
+.b m4
+macro.
+Try to avoid these.
+The point of having them here is to make it clear that they smell.
+.ip m4
+Site-independent
+.i m4 (1)
+include files that have information common to all configuration files.
+This can be thought of as a
+.q #include
+directory.
+.ip mailer
+Definitions of mailers,
+referenced using the
+.sm MAILER
+.b m4
+macro.
+Defined mailer types in this distribution are
+fax,
+local,
+smtp,
+uucp,
+and usenet.
+.ip ostype
+Definitions describing various operating system environments
+(such as the location of support files).
+These are referenced using the
+.sm OSTYPE
+.b m4
+macro.
+.ip sh
+Shell files used by the
+.b m4
+build process.
+You shouldn't have to mess with these.
+.ip siteconfig
+Local site configuration information,
+such as UUCP connectivity.
+They normally contain lists of site information, for example:
+.(b
+SITE(contessa)
+SITE(hoptoad)
+SITE(nkainc)
+SITE(well)
+.)b
+They are referenced using the SITECONFIG macro:
+.(b
+SITECONFIG(site.config.file, name_of_site, X)
+.)b
+where
+.i X
+is the macro/class name to use.
+It can be U
+(indicating locally connected hosts)
+or one of W, X, or Y
+for up to three remote UUCP hubs.
+.pp
+If you are in a new domain
+(e.g., a company),
+you will probably want to create a
+cf/domain
+file for your domain.
+This consists primarily of relay definitions:
+for example, Berkeley's domain definition
+defines relays for
+BitNET,
+CSNET,
+and UUCP.
+Of these,
+only the UUCP relay is particularly specific
+to Berkeley.
+All of these are internet-style domain names.
+Please check to make certain they are reasonable for your domain.
+.pp
+Subdomains at Berkeley are also represented in the
+cf/domain
+directory.
+For example,
+the domain
+cs-exposed
+is the Computer Science subdomain with the local hostname shown
+to other users;
+cs-hidden
+makes users appear to be from the CS.Berkeley.EDU subdomain
+(with no local host information included).
+You will probably have to update this directory
+to be appropriate for your domain.
+.pp
+You will have to use or create
+.b \&.mc
+files in the
+.i cf/cf
+subdirectory for your hosts.
+This is detailed in the
+cf/README
+file.
+.sh 2 "Details of Installation Files"
+.pp
+This subsection describes the files that
+comprise the
+.i sendmail
+installation.
+.sh 3 "/usr/\*(SD/sendmail"
+.pp
+The binary for
+.i sendmail
+is located in /usr/\*(SD\**.
+.(f
+\**This is usually
+/usr/sbin
+on 4.4BSD and newer systems;
+many systems install it in
+/usr/lib.
+I understand it is in /usr/ucblib
+on System V Release 4.
+.)f
+It should be setuid root.
+For security reasons,
+/, /usr, and /usr/\*(SD
+should be owned by root, mode 755\**.
+.(f
+\**Some vendors ship them owned by bin;
+this creates a security hole that is not actually related to
+.i sendmail .
+Other important directories that should have restrictive ownerships
+and permissions are
+/bin, /usr/bin, /etc, /usr/etc, /lib, and /usr/lib.
+.)f
+.sh 3 "/etc/sendmail.cf"
+.pp
+This is the configuration file for
+.i sendmail .
+This is the only non-library file name compiled into
+.i sendmail \**.
+.(f
+\**The system libraries can reference other files;
+in particular, system library subroutines that
+.i sendmail
+calls probably reference
+.i /etc/passwd
+and
+.i /etc/resolv.conf .
+.)f
+Some older systems install it in
+.b /usr/lib/sendmail.cf .
+.pp
+If you want to move this file,
+change
+.i src/pathnames.h .
+.pp
+The configuration file is normally created
+using the distribution files described above.
+If you have a particularly unusual system configuration
+you may need to create a special version.
+The format of this file is detailed in later sections
+of this document.
+.sh 3 "/usr/\*(SB/newaliases"
+.pp
+The
+.i newaliases
+command should just be a link to
+.i sendmail :
+.(b
+rm \-f /usr/\*(SB/newaliases
+ln \-s /usr/\*(SD/sendmail /usr/\*(SB/newaliases
+.)b
+This can be installed in whatever search path you prefer
+for your system.
+.sh 3 "/var/spool/mqueue"
+.pp
+The directory
+.i /var/spool/mqueue
+should be created to hold the mail queue.
+This directory should be mode 700
+and owned by root.
+.pp
+The actual path of this directory
+is defined in the
+.b Q
+option of the
+.i sendmail.cf
+file.
+.sh 3 "/etc/aliases*"
+.pp
+The system aliases are held in
+.q /etc/aliases .
+A sample is given in
+.q lib/aliases
+which includes some aliases which
+.i must
+be defined:
+.(b
+cp lib/aliases /etc/aliases
+.i "edit /etc/aliases"
+.)b
+You should extend this file with any aliases that are apropos to your system.
+.pp
+Normally
+.i sendmail
+looks at a version of these files maintained by the
+.i dbm \|(3)
+or
+.i db \|(3)
+routines.
+These are stored either in
+.q /etc/aliases.dir
+and
+.q /etc/aliases.pag
+or
+.q /etc/aliases.db
+depending on which database package you are using.
+These can initially be created as empty files,
+but they will have to be initialized promptly.
+These should be mode 644:
+.(b
+cp /dev/null /etc/aliases.dir
+cp /dev/null /etc/aliases.pag
+chmod 644 /etc/aliases.*
+newaliases
+.)b
+The
+.i db
+routines preset the mode reasonably,
+so this step can be skipped.
+The actual path of this file
+is defined in the
+.b A
+option of the
+.i sendmail.cf
+file.
+.sh 3 "/etc/rc"
+.pp
+It will be necessary to start up the
+.i sendmail
+daemon when your system reboots.
+This daemon performs two functions:
+it listens on the SMTP socket for connections
+(to receive mail from a remote system)
+and it processes the queue periodically
+to insure that mail gets delivered when hosts come up.
+.pp
+Add the following lines to
+.q /etc/rc
+(or
+.q /etc/rc.local
+as appropriate)
+in the area where it is starting up the daemons:
+.(b
+if [ \-f /usr/\*(SD/sendmail \-a \-f /etc/sendmail.cf ]; then
+ (cd /var/spool/mqueue; rm \-f [lnx]f*)
+ /usr/\*(SD/sendmail \-bd \-q30m &
+ echo \-n ' sendmail' >/dev/console
+fi
+.)b
+The
+.q cd
+and
+.q rm
+commands insure that all lock files have been removed;
+extraneous lock files may be left around
+if the system goes down in the middle of processing a message.
+The line that actually invokes
+.i sendmail
+has two flags:
+.q \-bd
+causes it to listen on the SMTP port,
+and
+.q \-q30m
+causes it to run the queue every half hour.
+.pp
+Some people use a more complex startup script,
+removing zero length qf files and df files for which there is no qf file.
+For example:
+.(b
+# remove zero length qf files
+for qffile in qf*
+do
+ if [ \-r $qffile ]
+ then
+ if [ ! \-s $qffile ]
+ then
+ echo \-n " <zero: $qffile>" > /dev/console
+ rm \-f $qffile
+ fi
+ fi
+done
+# rename tf files to be qf if the qf does not exist
+for tffile in tf*
+do
+ qffile=`echo $tffile | sed 's/t/q/'`
+ if [ \-r $tffile \-a ! \-f $qffile ]
+ then
+ echo \-n " <recovering: $tffile>" > /dev/console
+ mv $tffile $qffile
+ else
+ echo \-n " <extra: $tffile>" > /dev/console
+ rm \-f $tffile
+ fi
+done
+# remove df files with no corresponding qf files
+for dffile in df*
+do
+ qffile=`echo $dffile | sed 's/d/q/'`
+ if [ \-r $dffile \-a ! \-f $qffile ]
+ then
+ echo \-n " <incomplete: $dffile>" > /dev/console
+ mv $dffile `echo $dffile | sed 's/d/D/'`
+ fi
+done
+# announce files that have been saved during disaster recovery
+for xffile in [A-Z]f*
+do
+ echo \-n " <panic: $xffile>" > /dev/console
+done
+.)b
+.pp
+If you are not running a version of UNIX
+that supports Berkeley TCP/IP,
+do not include the
+.b \-bd
+flag.
+.sh 3 "/usr/lib/sendmail.hf"
+.pp
+This is the help file used by the SMTP
+.b HELP
+command.
+It should be copied from
+.q lib/sendmail.hf :
+.(b
+cp lib/sendmail.hf /usr/lib
+.)b
+The actual path of this file
+is defined in the
+.b H
+option of the
+.i sendmail.cf
+file.
+.sh 3 "/etc/sendmail.st"
+.pp
+If you wish to collect statistics
+about your mail traffic,
+you should create the file
+.q /etc/sendmail.st :
+.(b
+cp /dev/null /etc/sendmail.st
+chmod 666 /etc/sendmail.st
+.)b
+This file does not grow.
+It is printed with the program
+.q mailstats/mailstats.c.
+The actual path of this file
+is defined in the
+.b S
+option of the
+.i sendmail.cf
+file.
+.sh 3 "/usr/\*(SB/newaliases"
+.pp
+If
+.i sendmail
+is invoked as
+.q newaliases,
+it will simulate the
+.b \-bi
+flag
+(i.e., will rebuild the alias database;
+see below).
+This should be a link to /usr/\*(SD/sendmail.
+.sh 3 "/usr/\*(SB/mailq"
+.pp
+If
+.i sendmail
+is invoked as
+.q mailq,
+it will simulate the
+.b \-bp
+flag
+(i.e.,
+.i sendmail
+will print the contents of the mail queue;
+see below).
+This should be a link to /usr/\*(SD/sendmail.
+.sh 1 "NORMAL OPERATIONS"
+.sh 2 "The System Log"
+.pp
+The system log is supported by the
+.i syslogd \|(8)
+program.
+All messages from
+.i sendmail
+are logged under the
+.sm LOG_MAIL
+facility.
+.sh 3 "Format"
+.pp
+Each line in the system log
+consists of a timestamp,
+the name of the machine that generated it
+(for logging from several machines
+over the local area network),
+the word
+.q sendmail: ,
+and a message.
+.sh 3 "Levels"
+.pp
+If you have
+.i syslogd \|(8)
+or an equivalent installed,
+you will be able to do logging.
+There is a large amount of information that can be logged.
+The log is arranged as a succession of levels.
+At the lowest level
+only extremely strange situations are logged.
+At the highest level,
+even the most mundane and uninteresting events
+are recorded for posterity.
+As a convention,
+log levels under ten
+are considered generally
+.q useful;
+log levels above 64
+are reserved for debugging purposes.
+Levels from 11\-64 are reserved for verbose information
+that some sites might want.
+.pp
+A complete description of the log levels
+is given in section 4.6.
+.sh 2 "The Mail Queue"
+.pp
+The mail queue should be processed transparently.
+However, you may find that manual intervention is sometimes necessary.
+For example,
+if a major host is down for a period of time
+the queue may become clogged.
+Although
+.i sendmail
+ought to recover gracefully when the host comes up,
+you may find performance unacceptably bad in the meantime.
+.sh 3 "Printing the queue"
+.pp
+The contents of the queue can be printed
+using the
+.i mailq
+command
+(or by specifying the
+.b \-bp
+flag to
+.i sendmail ):
+.(b
+mailq
+.)b
+This will produce a listing of the queue id's,
+the size of the message,
+the date the message entered the queue,
+and the sender and recipients.
+.sh 3 "Forcing the queue"
+.pp
+.i Sendmail
+should run the queue automatically
+at intervals.
+The algorithm is to read and sort the queue,
+and then to attempt to process all jobs in order.
+When it attempts to run the job,
+.i sendmail
+first checks to see if the job is locked.
+If so, it ignores the job.
+.pp
+There is no attempt to insure that only one queue processor
+exists at any time,
+since there is no guarantee that a job cannot take forever
+to process
+(however,
+.i sendmail
+does include heuristics to try to abort jobs
+that are taking absurd amounts of time;
+technically, this violates RFC 821, but is blessed by RFC 1123).
+Due to the locking algorithm,
+it is impossible for one job to freeze the entire queue.
+However,
+an uncooperative recipient host
+or a program recipient
+that never returns
+can accumulate many processes in your system.
+Unfortunately,
+there is no completely general way to solve this.
+.pp
+In some cases,
+you may find that a major host going down
+for a couple of days
+may create a prohibitively large queue.
+This will result in
+.i sendmail
+spending an inordinate amount of time
+sorting the queue.
+This situation can be fixed by moving the queue to a temporary place
+and creating a new queue.
+The old queue can be run later when the offending host returns to service.
+.pp
+To do this,
+it is acceptable to move the entire queue directory:
+.(b
+cd /var/spool
+mv mqueue omqueue; mkdir mqueue; chmod 700 mqueue
+.)b
+You should then kill the existing daemon
+(since it will still be processing in the old queue directory)
+and create a new daemon.
+.pp
+To run the old mail queue,
+run the following command:
+.(b
+/usr/\*(SD/sendmail \-oQ/var/spool/omqueue \-q
+.)b
+The
+.b \-oQ
+flag specifies an alternate queue directory
+and the
+.b \-q
+flag says to just run every job in the queue.
+If you have a tendency toward voyeurism,
+you can use the
+.b \-v
+flag to watch what is going on.
+.pp
+When the queue is finally emptied,
+you can remove the directory:
+.(b
+rmdir /var/spool/omqueue
+.)b
+.sh 2 "The Alias Database"
+.pp
+The alias database exists in two forms.
+One is a text form,
+maintained in the file
+.i /etc/aliases.
+The aliases are of the form
+.(b
+name: name1, name2, ...
+.)b
+Only local names may be aliased;
+e.g.,
+.(b
+eric@prep.ai.MIT.EDU: eric@CS.Berkeley.EDU
+.)b
+will not have the desired effect.
+Aliases may be continued by starting any continuation lines
+with a space or a tab.
+Blank lines and lines beginning with a sharp sign
+(\c
+.q # )
+are comments.
+.pp
+The second form is processed by the
+.i dbm \|(3)
+(or
+.i db \|(3))
+library.
+This form is in the files
+.i /etc/aliases.dir
+and
+.i /etc/aliases.pag.
+This is the form that
+.i sendmail
+actually uses to resolve aliases.
+This technique is used to improve performance.
+.pp
+You can also use
+.sm NIS -based
+alias files.
+For example, the specification:
+.(b
+OA/etc/aliases
+OAnis:mail.aliases@my.nis.domain
+.)b
+will first search the /etc/aliases file
+and then the map named
+.q mail.aliases
+in
+.q my.nis.domain .
+Warning: if you build your own
+.sm NIS -based
+alias files,
+be sure to provide the
+.b \-l
+flag to
+.i makedbm (8)
+to map upper case letters in the keys to lower case;
+otherwise, aliases with upper case letters in their names
+won't match incoming addresses.
+.pp
+Additional flags can be added after the colon
+exactly like a
+.b K
+line \(em for example:
+.(b
+OAnis:-N mail.aliases@my.nis.domain
+.)b
+will search the appropriate NIS map and always include null bytes in the key.
+.sh 3 "Rebuilding the alias database"
+.pp
+The DB or DBM version of the database
+may be rebuilt explicitly by executing the command
+.(b
+newaliases
+.)b
+This is equivalent to giving
+.i sendmail
+the
+.b \-bi
+flag:
+.(b
+/usr/\*(SD/sendmail \-bi
+.)b
+.pp
+If the
+.q D
+option is specified in the configuration,
+.i sendmail
+will rebuild the alias database automatically
+if possible
+when it is out of date.
+Auto-rebuild can be dangerous
+on heavily loaded machines
+with large alias files;
+if it might take more than five minutes
+to rebuild the database,
+there is a chance that several processes will start the rebuild process
+simultaneously.
+.pp
+If you have multiple aliases databases specified,
+the
+.b \-bi
+flag rebuilds all the database types it understands
+(for example, it can rebuild dbm databases but not nis databases).
+.sh 3 "Potential problems"
+.pp
+There are a number of problems that can occur
+with the alias database.
+They all result from a
+.i sendmail
+process accessing the DBM version
+while it is only partially built.
+This can happen under two circumstances:
+One process accesses the database
+while another process is rebuilding it,
+or the process rebuilding the database dies
+(due to being killed or a system crash)
+before completing the rebuild.
+.pp
+Sendmail has two techniques to try to relieve these problems.
+First, it ignores interrupts while rebuilding the database;
+this avoids the problem of someone aborting the process
+leaving a partially rebuilt database.
+Second,
+at the end of the rebuild
+it adds an alias of the form
+.(b
+@: @
+.)b
+(which is not normally legal).
+Before
+.i sendmail
+will access the database,
+it checks to insure that this entry exists\**.
+.(f
+\**The
+.q a
+option is required in the configuration
+for this action to occur.
+This should normally be specified.
+.)f
+.sh 3 "List owners"
+.pp
+If an error occurs on sending to a certain address,
+say
+.q \fIx\fP ,
+.i sendmail
+will look for an alias
+of the form
+.q owner-\fIx\fP
+to receive the errors.
+This is typically useful
+for a mailing list
+where the submitter of the list
+has no control over the maintenance of the list itself;
+in this case the list maintainer would be the owner of the list.
+For example:
+.(b
+unix-wizards: eric@ucbarpa, wnj@monet, nosuchuser,
+ sam@matisse
+owner-unix-wizards: eric@ucbarpa
+.)b
+would cause
+.q eric@ucbarpa
+to get the error that will occur
+when someone sends to
+unix-wizards
+due to the inclusion of
+.q nosuchuser
+on the list.
+.pp
+List owners also cause the envelope sender address to be modified.
+The contents of the owner alias are used if they point to a single user,
+otherwise the name of the alias itself is used.
+For this reason, and to obey Internet conventions,
+a typical scheme would be:
+.(b
+list: some, set, of, addresses
+list-request: list-admin-1, list-admin-2, ...
+owner-list: list-request
+.)b
+.sh 2 "User Information Database"
+.pp
+If you have a version of
+.i sendmail
+with the user information database
+compiled in,
+and you have specified one or more databases using the
+.b U
+option,
+the databases will be searched for a
+.i user :maildrop
+entry.
+If found, the mail will be sent to the specified address.
+.pp
+If the first token passed to user part of the
+.q local
+mailer is an at sign,
+the at sign will be stripped off
+and this step will be skipped.
+.sh 2 "Per-User Forwarding (.forward Files)"
+.pp
+As an alternative to the alias database,
+any user may put a file with the name
+.q .forward
+in his or her home directory.
+If this file exists,
+.i sendmail
+redirects mail for that user
+to the list of addresses listed in the .forward file.
+For example, if the home directory for user
+.q mckusick
+has a .forward file with contents:
+.(b
+mckusick@ernie
+kirk@calder
+.)b
+then any mail arriving for
+.q mckusick
+will be redirected to the specified accounts.
+.pp
+Actually, the configuration file defines a sequence of filenames to check.
+By default, this is the user's .forward file,
+but can be defined to be more generally using the
+.b J
+option.
+If you change this,
+you will have to inform your user base of the change;
+\&.forward is pretty well incorporated into the collective subconscious.
+.sh 2 "Special Header Lines"
+.pp
+Several header lines have special interpretations
+defined by the configuration file.
+Others have interpretations built into
+.i sendmail
+that cannot be changed without changing the code.
+These builtins are described here.
+.sh 3 "Return-Receipt-To:"
+.pp
+If this header is sent,
+a message will be sent to any specified addresses
+when the final delivery is complete,
+that is,
+when successfully delivered to a mailer with the
+.b l
+flag (local delivery) set in the mailer descriptor\**.
+.(f
+\**Some sites disable this header,
+and other (non-\c
+.i sendmail )
+systems do not implement it.
+Do not assume that a failure to get a return receipt
+means that the mail did not arrive.
+Also, do not assume that getting a return receipt
+means that the mail has been read;
+it just means that the message has been delivered
+to the recipient's mailbox.
+.)f
+This header can be disabled with the
+.q noreceipts
+privacy flag.
+.sh 3 "Errors-To:"
+.pp
+If errors occur anywhere during processing,
+this header will cause error messages to go to
+the listed addresses.
+This is intended for mailing lists.
+.pp
+The Errors-To: header was created in the bad old days
+when UUCP didn't understand the distinction between an envelope and a header;
+this was a hack to provide what should now be passed
+as the envelope sender address.
+It should go away.
+It is only used if the
+.b l
+option is set.
+.sh 3 "Apparently-To:"
+.pp
+If a message comes in with no recipients listed in the message
+(in a To:, Cc:, or Bcc: line)
+then
+.i sendmail
+will add an
+.q "Apparently-To:"
+header line for any recipients it is aware of.
+This is not put in as a standard recipient line
+to warn any recipients that the list is not complete.
+.pp
+At least one recipient line is required under RFC 822.
+.sh 2 "IDENT Protocol Support"
+.pp
+.i Sendmail
+supports the IDENT protocol as defined in RFC 1413.
+Although this enhances identification
+of the author of an email message
+by doing a ``call back'' to the originating system to include
+the owner of a particular TCP connection
+in the audit trail
+it is in no sense perfect;
+a determined forger can easily spoof the IDENT protocol.
+The following description is excerpted from RFC 1413:
+.ba +5
+.lp
+6. Security Considerations
+.lp
+The information returned by this protocol is at most as trustworthy
+as the host providing it OR the organization operating the host. For
+example, a PC in an open lab has few if any controls on it to prevent
+a user from having this protocol return any identifier the user
+wants. Likewise, if the host has been compromised the information
+returned may be completely erroneous and misleading.
+.lp
+The Identification Protocol is not intended as an authorization or
+access control protocol. At best, it provides some additional
+auditing information with respect to TCP connections. At worst, it
+can provide misleading, incorrect, or maliciously incorrect
+information.
+.lp
+The use of the information returned by this protocol for other than
+auditing is strongly discouraged. Specifically, using Identification
+Protocol information to make access control decisions - either as the
+primary method (i.e., no other checks) or as an adjunct to other
+methods may result in a weakening of normal host security.
+.lp
+An Identification server may reveal information about users,
+entities, objects or processes which might normally be considered
+private. An Identification server provides service which is a rough
+analog of the CallerID services provided by some phone companies and
+many of the same privacy considerations and arguments that apply to
+the CallerID service apply to Identification. If you wouldn't run a
+"finger" server due to privacy considerations you may not want to run
+this protocol.
+.ba
+.sh 1 "ARGUMENTS"
+.pp
+The complete list of arguments to
+.i sendmail
+is described in detail in Appendix A.
+Some important arguments are described here.
+.sh 2 "Queue Interval"
+.pp
+The amount of time between forking a process
+to run through the queue
+is defined by the
+.b \-q
+flag.
+If you run in mode
+.b f
+or
+.b a
+this can be relatively large,
+since it will only be relevant
+when a host that was down comes back up.
+If you run in
+.b q
+mode
+it should be relatively short,
+since it defines the maximum amount of time that a message
+may sit in the queue.
+.pp
+RFC 1123 section 5.3.1.1 says that this value should be at least 30 minutes
+(although that probably doesn't make sense if you use ``queue-only'' mode).
+.sh 2 "Daemon Mode"
+.pp
+If you allow incoming mail over an IPC connection,
+you should have a daemon running.
+This should be set by your
+.i /etc/rc
+file using the
+.b \-bd
+flag.
+The
+.b \-bd
+flag and the
+.b \-q
+flag may be combined in one call:
+.(b
+/usr/\*(SD/sendmail \-bd \-q30m
+.)b
+.sh 2 "Forcing the Queue"
+.pp
+In some cases you may find that the queue has gotten clogged for some reason.
+You can force a queue run
+using the
+.b \-q
+flag (with no value).
+It is entertaining to use the
+.b \-v
+flag (verbose)
+when this is done to watch what happens:
+.(b
+/usr/\*(SD/sendmail \-q \-v
+.)b
+.pp
+You can also limit the jobs to those with a particular queue identifier,
+sender, or recipient
+using one of the queue modifiers.
+For example,
+.q \-qRberkeley
+restricts the queue run to jobs that have the string
+.q berkeley
+somewhere in one of the recipient addresses.
+Similarly,
+.q \-qSstring
+limits the run to particular senders and
+.q \-qIstring
+limits it to particular identifiers.
+.sh 2 "Debugging"
+.pp
+There are a fairly large number of debug flags
+built into
+.i sendmail .
+Each debug flag has a number and a level,
+where higher levels means to print out more information.
+The convention is that levels greater than nine are
+.q absurd,
+i.e.,
+they print out so much information that you wouldn't normally
+want to see them except for debugging that particular piece of code.
+Debug flags are set using the
+.b \-d
+option;
+the syntax is:
+.(b
+.ta \w'debug-option 'u
+debug-flag: \fB\-d\fP debug-list
+debug-list: debug-option [ , debug-option ]
+debug-option: debug-range [ . debug-level ]
+debug-range: integer | integer \- integer
+debug-level: integer
+.)b
+where spaces are for reading ease only.
+For example,
+.(b
+\-d12 Set flag 12 to level 1
+\-d12.3 Set flag 12 to level 3
+\-d3-17 Set flags 3 through 17 to level 1
+\-d3-17.4 Set flags 3 through 17 to level 4
+.)b
+For a complete list of the available debug flags
+you will have to look at the code
+(they are too dynamic to keep this documentation up to date).
+.sh 2 "Trying a Different Configuration File"
+.pp
+An alternative configuration file
+can be specified using the
+.b \-C
+flag; for example,
+.(b
+/usr/\*(SD/sendmail \-Ctest.cf
+.)b
+uses the configuration file
+.i test.cf
+instead of the default
+.i /etc/sendmail.cf.
+If the
+.b \-C
+flag has no value
+it defaults to
+.i sendmail.cf
+in the current directory.
+.sh 2 "Changing the Values of Options"
+.pp
+Options can be overridden using the
+.b \-o
+flag.
+For example,
+.(b
+/usr/\*(SD/sendmail \-oT2m
+.)b
+sets the
+.b T
+(timeout) option to two minutes
+for this run only.
+.pp
+Some options have security implications.
+Sendmail allows you to set these,
+but refuses to run as root thereafter.
+.sh 2 "Logging Traffic"
+.pp
+Many SMTP implementations do not fully implement the protocol.
+For example, some personal computer based SMTPs
+do not understand continuation lines in reply codes.
+These can be very hard to trace.
+If you suspect such a problem, you can set traffic logging using the
+.b \-X
+flag.
+For example,
+.(b
+/usr/\*(SD/sendmail \-X /tmp/traffic -bd
+.)b
+will log all traffic in the file
+.i /tmp/traffic .
+.pp
+This logs a lot of data very quickly and should never be used
+during normal operations.
+After starting up such a daemon,
+force the errant implementation to send a message to your host.
+All message traffic in and out of
+.i sendmail ,
+including the incoming SMTP traffic,
+will be logged in this file.
+.sh 2 "Dumping State"
+.pp
+You can ask
+.i sendmail
+to log a dump of the open files
+and the connection cache
+by sending it a
+.sm SIGUSR1
+signal.
+The results are logged at
+.sm LOG_DEBUG
+priority.
+.sh 1 "TUNING"
+.pp
+There are a number of configuration parameters
+you may want to change,
+depending on the requirements of your site.
+Most of these are set
+using an option in the configuration file.
+For example,
+the line
+.q OT5d
+sets option
+.q T
+to the value
+.q 5d
+(five days).
+.pp
+Most of these options have appropriate defaults for most sites.
+However,
+sites having very high mail loads may find they need to tune them
+as appropriate for their mail load.
+In particular,
+sites experiencing a large number of small messages,
+many of which are delivered to many recipients,
+may find that they need to adjust the parameters
+dealing with queue priorities.
+.sh 2 "Timeouts"
+.pp
+All time intervals are set
+using a scaled syntax.
+For example,
+.q 10m
+represents ten minutes, whereas
+.q 2h30m
+represents two and a half hours.
+The full set of scales is:
+.(b
+.ta 4n
+s seconds
+m minutes
+h hours
+d days
+w weeks
+.)b
+.sh 3 "Queue interval"
+.pp
+The argument to the
+.b \-q
+flag
+specifies how often a sub-daemon will run the queue.
+This is typically set to between fifteen minutes
+and one hour.
+RFC 1123 section 5.3.1.1 recommends that this be at least 30 minutes.
+.sh 3 "Read timeouts"
+.pp
+It is possible to time out when reading the standard input
+or when reading from a remote SMTP server.
+These timeouts are set using the
+.b r
+option in the configuration file.
+The argument is a list of
+.i keyword=value
+pairs.
+The recognized keywords, their default values, and the minimum values
+allowed by RFC 1123 section 5.3.2 are:
+.nr ii 1i
+.ip initial
+The wait for the initial 220 greeting message
+[5m, 5m].
+.ip helo
+The wait for a reply from a HELO or EHLO command
+[5m, unspecified].
+This may require a host name lookup, so
+five minutes is probably a reasonable minimum.
+.ip mail\(dg
+The wait for a reply from a MAIL command
+[10m, 5m].
+.ip rcpt\(dg
+The wait for a reply from a RCPT command
+[1h, 5m].
+This should be long
+because it could be pointing at a list
+that takes a long time to expand.
+.ip datainit\(dg
+The wait for a reply from a DATA command
+[5m, 2m].
+.ip datablock\(dg
+The wait for reading a data block
+(that is, the body of the message).
+[1h, 3m].
+This should be long because it also applies to programs
+piping input to
+.i sendmail
+which have no guarantee of promptness.
+.ip datafinal\(dg
+The wait for a reply from the dot terminating a message.
+[1h, 10m].
+If this is shorter than the time actually needed
+for the receiver to deliver the message,
+duplicates will be generated.
+This is discussed in RFC 1047.
+.ip rset
+The wait for a reply from a RSET command
+[5m, unspecified].
+.ip quit
+The wait for a reply from a QUIT command
+[2m, unspecified].
+.ip misc
+The wait for a reply from miscellaneous (but short) commands
+such as NOOP (no-operation) and VERB (go into verbose mode).
+[2m, unspecified].
+.ip command\(dg
+In server SMTP,
+the time to wait for another command.
+[1h, 5m].
+.ip ident
+The timeout waiting for a reply to an IDENT query
+[30s, unspecified].
+.lp
+For compatibility with old configuration files,
+if no ``keyword='' is specified,
+all the timeouts marked with \(dg are set to the indicated value.
+.pp
+Many of the RFC 1123 minimum values
+may well be too short.
+.i Sendmail
+was designed to the RFC 822 protocols,
+which did not specify read timeouts;
+hence,
+.i sendmail
+does not guarantee to reply to messages promptly.
+In particular, a
+.q RCPT
+command specifying a mailing list
+will expand and verify the entire list;
+a large list on a slow system
+may take more than five minutes\**.
+.(f
+\**This verification includes looking up every address
+with the name server;
+this involves network delays,
+and can in some cases can be considerable.
+.)f
+I recommend a one hour timeout \*-
+since this failure is rare,
+a long timeout is not onerous
+and may ultimately help reduce network load.
+.pp
+For example, the line:
+.(b
+Orcommand=25m,datablock=3h
+.)b
+sets the server SMTP command timeout to 25 minutes
+and the input data block timeout to three hours.
+.sh 3 "Message timeouts"
+.pp
+After sitting in the queue for a few days,
+a message will time out.
+This is to insure that at least the sender is aware
+of the inability to send a message.
+The timeout is typically set to three days.
+This timeout is set using the
+.b T
+option in the configuration file.
+.pp
+The time of submission is set in the queue,
+rather than the amount of time left until timeout.
+As a result, you can flush messages that have been hanging
+for a short period
+by running the queue
+with a short message timeout.
+For example,
+.(b
+/usr/\*(SD/sendmail \-oT1d \-q
+.)b
+will run the queue
+and flush anything that is one day old.
+.pp
+Since this option is global,
+and since you can not
+.i "a priori"
+know how long another host outside your domain will be down,
+a five day timeout is recommended.
+This allows a recipient to fix the problem even if it occurs
+at the beginning of a long weekend.
+RFC 1123 section 5.3.1.1 says that this parameter
+should be ``at least 4\-5 days''.
+.pp
+The
+.b T
+option can also take a second timeout indicating a time after which
+a warning message should be sent;
+the two timeouts are separated by a slash.
+For example, the value
+.(b
+5d/4h
+.)b
+causes email to fail after five days,
+but a warning message will be sent after four hours.
+This should be large enough that the message will have been tried
+several times.
+.sh 2 "Forking During Queue Runs"
+.pp
+By setting the
+.b Y
+option,
+.i sendmail
+will fork before each individual message
+while running the queue.
+This will prevent
+.i sendmail
+from consuming large amounts of memory,
+so it may be useful in memory-poor environments.
+However, if the
+.b Y
+option is not set,
+.i sendmail
+will keep track of hosts that are down during a queue run,
+which can improve performance dramatically.
+.pp
+If the
+.b Y
+option is set,
+.i sendmail
+can not use connection caching.
+.sh 2 "Queue Priorities"
+.pp
+Every message is assigned a priority when it is first instantiated,
+consisting of the message size (in bytes)
+offset by the message class times the
+.q "work class factor"
+and the number of recipients times the
+.q "work recipient factor."
+The priority is used to order the queue.
+Higher numbers for the priority mean that the message will be processed later
+when running the queue.
+.pp
+The message size is included so that large messages are penalized
+relative to small messages.
+The message class allows users to send
+.q "high priority"
+messages by including a
+.q Precedence:
+field in their message;
+the value of this field is looked up in the
+.b P
+lines of the configuration file.
+Since the number of recipients affects the amount of load a message presents
+to the system,
+this is also included into the priority.
+.pp
+The recipient and class factors
+can be set in the configuration file using the
+.b y
+and
+.b z
+options respectively.
+They default to 30000 (for the recipient factor)
+and 1800
+(for the class factor).
+The initial priority is:
+.EQ
+pri = msgsize - (class times bold z) + (nrcpt times bold y)
+.EN
+(Remember, higher values for this parameter actually mean
+that the job will be treated with lower priority.)
+.pp
+The priority of a job can also be adjusted each time it is processed
+(that is, each time an attempt is made to deliver it)
+using the
+.q "work time factor,"
+set by the
+.b Z
+option.
+This is added to the priority,
+so it normally decreases the precedence of the job,
+on the grounds that jobs that have failed many times
+will tend to fail again in the future.
+The
+.b Z
+option defaults to 90000.
+.sh 2 "Load Limiting"
+.pp
+.i Sendmail
+can be asked to queue (but not deliver)
+mail if the system load average gets too high
+using the
+.b x
+option.
+When the load average exceeds the value of the
+.b x
+option,
+the delivery mode is set to
+.b q
+(queue only)
+if the
+.i "Queue Factor"
+(\c
+.b q
+option)
+divided by the difference in the current load average and the
+.b x
+option
+plus one
+exceeds the priority of the message \(em
+that is, the message is queued iff:
+.EQ
+pri > { bold q } over { LA - { bold x } + 1 }
+.EN
+The
+.b q
+option defaults to 600000,
+so each point of load average is worth 600000
+priority points
+(as described above).
+.pp
+For drastic cases,
+the
+.b X
+option defines a load average at which
+.i sendmail
+will refuse
+to accept network connections.
+Locally generated mail
+(including incoming UUCP mail)
+is still accepted.
+.sh 2 "Delivery Mode"
+.pp
+There are a number of delivery modes that
+.i sendmail
+can operate in,
+set by the
+.q d
+configuration option.
+These modes
+specify how quickly mail will be delivered.
+Legal modes are:
+.(b
+.ta 4n
+i deliver interactively (synchronously)
+b deliver in background (asynchronously)
+q queue only (don't deliver)
+.)b
+There are tradeoffs.
+Mode
+.q i
+passes the maximum amount of information to the sender,
+but is hardly ever necessary.
+Mode
+.q q
+puts the minimum load on your machine,
+but means that delivery may be delayed for up to the queue interval.
+Mode
+.q b
+is probably a good compromise.
+However, this mode can cause large numbers of processes
+if you have a mailer that takes a long time to deliver a message.
+.pp
+If you run in mode
+.q q
+(queue only)
+or
+.q b
+(deliver in background)
+.i sendmail
+will not expand aliases and follow .forward files
+upon initial receipt of the mail.
+This speeds up the response to RCPT commands.
+.sh 2 "Log Level"
+.pp
+The level of logging can be set for
+.i sendmail .
+The default using a standard configuration table is level 9.
+The levels are as follows:
+.nr ii 0.5i
+.ip 0
+No logging.
+.ip 1
+Serious system failures and potential security problems.
+.ip 2
+Lost communications (network problems) and protocol failures.
+.ip 3
+Other serious failures.
+.ip 4
+Minor failures.
+.ip 5
+Message collection statistics.
+.ip 6
+Creation of error messages,
+VRFY and EXPN commands.
+.ip 7
+Delivery failures (host or user unknown, etc.).
+.ip 8
+Successful deliveries.
+.ip 9
+Messages being deferred
+(due to a host being down, etc.).
+.ip 10
+Database expansion (alias, forward, and userdb lookups).
+.ip 15
+Automatic alias database rebuilds.
+.ip 20
+Logs attempts to run locked queue files.
+These are not errors,
+but can be useful to note if your queue appears to be clogged.
+.ip 30
+Lost locks (only if using lockf instead of flock).
+.lp
+Additionally,
+values above 64 are reserved for extremely verbose debuggging output.
+No normal site would ever set these.
+.sh 2 "File Modes"
+.pp
+There are a number of files
+that may have a number of modes.
+The modes depend on what functionality you want
+and the level of security you require.
+.sh 3 "To suid or not to suid?"
+.pp
+.i Sendmail
+can safely be made
+setuid to root.
+At the point where it is about to
+.i exec \|(2)
+a mailer,
+it checks to see if the userid is zero;
+if so,
+it resets the userid and groupid to a default
+(set by the
+.b u
+and
+.b g
+options).
+(This can be overridden
+by setting the
+.b S
+flag to the mailer
+for mailers that are trusted
+and must be called as root.)
+However,
+this will cause mail processing
+to be accounted
+(using
+.i sa \|(8))
+to root
+rather than to the user sending the mail.
+.sh 3 "Should my alias database be writable?"
+.pp
+At Berkeley
+we have the alias database
+(/etc/aliases*)
+mode 644.
+While this is not as flexible as if the database
+were more 666, it avoids potential security problems
+with a globally writable database.
+.pp
+The database that
+.i sendmail
+actually used
+is represented by the two files
+.i aliases.dir
+and
+.i aliases.pag
+(both in /etc)
+(or
+.i aliases.db
+if you are running with the new Berkeley database primitives).
+The mode on these files should match the mode
+on /etc/aliases.
+If
+.i aliases
+is writable
+and the
+DBM
+files
+(\c
+.i aliases.dir
+and
+.i aliases.pag )
+are not,
+users will be unable to reflect their desired changes
+through to the actual database.
+However,
+if
+.i aliases
+is read-only
+and the DBM files are writable,
+a slightly sophisticated user
+can arrange to steal mail anyway.
+.pp
+If your DBM files are not writable by the world
+or you do not have auto-rebuild enabled
+(with the
+.q D
+option),
+then you must be careful to reconstruct the alias database
+each time you change the text version:
+.(b
+newaliases
+.)b
+If this step is ignored or forgotten
+any intended changes will also be ignored or forgotten.
+.sh 2 "Connection Caching"
+.pp
+When processing the queue,
+.i sendmail
+will try to keep the last few open connections open
+to avoid startup and shutdown costs.
+This only applies to IPC connections.
+.pp
+When trying to open a connection
+the cache is first searched.
+If an open connection is found, it is probed to see if it is still active
+by sending a
+.sm NOOP
+command.
+It is not an error if this fails;
+instead, the connection is closed and reopened.
+.pp
+Two parameters control the connection cache.
+The
+.b k
+option defines the number of simultaneous open connections
+that will be permitted.
+If it is set to zero,
+connections will be closed as quickly as possible.
+The default is one.
+This should be set as appropriate for your system size;
+it will limit the amount of system resources that
+.i sendmail
+will use during queue runs.
+.pp
+The
+.b K
+option specifies the maximum time that any cached connection
+will be permitted to idle.
+When the idle time exceeds this value
+the connection is closed.
+This number should be small
+(under ten minutes)
+to prevent you from grabbing too many resources
+from other hosts.
+The default is five minutes.
+.sh 2 "Name Server Access"
+.pp
+If your system supports the name server,
+then the probability is that
+.i sendmail
+will be using it regardless of how you configure
+.i sendmail .
+In particular, the system routine
+.i gethostbyname (3)
+is used to look up host names,
+and most vendor versions try some combination of DNS, NIS,
+and file lookup in /etc/hosts.
+.pp
+However, if you do not have a nameserver configured at all,
+such as at a UUCP-only site,
+.i sendmail
+will get a
+.q "connection refused"
+message when it tries to connect to the name server
+(either indirectly by calling
+.i gethostbyname
+or directly by looking up MX records).
+If the
+.b I
+option is set,
+.i sendmail
+will interpret this to mean a temporary failure
+and will queue the mail for later processing;
+otherwise, it ignores the name server data.
+If your name server is running properly,
+the setting of this option is not relevant;
+however, it is important that it be set properly
+to make error handling work properly.
+.pp
+This option also allows you to tweak name server options.
+The command line takes a series of flags as documented in
+.i resolver (3)
+(with the leading
+.q RES_
+deleted).
+Each can be preceded by an optional `+' or `\(mi'.
+For example, the line
+.(b
+OITrue +AAONLY \(miDNSRCH
+.)b
+turns on the AAONLY (accept authoritative answers only)
+and turns off the DNSRCH (search the domain path) options.
+Most resolver libraries default DNSRCH, DEFNAMES, and RECURSE
+flags on and all others off.
+Note the use of the initial ``True'' \*-
+this is for compatibility with previous versions of
+.i sendmail ,
+but is not otherwise necessary.
+.pp
+Version level 1 configurations
+turn DNSRCH and DEFNAMES off when doing delivery lookups,
+but leave them on everywhere else.
+Version 8 of
+.i sendmail
+ignores them when doing canonification lookups
+(that is, when using $[ ... $]),
+and always does the search.
+If you don't want to do automatic name extension,
+don't call $[ ... $].
+.pp
+The search rules for $[ ... $] are somewhat different than usual.
+If the name (that is, the ``...'')
+has at least one dot, it always tries the unmodified name first.
+If that fails, it tries the reduced search path,
+and lastly tries the unmodified name
+(but only for names without a dot,
+since names with a dot have already been tried).
+This allows names such as
+``utc.CS''
+to match the site in Czechoslovakia
+rather than the site in your local Computer Science department.
+It also prefers A and CNAME records over MX records \*-
+that is, if it finds an MX record it makes note of it,
+but keeps looking.
+This way, if you have a wildcard MX record matching your domain,
+it will not assume that all names match.
+.sh 2 "Moving the Per-User Forward Files"
+.pp
+Some sites mount each user's home directory
+from a local disk on their workstation,
+so that local access is fast.
+However, the result is that .forward file lookups are slow.
+In some cases,
+mail can even be delivered on machines inappropriately
+because of a file server being down.
+The performance can be especially bad if you run the automounter.
+.pp
+The
+.b J
+option allows you to set a path of forward files.
+For example, the config file line
+.(b
+OJ/var/forward/$u:$z/.forward
+.)b
+would first look for a file with the same name as the user's login
+in /var/forward;
+if that is not found (or is inaccessible)
+the file
+.q \&.forward
+in the user's home directory is searched.
+A truly perverse site could also search by sender
+by using $r, $s, or $f.
+.pp
+If you create a directory such as /var/forward,
+it should be mode 1777
+(that is, the sticky bit should be set).
+Users should create the files mode 644.
+.sh 2 "Free Space"
+.pp
+On systems that have the
+.i statfs (2)
+system call,
+you can specify a minimum number of free blocks on the queue filesystem
+using the
+.b b
+option.
+If there are fewer than the indicated number of blocks free
+on the filesystem on which the queue is mounted
+the SMTP server will reject mail
+with the
+452 error code.
+This invites the SMTP client to try again later.
+.pp
+Beware of setting this option too high;
+it can cause rejection of email
+when that mail would be processed without difficulty.
+.pp
+This option can also specify an advertised
+.q "maximum message size"
+for hosts that speak ESMTP.
+.sh 2 "Privacy Flags"
+.pp
+The
+.b p
+option allows you to set certain
+``privacy''
+flags.
+Actually, many of them don't give you any extra privacy,
+rather just insisting that client SMTP servers
+use the HELO command
+before using certain commands.
+.pp
+The option takes a series of flag names;
+the final privacy is the inclusive or of those flags.
+For example:
+.(b
+Op needmailhelo, noexpn
+.)b
+insists that the HELO or EHLO command be used before a MAIL command is accepted
+and disables the EXPN command.
+.pp
+The
+.q restrictmailq
+option restricts printing the queue to the group that owns the queue directory.
+It is absurd to set this if you don't also protect the logs.
+.pp
+The
+.q restrictqrun
+option restricts people running the queue
+(that is, using the
+.b \-q
+command line flag)
+to root and the owner of the queue directory.
+.sh 2 "Send to Me Too"
+.pp
+Normally,
+.i sendmail
+deletes the (envelope) sender from any list expansions.
+For example, if
+.q matt
+sends to a list that contains
+.q matt
+as one of the members he won't get a copy of the message.
+If the
+.b \-m
+(me too)
+command line flag, or if the
+.b m
+option is set in the configuration file,
+this behaviour is supressed.
+Some sites like to run the
+.sm SMTP
+daemon with
+.b \-m .
+.sh 1 "THE WHOLE SCOOP ON THE CONFIGURATION FILE"
+.pp
+This section describes the configuration file
+in detail,
+including hints on how to write one of your own
+if you have to.
+.pp
+There is one point that should be made clear immediately:
+the syntax of the configuration file
+is designed to be reasonably easy to parse,
+since this is done every time
+.i sendmail
+starts up,
+rather than easy for a human to read or write.
+On the
+.q "future project"
+list is a
+configuration-file compiler.
+.pp
+An overview of the configuration file
+is given first,
+followed by details of the semantics.
+.sh 2 "Configuration File Lines"
+.pp
+The configuration file is organized as a series of lines,
+each of which begins with a single character
+defining the semantics for the rest of the line.
+Lines beginning with a space or a tab
+are continuation lines
+(although the semantics are not well defined in many places).
+Blank lines and lines beginning with a sharp symbol
+(`#')
+are comments.
+.sh 3 "R and S \*- rewriting rules"
+.pp
+The core of address parsing
+are the rewriting rules.
+These are an ordered production system.
+.i Sendmail
+scans through the set of rewriting rules
+looking for a match on the left hand side
+(LHS)
+of the rule.
+When a rule matches,
+the address is replaced by the right hand side
+(RHS)
+of the rule.
+.pp
+There are several sets of rewriting rules.
+Some of the rewriting sets are used internally
+and must have specific semantics.
+Other rewriting sets
+do not have specifically assigned semantics,
+and may be referenced by the mailer definitions
+or by other rewriting sets.
+.pp
+The syntax of these two commands are:
+.(b F
+.b S \c
+.i n
+.)b
+Sets the current ruleset being collected to
+.i n .
+If you begin a ruleset more than once
+it deletes the old definition.
+.(b F
+.b R \c
+.i lhs
+.i rhs
+.i comments
+.)b
+The
+fields must be separated
+by at least one tab character;
+there may be embedded spaces
+in the fields.
+The
+.i lhs
+is a pattern that is applied to the input.
+If it matches,
+the input is rewritten to the
+.i rhs .
+The
+.i comments
+are ignored.
+.pp
+Macro expansions of the form
+.b $ \c
+.i x
+are performed when the configuration file is read.
+Expansions of the form
+.b $& \c
+.i x
+are performed at run time using a somewhat less general algorithm.
+This for is intended only for referencing internally defined macros
+such as
+.b $h
+that are changed at runtime.
+.sh 4 "The left hand side"
+.pp
+The left hand side of rewriting rules contains a pattern.
+Normal words are simply matched directly.
+Metasyntax is introduced using a dollar sign.
+The metasymbols are:
+.(b
+.ta \w'\fB$=\fP\fIx\fP 'u
+\fB$*\fP Match zero or more tokens
+\fB$+\fP Match one or more tokens
+\fB$\-\fP Match exactly one token
+\fB$=\fP\fIx\fP Match any phrase in class \fIx\fP
+\fB$~\fP\fIx\fP Match any word not in class \fIx\fP
+.)b
+If any of these match,
+they are assigned to the symbol
+.b $ \c
+.i n
+for replacement on the right hand side,
+where
+.i n
+is the index in the LHS.
+For example,
+if the LHS:
+.(b
+$\-:$+
+.)b
+is applied to the input:
+.(b
+UCBARPA:eric
+.)b
+the rule will match, and the values passed to the RHS will be:
+.(b
+.ta 4n
+$1 UCBARPA
+$2 eric
+.)b
+.pp
+Additionally, the LHS can include
+.b $@
+to match zero tokens.
+This is
+.i not
+bound to a
+.b $ \c
+.i N
+on the RHS, and is normally only used when it stands alone
+in order to match the null input.
+.sh 4 "The right hand side"
+.pp
+When the left hand side of a rewriting rule matches,
+the input is deleted and replaced by the right hand side.
+Tokens are copied directly from the RHS
+unless they begin with a dollar sign.
+Metasymbols are:
+.(b
+.ta \w'$#mailer\0\0\0'u
+\fB$\fP\fIn\fP Substitute indefinite token \fIn\fP from LHS
+\fB$[\fP\fIname\fP\fB$]\fP Canonicalize \fIname\fP
+\fB$(\fP\fImap key\fP \fB$@\fP\fIarguments\fP \fB$:\fP\fIdefault\fP \fB$)\fP
+ Generalized keyed mapping function
+\fB$>\fP\fIn\fP \*(lqCall\*(rq ruleset \fIn\fP
+\fB$#\fP\fImailer\fP Resolve to \fImailer\fP
+\fB$@\fP\fIhost\fP Specify \fIhost\fP
+\fB$:\fP\fIuser\fP Specify \fIuser\fP
+.)b
+.pp
+The
+.b $ \c
+.i n
+syntax substitutes the corresponding value from a
+.b $+ ,
+.b $\- ,
+.b $* ,
+.b $= ,
+or
+.b $~
+match on the LHS.
+It may be used anywhere.
+.pp
+A host name enclosed between
+.b $[
+and
+.b $]
+is looked up using the
+.i gethostent \|(3)
+routines and replaced by the canonical name\**.
+.(f
+\**This is actually
+completely equivalent
+to $(host \fIhostname\fP$).
+In particular, a
+.b $:
+default can be used.
+.)f
+For example,
+.q $[csam$]
+might become
+.q lbl-csam.arpa
+and
+.q $[[128.32.130.2]$]
+would become
+.q vangogh.CS.Berkeley.EDU.
+.i Sendmail
+recognizes it's numeric IP address
+without calling the name server
+and replaces it with it's canonical name.
+.pp
+The
+.b $(
+\&...
+.b $)
+syntax is a more general form of lookup;
+it uses a named map instead of an implicit map.
+If no lookup is found, the indicated
+.i default
+is inserted;
+if no default is specified and no lookup matches,
+the value is left unchanged.
+.pp
+The
+.b $> \c
+.i n
+syntax
+causes the remainder of the line to be substituted as usual
+and then passed as the argument to ruleset
+.i n .
+The final value of ruleset
+.i n
+then becomes
+the substitution for this rule.
+.pp
+The
+.b $#
+syntax should
+.i only
+be used in ruleset zero
+or a subroutine of ruleset zero.
+It causes evaluation of the ruleset to terminate immediately,
+and signals to
+.i sendmail
+that the address has completely resolved.
+The complete syntax is:
+.(b
+\fB$#\fP\fImailer\fP \fB$@\fP\fIhost\fP \fB$:\fP\fIuser\fP
+.)b
+This specifies the
+{mailer, host, user}
+3-tuple necessary to direct the mailer.
+If the mailer is local
+the host part may be omitted\**.
+.(f
+\**You may want to use it for special
+.q "per user"
+extensions.
+For example, at CMU you can send email to
+.q jgm+foo ;
+the part after the plus sign
+is not part of the user name,
+and is passed to the local mailer for local use.
+.)f
+The
+.i mailer
+must be a single word,
+but the
+.i host
+and
+.i user
+may be multi-part.
+If the
+.i mailer
+is the builtin IPC mailer,
+the
+.i host
+may be a colon-separated list of hosts
+that are searched in order for the first working address
+(exactly like MX records).
+The
+.i user
+is later rewritten by the mailer-specific envelope rewriting set
+and assigned to the
+.b $u
+macro.
+As a special case, if the value to
+.b $#
+is
+.q local
+and the first character of the
+.b $:
+value is
+.q @ ,
+the
+.q @
+is stripped off, and a flag is set in the address descriptor
+that causes sendmail to not do ruleset 5 processing.
+.pp
+Normally, a rule that matches is retried,
+that is,
+the rule loops until it fails.
+A RHS may also be preceded by a
+.b $@
+or a
+.b $:
+to change this behavior.
+A
+.b $@
+prefix causes the ruleset to return with the remainder of the RHS
+as the value.
+A
+.b $:
+prefix causes the rule to terminate immediately,
+but the ruleset to continue;
+this can be used to avoid continued application of a rule.
+The prefix is stripped before continuing.
+.pp
+The
+.b $@
+and
+.b $:
+prefixes may precede a
+.b $>
+spec;
+for example:
+.(b
+.ta 8n
+R$+ $: $>7 $1
+.)b
+matches anything,
+passes that to ruleset seven,
+and continues;
+the
+.b $:
+is necessary to avoid an infinite loop.
+.pp
+Substitution occurs in the order described,
+that is,
+parameters from the LHS are substituted,
+hostnames are canonicalized,
+.q subroutines
+are called,
+and finally
+.b $# ,
+.b $@ ,
+and
+.b $:
+are processed.
+.sh 4 "Semantics of rewriting rule sets"
+.pp
+There are five rewriting sets
+that have specific semantics.
+These are related as depicted by figure 2.
+.(z
+.hl
+.ie n \{\
+.(c
+ +---+
+ -->| 0 |-->resolved address
+ / +---+
+ / +---+ +---+
+ / ---->| 1 |-->| S |--
+ +---+ / +---+ / +---+ +---+ \e +---+
+addr-->| 3 |-->| D |-- --->| 4 |-->msg
+ +---+ +---+ \e +---+ +---+ / +---+
+ --->| 2 |-->| R |--
+ +---+ +---+
+.)c
+
+.\}
+.el .ie !"\*(.T"" \
+\{\
+.PS
+boxwid = 0.3i
+boxht = 0.3i
+movewid = 0.3i
+moveht = 0.3i
+linewid = 0.3i
+lineht = 0.3i
+
+ box invis "addr"; arrow
+Box3: box "3"
+A1: arrow
+BoxD: box "D"; line; L1: Here
+C: [
+ C1: arrow; box "1"; arrow; box "S"; line; E1: Here
+ move to C1 down 0.5; right
+ C2: arrow; box "2"; arrow; box "R"; line; E2: Here
+ ] with .w at L1 + (0.5, 0)
+ move to C.e right 0.5
+L4: arrow; box "4"; arrow; box invis "msg"
+ line from L1 to C.C1
+ line from L1 to C.C2
+ line from C.E1 to L4
+ line from C.E2 to L4
+ move to BoxD.n up 0.6; right
+Box0: arrow; box "0"
+ arrow; box invis "resolved address" width 1.3
+ line from 1/3 of the way between A1 and BoxD.w to Box0
+.PE
+.\}
+.el .sp 2i
+.ce
+Figure 2 \*- Rewriting set semantics
+.(c
+D \*- sender domain addition
+S \*- mailer-specific sender rewriting
+R \*- mailer-specific recipient rewriting
+.)c
+.hl
+.)z
+.pp
+Ruleset three
+should turn the address into
+.q "canonical form."
+This form should have the basic syntax:
+.(b
+local-part@host-domain-spec
+.)b
+If no
+.q @
+sign is specified,
+then the
+host-domain-spec
+.i may
+be appended from the
+sender address
+(if the
+.b C
+flag is set in the mailer definition
+corresponding to the
+.i sending
+mailer).
+Ruleset three
+is applied by
+.i sendmail
+before doing anything with any address.
+.pp
+Ruleset zero
+is applied after ruleset three
+to addresses that are going to actually specify recipients.
+It must resolve to a
+.i "{mailer, host, user}"
+triple.
+The
+.i mailer
+must be defined in the mailer definitions
+from the configuration file.
+The
+.i host
+is defined into the
+.b $h
+macro
+for use in the argv expansion of the specified mailer.
+.pp
+Rulesets one and two
+are applied to all sender and recipient addresses respectively.
+They are applied before any specification
+in the mailer definition.
+They must never resolve.
+.pp
+Ruleset four is applied to all addresses
+in the message.
+It is typically used
+to translate internal to external form.
+.sh 4 "IPC mailers"
+.pp
+Some special processing occurs
+if the ruleset zero resolves to an IPC mailer
+(that is, a mailer that has
+.q [IPC]
+listed as the Path in the
+.b M
+configuration line.
+The host name passed after
+.q $@
+has MX expansion performed;
+this looks the name up in DNS to find alternate delivery sites.
+.pp
+The host name can also be provided as a dotted quad in square brackets;
+for example:
+.(b
+[128.32.149.78]
+.)b
+This causes direct conversion of the numeric value
+to a TCP/IP host address.
+.pp
+The host name passed in after the
+.q $@
+may also be a colon-separated list of hosts.
+Each is separately MX expanded and the results are concatenated
+to make (essentially) one long MX list.
+The intent here is to create
+.q fake
+MX records that are not published in DNS
+for private internal networks.
+.pp
+As a final special case, the host name can be passed in
+as a text string
+in square brackets:
+.(b
+[ucbvax.berkeley.edu]
+.)b
+This form avoids the MX mapping.
+.b N.B.:
+This is intended only for situations where you have a network firewall,
+so that your MX record points to a gateway machine;
+this machine could then do direct delivery to machines
+within your local domain.
+Use of this feature directly violates RFC 1123 section 5.3.5:
+it should not be used lightly.
+.sh 3 "D \*- define macro"
+.pp
+Macros are named with a single character.
+These may be selected from the entire ASCII set,
+but user-defined macros
+should be selected from the set of upper case letters only.
+Lower case letters
+and special symbols
+are used internally.
+.pp
+The syntax for macro definitions is:
+.(b F
+.b D \c
+.i x\|val
+.)b
+where
+.i x
+is the name of the macro
+and
+.i val
+is the value it should have.
+.pp
+Macros are interpolated
+using the construct
+.b $ \c
+.i x ,
+where
+.i x
+is the name of the macro to be interpolated.
+This interpolation is done when the configuration file is read,
+except in
+.b M
+lines.
+The special construct
+.b $& \c
+.i x
+can be used in
+.b R
+lines to get deferred interpolation.
+.pp
+Conditionals can be specified using the syntax:
+.(b
+$?x text1 $| text2 $.
+.)b
+This interpolates
+.i text1
+if the macro
+.b $x
+is set,
+and
+.i text2
+otherwise.
+The
+.q else
+(\c
+.b $| )
+clause may be omitted.
+.pp
+Lower case macro names are reserved to have
+special semantics,
+used to pass information in or out of
+.i sendmail ,
+and special characters are reserved to
+provide conditionals, etc.
+Upper case names
+(that is,
+.b $A
+through
+.b $Z )
+are specifically reserved for configuration file authors.
+.pp
+The following macros are defined and/or used internally by
+.i sendmail
+for interpolation into argv's for mailers
+or for other contexts.
+The ones marked \(dg are information passed into sendmail\**,
+.(f
+\**As of version 8.6,
+all of these macros have reasonable defaults.
+Previous versions required that they be defined.
+.)f
+the ones marked \(dd are information passed both in and out of sendmail,
+and the unmarked macros are passed out of sendmail
+but are not otherwise used internally.
+These macros are:
+.nr ii 5n
+.ip $a
+.b "The origination date in RFC 822 format."
+.ip $b
+.b "The current date in RFC 822 format."
+.ip $c
+.b "The hop count."
+.ip $d
+.b "The current date in UNIX (ctime) format."
+.ip $e\(dg
+.b "The SMTP entry message."
+This is printed out when SMTP starts up.
+The first word must be the
+.b $j
+macro as specified by RFC821.
+Defaults to
+.q "$j Sendmail $v ready at $b" .
+Commonly redefined to include the configuration version number, e.g.,
+.q "$j Sendmail $v/$Z ready at $b"
+.ip $f
+.b "The sender (from) address."
+.ip $g
+.b "The sender address relative to the recipient."
+.ip $h
+.b "The recipient host."
+.ip $i
+.b "The queue id."
+.ip $j\(dd
+.b "The \*(lqofficial\*(rq domain name for this site."
+This is fully qualified if the full qualification can be found.
+It
+.i must
+be redefined to be the fully qualified domain name
+if your system is not configured so that information can find
+it automatically.
+.ip $k
+.b "The UUCP node name (from the uname system call)."
+.ip $l\(dg
+.b "The format of the UNIX from line."
+Unless you have changed the UNIX mailbox format,
+you should not change the default,
+which is
+.q "From $g $d" .
+.ip $m
+.b "The domain part of the \fIgethostname\fP return value."
+Under normal circumstances,
+.b $j
+is equivalent to
+.b $w.$m .
+.ip $n\(dg
+.b "The name of the daemon (for error messages)."
+Defaults to
+.q MAILER-DAEMON .
+.ip $o\(dg
+.b "The set of \*(lqoperators\*(rq in addresses."
+A list of characters
+which will be considered tokens
+and which will separate tokens
+when doing parsing.
+For example, if
+.q @
+were in the
+.b $o
+macro, then the input
+.q a@b
+would be scanned as three tokens:
+.q a,
+.q @,
+and
+.q b.
+Defaults to
+.q ".:@[]" ,
+which is the minimum set necessary to do RFC 822 parsing;
+a richer set of operators is
+.q ".:%@!/[]" ,
+which adds support for UUCP, the %-hack, and X.400 addresses.
+.ip $p
+.b "Sendmail's process id."
+.ip $q\(dg
+.b "Default format of sender address."
+The
+.b $q
+macro specifies how an address should appear in a message
+when it is defaulted.
+Defaults to
+.q "<$g>" .
+It is commonly redefined to be
+.q "$?x$x <$g>$|$g$."
+or
+.q "$g$?x ($x)$." ,
+corresponding to the following two formats:
+.(b
+Eric Allman <eric@CS.Berkeley.EDU>
+eric@CS.Berkeley.EDU (Eric Allman)
+.)b
+.i Sendmail
+properly quotes names that have special characters
+if the first form is used.
+.ip $r
+.b "Protocol used to receive the message."
+.ip $s
+.b "Sender's host name."
+.ip $t
+.b "A numeric representation of the current time."
+.ip $u
+.b "The recipient user."
+.ip $v
+.b "The version number of \fIsendmail\fP."
+.ip $w\(dd
+.b "The hostname of this site."
+.pp
+The
+.b $w
+macro is set to the root name of this host (but see below for caveats).
+.ip $x
+.b "The full name of the sender."
+.ip $z
+.b "The home directory of the recipient."
+.ip $_
+.b "The validated sender address."
+.pp
+There are three types of dates that can be used.
+The
+.b $a
+and
+.b $b
+macros are in RFC 822 format;
+.b $a
+is the time as extracted from the
+.q Date:
+line of the message
+(if there was one),
+and
+.b $b
+is the current date and time
+(used for postmarks).
+If no
+.q Date:
+line is found in the incoming message,
+.b $a
+is set to the current time also.
+The
+.b $d
+macro is equivalent to the
+.b $b
+macro in UNIX
+(ctime)
+format.
+.pp
+The macros
+.b $w ,
+.b $j ,
+and
+.b $m
+are set to the identity of this host.
+.i Sendmail
+tries to find the fully qualified name of the host
+if at all possible;
+it does this by calling
+.i gethostname (2)
+to get the current hostname
+and then passing that to
+.i gethostbyname (3)
+which is supposed to return the canonical version of that host name.\**
+.(f
+\**For example, on some systems
+.i gethostname
+might return
+.q foo
+which would be mapped to
+.q foo.bar.com
+by
+.i gethostbyname .
+.)f
+Assuming this is successful,
+.b $j
+is set to the fully qualified name
+and
+.b $m
+is set to the domain part of the name
+(everything after the first dot).
+The
+.b $w
+macro is set to the first word
+(everything before the first dot)
+if you have a level 5 or higher configuration file;
+otherwise, it is set to the same value as
+.b $j .
+If the canonification is not successful,
+it is imperative that the config file set
+.b $j
+to the fully qualified domain name\**.
+.(f
+\**Older versions of sendmail didn't pre-define
+.b $j
+at all, so up until 8.6,
+config files
+.i always
+had to define
+.b $j .
+.)f
+.pp
+The
+.b $f
+macro is the id of the sender
+as originally determined;
+when mailing to a specific host
+the
+.b $g
+macro is set to the address of the sender
+.ul
+relative to the recipient.
+For example,
+if I send to
+.q bollard@matisse.CS.Berkeley.EDU
+from the machine
+.q vangogh.CS.Berkeley.EDU
+the
+.b $f
+macro will be
+.q eric
+and the
+.b $g
+macro will be
+.q eric@vangogh.CS.Berkeley.EDU.
+.pp
+The
+.b $x
+macro is set to the full name of the sender.
+This can be determined in several ways.
+It can be passed as flag to
+.i sendmail .
+The second choice is the value of the
+.q Full-name:
+line in the header if it exists,
+and the third choice is the comment field
+of a
+.q From:
+line.
+If all of these fail,
+and if the message is being originated locally,
+the full name is looked up in the
+.i /etc/passwd
+file.
+.pp
+When sending,
+the
+.b $h ,
+.b $u ,
+and
+.b $z
+macros get set to the host, user, and home directory
+(if local)
+of the recipient.
+The first two are set from the
+.b $@
+and
+.b $:
+part of the rewriting rules, respectively.
+.pp
+The
+.b $p
+and
+.b $t
+macros are used to create unique strings
+(e.g., for the
+.q Message-Id:
+field).
+The
+.b $i
+macro is set to the queue id on this host;
+if put into the timestamp line
+it can be extremely useful for tracking messages.
+The
+.b $v
+macro is set to be the version number of
+.i sendmail ;
+this is normally put in timestamps
+and has been proven extremely useful for debugging.
+.pp
+The
+.b $c
+field is set to the
+.q "hop count,"
+i.e., the number of times this message has been processed.
+This can be determined
+by the
+.b \-h
+flag on the command line
+or by counting the timestamps in the message.
+.pp
+The
+.b $r
+and
+.b $s
+fields are set to the protocol used to communicate with
+.i sendmail
+and the sending hostname.
+.pp
+The
+.b $_
+is set to a validated sender host name.
+If the sender is running an RFC 1413 compliant IDENT server,
+it will include the user name on that host.
+.sh 3 "C and F \*- define classes"
+.pp
+Classes of phrases may be defined
+to match on the left hand side of rewriting rules,
+where a
+.q phrase
+is a sequence of characters that do not contain space characters.
+For example
+a class of all local names for this site
+might be created
+so that attempts to send to oneself
+can be eliminated.
+These can either be defined directly in the configuration file
+or read in from another file.
+Classes may be given names
+from the set of upper case letters.
+Lower case letters and special characters
+are reserved for system use.
+.pp
+The syntax is:
+.(b F
+.b C \c
+.i c\|phrase1
+.i phrase2...
+.br
+.b F \c
+.i c\|file
+.)b
+The first form defines the class
+.i c
+to match any of the named words.
+It is permissible to split them among multiple lines;
+for example, the two forms:
+.(b
+CHmonet ucbmonet
+.)b
+and
+.(b
+CHmonet
+CHucbmonet
+.)b
+are equivalent.
+The second form
+reads the elements of the class
+.i c
+from the named
+.i file .
+.pp
+The
+.b $~
+(match entries not in class)
+only matches a single word;
+multi-word entries in the class are ignored in this context.
+.pp
+The class
+.b $=w
+is set to be the set of all names
+this host is known by.
+This can be used to match local hostnames.
+.pp
+The class
+.b $=k
+is set to be the same as
+.b $k ,
+that is, the UUCP node name.
+.pp
+The class
+.b $=m
+is set to the set of domains by which this host is known,
+initially just
+.b $m .
+.pp
+.i Sendmail
+can be compiled to allow a
+.i scanf (3)
+string on the
+.b F
+line.
+This lets you do simplistic parsing of text files.
+For example, to read all the user names in your system
+.i /etc/passwd
+file into a class, use
+.(b
+FL/etc/passwd %[^:]
+.)b
+which reads every line up to the first colon.
+.sh 3 "M \*- define mailer"
+.pp
+Programs and interfaces to mailers
+are defined in this line.
+The format is:
+.(b F
+.b M \c
+.i name ,
+{\c
+.i field =\c
+.i value \|}*
+.)b
+where
+.i name
+is the name of the mailer
+(used internally only)
+and the
+.q field=name
+pairs define attributes of the mailer.
+Fields are:
+.(b
+.ta 1i
+Path The pathname of the mailer
+Flags Special flags for this mailer
+Sender A rewriting set for sender addresses
+Recipient A rewriting set for recipient addresses
+Argv An argument vector to pass to this mailer
+Eol The end-of-line string for this mailer
+Maxsize The maximum message length to this mailer
+Linelimit The maximum line length in the message body
+Directory The working directory for the mailer
+.)b
+Only the first character of the field name is checked.
+.pp
+The following flags may be set in the mailer description.
+Any other flags may be used freely
+to conditionally assign headers to messages
+destined for particular mailers.
+.nr ii 4n
+.ip a
+Run Extended SMTP (ESMTP) protocol (defined in RFCs 1425, 1426, and 1427).
+.ip b
+Force a blank line on the end of a message.
+This is intended to work around some stupid versions of
+/bin/mail
+that require a blank line, but do not provide it themselves.
+It would not normally be used on network mail.
+.ip c
+Do not include comments in addresses.
+This should only be used if you have to work around
+a remote mailer that gets confused by comments.
+.ip C
+If mail is
+.i received
+from a mailer with this flag set,
+any addresses in the header that do not have an at sign
+(\c
+.q @ )
+after being rewritten by ruleset three
+will have the
+.q @domain
+clause from the sender
+tacked on.
+This allows mail with headers of the form:
+.(b
+From: usera@hosta
+To: userb@hostb, userc
+.)b
+to be rewritten as:
+.(b
+From: usera@hosta
+To: userb@hostb, userc@hosta
+.)b
+automatically.
+.ip D
+This mailer wants a
+.q Date:
+header line.
+.ip e
+This mailer is expensive to connect to,
+so try to avoid connecting normally;
+any necessary connection will occur during a queue run.
+.ip E
+Escape lines beginning with
+.q From
+in the message with a `>' sign.
+.ip f
+The mailer wants a
+.b \-f
+.i from
+flag,
+but only if this is a network forward operation
+(i.e.,
+the mailer will give an error
+if the executing user
+does not have special permissions).
+.ip F
+This mailer wants a
+.q From:
+header line.
+.ip g
+Normally,
+.i sendmail
+sends internally generated email (e.g., error messages)
+using the null return address\**
+.(f
+\**Actually, this only applies to SMTP,
+which uses the ``MAIL FROM:<>'' command.
+.)f
+as required by RFC 1123.
+However, some mailers don't accept a null return address.
+If necessary,
+you can set the
+.b g
+flag to prevent
+.i sendmail
+from obeying the standards;
+error messages will be sent as from the MAILER-DAEMON
+(actually, the value of the
+.b $n
+macro).
+.ip h
+Upper case should be preserved in host names
+for this mailer.
+.ip I
+This mailer will be speaking SMTP
+to another
+.i sendmail
+\*-
+as such it can use special protocol features.
+This option is not required
+(i.e.,
+if this option is omitted the transmission will still operate successfully,
+although perhaps not as efficiently as possible).
+.ip l
+This mailer is local
+(i.e.,
+final delivery will be performed).
+.ip L
+Limit the line lengths as specified in RFC821.
+This deprecated option should be replaced by the
+.b L=
+mail declaration.
+For historic reasons, the
+.b L
+flag also sets the
+.b 7
+flag.
+.ip m
+This mailer can send to multiple users
+on the same host
+in one transaction.
+When a
+.b $u
+macro occurs in the
+.i argv
+part of the mailer definition,
+that field will be repeated as necessary
+for all qualifying users.
+.ip M
+This mailer wants a
+.q Message-Id:
+header line.
+.ip n
+Do not insert a UNIX-style
+.q From
+line on the front of the message.
+.ip p
+Use the route-addr style reverse-path in the SMTP
+.q "MAIL FROM:"
+command
+rather than just the return address;
+although this is required in RFC821 section 3.1,
+many hosts do not process reverse-paths properly.
+Reverse-paths are officially discouraged by RFC 1123.
+.ip P
+This mailer wants a
+.q Return-Path:
+line.
+.ip r
+Same as
+.b f ,
+but sends a
+.b \-r
+flag.
+.ip s
+Strip quote characters off of the address
+before calling the mailer.
+.ip S
+Don't reset the userid
+before calling the mailer.
+This would be used in a secure environment
+where
+.i sendmail
+ran as root.
+This could be used to avoid forged addresses.
+This flag is suppressed if given from an
+.q unsafe
+environment
+(e.g, a user's mail.cf file).
+.ip u
+Upper case should be preserved in user names
+for this mailer.
+.ip U
+This mailer wants Unix-style
+.q From
+lines with the ugly UUCP-style
+.q "remote from <host>"
+on the end.
+.ip x
+This mailer wants a
+.q Full-Name:
+header line.
+.ip X
+This mailer want to use the hidden dot algorithm
+as specified in RFC821;
+basically,
+any line beginning with a dot
+will have an extra dot prepended
+(to be stripped at the other end).
+This insures that lines in the message containing a dot
+will not terminate the message prematurely.
+.ip 7
+Strip all output to seven bits.
+This is the default if the
+.b L
+flag is set.
+Note that clearing this option is not
+sufficient to get full eight bit data passed through
+.i sendmail .
+If the
+.b 7
+option is set, this is essentially always set,
+since the eighth bit was stripped on input.
+.pp
+The mailer with the special name
+.q error
+can be used to generate a user error.
+The (optional) host field is an exit status to be returned,
+and the user field is a message to be printed.
+The exit status may be numeric or one of the values
+USAGE, NOUSER, NOHOST, UNAVAILABLE, SOFTWARE, TEMPFAIL, PROTOCOL, or CONFIG
+to return the corresponding EX_ exit code.
+For example, the entry:
+.(b
+$#error $@ NOHOST $: Host unknown in this domain
+.)b
+on the RHS of a rule
+will cause the specified error to be generated
+and the
+.q "Host unknown"
+exit status to be returned
+if the LHS matches.
+This mailer is only functional in ruleset zero.
+.pp
+The mailer named
+.q local
+.i must
+be defined in every configuration file.
+This is used to deliver local mail,
+and is treated specially in several ways.
+Additionally, three other mailers named
+.q prog ,
+.q *file* ,
+and
+.q *include*
+may be defined to tune the delivery of messages to programs,
+files,
+and :include: lists respectively.
+They default to:
+.(b
+Mprog, P=/bin/sh, F=lsD, A=sh \-c $u
+M*file*, P=/dev/null, F=lsDFMPEu, A=FILE
+M*include*, P=/dev/null, F=su, A=INCLUDE
+.)b
+.pp
+The Sender and Recipient rewriting sets
+may either be a simple integer
+or may be two integers separated by a slash;
+if so, the first rewriting set is applied to envelope
+addresses
+and the second is applied to headers.
+.pp
+The Directory
+is actually a colon-separated path of directories to try.
+For example, the definition
+.q D=$z:/
+first tries to execute in the recipient's home directory;
+if that is not available,
+it tries to execute in the root of the filesystem.
+This is intended to be used only on the
+.q prog
+mailer,
+since some shells (such as
+.i csh )
+refuse to execute if they cannot read the home directory.
+Since the queue directory is not normally readable by normal users
+.i csh
+scripts as recipients can fail.
+.sh 3 "H \*- define header"
+.pp
+The format of the header lines that
+.i sendmail
+inserts into the message
+are defined by the
+.b H
+line.
+The syntax of this line is:
+.(b F
+.b H [\c
+.b ? \c
+.i mflags \c
+.b ? ]\c
+.i hname \c
+.b :
+.i htemplate
+.)b
+Continuation lines in this spec
+are reflected directly into the outgoing message.
+The
+.i htemplate
+is macro expanded before insertion into the message.
+If the
+.i mflags
+(surrounded by question marks)
+are specified,
+at least one of the specified flags
+must be stated in the mailer definition
+for this header to be automatically output.
+If one of these headers is in the input
+it is reflected to the output
+regardless of these flags.
+.pp
+Some headers have special semantics
+that will be described below.
+.sh 3 "O \*- set option"
+.pp
+There are a number of
+.q random
+options that
+can be set from a configuration file.
+Options are represented by single characters.
+The syntax of this line is:
+.(b F
+.b O \c
+.i o\|value
+.)b
+This sets option
+.i o
+to be
+.i value .
+Depending on the option,
+.i value
+may be a string, an integer,
+a boolean
+(with legal values
+.q t ,
+.q T ,
+.q f ,
+or
+.q F ;
+the default is TRUE),
+or
+a time interval.
+.pp
+The options supported are:
+.nr ii 1i
+.ip a\fIN\fP
+If set,
+wait up to
+.i N
+minutes for an
+.q @:@
+entry to exist in the alias database
+before starting up.
+If it does not appear in
+.i N
+minutes,
+rebuild the database
+(if the
+.b D
+option is also set)
+or issue a warning.
+.ip "A\fIspec, spec, ...\fP"
+Specify possible alias file(s).
+Each
+.i spec
+should be in the format
+``\c
+.i class \c
+.b :
+.i file ''
+where
+.i class \c
+.b :
+is optional and defaults to ``implicit''.
+Depending on how
+.i sendmail
+is compiled, valid classes are
+.q implicit
+(search through a compiled-in list of alias file types,
+for back compatibility),
+.q hash
+(if
+.sm NEWDB
+is specified),
+.q dbm
+(if
+.sm NDBM
+is specified),
+.q stab
+(internal symbol table \*- not normally used
+unless you have no other database lookup),
+or
+.q nis
+(if
+.sm NIS
+is specified).
+If a list of
+.i spec s
+are provided,
+.i sendmail
+searches them in order.
+.ip b\fIN\fP/\fIM\fP
+Insist on at least
+.i N
+blocks free on the filesystem that holds the queue files
+before accepting email via SMTP.
+If there is insufficient space
+.i sendmail
+gives a 452 response
+to the MAIL command.
+This invites the sender to try again later.
+The optional
+.i M
+is a maximum message size advertised in the ESMTP EHLO response.
+It is currently otherwise unused.
+.ip B\fIc\fP
+Set the blank substitution character to
+.i c .
+Unquoted spaces in addresses are replaced by this character.
+Defaults to space (i.e., no change is made).
+.ip c
+If an outgoing mailer is marked as being expensive,
+don't connect immediately.
+This requires that queueing be compiled in,
+since it will depend on a queue run process to
+actually send the mail.
+.ip C\fIN\fP
+Checkpoints the queue every
+.i N
+(default 10)
+addresses sent.
+If your system crashes during delivery to a large list,
+this prevents retransmission to any but the last
+.I N
+recipients.
+.ip d\fIx\fP
+Deliver in mode
+.i x .
+Legal modes are:
+.(b
+.ta 4n
+i Deliver interactively (synchronously)
+b Deliver in background (asynchronously)
+q Just queue the message (deliver during queue run)
+.)b
+Defaults to ``b'' if no option is specified,
+``i'' if it is specified but given no argument
+(i.e., ``Od'' is equivalent to ``Odi'').
+.ip D
+If set,
+rebuild the alias database if necessary and possible.
+If this option is not set,
+.i sendmail
+will never rebuild the alias database
+unless explicitly requested
+using
+.b \-bi .
+.ip e\fIx\fP
+Dispose of errors using mode
+.i x .
+The values for
+.i x
+are:
+.(b
+p Print error messages (default)
+q No messages, just give exit status
+m Mail back errors
+w Write back errors (mail if user not logged in)
+e Mail back errors and give zero exit stat always
+.)b
+.ip E\fIfile/message\fP
+Prepend error messages with the indicated message.
+If it begins with a slash,
+it is assumed to be the pathname of a file
+containing a message (this is the recommended setting).
+Otherwise, it is a literal message.
+The error file might contain the name, email address, and/or phone number
+of a local postmaster who could provide assistance
+in to end users.
+If the option is missing or null,
+or if it names a file which does not exist or which is not readable,
+no message is printed.
+.ip f
+Save
+Unix-style
+.q From
+lines at the front of headers.
+Normally they are assumed redundant
+and discarded.
+.ip F\fImode\fP
+The file mode for queue files.
+.ip g\fIn\fP
+Set the default group id
+for mailers to run in
+to
+.i n .
+Defaults to 1.
+The value can also be given as a symbolic group name.
+.ip G
+Allow fuzzy matching on the GECOS field.
+If this flag is set,
+and the usual user name lookups fail
+(that is, there is no alias with this name and a
+.i getpwnam
+fails),
+sequentially search the password file
+for a matching entry in the GECOS field.
+This also requires that MATCHGECOS
+be turned on during compilation.
+This option is not recommended.
+.ip h\fIN\fP
+The maximum hop count.
+Messages that have been processed more than
+.i N
+times are assumed to be in a loop and are rejected.
+Defaults to 25.
+.ip H\fIfile\fP
+Specify the help file
+for SMTP.
+.ip i
+Ignore dots in incoming messages.
+This is always disabled (that is, dots are always accepted)
+when reading SMTP mail.
+.ip I
+Insist that the BIND name server be running
+to resolve host names.
+If this is not set and the name server is not running,
+the
+.i /etc/hosts
+file will be considered complete.
+In general, you do want to set this option
+if your
+.i /etc/hosts
+file does not include all hosts known to you
+or if you are using the MX (mail forwarding) feature of the BIND name server.
+The name server will still be consulted
+even if this option is not set, but
+.i sendmail
+will feel free to resort to reading
+.i /etc/hosts
+if the name server is not available.
+Thus, you should
+.i never
+set this option if you do not run the name server.
+.ip j
+If set, send error messages in MIME format
+(see RFC1341 and RFC1344 for details).
+.ip J\fIpath\fP
+Set the path for searching for users' .forward files.
+The default is
+.q $z/.forward .
+Some sites that use the automounter may prefer to change this to
+.q /var/forward/$u
+to search a file with the same name as the user in a system directory.
+It can also be set to a sequence of paths separated by colons;
+.i sendmail
+stops at the first file it can successfully and safely open.
+For example,
+.q /var/forward/$u:$z/.forward
+will search first in /var/forward/\c
+.i username
+and then in
+.i ~username /.forward
+(but only if the first file does not exist).
+.ip k\fIN\fP
+The maximum number of open connections that will be cached at a time.
+The default is one.
+This delays closing the current connection until
+either this invocation of
+.i sendmail
+needs to connect to another host
+or it terminates.
+Setting it to zero defaults to the old behavior,
+that is, connections are closed immediately.
+.ip K\fItimeout\fP
+The maximum amount of time a cached connection will be permitted to idle
+without activity.
+If this time is exceeded,
+the connection is immediately closed.
+This value should be small (on the order of ten minutes).
+Before
+.i sendmail
+uses a cached connection,
+it always sends a NOOP (no operation) command
+to check the connection;
+if this fails, it reopens the connection.
+This keeps your end from failing if the other end times out.
+The point of this option is to be a good network neighbor
+and avoid using up excessive resources
+on the other end.
+The default is five minutes.
+.ip l
+If there is an
+.q Errors-To:
+header, send error messages to the addresses listed there.
+They normally go to the envelope sender.
+Use of this option causes
+.i sendmail
+to violate RFC 1123.
+.ip L\fIn\fP
+Set the default log level to
+.i n .
+Defaults to 9.
+.ip m
+Send to me too,
+even if I am in an alias expansion.
+.ip M\fIx\|value\fP
+Set the macro
+.i x
+to
+.i value .
+This is intended only for use from the command line.
+.ip n
+Validate the RHS of aliases when rebuilding the alias database.
+.ip o
+Assume that the headers may be in old format,
+i.e.,
+spaces delimit names.
+This actually turns on
+an adaptive algorithm:
+if any recipient address contains a comma, parenthesis,
+or angle bracket,
+it will be assumed that commas already exist.
+If this flag is not on,
+only commas delimit names.
+Headers are always output with commas between the names.
+.ip O\fIoptions\fP
+Set server SMTP options.
+The options are
+.i key=value
+pairs.
+Known keys are:
+.(b
+.ta 1i
+Port Name/number of listening port (defaults to "smtp")
+Addr Address mask (defaults INADDR_ANY)
+Family Address family (defaults to INET)
+Listen Size of listen queue (defaults to 10)
+.)b
+The
+.i Addr ess
+mask may be a numeric address in dot notation
+or a network name.
+.ip p\fI\|opt,opt,...\fP
+Set the privacy
+.i opt ions.
+``Privacy'' is really a misnomer;
+many of these are just a way of insisting on stricter adherence
+to the SMTP protocol.
+The
+.i opt ions
+can be selected from:
+.(b
+.ta \w'needvrfyhelo'u+3n
+public Allow open access
+needmailhelo Insist on HELO or EHLO command before MAIL
+needexpnhelo Insist on HELO or EHLO command before EXPN
+noexpn Disallow EXPN entirely
+needvrfyhelo Insist on HELO or EHLO command before VRFY
+novrfy Disallow VRFY entirely
+restrictmailq Restrict mailq command
+restrictqrun Restrict \-q command line flag
+noreceipts Ignore Return-Receipt-To: header
+goaway Disallow essentially all SMTP status queries
+authwarnings Put X-Authentication-Warning: headers in messages
+.)b
+The
+.q goaway
+pseudo-flag sets all flags except
+.q restrictmailq
+and
+.q restrictqrun .
+If mailq is restricted,
+only people in the same group as the queue directory
+can print the queue.
+If queue runs are restricted,
+only root and the owner of the queue directory
+can run the queue.
+Authentication Warnings add warnings about various conditions
+that may indicate attempts to spoof the mail system,
+such as using an non-standard queue directory.
+.ip P\fIpostmaster\fP
+If set,
+copies of error messages will be sent to the named
+.i postmaster .
+Only the header of the failed message is sent.
+Since most errors are user problems,
+this is probably not a good idea on large sites,
+and arguably contains all sorts of privacy violations,
+but it seems to be popular with certain operating systems vendors.
+.ip q\fIfactor\fP
+Use
+.i factor
+as the multiplier in the map function
+to decide when to just queue up jobs rather than run them.
+This value is divided by the difference between the current load average
+and the load average limit
+(\c
+.b x
+flag)
+to determine the maximum message priority
+that will be sent.
+Defaults to 600000.
+.ip Q\fIdir\fP
+Use the named
+.i dir
+as the queue directory.
+.ip r\|\fItimeouts\fP
+Timeout reads after
+.i time
+interval.
+The
+.i timeouts
+argument is a list of
+.i keyword=value
+pairs.
+The recognized timeouts and their default values, and their
+minimum values specified in RFC 1123 section 5.3.2 are:
+.(b
+.ta \w'datafinal'u+3n
+initial wait for initial greeting message [5m, 5m]
+helo reply to HELO or EHLO command [5m, none]
+mail reply to MAIL command [10m, 5m]
+rcpt reply to RCPT command [1h, 5m]
+datainit reply to DATA command [5m, 2m]
+datablock data block read [1h, 3m]
+datafinal reply to final ``.'' in data [1h, 10m]
+rset reply to RSET command [5m, none]
+quit reply to QUIT command [2m, none]
+misc reply to NOOP and VERB commands [2m, none]
+command command read [1h, 5m]
+ident IDENT protocol timeout [30s, none]
+.)b
+All but
+.q command
+apply to client SMTP.
+For back compatibility,
+a timeout with no ``keyword='' part
+will set all of the longer values.
+.ip R
+Normally,
+.i sendmail
+tries to eliminate any unnecessary explicit routes
+when sending an error message
+(as discussed in RFC 1123 \(sc 5.2.6).
+For example,
+when sending an error message to
+.(b
+<@known1,@known2,@unknown:user@known3>
+.)b
+.i sendmail
+will strip off the
+.q @known1
+in order to make the route as direct as possible.
+However, if the
+.b R
+option is set, this will be disabled,
+and the mail will be sent to the first address in the route,
+even if later addresses are known.
+This may be useful if you are caught behind a firewall.
+.ip s
+Be super-safe when running things,
+i.e.,
+always instantiate the queue file,
+even if you are going to attempt immediate delivery.
+.i Sendmail
+always instantiates the queue file
+before returning control the client
+under any circumstances.
+.ip S\fIfile\fP
+Log statistics in the named
+.i file .
+.ip t\fItzinfo\fP
+Set the local time zone info to
+.i tzinfo
+\*- for example,
+.q PST8PDT .
+Actually, if this is not set,
+the TZ environment variable is cleared (so the system default is used);
+if set but null, the user's TZ variable is used,
+and if set and non-null the TZ variable is set to this value.
+.ip T\fIrtime/wtime\fP
+Set the queue timeout to
+.i rtime .
+After this interval,
+messages that have not been successfully sent
+will be returned to the sender.
+Defaults to five days.
+The optional
+.i wtime
+is the time after which a warning message is sent.
+If it is missing or zero
+then no warning messages are sent.
+.ip u\fIn\fP
+Set the default userid for mailers to
+.i n .
+Mailers without the
+.i S
+flag in the mailer definition
+will run as this user.
+Defaults to 1.
+The value can also be given as a symbolic user name.
+.ip U\fIudbspec\fP
+The user database specification.
+.ip v
+Run in verbose mode.
+If this is set,
+.i sendmail
+adjusts options
+.b c
+(don't connect to expensive mailers)
+and
+.b d
+(delivery mode)
+so that all mail is delivered completely
+in a single job
+so that you can see the entire delivery process.
+Option
+.b v
+should
+.i never
+be set in the configuration file;
+it is intended for command line use only.
+.ip V\fIfallbackhost\fP
+If specified, the
+.i fallbackhost
+acts like a very low priority MX
+on every host.
+This is intended to be used by sites with poor network connectivity.
+.ip w
+If you are the
+.q best
+(that is, lowest preference)
+MX for a given host,
+you should normally detect this situation
+and treat that condition specially,
+by forwarding the mail to a UUCP feed,
+treating it as local,
+or whatever.
+However, in some cases (such as Internet firewalls)
+you may want to try to connect directly to that host
+as though it had no MX records at all.
+Setting this option causes
+.i sendmail
+to try this.
+The downside is that errors in your configuration
+are likely to be diagnosed as
+.q "host unknown"
+or
+.q "message timed out"
+instead of something more meaningful.
+This option is disrecommended.
+.ip x\fILA\fP
+When the system load average exceeds
+.i LA ,
+just queue messages
+(i.e., don't try to send them).
+Defaults to 8.
+.ip X\fILA\fP
+When the system load average exceeds
+.i LA ,
+refuse incoming SMTP connections.
+Defaults to 12.
+.ip y\fIfact\fP
+The indicated
+.i fact or
+is added to the priority (thus
+.i lowering
+the priority of the job)
+for each recipient,
+i.e., this value penalizes jobs with large numbers of recipients.
+Defaults to 30000.
+.ip Y
+If set,
+deliver each job that is run from the queue in a separate process.
+Use this option if you are short of memory,
+since the default tends to consume considerable amounts of memory
+while the queue is being processed.
+.ip z\fIfact\fP
+The indicated
+.i fact or
+is multiplied by the message class
+(determined by the Precedence: field in the user header
+and the
+.b P
+lines in the configuration file)
+and subtracted from the priority.
+Thus, messages with a higher Priority: will be favored.
+Defaults to 1800.
+.ip Z\fIfact\fP
+The
+.i fact or
+is added to the priority
+every time a job is processed.
+Thus,
+each time a job is processed,
+its priority will be decreased by the indicated value.
+In most environments this should be positive,
+since hosts that are down are all too often down for a long time.
+Defaults to 90000.
+.ip 7
+Strip input to seven bits for compatibility with old systems.
+This shouldn't be necessary.
+.lp
+All options can be specified on the command line using the
+\-o flag,
+but most will cause
+.i sendmail
+to relinquish its setuid permissions.
+The options that will not cause this are
+b, d, e, i, L, m, o, p, r, s, v, C, and 7.
+Also, M (define macro) when defining the r or s macros
+is also considered
+.q safe .
+.sh 3 "P \*- precedence definitions"
+.pp
+Values for the
+.q "Precedence:"
+field may be defined using the
+.b P
+control line.
+The syntax of this field is:
+.(b
+\fBP\fP\fIname\fP\fB=\fP\fInum\fP
+.)b
+When the
+.i name
+is found in a
+.q Precedence:
+field,
+the message class is set to
+.i num .
+Higher numbers mean higher precedence.
+Numbers less than zero
+have the special property
+that if an error occurs during processing
+the body of the message will not be returned;
+this is expected to be used for
+.q "bulk"
+mail such as through mailing lists.
+The default precedence is zero.
+For example,
+our list of precedences is:
+.(b
+Pfirst-class=0
+Pspecial-delivery=100
+Plist=\-30
+Pbulk=\-60
+Pjunk=\-100
+.)b
+People writing mailing list exploders
+are encouraged to use
+.q "Precedence: list" .
+Older versions of
+.i sendmail
+(which discarded all error returns for negative precedences)
+didn't recognize this name, giving it a default precedence of zero.
+This allows list maintainers to see error returns
+on both old and new versions of
+.i sendmail .
+.sh 3 "V \*- configuration version level"
+.pp
+To provide compatibility with old configuration files,
+the
+.b V
+line has been added to define some very basic semantics
+of the configuration file.
+These are not intended to be long term supports;
+rather, they describe compatibility features
+which will probably be removed in future releases.
+.pp
+.b N.B.:
+these version
+.i levels
+have nothing
+to do with the version
+.i number
+on the files.
+For example,
+as of this writing
+version 8 config files
+(specifically, 8.6)
+used version level 5 configurations.
+.pp
+.q Old
+configuration files are defined as version level one.
+Version level two files make the following changes:
+.np
+Host name canonification ($[ ... $])
+appends a dot if the name is recognized;
+this gives the config file a way of finding out if anything matched.
+(Actually, this just initializes the
+.q host
+map with the
+.q \-a.
+flag \*- you can reset it to anything you prefer
+by declaring the map explicitly.)
+.np
+Default host name extension is consistent throughout processing;
+version level one configurations turned off domain extension
+(that is, adding the local domain name)
+during certain points in processing.
+Version level two configurations are expected to include a trailing dot
+to indicate that the name is already canonical.
+.np
+Local names that are not aliases
+are passed through a new distinguished ruleset five;
+this can be used to append a local relay.
+This behaviour can be prevented by resolving the local name
+with an initial `@'.
+That is, something that resolves to a local mailer and a user name of
+.q vikki
+will be passed through ruleset five,
+but a user name of
+.q @vikki
+will have the `@' stripped,
+will not be passed through ruleset five,
+but will otherwise be treated the same as the prior example.
+The expectation is that this might be used to implement a policy
+where mail sent to
+.q vikki
+was handled by a central hub,
+but mail sent to
+.q vikki@localhost
+was delivered directly.
+.pp
+Version level three files
+allow # initiated comments on all lines.
+Exceptions are backslash escaped # marks
+and the $# syntax.
+.pp
+Version level four configurations
+are completely equivalent to level three
+for historical reasons.
+.pp
+Version level five configuration files
+change the default definition of
+.b $w
+to be just the first component of the hostname.
+.pp
+The
+.b V
+line may have an optional
+.b / \c
+.i vendor
+to indicate that this configuration file uses modifications
+specific to a particular vendor\**.
+.(f
+\**And of course, vendors are encouraged to add themselves
+to the list of recognized vendors by editing the routine
+.i setvendor
+in
+.i conf.c .
+.)f
+.sh 3 "K \*- key file declaration"
+.pp
+Special maps can be defined using the line:
+.(b
+Kmapname mapclass arguments
+.)b
+The
+.i mapname
+is the handle by which this map is referenced in the rewriting rules.
+The
+.i mapclass
+is the name of a type of map;
+these are compiled in to
+.i sendmail .
+The
+.i arguments
+are interpreted depending on the class;
+typically,
+there would be a single argument naming the file containing the map.
+.pp
+Maps are referenced using the syntax:
+.(b
+$( \fImap\fP \fIkey\fP $@ \fIarguments\fP $: \fIdefault\fP $)
+.)b
+where either or both of the
+.i arguments
+or
+.i default
+portion may be omitted.
+The
+.i arguments
+may appear more than once.
+The indicated
+.i key
+and
+.i arguments
+are passed to the appropriate mapping function.
+If it returns a value, it replaces the input.
+If it does not return a value and the
+.i default
+is specified, the
+.i default
+replaces the input.
+Otherwise, the input is unchanged.
+.pp
+During replacement of either a map value or default
+the string
+.q %\fIn\fP
+(where
+.i n
+is a digit)
+is replaced by the corresponding
+.i argument .
+Argument zero
+is always the database key.
+For example, the rule
+.(b
+.ta 1.5i
+R$- ! $+ $: $(uucp $1 $@ $2 $: %1 @ %0 . UUCP $)
+.)b
+Looks up the UUCP name in a (user defined) UUCP map;
+if not found it turns it into
+.q \&.UUCP
+form.
+The database might contain records like:
+.(b
+decvax %1@%0.DEC.COM
+research %1@%0.ATT.COM
+.)b
+.pp
+The built in map with both name and class
+.q host
+is the host name canonicalization lookup.
+Thus,
+the syntax:
+.(b
+$(host \fIhostname\fP$)
+.)b
+is equivalent to:
+.(b
+$[\fIhostname\fP$]
+.)b
+.pp
+There are four predefined database lookup classes:
+.q dbm ,
+.q btree ,
+.q hash ,
+and
+.q nis .
+The first requires that
+.i sendmail
+be compiled with the
+.b ndbm
+library;
+the second two require the
+.b db
+library,
+and the third requires that
+.i sendmail
+be compiled with NIS support.
+All four accept as arguments the same optional flags
+and a filename
+(or a mapname for NIS;
+the filename is the root of the database path,
+so that
+.q .db
+or some other extension appropriate for the database type
+will be added to get the actual database name).
+Known flags are:
+.ip "\-o"
+Indicates that this map is optional \*- that is,
+if it cannot be opened,
+no error is produced,
+and
+.i sendmail
+will behave as if the map existed but was empty.
+.ip "\-N"
+Normally when maps are written,
+the trailing null byte is not included as part of the key.
+If this flag is indicated it will be included.
+During lookups, only the null-byte-included form will be searched.
+See also
+.b \-O.
+.ip "\-O"
+If neither
+.b \-N
+or
+.b \-O
+are specified,
+.i sendmail
+uses an adaptive algorithm to decide whether or not to look for null bytes
+on the end of keys.
+It starts by trying both;
+if it finds any key with a null byte it never tries again without a null byte
+and vice versa.
+If this flag is specified,
+it never tries with a null byte;
+this can speed matches but is never necessary.
+If both
+.b \-N
+and
+.b \-O
+are specified,
+.i sendmail
+will never try any matches at all \(em
+that is, everything will appear to fail.
+.ip "\-a\fIx\fP"
+Append the string
+.i x
+on successful matches.
+For example, the default
+.i host
+map appends a dot on successful matches.
+.ip "\-f"
+Do not fold upper to lower case before looking up the key.
+.ip "\-m"
+Match only (without replacing the value).
+If you only care about the existence of a key and not the value
+(as you might when searching the NIS map
+.q hosts.byname
+for example),
+this flag prevents the map from substituting the value.
+However,
+The \-a argument is still appended on a match,
+and the default is still taken if the match fails.
+.pp
+The
+.i dbm
+map appends the strings
+.q \&.pag
+and
+.q \&.dir
+to the given filename;
+the two
+.i db -based
+maps append
+.q \&.db .
+For example, the map specification
+.(b
+Kuucp dbm \-o \-N /usr/lib/uucpmap
+.)b
+specifies an optional map named
+.q uucp
+of class
+.q dbm ;
+it always has null bytes at the end of every string,
+and the data is located in
+/usr/lib/uucpmap.{dir,pag}.
+.pp
+The program
+.i makemap (8)
+can be used to build any of the three database-oriented maps.
+It takes the following flags:
+.ip \-f
+Fold upper to lower case in the map.
+.ip \-N
+Include null bytes in keys.
+.ip \-o
+Append to an existing (old) file.
+.ip \-r
+Allow replacement of existing keys;
+normally, re-inserting an existing key is an error.
+.ip \-v
+Print what is happening.
+.lp
+The
+.i sendmail
+daemon does not have to be restarted to read the new maps
+as long as you change them in place;
+file locking is used so that the maps won't be read
+while they are being updated.\**
+.(f
+\**That is, don't create new maps and then use
+.i mv (1)
+to move them into place.
+I consider this a shortfall (a.k.a. bug) in
+.i sendmail
+which should be fixed in a future release.
+.)f
+.pp
+There are also two builtin maps that are,
+strictly speaking,
+not database lookups.
+.pp
+The
+.q host
+map does host domain canonification;
+given a host name it calls the name server
+to find the canonical name for that host.
+.pp
+The
+.q dequote
+map strips double quotes (") from a name.
+It does not strip backslashes.
+It will not strip quotes if the resulting string
+would contain unscannable syntax
+(that is, basic errors like unbalanced angle brackets;
+more sophisticated errors such as unknown hosts are not checked).
+The intent is for use when trying to accept mail from systems such as
+DECnet
+that routinely quote odd syntax such as
+.(b
+"49ers::ubell"
+.)b
+A typical usage is probably something like:
+.(b
+Kdequote dequote
+
+\&...
+
+R$\- $: $(dequote $1 $)
+R$\- $+ $: $>3 $1 $2
+.)b
+Care must be taken to prevent unexpected results;
+for example,
+.(b
+"|someprogram < input > output"
+.)b
+will have quotes stripped,
+but the result is probably not what you had in mind.
+Fortunately these cases are rare.
+.pp
+New classes can be added in the routine
+.b setupmaps
+in file
+.b conf.c .
+.sh 2 "Building a Configuration File From Scratch"
+.pp
+Building a configuration table from scratch is an extremely difficult job.
+Fortunately,
+it is almost never necessary to do so;
+nearly every situation that may come up
+may be resolved by changing an existing table.
+In any case,
+it is critical that you understand what it is that you are trying to do
+and come up with a philosophy for the configuration table.
+This section is intended to explain what the real purpose
+of a configuration table is
+and to give you some ideas
+for what your philosophy might be.
+.pp
+.b "Do not even consider"
+writing your own configuration file
+without carefully studying
+RFC 821, 822, and 1123.
+You should also read RFC 976
+if you are doing UUCP exchange.
+.sh 3 "What you are trying to do"
+.pp
+The configuration table has three major purposes.
+The first and simplest
+is to set up the environment for
+.i sendmail .
+This involves setting the options,
+defining a few critical macros,
+etc.
+Since these are described in other places,
+we will not go into more detail here.
+.pp
+The second purpose is to rewrite addresses in the message.
+This should typically be done in two phases.
+The first phase maps addresses in any format
+into a canonical form.
+This should be done in ruleset three.
+The second phase maps this canonical form
+into the syntax appropriate for the receiving mailer.
+.i Sendmail
+does this in three subphases.
+Rulesets one and two
+are applied to all sender and recipient addresses respectively.
+After this,
+you may specify per-mailer rulesets
+for both sender and recipient addresses;
+this allows mailer-specific customization.
+Finally,
+ruleset four is applied to do any default conversion
+to external form.
+.pp
+The third purpose
+is to map addresses into the actual set of instructions
+necessary to get the message delivered.
+Ruleset zero must resolve to the internal form,
+which is in turn used as a pointer to a mailer descriptor.
+The mailer descriptor describes the interface requirements
+of the mailer.
+.sh 3 "Philosophy"
+.pp
+The particular philosophy you choose will depend heavily
+on the size and structure of your organization.
+I will present a few possible philosophies here.
+There are as many philosophies as there are config designers;
+feel free to develop your own.
+.pp
+One general point applies to all of these philosophies:
+it is almost always a mistake
+to try to do full host route resolution.
+For example,
+if you are on a UUCP-only site
+and you are trying to get names of the form
+.q user@host
+to the Internet,
+it does not pay to route them to
+.q xyzvax!decvax!ucbvax!c70!user@host
+since you then depend on several links not under your control,
+some of which are likely to misparse it anyway.
+The best approach to this problem
+is to simply forward the message for
+.q user@host
+to
+.q xyzvax
+and let xyzvax
+worry about it from there.
+In summary,
+just get the message closer to the destination,
+rather than determining the full path.
+.sh 4 "Large site, many hosts \*- minimum information"
+.pp
+Berkeley is an example of a large site,
+i.e., more than two or three hosts
+and multiple mail connections.
+We have decided that the only reasonable philosophy
+in our environment
+is to designate one host as the guru for our site.
+It must be able to resolve any piece of mail it receives.
+The other sites should have the minimum amount of information
+they can get away with.
+In addition,
+any information they do have
+should be hints rather than solid information.
+.pp
+For example,
+a typical site on our local ether network is
+.q monet
+(actually
+.q monet.CS.Berkeley.EDU ).
+When monet receives mail for delivery,
+it checks whether it knows
+that the destination host is directly reachable;
+if so, mail is sent to that host.
+If it receives mail for any unknown host,
+it just passes it directly to
+.q ucbvax.CS.Berkeley.EDU ,
+our master host.
+Ucbvax may determine that the host name is illegal
+and reject the message,
+or may be able to do delivery.
+However, it is important to note that when a new mail connection is added,
+the only host that
+.i must
+have its tables updated
+is ucbvax;
+the others
+.i may
+be updated if convenient,
+but this is not critical.
+.pp
+This picture is slightly muddied
+due to network connections that are not actually located
+on ucbvax.
+For example,
+some UUCP connections are currently on
+.q ucbarpa.
+However,
+monet
+.i "does not"
+know about this;
+the information is hidden totally between ucbvax and ucbarpa.
+Mail going from monet to a UUCP host
+is transferred via the ethernet
+from monet to ucbvax,
+then via the ethernet from ucbvax to ucbarpa,
+and then is submitted to UUCP.
+Although this involves some extra hops,
+we feel this is an acceptable tradeoff.
+.pp
+An interesting point is that it would be possible
+to update monet
+to send appropriate UUCP mail directly to ucbarpa
+if the load got too high;
+if monet failed to note a host as connected to ucbarpa
+it would go via ucbvax as before,
+and if monet incorrectly sent a message to ucbarpa
+it would still be sent by ucbarpa
+to ucbvax as before.
+The only problem that can occur is loops,
+for example,
+if ucbarpa thought that ucbvax had the UUCP connection
+and vice versa.
+For this reason,
+updates should
+.i always
+happen to the master host first.
+.pp
+This philosophy results as much from the need
+to have a single source for the configuration files
+(typically built using
+.i m4 \|(1)
+or some similar tool)
+as any logical need.
+Maintaining more than three separate tables by hand
+is essentially an impossible job.
+.sh 4 "Small site \*- complete information"
+.pp
+A small site
+(two or three hosts and few external connections)
+may find it more reasonable to have complete information
+at each host.
+This would require that each host
+know exactly where each network connection is,
+possibly including the names of each host on that network.
+As long as the site remains small
+and the configuration remains relatively static,
+the update problem will probably not be too great.
+.sh 4 "Single host"
+.pp
+This is in some sense the trivial case.
+The only major issue is trying to insure that you don't
+have to know too much about your environment.
+For example,
+if you have a UUCP connection
+you might find it useful to know about the names of hosts
+connected directly to you,
+but this is really not necessary
+since this may be determined from the syntax.
+.sh 4 "A completely different philosophy"
+.pp
+This is adapted from Bruce Lilly.
+Any errors in interpretation are mine.
+.pp
+Do minimal changes in ruleset 3:
+fix some common but unambiguous errors (e.g. trailing dot on domains) and
+hide bang paths foo!bar into bar@foo.UUCP.
+The resulting "canonical" form is any valid RFC822/RFC1123/RFC976 address.
+.pp
+Ruleset 0 does the bulk of the work.
+It removes the trailing "@.UUCP" that hides bang paths,
+strips anything not needed to resolve,
+e.g. the phrase from phrase <route-addr> and from named groups,
+rejects unparseable addresses using $#error,
+and finally
+resolves to a mailer/host/user triple.
+Ruleset 0 is rather lengthy
+as it has to handle 3 basic address forms:
+RFC976 bang paths,
+RFC1123 %-hacks
+(including vanilla RFC822 local-part@domain),
+and RFC822 source routes.
+It's also complicated by having to handle named lists.
+.pp
+The header rewriting rulesets 1 and 2
+remove the trailing "@.UUCP" that hides bang paths.
+Ruleset 2 also strips the $# mailer $@ host (for test mode).
+.pp
+Ruleset 4 does absolutely nothing.
+.pp
+The per-mailer rewriting rulesets conform the envelope and
+header addresses to the requirements of the specific
+mailer.
+.pp
+Lots of rulesets-as-subroutines are used.
+.pp
+As a result, header addresses are subject to minimal munging
+(per RFC1123), and the general plan is per RFC822 sect. 3.4.10.
+.sh 3 "Relevant issues"
+.pp
+The canonical form you use
+should almost certainly be as specified in
+the Internet protocols
+RFC819 and RFC822.
+Copies of these RFC's are included on the
+.i sendmail
+tape
+as
+.i doc/rfc819.lpr
+and
+.i doc/rfc822.lpr .
+.pp
+RFC822
+describes the format of the mail message itself.
+.i Sendmail
+follows this RFC closely,
+to the extent that many of the standards described in this document
+can not be changed without changing the code.
+In particular,
+the following characters have special interpretations:
+.(b
+< > ( ) " \e
+.)b
+Any attempt to use these characters for other than their RFC822
+purpose in addresses is probably doomed to disaster.
+.pp
+RFC819
+describes the specifics of the domain-based addressing.
+This is touched on in RFC822 as well.
+Essentially each host is given a name
+which is a right-to-left dot qualified pseudo-path
+from a distinguished root.
+The elements of the path need not be physical hosts;
+the domain is logical rather than physical.
+For example,
+at Berkeley
+one legal host might be
+.q a.CC.Berkeley.EDU ;
+reading from right to left,
+.q EDU
+is a top level domain
+comprising educational institutions,
+.q Berkeley
+is a logical domain name,
+.q CC
+represents the Computer Center,
+(in this case a strictly logical entity),
+and
+.q a
+is a host in the Computer Center.
+.pp
+Beware when reading RFC819
+that there are a number of errors in it.
+.sh 3 "How to proceed"
+.pp
+Once you have decided on a philosophy,
+it is worth examining the available configuration tables
+to decide if any of them are close enough
+to steal major parts of.
+Even under the worst of conditions,
+there is a fair amount of boiler plate that can be collected safely.
+.pp
+The next step is to build ruleset three.
+This will be the hardest part of the job.
+Beware of doing too much to the address in this ruleset,
+since anything you do will reflect through
+to the message.
+In particular,
+stripping of local domains is best deferred,
+since this can leave you with addresses with no domain spec at all.
+Since
+.i sendmail
+likes to append the sending domain to addresses with no domain,
+this can change the semantics of addresses.
+Also try to avoid
+fully qualifying domains in this ruleset.
+Although technically legal,
+this can lead to unpleasantly and unnecessarily long addresses
+reflected into messages.
+The Berkeley configuration files
+define ruleset nine
+to qualify domain names and strip local domains.
+This is called from ruleset zero
+to get all addresses into a cleaner form.
+.pp
+Once you have ruleset three finished,
+the other rulesets should be relatively trivial.
+If you need hints,
+examine the supplied configuration tables.
+.sh 3 "Testing the rewriting rules \*- the \-bt flag"
+.pp
+When you build a configuration table,
+you can do a certain amount of testing
+using the
+.q "test mode"
+of
+.i sendmail .
+For example,
+you could invoke
+.i sendmail
+as:
+.(b
+sendmail \-bt \-Ctest.cf
+.)b
+which would read the configuration file
+.q test.cf
+and enter test mode.
+In this mode,
+you enter lines of the form:
+.(b
+rwset address
+.)b
+where
+.i rwset
+is the rewriting set you want to use
+and
+.i address
+is an address to apply the set to.
+Test mode shows you the steps it takes
+as it proceeds,
+finally showing you the address it ends up with.
+You may use a comma separated list of rwsets
+for sequential application of rules to an input.
+For example:
+.(b
+3,1,21,4 monet:bollard
+.)b
+first applies ruleset three to the input
+.q monet:bollard.
+Ruleset one is then applied to the output of ruleset three,
+followed similarly by rulesets twenty-one and four.
+.pp
+If you need more detail,
+you can also use the
+.q \-d21
+flag to turn on more debugging.
+For example,
+.(b
+sendmail \-bt \-d21.99
+.)b
+turns on an incredible amount of information;
+a single word address
+is probably going to print out several pages worth of information.
+.pp
+You should be warned that internally,
+.i sendmail
+applies ruleset 3 to all addresses.
+In this version of
+.i sendmail ,
+you will have to do that manually.
+For example, older versions allowed you to use
+.(b
+0 bruce@broadcast.sony.com
+.)b
+This version requires that you use:
+.(b
+3,0 bruce@broadcast.sony.com
+.)b
+.sh 3 "Building mailer descriptions"
+.pp
+To add an outgoing mailer to your mail system,
+you will have to define the characteristics of the mailer.
+.pp
+Each mailer must have an internal name.
+This can be arbitrary,
+except that the names
+.q local
+and
+.q prog
+must be defined.
+.pp
+The pathname of the mailer must be given in the P field.
+If this mailer should be accessed via an IPC connection,
+use the string
+.q [IPC]
+instead.
+.pp
+The F field defines the mailer flags.
+You should specify an
+.q f
+or
+.q r
+flag to pass the name of the sender as a
+.b \-f
+or
+.b \-r
+flag respectively.
+These flags are only passed if they were passed to
+.i sendmail ,
+so that mailers that give errors under some circumstances
+can be placated.
+If the mailer is not picky
+you can just specify
+.q "\-f $g"
+in the argv template.
+If the mailer must be called as
+.b root
+the
+.q S
+flag should be given;
+this will not reset the userid
+before calling the mailer\**.
+.(f
+\**\c
+.i Sendmail
+must be running setuid to root
+for this to work.
+.)f
+If this mailer is local
+(i.e., will perform final delivery
+rather than another network hop)
+the
+.q l
+flag should be given.
+Quote characters
+(backslashes and " marks)
+can be stripped from addresses if the
+.q s
+flag is specified;
+if this is not given
+they are passed through.
+If the mailer is capable of sending to more than one user
+on the same host
+in a single transaction
+the
+.q m
+flag should be stated.
+If this flag is on,
+then the argv template containing
+.b $u
+will be repeated for each unique user
+on a given host.
+The
+.q e
+flag will mark the mailer as being
+.q expensive,
+which will cause
+.i sendmail
+to defer connection
+until a queue run\**.
+.(f
+\**The
+.q c
+configuration option must be given
+for this to be effective.
+.)f
+.pp
+An unusual case is the
+.q C
+flag.
+This flag applies to the mailer that the message is received from,
+rather than the mailer being sent to;
+if set,
+the domain spec of the sender
+(i.e., the
+.q @host.domain
+part)
+is saved
+and is appended to any addresses in the message
+that do not already contain a domain spec.
+For example,
+a message of the form:
+.(b
+From: eric@vangogh.CS.Berkeley.EDU
+To: wnj@monet.CS.Berkeley.EDU, mckusick
+.)b
+will be modified to:
+.(b
+From: eric@vangogh.CS.Berkeley.EDU
+To: wnj@monet.CS.Berkeley.EDU, mckusick@vangogh.CS.Berkeley.EDU
+.)b
+.i "if and only if"
+the
+.q C
+flag is defined in the mailer resolved to
+by running
+.q eric@vangogh.CS.Berkeley.EDU
+through rulesets 3 and 0.
+.pp
+Other flags are described
+in Appendix C.
+.pp
+The S and R fields in the mailer description
+are per-mailer rewriting sets
+to be applied to sender and recipient addresses
+respectively.
+These are applied after the sending domain is appended
+and the general rewriting sets
+(numbers one and two)
+are applied,
+but before the output rewrite
+(ruleset four)
+is applied.
+A typical use is to append the current domain
+to addresses that do not already have a domain.
+For example,
+a header of the form:
+.(b
+From: eric
+.)b
+might be changed to be:
+.(b
+From: eric@vangogh.CS.Berkeley.EDU
+.)b
+or
+.(b
+From: ucbvax!eric
+.)b
+depending on the domain it is being shipped into.
+These sets can also be used
+to do special purpose output rewriting
+in cooperation with ruleset four.
+.pp
+The S and R fields
+can be specified as two numbers separated by a slash
+(e.g.,
+.q "S=10/11" ),
+meaning that all envelope addresses will be processed through ruleset 10
+and all header addresses will be processed through ruleset 11.
+With only one number specified,
+both envelope and header rewriting sets are set to the indicated ruleset.
+.pp
+The E field defines the string to use
+as an end-of-line indication.
+A string containing only newline is the default.
+The usual backslash escapes
+(\er, \en, \ef, \eb)
+may be used.
+.pp
+Finally,
+an argv template is given as the A field.
+It may have embedded spaces.
+If there is no argv with a
+.b $u
+macro in it,
+.i sendmail
+will speak SMTP
+to the mailer.
+If the pathname for this mailer is
+.q [IPC],
+the argv should be
+.(b
+IPC $h [ \fIport\fP ]
+.)b
+where
+.i port
+is the optional port number
+to connect to.
+.pp
+For example,
+the specifications:
+.(b
+.ta \w'Mlocal, 'u +\w'P=/bin/mail, 'u +\w'F=rlsm, 'u +\w'S=10, 'u +\w'R=20, 'u
+Mlocal, P=/bin/mail, F=rlsm S=10, R=20, A=mail \-d $u
+Mether, P=[IPC], F=meC, S=11, R=21, A=IPC $h, M=100000
+.)b
+specifies a mailer to do local delivery
+and a mailer for ethernet delivery.
+The first is called
+.q local,
+is located in the file
+.q /bin/mail,
+takes a picky
+.b \-r
+flag,
+does local delivery,
+quotes should be stripped from addresses,
+and multiple users can be delivered at once;
+ruleset ten
+should be applied to sender addresses in the message
+and ruleset twenty
+should be applied to recipient addresses;
+the argv to send to a message will be the word
+.q mail,
+the word
+.q \-d,
+and words containing the name of the receiving user.
+If a
+.b \-r
+flag is inserted
+it will be between the words
+.q mail
+and
+.q \-d.
+The second mailer is called
+.q ether,
+it should be connected to via an IPC connection,
+it can handle multiple users at once,
+connections should be deferred,
+and any domain from the sender address
+should be appended to any receiver name
+without a domain;
+sender addresses should be processed by ruleset eleven
+and recipient addresses by ruleset twenty-one.
+There is a 100,000 byte limit on messages passed through this mailer.
+.sh 2 "The User Database"
+.pp
+If you have a version of
+.i sendmail
+with the user database package
+compiled in,
+the handling of sender and recipient addresses
+is modified.
+.pp
+The location of this database is controlled with the
+.b U
+option.
+.sh 3 "Structure of the user database"
+.pp
+The database is a sorted (BTree-based) structure.
+User records are stored with the key:
+.(b
+\fIuser-name\fP\fB:\fP\fIfield-name\fP
+.)b
+The sorted database format ensures that user records are clustered together.
+Meta-information is always stored with a leading colon.
+.pp
+Field names define both the syntax and semantics of the value.
+Defined fields include:
+.nr ii 1i
+.ip maildrop
+The delivery address for this user.
+There may be multiple values of this record.
+In particular,
+mailing lists will have one
+.i maildrop
+record for each user on the list.
+.ip "mailname"
+The outgoing mailname for this user.
+For each outgoing name,
+there should be an appropriate
+.i maildrop
+record for that name to allow return mail.
+See also
+.i :default:mailname .
+.ip mailsender
+Changes any mail sent to this address to have the indicated envelope sender.
+This is intended for mailing lists,
+and will normally be the name of an appropriate -request address.
+It is very similar to the owner-\c
+.i list
+syntax in the alias file.
+.ip fullname
+The full name of the user.
+.ip office-address
+The office address for this user.
+.ip office-phone
+The office phone number for this user.
+.ip office-fax
+The office FAX number for this user.
+.ip home-address
+The home address for this user.
+.ip home-phone
+The home phone number for this user.
+.ip home-fax
+The home FAX number for this user.
+.ip project
+A (short) description of the project this person is affiliated with.
+In the University this is often just the name of their graduate advisor.
+.ip plan
+A pointer to a file from which plan information can be gathered.
+.pp
+As of this writing,
+only a few of these fields are actually being used by
+.i sendmail :
+.i maildrop
+and
+.i mailname .
+A
+.i finger
+program that uses the other fields is planned.
+.sh 3 "User database semantics"
+.pp
+When the rewriting rules submit an address to the local mailer,
+the user name is passed through the alias file.
+If no alias is found (or if the alias points back to the same address),
+the name (with
+.q :maildrop
+appended)
+is then used as a key in the user database.
+If no match occurs (or if the maildrop points at the same address),
+forwarding is tried.
+.pp
+If the first token of the user name returned by ruleset 0
+is an
+.q @
+sign, the user database lookup is skipped.
+The intent is that the user database will act as a set of defaults
+for a cluster (in our case, the Computer Science Division);
+mail sent to a specific machine should ignore these defaults.
+.pp
+When mail is sent,
+the name of the sending user is looked up in the database.
+If that user has a
+.q mailname
+record,
+the value of that record is used as their outgoing name.
+For example, I might have a record:
+.(b
+eric:mailname Eric.Allman@CS.Berkeley.EDU
+.)b
+This would cause my outgoing mail to be sent as Eric.Allman.
+.pp
+If a
+.q maildrop
+is found for the user,
+but no corresponding
+.q mailname
+record exists,
+the record
+.q :default:mailname
+is consulted.
+If present, this is the name of a host to override the local host.
+For example, in our case we would set it to
+.q CS.Berkeley.EDU .
+The effect is that anyone known in the database
+gets their outgoing mail stamped as
+.q user@CS.Berkeley.EDU ,
+but people not listed in the database use the local hostname.
+.sh 3 "Creating the database\**"
+.(f
+\**These instructions are known to be incomplete.
+A future version of the user database is planned
+including things such as finger service \*- and good documentation.
+.)f
+.pp
+The user database is built from a text file
+using the
+.i makemap
+utility
+(in the distribution in the makemap subdirectory).
+The text file is a series of lines corresponding to userdb records;
+each line has a key and a value separated by white space.
+The key is always in the format described above \*-
+for example:
+.(b
+eric:maildrop
+.)b
+This file is normally installed in a system directory;
+for example, it might be called
+.i /etc/userdb .
+To make the database version of the map, run the program:
+.(b
+makemap btree /etc/userdb.db < /etc/userdb
+.)b
+Then create a config file that uses this.
+For example, using the V8 M4 configuration, include the
+following line in your .mc file:
+.(b
+define(\`confUSERDB_SPEC\', /etc/userdb.db)
+.)b
+.sh 1 "OTHER CONFIGURATION"
+.pp
+There are some configuration changes that can be made by
+recompiling
+.i sendmail .
+This section describes what changes can be made
+and what has to be modified to make them.
+.sh 2 "Parameters in src/Makefile"
+.pp
+These parameters are intended to describe the compilation environment,
+not site policy,
+and should normally be defined in src/Makefile.
+.ip NDBM
+If set,
+the new version of the DBM library
+that allows multiple databases will be used.
+If neither NDBM nor NEWDB are set,
+a much less efficient method of alias lookup is used.
+.ip NEWDB
+If set, use the new database package from Berkeley (from 4.4BSD).
+This package is substantially faster than DBM or NDBM.
+If NEWDB and NDBM are both set,
+.i sendmail
+will read DBM files,
+but will create and use NEWDB files.
+.ip NIS
+Include support for NIS.
+If set together with
+.i both
+NEWDB and NDBM,
+.i sendmail
+will create both DBM and NEWDB files if and only if
+the file /var/yp/Makefile
+exists and is readable.
+This is intended for compatibility with Sun Microsystems'
+.i mkalias
+program used on YP masters.
+.ip SYSTEM5
+Set all of the compilation parameters appropriate for System V.
+.ip LOCKF
+Use System V
+.b lockf
+instead of Berkeley
+.b flock .
+Due to the highly unusual semantics of locks
+across forks in
+.b lockf ,
+this should never be used unless absolutely necessary.
+Set by default if
+SYSTEM5 is set.
+.ip SYS5TZ
+Use System V
+time zone semantics.
+.ip HASINITGROUPS
+Set this if your system has the
+.i initgroups()
+call
+(if you have multiple group support).
+This is the default if SYSTEM5 is
+.i not
+defined or if you are on HPUX.
+.ip HASUNAME
+Set this if you have the
+.i uname (2)
+system call (or corresponding library routine).
+Set by default if
+SYSTEM5
+is set.
+.ip HASSTATFS
+Set this if you have the
+.i statfs (2)
+system call.
+This will allow you to give a temporary failure
+message to incoming SMTP email
+when you are low on disk space.
+It is set by default on 4.4BSD and OSF/1 systems.
+.ip HASUSTAT
+Set if you have the
+.i ustat (2)
+system call.
+This is an alternative implementation of disk space control.
+You should only set one of HASSTATFS or HASUSTAT;
+the first is preferred.
+.ip _PATH_SENDMAILCF
+The pathname of the sendmail.cf file.
+.ip _PATH_SENDMAILPID
+The pathname of the sendmail.pid file.
+.ip LA_TYPE
+The load average type.
+Details are described below.
+.lp
+The are several built-in ways of computing the load average.
+.i Sendmail
+tries to auto-configure them based on imperfect guesses;
+you can select one using the
+.i cc
+option
+.b \-DLA_TYPE= \c
+.i type ,
+where
+.i type
+is:
+.ip LA_INT
+The kernel stores the load average in the kernel as an array of long integers.
+The actual values are scaled by a factor FSCALE
+(default 256).
+.ip LA_SHORT
+The kernel stores the load average in the kernel as an array of short integers.
+The actual values are scaled by a factor FSCALE
+(default 256).
+.ip LA_FLOAT
+The kernel stores the load average in the kernel as an array of
+double precision floats.
+.ip LA_MACH
+Use MACH-style load averages.
+.ip LA_SUBR
+Call the
+.i getloadavg
+routine to get the load average as an array of doubles.
+.ip LA_ZERO
+Always return zero as the load average.
+This is the fallback case.
+.lp
+If type
+.sm LA_INT ,
+.sm LA_SHORT ,
+or
+.sm LA_FLOAT
+is specified,
+you may also need to specify
+.sm _PATH_UNIX
+(the path to your system binary)
+and
+.sm LA_AVENRUN
+(the name of the variable containing the load average in the kernel;
+usually
+.q _avenrun
+or
+.q avenrun ).
+.pp
+There are also several compilation flags to indicate the environment
+such as
+.q _AIX3
+and
+.q _SCO_unix_ .
+See the READ_ME
+file for the latest scoop on these flags.
+.sh 2 "Parameters in src/conf.h"
+.pp
+Parameters and compilation options
+are defined in conf.h.
+Most of these need not normally be tweaked;
+common parameters are all in sendmail.cf.
+However, the sizes of certain primitive vectors, etc.,
+are included in this file.
+The numbers following the parameters
+are their default value.
+.nr ii 1.2i
+.ip "MAXLINE [1024]"
+The maximum line length of any input line.
+If message lines exceed this length
+they will still be processed correctly;
+however, header lines,
+configuration file lines,
+alias lines,
+etc.,
+must fit within this limit.
+.ip "MAXNAME [256]"
+The maximum length of any name,
+such as a host or a user name.
+.ip "MAXPV [40]"
+The maximum number of parameters to any mailer.
+This limits the number of recipients that may be passed in one transaction.
+It can be set to any arbitrary number above about 10,
+since
+.i sendmail
+will break up a delivery into smaller batches as needed.
+A higher number may reduce load on your system, however.
+.ip "MAXATOM [100]"
+The maximum number of atoms
+(tokens)
+in a single address.
+For example,
+the address
+.q "eric@CS.Berkeley.EDU"
+is seven atoms.
+.ip "MAXMAILERS [25]"
+The maximum number of mailers that may be defined
+in the configuration file.
+.ip "MAXRWSETS [100]"
+The maximum number of rewriting sets
+that may be defined.
+.ip "MAXPRIORITIES [25]"
+The maximum number of values for the
+.q Precedence:
+field that may be defined
+(using the
+.b P
+line in sendmail.cf).
+.ip "MAXUSERENVIRON [40]"
+The maximum number of items in the user environment
+that will be passed to subordinate mailers.
+.ip "QUEUESIZE [1000]"
+The maximum number of entries that will be processed
+in a single queue run.
+.ip "MAXMXHOSTS [20]"
+The maximum number of MX records we will accept for any single host.
+.lp
+A number of other compilation options exist.
+These specify whether or not specific code should be compiled in.
+.nr ii 1.2i
+.ip DEBUG
+If set, debugging information is compiled in.
+To actually get the debugging output,
+the
+.b \-d
+flag must be used.
+.b "WE STRONGLY RECOMMEND THAT THIS BE LEFT ON."
+Some people, believing that it was a security hole
+(it was, once)
+have turned it off and thus crippled debuggers.
+.ip NETINET
+If set,
+support for Internet protocol networking is compiled in.
+Previous versions of
+.i sendmail
+referred to this as
+.sm DAEMON ;
+this old usage is now incorrect.
+.ip NETISO
+If set,
+support for ISO protocol networking is compiled in
+(it may be appropriate to #define this in the Makefile instead of conf.h).
+.ip LOG
+If set,
+the
+.i syslog
+routine in use at some sites is used.
+This makes an informational log record
+for each message processed,
+and makes a higher priority log record
+for internal system errors.
+.ip MATCHGECOS
+Compile in the code to do ``fuzzy matching'' on the GECOS field
+in /etc/passwd.
+This also requires that option G be turned on.
+.ip NAMED_BIND
+Compile in code to use the
+Berkeley Internet Name Domain (BIND) server
+to resolve TCP/IP host names.
+.ip NOTUNIX
+If you are using a non-UNIX mail format,
+you can set this flag to turn off special processing
+of UNIX-style
+.q "From "
+lines.
+.ip QUEUE
+This flag should be set to compile in the queueing code.
+If this is not set,
+mailers must accept the mail immediately
+or it will be returned to the sender.
+.ip SETPROCTITLE
+If defined,
+.i sendmail
+will change its
+.i argv
+array to indicate its current status.
+This can be used in conjunction with the
+.i ps
+command to find out just what it's up to.
+.ip SMTP
+If set,
+the code to handle user and server SMTP will be compiled in.
+This is only necessary if your machine has some mailer
+that speaks SMTP
+(this means most machines everywhere).
+.ip UGLYUUCP
+If you have a UUCP host adjacent to you which is not running
+a reasonable version of
+.i rmail ,
+you will have to set this flag to include the
+.q "remote from sysname"
+info on the from line.
+Otherwise, UUCP gets confused about where the mail came from.
+.ip USERDB
+Include the
+.b experimental
+Berkeley user information database package.
+This adds a new level of local name expansion
+between aliasing and forwarding.
+It also uses the NEWDB package.
+This may change in future releases.
+.ip IDENTPROTO
+Compile in the IDENT protocol as defined in RFC 1413.
+This defaults on for all systems except Ultrix,
+which apparently has the interesting
+.q feature
+that when it receives a
+.q "host unreachable"
+message it closes all open connections to that host.
+Since some firewall gateways send this error code
+when you access an unauthorized port (such as 113, used by IDENT),
+Ultrix cannot receive email from such hosts.
+.sh 2 "Configuration in src/conf.c"
+.pp
+The following changes can be made in conf.c.
+.sh 3 "Built-in Header Semantics"
+.pp
+Not all header semantics are defined in the configuration file.
+Header lines that should only be included by certain mailers
+(as well as other more obscure semantics)
+must be specified in the
+.i HdrInfo
+table in
+.i conf.c .
+This table contains the header name
+(which should be in all lower case)
+and a set of header control flags (described below),
+The flags are:
+.ip H_ACHECK
+Normally when the check is made to see if a header line is compatible
+with a mailer,
+.i sendmail
+will not delete an existing line.
+If this flag is set,
+.i sendmail
+will delete
+even existing header lines.
+That is,
+if this bit is set and the mailer does not have flag bits set
+that intersect with the required mailer flags
+in the header definition in
+sendmail.cf,
+the header line is
+.i always
+deleted.
+.ip H_EOH
+If this header field is set,
+treat it like a blank line,
+i.e.,
+it will signal the end of the header
+and the beginning of the message text.
+.ip H_FORCE
+Add this header entry
+even if one existed in the message before.
+If a header entry does not have this bit set,
+.i sendmail
+will not add another header line if a header line
+of this name already existed.
+This would normally be used to stamp the message
+by everyone who handled it.
+.ip H_TRACE
+If set,
+this is a timestamp
+(trace)
+field.
+If the number of trace fields in a message
+exceeds a preset amount
+the message is returned
+on the assumption that it has an aliasing loop.
+.ip H_RCPT
+If set,
+this field contains recipient addresses.
+This is used by the
+.b \-t
+flag to determine who to send to
+when it is collecting recipients from the message.
+.ip H_FROM
+This flag indicates that this field
+specifies a sender.
+The order of these fields in the
+.i HdrInfo
+table specifies
+.i sendmail 's
+preference
+for which field to return error messages to.
+.nr ii 5n
+.lp
+Let's look at a sample
+.i HdrInfo
+specification:
+.(b
+.ta 4n +\w'"return-receipt-to", 'u
+struct hdrinfo HdrInfo[] =
+\&{
+ /* originator fields, most to least significant */
+ "resent-sender", H_FROM,
+ "resent-from", H_FROM,
+ "sender", H_FROM,
+ "from", H_FROM,
+ "full-name", H_ACHECK,
+ /* destination fields */
+ "to", H_RCPT,
+ "resent-to", H_RCPT,
+ "cc", H_RCPT,
+ /* message identification and control */
+ "message", H_EOH,
+ "text", H_EOH,
+ /* trace fields */
+ "received", H_TRACE|H_FORCE,
+
+ NULL, 0,
+};
+.)b
+This structure indicates that the
+.q To: ,
+.q Resent-To: ,
+and
+.q Cc:
+fields
+all specify recipient addresses.
+Any
+.q Full-Name:
+field will be deleted unless the required mailer flag
+(indicated in the configuration file)
+is specified.
+The
+.q Message:
+and
+.q Text:
+fields will terminate the header;
+these are used by random dissenters around the network world.
+The
+.q Received:
+field will always be added,
+and can be used to trace messages.
+.pp
+There are a number of important points here.
+First,
+header fields are not added automatically just because they are in the
+.i HdrInfo
+structure;
+they must be specified in the configuration file
+in order to be added to the message.
+Any header fields mentioned in the configuration file but not
+mentioned in the
+.i HdrInfo
+structure have default processing performed;
+that is,
+they are added unless they were in the message already.
+Second,
+the
+.i HdrInfo
+structure only specifies cliched processing;
+certain headers are processed specially by ad hoc code
+regardless of the status specified in
+.i HdrInfo .
+For example,
+the
+.q Sender:
+and
+.q From:
+fields are always scanned on ARPANET mail
+to determine the sender\**;
+.(f
+\**Actually, this is no longer true in SMTP;
+this information is contained in the envelope.
+The older ARPANET protocols did not completely distinguish
+envelope from header.
+.)f
+this is used to perform the
+.q "return to sender"
+function.
+The
+.q "From:"
+and
+.q "Full-Name:"
+fields are used to determine the full name of the sender
+if possible;
+this is stored in the macro
+.b $x
+and used in a number of ways.
+.sh 3 "Restricting Use of Email"
+.pp
+If it is necessary to restrict mail through a relay,
+the
+.i checkcompat
+routine can be modified.
+This routine is called for every recipient address.
+It returns an exit status
+indicating the status of the message.
+The status
+.sm EX_OK
+accepts the address,
+.sm EX_TEMPFAIL
+queues the message for a later try,
+and other values
+(commonly
+.sm EX_UNAVAILABLE )
+reject the message.
+It is up to
+.i checkcompat
+to print an error message
+(using
+.i usrerr )
+if the message is rejected.
+For example,
+.i checkcompat
+could read:
+.(b
+.re
+.sz -1
+.ta 4n +4n +4n +4n +4n +4n +4n
+int
+checkcompat(to, e)
+ register ADDRESS *to;
+ register ENVELOPE *e;
+\&{
+ register STAB *s;
+
+ s = stab("private", ST_MAILER, ST_FIND);
+ if (s != NULL && e\->e_from.q_mailer != LocalMailer &&
+ to->q_mailer == s->s_mailer)
+ {
+ usrerr("No private net mail allowed through this machine");
+ return (EX_UNAVAILABLE);
+ }
+ if (MsgSize > 50000 && to\->q_mailer != LocalMailer)
+ {
+ usrerr("Message too large for non-local delivery");
+ NoReturn = TRUE;
+ return (EX_UNAVAILABLE);
+ }
+ return (EX_OK);
+}
+.sz
+.)b
+This would reject messages greater than 50000 bytes
+unless they were local.
+The
+.i NoReturn
+flag can be sent to suppress the return of the actual body
+of the message in the error return.
+The actual use of this routine is highly dependent on the
+implementation,
+and use should be limited.
+.sh 3 "Load Average Computation"
+.pp
+The routine
+.i getla
+should return an approximation of the current system load average
+as an integer.
+There are four versions included on compilation flags
+as described above.
+.sh 3 "New Database Map Classes"
+.pp
+New key maps can be added by creating a class initialization function
+and a lookup function.
+These are then added to the routine
+.i setupmaps.
+.pp
+The initialization function is called as
+.(b
+\fIxxx\fP_map_init(MAP *map, char *mapname, char *args)
+.)b
+The
+.i map
+is an internal data structure.
+The
+.i mapname
+is the name of the map (used for error messages).
+The
+.i args
+is a pointer to the rest of the configuration file line;
+flags and filenames can be extracted from this line.
+The initialization function must return
+.sm TRUE
+if it successfully opened the map,
+.sm FALSE
+otherwise.
+.pp
+The lookup function is called as
+.(b
+\fIxxx\fP_map_lookup(MAP *map, char buf[], int bufsize, char **av, int *statp)
+.)b
+The
+.i map
+defines the map internally.
+The parameters
+.i buf
+and
+.i bufsize
+have the input key.
+This may be (and often is) used destructively.
+The
+.i av
+is a list of arguments passed in from the rewrite line.
+The lookup function should return a pointer to the new value.
+IF the map lookup fails,
+.i *statp
+should be set to an exit status code;
+in particular, it should be set to
+.sm EX_TEMPFAIL
+if recovery is to be attempted by the higher level code.
+.sh 3 "Queueing Function"
+.pp
+The routine
+.i shouldqueue
+is called to decide if a message should be queued
+or processed immediately.
+Typically this compares the message priority to the current load average.
+The default definition is:
+.(b
+bool
+shouldqueue(pri, ctime)
+ long pri;
+ time_t ctime;
+{
+ if (CurrentLA < QueueLA)
+ return (FALSE);
+ if (CurrentLA >= RefuseLA)
+ return (TRUE);
+ return (pri > (QueueFactor / (CurrentLA \- QueueLA + 1)));
+}
+.)b
+If the current load average
+(global variable
+.i CurrentLA ,
+which is set before this function is called)
+is less than the low threshold load average
+(option
+.b x ,
+variable
+.i QueueLA ),
+.i shouldqueue
+returns
+.sm FALSE
+immediately
+(that is, it should
+.i not
+queue).
+If the current load average exceeds the high threshold load average
+(option
+.b X ,
+variable
+.i RefuseLA ),
+.i shouldqueue
+returns
+.sm TRUE
+immediately.
+Otherwise, it computes the function based on the message priority,
+the queue factor
+(option
+.b q ,
+global variable
+.i QueueFactor ),
+and the current and threshold load averages.
+.pp
+An implementation wishing to take the actual age of the message into account
+can also use the
+.i ctime
+parameter,
+which is the time that the message was first submitted to
+.i sendmail .
+Note that the
+.i pri
+parameter is already weighted
+by the number of times the message has been tried
+(although this tends to lower the priority of the message with time);
+the expectation is that the
+.i ctime
+would be used as an
+.q "escape clause"
+to ensure that messages are eventually processed.
+.sh 3 "Refusing Incoming SMTP Connections"
+.pp
+The function
+.i refuseconnections
+returns
+.sm TRUE
+if incoming SMTP connections should be refused.
+The current implementation is based exclusively on the current load average
+and the refuse load average option
+(option
+.b X ,
+global variable
+.i RefuseLA ):
+.(b
+bool
+refuseconnections()
+{
+ return (CurrentLA >= RefuseLA);
+}
+.)b
+A more clever implementation
+could look at more system resources.
+.sh 3 "Load Average Computation"
+.pp
+The routine
+.i getla
+returns the current load average (as a rounded integer).
+The distribution includes several possible implementations.
+.sh 2 "Configuration in src/daemon.c"
+.pp
+The file
+.i src/daemon.c
+contains a number of routines that are dependent
+on the local networking environment.
+The version supplied assumes you have BSD style sockets.
+.pp
+In previous releases,
+we recommended that you modify the routine
+.i maphostname
+if you wanted to generalize
+.b $[
+\&...\&
+.b $]
+lookups.
+We now recommend that you create a new keyed map instead.
+.sh 1 "CHANGES IN VERSION 8"
+.pp
+The following summarizes changes
+since the last commonly available version of
+.i sendmail
+(5.67):
+.sh 2 "Connection Caching"
+.pp
+Instead of closing SMTP connections immediately,
+those connections are cached for possible future use.
+The advent of MX records made this effective for mailing lists;
+in addition,
+substantial performance improvements can be expected for queue processing.
+.sh 2 "MX Piggybacking"
+.pp
+If two hosts with different names in a single message
+happen to have the same set of MX hosts,
+they can be sent in the same transaction.
+Version 8 notices this and tries to batch the messages.
+.sh 2 "RFC 1123 Compliance"
+.pp
+A number of changes have been made to make
+.i sendmail
+.q "conditionally compliant"
+(that is,
+.i sendmail
+satisfies all of the
+.q MUST
+clauses and most but not all of the
+.q SHOULD
+clauses in RFC 1123).
+.pp
+The major areas of change are (numbers are RFC 1123 section numbers):
+.nr ii \w'5.3.1.1\0\0'u
+.ip 5.2.7
+Response to RCPT command is fast.
+.ip 5.2.8
+Numeric IP addresses are logged in Received: lines.
+.ip 5.2.17
+Self domain literal is properly handled.
+.ip 5.3.2
+Better control over individual timeouts.
+.ip 5.3.3
+Error messages are sent as
+.q From:<> .
+.ip 5.3.3
+Error messages are never sent to
+.q <> .
+.ip 5.3.3
+Route-addrs are pruned.
+.lp
+The areas in which
+.i sendmail
+is not
+.q "unconditionally compliant"
+are:
+.ip 5.2.6
+.i Sendmail
+does do header munging.
+.ip 5.2.10
+.i Sendmail
+doesn't always use the exact SMTP message text
+as listed in RFC 821.
+.ip 5.3.1.1
+.i Sendmail
+doesn't guarantee only one connect for each host in queue runs.
+.ip 5.3.1.1
+.i Sendmail
+doesn't always provide adequate concurrency limits.
+.sh 2 "Extended SMTP Support"
+.pp
+Version 8 includes both sending and receiving support for Extended
+SMTP support as defined by RFC 1425 (basic) and RFC 1427 (SIZE);
+and limited support for RFC 1426 (BODY).
+.sh 2 "Eight-Bit Clean"
+.pp
+Previous versions of
+.i sendmail
+used the 0200 bit for quoting.
+This version avoids that use.
+However, for compatibility with RFC 822,
+you can set option `7' to get seven bit stripping.
+.pp
+Individual mailers can still produce seven bit output using the
+`7' mailer flag.
+.sh 2 "User Database"
+.pp
+The user database is an as-yet experimental attempt
+to provide unified large-site name support.
+We are installing it at Berkeley;
+future versions may show significant modifications.
+.sh 2 "Improved BIND Support"
+.pp
+The BIND support,
+particularly for MX records,
+had a number of annoying
+.q features
+which have been removed in this release.
+In particular,
+these more tightly bind (pun intended) the name server to
+.i sendmail ,
+so that the name server resolution rules are incorporated directly into
+.b sendmail .
+.sh 2 "Keyed Files"
+.pp
+Generalized keyed files is an idea taken directly from
+.sm IDA
+.i sendmail
+(albeit with a completely different implementation).
+They can be useful on large sites.
+.pp
+Version 8 also understands YP.
+.sh 2 "Multi-Word Classes"
+.pp
+Classes can now be multiple words.
+For example,
+.(b
+CShofmann.CS.Berkeley.EDU
+.)b
+allows you to match the entire string
+.q hofmann.CS.Berkeley.EDU
+using the single construct
+.q $=S .
+.sh 2 "Deferred Macro Expansion"
+.pp
+The
+.b $& \c
+.i x
+construct has been adopted from
+.sm IDA .
+.sh 2 "IDENT Protocol Support"
+.pp
+The IDENT protocol as defined in RFC 1413 is supported.
+.sh 2 "Parsing Bug Fixes"
+.pp
+A number of small bugs having to do with things like
+backslash-escaped quotes inside of comments
+have been fixed.
+.sh 2 "Separate Envelope/Header Processing"
+.pp
+Since the From: line is passed in separately from the envelope sender,
+these have both been made visible;
+the
+.b $g
+macro is set to the envelope sender during processing
+of mailer argument vectors
+and the header sender during processing of headers.
+.pp
+It is also possible to specify separate per-mailer
+envelope and header processing.
+The
+.b S enderRWSet
+and
+.b R ecipientRWset
+arguments for mailers
+can be specified as
+.i envelope/header
+to give different rewritings for envelope versus header addresses.
+.sh 2 "Owner-List Propagates to Envelope"
+.pp
+When an alias has an associated owner\-list name,
+that alias is used to change the envelope sender address.
+This will cause downstream errors to be returned to that owner.
+.sh 2 "Dynamic Header Allocation"
+.pp
+The fixed size limit on header lines has been eliminated.
+.sh 2 "New Command Line Flags"
+.pp
+The
+.b \-B
+flag has been added to pass in body type information.
+.pp
+The
+.b \-p
+flag has been added
+to pass in protocol information.
+.pp
+The
+.b \-X
+flag has been added
+to allow logging of all protocol in and out of
+.i sendmail
+for debugging.
+.sh 2 "Enhanced Command Line Flags"
+.pp
+The
+.b \-q
+flag can limit limit a queue run to specific recipients, senders, or queue ids
+using
+.b \-qR\c
+.i substring ,
+.b \-qS\c
+.i substring ,
+or
+.b \-qI\c
+.i substring
+respectively.
+.sh 2 "New and Old Configuration Line Types"
+.pp
+The
+.b T
+(Trusted users) configuration line has been deleted.
+It will still be accepted but will be ignored.
+.pp
+The
+.b K
+line has been added to declare database maps.
+.pp
+The
+.b V
+line has been added to declare the configuration version level.
+.pp
+The
+.b M
+line has a
+.q D=
+field that lets you change into a temporary directory while that mailer
+is running.
+.sh 2 "New Options"
+.pp
+Several new options have been added,
+many to support new features,
+others to allow tuning that was previously available
+only by recompiling.
+They are described in detail in Section 5.1.5.
+Briefly,
+.nr ii 0.5i
+.ip b
+Insist on a minimum number of disk blocks.
+.ip C
+Set checkpoint interval.
+.ip E
+Default error message.
+.ip G
+Enable GECOS matching.
+.ip h
+Maximum hop count.
+.ip j
+Send errors in MIME-encapsulated format.
+.ip J
+Forward file path.
+.ip k
+Connection cache size
+.ip K
+Connection cache lifetime.
+.ip l
+Enable Errors-To: header.
+These headers violate RFC 1123;
+this option is included to provide back compatibility
+with old versions of
+.i sendmail .
+.ip O
+Set incoming SMTP daemon options, such as an alternate SMTP port.
+.ip p
+Privacy options.
+.ip R
+Don't prune route-addrs.
+.ip U
+User database spec.
+.ip V
+Fallback
+.q MX
+host.
+.ip w
+.q "Best MX"
+handling technique.
+.ip 7
+Do not run eight bit clean.
+.sh 2 "Extended Options"
+.pp
+The
+.b r
+(read timeout),
+.b I
+(use BIND),
+and
+.b T
+(queue timeout)
+options have been extended to pass in more information.
+.sh 2 "New Mailer Flags"
+.pp
+Several new mailer flags have been added.
+.ip a
+Try to use ESMTP when creating a connection.
+If this is not set,
+.i sendmail
+will still try if the other end hints that it knows about ESMTP
+in its greeting message;
+this flag says to try even if it doesn't hint.
+If the EHLO (extended hello)
+command fails,
+.i sendmail
+falls back to old SMTP.
+.ip b
+Ensure that there is a blank line at the end of all messages.
+.ip c
+Strip all comments from addresses;
+this should only be used as a last resort
+when dealing with cranky mailers.
+.ip g
+Never use the null sender as the envelope sender,
+even when running SMTP.
+Although this violates RFC 1123,
+it may be necessary when you must deal with some obnoxious old hosts.
+.ip 7
+Strip all output to 7 bits.
+.sh 2 "New Pre-Defined Macros"
+.pp
+The following macros are pre-defined:
+.ip $k
+The UUCP node name,
+nominally from
+.i uname (2)
+call.
+.ip $m
+The domain part of our full hostname.
+.ip $_
+The RFC 1413-provided sender address.
+.sh 2 "New LHS Token"
+.pp
+Version 8 allows
+.b $@
+on the Left Hand Side of an
+.q R
+line to match zero tokens.
+This is intended to be used to match the null input.
+.sh 2 "Bigger Defaults"
+.pp
+Version 8 allows up to 100 rulesets instead of 30.
+It is recommended that rulesets 0\-9 be reserved for
+.i sendmail 's
+dedicated use in future releases.
+.pp
+The total number of MX records that can be used has been raised to 20.
+.pp
+The number of queued messages that can be handled at one time
+has been raised from 600 to 1000.
+.sh 2 "Different Default Tuning Parameters"
+.pp
+Version 8 has changed the default parameters
+for tuning queue costs
+to make the number of recipients more important
+than the size of the message (for small messages).
+This is reasonable if you are connected with reasonably fast links.
+.sh 2 "Auto-Quoting in Addresses"
+.pp
+Previously, the
+.q "Full Name <email address>"
+syntax would generate incorrect protocol output
+if
+.q "Full Name"
+had special characters such as dot.
+This version puts quotes around such names.
+.sh 2 "Symbolic Names On Error Mailer"
+.pp
+Several names have been built in to the $@ portion of the $#error
+mailer.
+.sh 2 "SMTP VRFY Doesn't Expand"
+.pp
+Previous versions of
+.i sendmail
+treated VRFY and EXPN the same.
+In this version,
+VRFY doesn't expand aliases or follow .forward files.
+EXPN still does.
+.pp
+As an optimization, if you run with your default delivery mode being
+queue-only or deliver-in-background,
+the RCPT command will also not chase aliases and .forward files.
+It will chase them when it processes the queue.
+.sh 2 "[IPC] Mailers Allow Multiple Hosts"
+.pp
+When an address resolves to a mailer that has
+.q [IPC]
+as its
+.q Path ,
+the $@ part (host name)
+can be a colon-separated list of hosts instead of a single hostname.
+This asks
+.i sendmail
+to search the list for the first entry that is available
+exactly as though it were an MX record.
+The intent is to route internal traffic through internal networks
+without publishing an MX record to the net.
+MX expansion is still done on the individual items.
+.sh 2 "Aliases Extended"
+.pp
+The implementation has been merged with maps.
+Among other things,
+this supports NIS-based aliases.
+.sh 2 "Portability and Security Enhancements"
+.pp
+A number of internal changes have been made to enhance portability.
+.pp
+Several fixes have been made to increase the paranoia factor.
+.sh 2 "Miscellaneous Changes"
+.pp
+.i Sendmail
+writes a
+.i /etc/sendmail.pid
+file with the current process id of the SMTP daemon.
+.pp
+Two people using the same program in their .forward file
+are considered different
+so that duplicate elimination doesn't delete one of them.
+.pp
+The
+.i mailstats
+program prints mailer names
+and gets the location of the
+.i sendmail.st
+file from
+.i /etc/sendmail.cf .
+.pp
+Many minor bugs have been fixed, such as handling of backslashes
+inside of quotes.
+.pp
+A hook (ruleset 5) has been added
+to allow rewriting of local addresses after aliasing.
+.sh 1 "ACKNOWLEDGEMENTS"
+.pp
+I've worked on
+.i sendmail
+for many years,
+and many employers have been remarkably patient
+about letting me work on a large project
+that was not part of my official job.
+This includes time on the INGRES Project at Berkeley,
+at Britton Lee,
+and again on the Mammoth Project at Berkeley.
+.pp
+Much of the second wave of improvements
+should be credited to Bryan Costales of ICSI.
+As he passed me drafts of his book on
+.i sendmail
+I was inspired to start working on things again.
+Bryan was also available to bounce ideas off of.
+.pp
+Many, many people contributed chunks of code and ideas to
+.i sendmail .
+It has proven to be a group network effort.
+Version 8 in particular was a group project.
+The following people made notable contributions:
+.(l
+Keith Bostic, CSRG, University of California, Berkeley
+Michael J. Corrigan, University of California, San Diego
+Bryan Costales, International Computer Science Institute
+Pa\*:r (Pell) Emanuelsson
+Craig Everhart, Transarc Corporation
+Tom Ivar Helbekkmo, Norwegian School of Economics
+Allan E. Johannesen, WPI
+Jonathan Kamens, OpenVision Technologies, Inc.
+Takahiro Kanbe, Fuji Xerox Information Systems Co., Ltd.
+Brian Kantor, University of California, San Diego
+Murray S. Kucherawy, HookUp Communication Corp.
+Bruce Lilly, Sony U.S.
+Karl London
+Nakamura Motonori, Kyoto University
+John Gardiner Myers, Carnegie Mellon University
+Neil Rickert, Northern Illinois University
+Eric Schnoebelen, Convex Computer Corp.
+Eric Wassenaar, National Institute for Nuclear and High Energy Physics, Amsterdam
+Christophe Wolfhugel, Herve Schauer Consultants (Paris)
+.)l
+I apologize for anyone I have omitted, misspelled, misattributed, or
+otherwise missed.
+Many other people have contributed ideas, comments, and encouragement.
+I appreciate their contribution as well.
+.++ A
+.+c "COMMAND LINE FLAGS"
+.ba 0
+.nr ii 1i
+.pp
+Arguments must be presented with flags before addresses.
+The flags are:
+.ip \-b\fIx\fP
+Set operation mode to
+.i x .
+Operation modes are:
+.(b
+.ta 4n
+m Deliver mail (default)
+s Speak SMTP on input side
+d Run as a daemon
+t Run in test mode
+v Just verify addresses, don't collect or deliver
+i Initialize the alias database
+p Print the mail queue
+.)b
+.ip \-B\fItype\fP
+Indicate body type.
+.ip \-C\fIfile\fP
+Use a different configuration file.
+.i Sendmail
+runs as the invoking user (rather than root)
+when this flag is specified.
+.ip \-d\fIlevel\fP
+Set debugging level.
+.ip "\-f\ \fIaddr\fP"
+The sender's machine address is
+.i addr .
+.ip \-F\fIname\fP
+Sets the full name of this user to
+.i name .
+.ip "\-h\ \fIcnt\fP"
+Sets the
+.q "hop count"
+to
+.i cnt .
+This represents the number of times this message has been processed
+by
+.i sendmail
+(to the extent that it is supported by the underlying networks).
+.i Cnt
+is incremented during processing,
+and if it reaches
+MAXHOP
+(currently 30)
+.i sendmail
+throws away the message with an error.
+.ip \-n
+Don't do aliasing or forwarding.
+.ip "\-r\ \fIaddr\fP"
+An obsolete form of
+.b \-f .
+.ip \-o\fIx\|value\fP
+Set option
+.i x
+to the specified
+.i value .
+These options are described in Appendix B.
+.ip \-p\fIprotocol\fP
+Set the sending protocol.
+Programs are encouraged to set this.
+The protocol field can be in the form
+.i protocol \c
+.b : \c
+.i host
+to set both the sending protocol and sending host.
+For example,
+.q \-pUUCP:uunet
+sets the sending protocol to UUCP
+and the sending host to uunet.
+(Some existing programs use \-oM to set the r and s macros;
+this is equivalent to using \-p.)
+.ip \-q\fItime\fP
+Try to process the queued up mail.
+If the time is given,
+a
+.i sendmail
+will run through the queue at the specified interval
+to deliver queued mail;
+otherwise, it only runs once.
+.ip \-q\fIXstring\fP
+Run the queue once,
+limiting the jobs to those matching
+.i Xstring .
+The key letter
+.i X
+can be
+.b I
+to limit based on queue identifier,
+.b R
+to limit based on recipient,
+or
+.b S
+to limit based on sender.
+A particular queued job is accepted if one of the corresponding addresses
+contains the indicated
+.i string .
+.ip \-t
+Read the header for
+.q To: ,
+.q Cc: ,
+and
+.q Bcc:
+lines, and send to everyone listed in those lists.
+The
+.q Bcc:
+line will be deleted before sending.
+Any addresses in the argument vector will be deleted
+from the send list.
+.ip "\-X \fIlogfile\fP"
+Log all traffic in and out of
+.i sendmail
+in the indicated
+.i logfile
+for debugging mailer problems.
+This produces a lot of data very quickly and should be used sparingly.
+.pp
+There are a number of options that may be specified as
+primitive flags.
+These are the e, i, m, and v options.
+Also,
+the f option
+may be specified as the
+.b \-s
+flag.
+.+c "QUEUE FILE FORMATS"
+.pp
+This appendix describes the format of the queue files.
+These files live in the directory defined by the
+.b Q
+option in the
+.i sendmail.cf
+file, usually
+.i /var/spool/mqueue
+or
+.i /usr/spool/mqueue .
+.pp
+All queue files have the name
+\fIx\fP\|\fBf\fP\fIAAA99999\fP
+where
+.i AAA99999
+is the
+.i id
+for this message
+and the
+.i x
+is a type.
+The first letter of the id encodes the hour of the day
+that the message was received by the system
+(with A being the hour between midnight and 1:00AM).
+All files with the same id collectively define one message.
+.pp
+The types are:
+.nr ii 0.5i
+.ip d
+The data file.
+The message body (excluding the header) is kept in this file.
+.ip l
+The lock file.
+If this file exists,
+the job is currently being processed,
+and a queue run will not process the file.
+For that reason,
+an extraneous
+.b lf
+file can cause a job to apparently disappear
+(it will not even time out!).
+[Actually, this file is obsolete on most systems that support the
+.b flock
+or
+.b lockf
+system calls.]
+.ip n
+This file is created when an id is being created.
+It is a separate file to insure that no mail can ever be destroyed
+due to a race condition.
+It should exist for no more than a few milliseconds
+at any given time.
+[This is only used on old versions of
+.i sendmail ;
+it is not used
+on newer versions.]
+.ip q
+The queue control file.
+This file contains the information necessary to process the job.
+.ip t
+A temporary file.
+These are an image of the
+.b qf
+file when it is being rebuilt.
+It should be renamed to a
+.b qf
+file very quickly.
+.ip x
+A transcript file,
+existing during the life of a session
+showing everything that happens
+during that session.
+.pp
+The
+.b qf
+file is structured as a series of lines
+each beginning with a code letter.
+The lines are as follows:
+.ip D
+The name of the data file.
+There may only be one of these lines.
+.ip H
+A header definition.
+There may be any number of these lines.
+The order is important:
+they represent the order in the final message.
+These use the same syntax
+as header definitions in the configuration file.
+.ip C
+The controlling address.
+The syntax is
+.q localuser:aliasname .
+Recipient addresses following this line
+will be flagged so that deliveries will be run as the
+.i localuser
+(a user name from the /etc/passwd file);
+.i aliasname
+is the name of the alias that expanded to this address
+(used for printing messages).
+.ip R
+A recipient address.
+This will normally be completely aliased,
+but is actually realiased when the job is processed.
+There will be one line
+for each recipient.
+.ip S
+The sender address.
+There may only be one of these lines.
+.ip E
+An error address.
+If any such lines exist,
+they represent the addresses that should receive error messages.
+.ip T
+The job creation time.
+This is used to compute when to time out the job.
+.ip P
+The current message priority.
+This is used to order the queue.
+Higher numbers mean lower priorities.
+The priority changes
+as the message sits in the queue.
+The initial priority depends on the message class
+and the size of the message.
+.ip M
+A message.
+This line is printed by the
+.i mailq
+command,
+and is generally used to store status information.
+It can contain any text.
+.ip F
+Flag bits, represented as one letter per flag.
+Defined flag bits are
+.b r
+indicating that this is a response message
+and
+.b w
+indicating that a warning message has been sent
+announcing that the mail has been delayed.
+.ip $
+A macro definition.
+The values of certain macros
+(as of this writing, only
+.b $r
+and
+.b $s )
+are passed through to the queue run phase.
+.ip B
+The body type.
+The remainder of the line is a text string defining the body type.
+If this field is missing,
+the body type is assumed to be
+.q "undefined"
+and no special processing is attempted.
+Legal values are
+.q 7BIT
+and
+.q 8BITMIME .
+.pp
+As an example,
+the following is a queue file sent to
+.q eric@mammoth.Berkeley.EDU
+and
+.q bostic@okeeffe.CS.Berkeley.EDU \**:
+.(f
+\**This example is contrived and probably inaccurate for your environment.
+Glance over it to get an idea;
+nothing can replace looking at what your own system generates.
+.)f
+.(b
+P835771
+T404261372
+DdfAAA13557
+Seric
+Eowner-sendmail@vangogh.CS.Berkeley.EDU
+Ceric:sendmail@vangogh.CS.Berkeley.EDU
+Reric@mammoth.Berkeley.EDU
+Rbostic@okeeffe.CS.Berkeley.EDU
+H?P?return-path: <owner-sendmail@vangogh.CS.Berkeley.EDU>
+Hreceived: by vangogh.CS.Berkeley.EDU (5.108/2.7) id AAA06703;
+ Fri, 17 Jul 92 00:28:55 -0700
+Hreceived: from mail.CS.Berkeley.EDU by vangogh.CS.Berkeley.EDU (5.108/2.7)
+ id AAA06698; Fri, 17 Jul 92 00:28:54 -0700
+Hreceived: from [128.32.31.21] by mail.CS.Berkeley.EDU (5.96/2.5)
+ id AA22777; Fri, 17 Jul 92 03:29:14 -0400
+Hreceived: by foo.bar.baz.de (5.57/Ultrix3.0-C)
+ id AA22757; Fri, 17 Jul 92 09:31:25 GMT
+H?F?from: eric@foo.bar.baz.de (Eric Allman)
+H?x?full-name: Eric Allman
+Hmessage-id: <9207170931.AA22757@foo.bar.baz.de>
+HTo: sendmail@vangogh.CS.Berkeley.EDU
+Hsubject: this is an example message
+.)b
+This shows the name of the data file,
+the person who sent the message,
+the submission time
+(in seconds since January 1, 1970),
+the message priority,
+the message class,
+the recipients,
+and the headers for the message.
+.+c "SUMMARY OF SUPPORT FILES"
+.pp
+This is a summary of the support files
+that
+.i sendmail
+creates or generates.
+Many of these can be changed by editing the sendmail.cf file;
+check there to find the actual pathnames.
+.nr ii 1i
+.ip "/usr/\*(SD/sendmail"
+The binary of
+.i sendmail .
+.ip /usr/\*(SB/newaliases
+A link to /usr/\*(SD/sendmail;
+causes the alias database to be rebuilt.
+Running this program is completely equivalent to giving
+.i sendmail
+the
+.b \-bi
+flag.
+.ip /usr/\*(SB/mailq
+Prints a listing of the mail queue.
+This program is equivalent to using the
+.b \-bp
+flag to
+.i sendmail .
+.ip /etc/sendmail.cf
+The configuration file,
+in textual form.
+.ip /usr/lib/sendmail.hf
+The SMTP help file.
+.ip /etc/sendmail.st
+A statistics file; need not be present.
+.ip /etc/sendmail.pid
+Created in daemon mode;
+it contains the process id of the current SMTP daemon.
+If you use this in scripts;
+use ``head \-1'' to get just the first line;
+later versions of
+.i sendmail
+may add information to subsequent lines.
+.ip /etc/aliases
+The textual version of the alias file.
+.ip /etc/aliases.{pag,dir}
+The alias file in
+.i dbm \|(3)
+format.
+.ip /var/spool/mqueue
+The directory in which the mail queue
+and temporary files reside.
+.ip /var/spool/mqueue/qf*
+Control (queue) files for messages.
+.ip /var/spool/mqueue/df*
+Data files.
+.ip /var/spool/mqueue/tf*
+Temporary versions of the qf files,
+used during queue file rebuild.
+.ip /var/spool/mqueue/xf*
+A transcript of the current session.
+.\".ro
+.\".ls 1
+.\".tp
+.\".sp 2i
+.\".in 0
+.\".ce 100
+.\".sz 24
+.\".b SENDMAIL
+.\".sz 14
+.\".sp
+.\"INSTALLATION AND OPERATION GUIDE
+.\".sp
+.\".sz 10
+.\"Eric Allman
+.\"Britton-Lee, Inc.
+.\".sp
+.\"Version 8.36
+.\".ce 0
+.bp 2
+.rs
+.sp |4i
+.ce 2
+This page intentionally left blank;
+replace it with a blank sheet for double-sided output.
+.bp 3
+.ce
+.sz 12
+TABLE OF CONTENTS
+.sz 10
+.sp
+.\" remove some things to avoid "out of temp file space" problem
+.rm sh
+.rm (x
+.rm )x
+.rm ip
+.rm pp
+.rm lp
+.rm he
+.rm fo
+.rm eh
+.rm oh
+.rm ef
+.rm of
+.xp
diff --git a/usr.sbin/sendmail/doc/usenix/Makefile b/usr.sbin/sendmail/doc/usenix/Makefile
new file mode 100644
index 00000000000..ea0665c67be
--- /dev/null
+++ b/usr.sbin/sendmail/doc/usenix/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.2 (Berkeley) 2/28/94
+
+SRCS= usenix.me
+MACROS= -me
+
+all: usenix.ps
+
+usenix.ps: ${SRCS}
+ rm -f ${.TARGET}
+ ${PIC} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/sendmail/doc/usenix/usenix.me b/usr.sbin/sendmail/doc/usenix/usenix.me
new file mode 100644
index 00000000000..0fbb6723c13
--- /dev/null
+++ b/usr.sbin/sendmail/doc/usenix/usenix.me
@@ -0,0 +1,1076 @@
+.nr si 3n
+.he 'Mail Systems and Addressing in 4.2bsd''%'
+.fo 'Version 8.2'USENIX \- Jan 83'Last Mod 11/27/93'
+.if n .ls 2
+.+c
+.(l C
+.sz 14
+Mail Systems and Addressing
+in 4.2bsd
+.sz
+.sp
+Eric Allman*
+.sp 0.5
+.i
+Britton-Lee, Inc.
+1919 Addison Street, Suite 105.
+Berkeley, California 94704.
+.sp 0.5
+.r
+eric@Berkeley.ARPA
+ucbvax!eric
+.)l
+.sp
+.(l F
+.ce
+ABSTRACT
+.sp \n(psu
+Routing mail through a heterogeneous internet presents many new
+problems.
+Among the worst of these is that of address mapping.
+Historically, this has been handled on an ad hoc basis.
+However,
+this approach has become unmanageable as internets grow.
+.sp \n(psu
+Sendmail acts a unified
+.q "post office"
+to which all mail can be
+submitted.
+Address interpretation is controlled by a production
+system,
+which can parse both old and new format addresses.
+The
+new format is
+.q "domain-based,"
+a flexible technique that can
+handle many common situations.
+Sendmail is not intended to perform
+user interface functions.
+.sp \n(psu
+Sendmail will replace delivermail in the Berkeley 4.2 distribution.
+Several major hosts are now or will soon be running sendmail.
+This change will affect any users that route mail through a sendmail
+gateway.
+The changes that will be user visible are emphasized.
+.)l
+.sp 2
+.(f
+*A considerable part of this work
+was done while under the employ
+of the INGRES Project
+at the University of California at Berkeley.
+.)f
+.pp
+The mail system to appear in 4.2bsd
+will contain a number of changes.
+Most of these changes are based on the replacement of
+.i delivermail
+with a new module called
+.i sendmail.
+.i Sendmail
+implements a general internetwork mail routing facility,
+featuring aliasing and forwarding,
+automatic routing to network gateways,
+and flexible configuration.
+Of key interest to the mail system user
+will be the changes in the network addressing structure.
+.pp
+In a simple network,
+each node has an address,
+and resources can be identified
+with a host-resource pair;
+in particular,
+the mail system can refer to users
+using a host-username pair.
+Host names and numbers have to be administered by a central authority,
+but usernames can be assigned locally to each host.
+.pp
+In an internet,
+multiple networks with different characteristics
+and managements
+must communicate.
+In particular,
+the syntax and semantics of resource identification change.
+Certain special cases can be handled trivially
+by
+.i "ad hoc"
+techniques,
+such as
+providing network names that appear local to hosts
+on other networks,
+as with the Ethernet at Xerox PARC.
+However, the general case is extremely complex.
+For example,
+some networks require that the route the message takes
+be explicitly specified by the sender,
+simplifying the database update problem
+since only adjacent hosts must be entered
+into the system tables,
+while others use logical addressing,
+where the sender specifies the location of the recipient
+but not how to get there.
+Some networks use a left-associative syntax
+and others use a right-associative syntax,
+causing ambiguity in mixed addresses.
+.pp
+Internet standards seek to eliminate these problems.
+Initially, these proposed expanding the address pairs
+to address triples,
+consisting of
+{network, host, username}
+triples.
+Network numbers must be universally agreed upon,
+and hosts can be assigned locally
+on each network.
+The user-level presentation was changed
+to address domains,
+comprised of a local resource identification
+and a hierarchical domain specification
+with a common static root.
+The domain technique
+separates the issue of physical versus logical addressing.
+For example,
+an address of the form
+.q "eric@a.cc.berkeley.arpa"
+describes the logical
+organization of the address space
+(user
+.q eric
+on host
+.q a
+in the Computer Center
+at Berkeley)
+but not the physical networks used
+(for example, this could go over different networks
+depending on whether
+.q a
+were on an ethernet
+or a store-and-forward network).
+.pp
+.i Sendmail
+is intended to help bridge the gap
+between the totally
+.i "ad hoc"
+world
+of networks that know nothing of each other
+and the clean, tightly-coupled world
+of unique network numbers.
+It can accept old arbitrary address syntaxes,
+resolving ambiguities using heuristics
+specified by the system administrator,
+as well as domain-based addressing.
+It helps guide the conversion of message formats
+between disparate networks.
+In short,
+.i sendmail
+is designed to assist a graceful transition
+to consistent internetwork addressing schemes.
+.sp
+.pp
+Section 1 defines some of the terms
+frequently left fuzzy
+when working in mail systems.
+Section 2 discusses the design goals for
+.i sendmail .
+In section 3,
+the new address formats
+and basic features of
+.i sendmail
+are described.
+Section 4 discusses some of the special problems
+of the UUCP network.
+The differences between
+.i sendmail
+and
+.i delivermail
+are presented in section 5.
+.sp
+.(l F
+.b DISCLAIMER:
+A number of examples
+in this paper
+use names of actual people
+and organizations.
+This is not intended
+to imply a commitment
+or even an intellectual agreement
+on the part of these people or organizations.
+In particular,
+Bell Telephone Laboratories (BTL),
+Digital Equipment Corporation (DEC),
+Lawrence Berkeley Laboratories (LBL),
+Britton-Lee Incorporated (BLI),
+and the University of California at Berkeley
+are not committed to any of these proposals at this time.
+Much of this paper
+represents no more than
+the personal opinions of the author.
+.)l
+.sh 1 "DEFINITIONS"
+.pp
+There are four basic concepts
+that must be clearly distinguished
+when dealing with mail systems:
+the user (or the user's agent),
+the user's identification,
+the user's address,
+and the route.
+These are distinguished primarily by their position independence.
+.sh 2 "User and Identification"
+.pp
+The user is the being
+(a person or program)
+that is creating or receiving a message.
+An
+.i agent
+is an entity operating on behalf of the user \*-
+such as a secretary who handles my mail.
+or a program that automatically returns a
+message such as
+.q "I am at the UNICOM conference."
+.pp
+The identification is the tag
+that goes along with the particular user.
+This tag is completely independent of location.
+For example,
+my identification is the string
+.q "Eric Allman,"
+and this identification does not change
+whether I am located at U.C. Berkeley,
+at Britton-Lee,
+or at a scientific institute in Austria.
+.pp
+Since the identification is frequently ambiguous
+(e.g., there are two
+.q "Robert Henry" s
+at Berkeley)
+it is common to add other disambiguating information
+that is not strictly part of the identification
+(e.g.,
+Robert
+.q "Code Generator"
+Henry
+versus
+Robert
+.q "System Administrator"
+Henry).
+.sh 2 "Address"
+.pp
+The address specifies a location.
+As I move around,
+my address changes.
+For example,
+my address might change from
+.q eric@Berkeley.ARPA
+to
+.q eric@bli.UUCP
+or
+.q allman@IIASA.Austria
+depending on my current affiliation.
+.pp
+However,
+an address is independent of the location of anyone else.
+That is,
+my address remains the same to everyone who might be sending me mail.
+For example,
+a person at MIT and a person at USC
+could both send to
+.q eric@Berkeley.ARPA
+and have it arrive to the same mailbox.
+.pp
+Ideally a
+.q "white pages"
+service would be provided to map user identifications
+into addresses
+(for example, see
+[Solomon81]).
+Currently this is handled by passing around
+scraps of paper
+or by calling people on the telephone
+to find out their address.
+.sh 2 "Route"
+.pp
+While an address specifies
+.i where
+to find a mailbox,
+a route specifies
+.i how
+to find the mailbox.
+Specifically,
+it specifies a path
+from sender to receiver.
+As such, the route is potentially different
+for every pair of people in the electronic universe.
+.pp
+Normally the route is hidden from the user
+by the software.
+However,
+some networks put the burden of determining the route
+onto the sender.
+Although this simplifies the software,
+it also greatly impairs the usability
+for most users.
+The UUCP network is an example of such a network.
+.sh 1 "DESIGN GOALS"
+.pp
+Design goals for
+.i sendmail \**
+.(f
+\**This section makes no distinction between
+.i delivermail
+and
+.i sendmail.
+.)f
+include:
+.np
+Compatibility with the existing mail programs,
+including Bell version 6 mail,
+Bell version 7 mail,
+Berkeley
+.i Mail
+[Shoens79],
+BerkNet mail
+[Schmidt79],
+and hopefully UUCP mail
+[Nowitz78].
+ARPANET mail
+[Crocker82]
+was also required.
+.np
+Reliability, in the sense of guaranteeing
+that every message is correctly delivered
+or at least brought to the attention of a human
+for correct disposal;
+no message should ever be completely lost.
+This goal was considered essential
+because of the emphasis on mail in our environment.
+It has turned out to be one of the hardest goals to satisfy,
+especially in the face of the many anomalous message formats
+produced by various ARPANET sites.
+For example,
+certain sites generate improperly formated addresses,
+occasionally
+causing error-message loops.
+Some hosts use blanks in names,
+causing problems with
+mail programs that assume that an address
+is one word.
+The semantics of some fields
+are interpreted slightly differently
+by different sites.
+In summary,
+the obscure features of the ARPANET mail protocol
+really
+.i are
+used and
+are difficult to support,
+but must be supported.
+.np
+Existing software to do actual delivery
+should be used whenever possible.
+This goal derives as much from political and practical considerations
+as technical.
+.np
+Easy expansion to
+fairly complex environments,
+including multiple
+connections to a single network type
+(such as with multiple UUCP or Ethernets).
+This goal requires consideration of the contents of an address
+as well as its syntax
+in order to determine which gateway to use.
+.np
+Configuration information should not be compiled into the code.
+A single compiled program should be able to run as is at any site
+(barring such basic changes as the CPU type or the operating system).
+We have found this seemingly unimportant goal
+to be critical in real life.
+Besides the simple problems that occur when any program gets recompiled
+in a different environment,
+many sites like to
+.q fiddle
+with anything that they will be recompiling anyway.
+.np
+.i Sendmail
+must be able to let various groups maintain their own mailing lists,
+and let individuals specify their own forwarding,
+without modifying the system alias file.
+.np
+Each user should be able to specify which mailer to execute
+to process mail being delivered for him.
+This feature allows users who are using specialized mailers
+that use a different format to build their environment
+without changing the system,
+and facilitates specialized functions
+(such as returning an
+.q "I am on vacation"
+message).
+.np
+Network traffic should be minimized
+by batching addresses to a single host where possible,
+without assistance from the user.
+.pp
+These goals motivated the architecture illustrated in figure 1.
+.(z
+.hl
+.ie t \
+. sp 18
+.el \{\
+.(c
++---------+ +---------+ +---------+
+| sender1 | | sender2 | | sender3 |
++---------+ +---------+ +---------+
+ | | |
+ +----------+ + +----------+
+ | | |
+ v v v
+ +-------------+
+ | sendmail |
+ +-------------+
+ | | |
+ +----------+ + +----------+
+ | | |
+ v v v
++---------+ +---------+ +---------+
+| mailer1 | | mailer2 | | mailer3 |
++---------+ +---------+ +---------+
+.)c
+.\}
+
+.ce
+Figure 1 \*- Sendmail System Structure.
+.hl
+.)z
+The user interacts with a mail generating and sending program.
+When the mail is created,
+the generator calls
+.i sendmail ,
+which routes the message to the correct mailer(s).
+Since some of the senders may be network servers
+and some of the mailers may be network clients,
+.i sendmail
+may be used as an internet mail gateway.
+.sh 1 "USAGE"
+.sh 2 "Address Formats"
+.pp
+Arguments may be flags or addresses.
+Flags set various processing options.
+Following flag arguments,
+address arguments may be given.
+Addresses follow the syntax in RFC822
+[Crocker82]
+for ARPANET
+address formats.
+In brief, the format is:
+.np
+Anything in parentheses is thrown away
+(as a comment).
+.np
+Anything in angle brackets (\c
+.q "<\|>" )
+is preferred
+over anything else.
+This rule implements the ARPANET standard that addresses of the form
+.(b
+user name <machine-address>
+.)b
+will send to the electronic
+.q machine-address
+rather than the human
+.q "user name."
+.np
+Double quotes
+(\ "\ )
+quote phrases;
+backslashes quote characters.
+Backslashes are more powerful
+in that they will cause otherwise equivalent phrases
+to compare differently \*- for example,
+.i user
+and
+.i
+"user"
+.r
+are equivalent,
+but
+.i \euser
+is different from either of them.
+This might be used
+to avoid normal aliasing
+or duplicate suppression algorithms.
+.pp
+Parentheses, angle brackets, and double quotes
+must be properly balanced and nested.
+The rewriting rules control remaining parsing\**.
+.(f
+\**Disclaimer: Some special processing is done
+after rewriting local names; see below.
+.)f
+.pp
+Although old style addresses are still accepted
+in most cases,
+the preferred address format
+is based on ARPANET-style domain-based addresses
+[Su82a].
+These addresses are based on a hierarchical, logical decomposition
+of the address space.
+The addresses are hierarchical in a sense
+similar to the U.S. postal addresses:
+the messages may first be routed to the correct state,
+with no initial consideration of the city
+or other addressing details.
+The addresses are logical
+in that each step in the hierarchy
+corresponds to a set of
+.q "naming authorities"
+rather than a physical network.
+.pp
+For example,
+the address:
+.(l
+eric@HostA.BigSite.ARPA
+.)l
+would first look up the domain
+BigSite
+in the namespace administrated by
+ARPA.
+A query could then be sent to
+BigSite
+for interpretation of
+HostA.
+Eventually the mail would arrive at
+HostA,
+which would then do final delivery
+to user
+.q eric.
+.sh 2 "Mail to Files and Programs"
+.pp
+Files and programs are legitimate message recipients.
+Files provide archival storage of messages,
+useful for project administration and history.
+Programs are useful as recipients in a variety of situations,
+for example,
+to maintain a public repository of systems messages
+(such as the Berkeley
+.i msgs
+program).
+.pp
+Any address passing through the initial parsing algorithm
+as a local address
+(i.e, not appearing to be a valid address for another mailer)
+is scanned for two special cases.
+If prefixed by a vertical bar (\c
+.q \^|\^ )
+the rest of the address is processed as a shell command.
+If the user name begins with a slash mark (\c
+.q /\^ )
+the name is used as a file name,
+instead of a login name.
+.sh 2 "Aliasing, Forwarding, Inclusion"
+.pp
+.i Sendmail
+reroutes mail three ways.
+Aliasing applies system wide.
+Forwarding allows each user to reroute incoming mail
+destined for that account.
+Inclusion directs
+.i sendmail
+to read a file for a list of addresses,
+and is normally used
+in conjunction with aliasing.
+.sh 3 "Aliasing"
+.pp
+Aliasing maps local addresses to address lists using a system-wide file.
+This file is hashed to speed access.
+Only addresses that parse as local
+are allowed as aliases;
+this guarantees a unique key
+(since there are no nicknames for the local host).
+.sh 3 "Forwarding"
+.pp
+After aliasing,
+if an recipient address specifies a local user
+.i sendmail
+searches for a
+.q .forward
+file in the recipient's home directory.
+If it exists,
+the message is
+.i not
+sent to that user,
+but rather to the list of addresses in that file.
+Often
+this list will contain only one address,
+and the feature will be used for network mail forwarding.
+.pp
+Forwarding also permits a user to specify a private incoming mailer.
+For example,
+forwarding to:
+.(b
+"\^|\|/usr/local/newmail myname"
+.)b
+will use a different incoming mailer.
+.sh 3 "Inclusion"
+.pp
+Inclusion is specified in RFC 733 [Crocker77] syntax:
+.(b
+:Include: pathname
+.)b
+An address of this form reads the file specified by
+.i pathname
+and sends to all users listed in that file.
+.pp
+The intent is
+.i not
+to support direct use of this feature,
+but rather to use this as a subset of aliasing.
+For example,
+an alias of the form:
+.(b
+project: :include:/usr/project/userlist
+.)b
+is a method of letting a project maintain a mailing list
+without interaction with the system administration,
+even if the alias file is protected.
+.pp
+It is not necessary to rebuild the index on the alias database
+when a :include: list is changed.
+.sh 2 "Message Collection"
+.pp
+Once all recipient addresses are parsed and verified,
+the message is collected.
+The message comes in two parts:
+a message header and a message body,
+separated by a blank line.
+The body is an uninterpreted
+sequence of text lines.
+.pp
+The header is formated as a series of lines
+of the form
+.(b
+ field-name: field-value
+.)b
+Field-value can be split across lines by starting the following
+lines with a space or a tab.
+Some header fields have special internal meaning,
+and have appropriate special processing.
+Other headers are simply passed through.
+Some header fields may be added automatically,
+such as time stamps.
+.sh 1 "THE UUCP PROBLEM"
+.pp
+Of particular interest
+is the UUCP network.
+The explicit routing
+used in the UUCP environment
+causes a number of serious problems.
+First,
+giving out an address
+is impossible
+without knowing the address of your potential correspondent.
+This is typically handled
+by specifying the address
+relative to some
+.q "well-known"
+host
+(e.g.,
+ucbvax or decvax).
+Second,
+it is often difficult to compute
+the set of addresses
+to reply to
+without some knowledge
+of the topology of the network.
+Although it may be easy for a human being
+to do this
+under many circumstances,
+a program does not have equally sophisticated heuristics
+built in.
+Third,
+certain addresses will become painfully and unnecessarily long,
+as when a message is routed through many hosts in the USENET.
+And finally,
+certain
+.q "mixed domain"
+addresses
+are impossible to parse unambiguously \*-
+e.g.,
+.(l
+decvax!ucbvax!lbl-h!user@LBL-CSAM
+.)l
+might have many possible resolutions,
+depending on whether the message was first routed
+to decvax
+or to LBL-CSAM.
+.pp
+To solve this problem,
+the UUCP syntax
+would have to be changed to use addresses
+rather than routes.
+For example,
+the address
+.q decvax!ucbvax!eric
+might be expressed as
+.q eric@ucbvax.UUCP
+(with the hop through decvax implied).
+This address would itself be a domain-based address;
+for example,
+an address might be of the form:
+.(l
+mark@d.cbosg.btl.UUCP
+.)l
+Hosts outside of Bell Telephone Laboratories
+would then only need to know
+how to get to a designated BTL relay,
+and the BTL topology
+would only be maintained inside Bell.
+.pp
+There are three major problems
+associated with turning UUCP addresses
+into something reasonable:
+defining the namespace,
+creating and propagating the necessary software,
+and building and maintaining the database.
+.sh 2 "Defining the Namespace"
+.pp
+Putting all UUCP hosts into a flat namespace
+(e.g.,
+.q \&...@host.UUCP )
+is not practical for a number of reasons.
+First,
+with over 1600 sites already,
+and (with the increasing availability of inexpensive microcomputers
+and autodialers)
+several thousand more coming within a few years,
+the database update problem
+is simply intractable
+if the namespace is flat.
+Second,
+there are almost certainly name conflicts today.
+Third,
+as the number of sites grow
+the names become ever less mnemonic.
+.pp
+It seems inevitable
+that there be some sort of naming authority
+for the set of top level names
+in the UUCP domain,
+as unpleasant a possibility
+as that may seem.
+It will simply not be possible
+to have one host resolving all names.
+It may however be possible
+to handle this
+in a fashion similar to that of assigning names of newsgroups
+in USENET.
+However,
+it will be essential to encourage everyone
+to become subdomains of an existing domain
+whenever possible \*-
+even though this will certainly bruise some egos.
+For example,
+if a new host named
+.q blid
+were to be added to the UUCP network,
+it would probably actually be addressed as
+.q d.bli.UUCP
+(i.e.,
+as host
+.q d
+in the pseudo-domain
+.q bli
+rather than as host
+.q blid
+in the UUCP domain).
+.sh 2 "Creating and Propagating the Software"
+.pp
+The software required to implement a consistent namespace
+is relatively trivial.
+Two modules are needed,
+one to handle incoming mail
+and one to handle outgoing mail.
+.pp
+The incoming module
+must be prepared to handle either old or new style addresses.
+New-style addresses
+can be passed through unchanged.
+Old style addresses
+must be turned into new style addresses
+where possible.
+.pp
+The outgoing module
+is slightly trickier.
+It must do a database lookup on the recipient addresses
+(passed on the command line)
+to determine what hosts to send the message to.
+If those hosts do not accept new-style addresses,
+it must transform all addresses in the header of the message
+into old style using the database lookup.
+.pp
+Both of these modules
+are straightforward
+except for the issue of modifying the header.
+It seems prudent to choose one format
+for the message headers.
+For a number of reasons,
+Berkeley has elected to use the ARPANET protocols
+for message formats.
+However,
+this protocol is somewhat difficult to parse.
+.pp
+Propagation is somewhat more difficult.
+There are a large number of hosts
+connected to UUCP
+that will want to run completely standard systems
+(for very good reasons).
+The strategy is not to convert the entire network \*-
+only enough of it it alleviate the problem.
+.sh 2 "Building and Maintaining the Database"
+.pp
+This is by far the most difficult problem.
+A prototype for this database
+already exists,
+but it is maintained by hand
+and does not pretend to be complete.
+.pp
+This problem will be reduced considerably
+if people choose to group their hosts
+into subdomains.
+This would require a global update
+only when a new top level domain
+joined the network.
+A message to a host in a subdomain
+could simply be routed to a known domain gateway
+for further processing.
+For example,
+the address
+.q eric@a.bli.UUCP
+might be routed to the
+.q bli
+gateway
+for redistribution;
+new hosts could be added
+within BLI
+without notifying the rest of the world.
+Of course,
+other hosts
+.i could
+be notified as an efficiency measure.
+.pp
+There may be more than one domain gateway.
+A domain such as BTL,
+for instance,
+might have a dozen gateways to the outside world;
+a non-BTL site
+could choose the closest gateway.
+The only restriction
+would be that all gateways
+maintain a consistent view of the domain
+they represent.
+.sh 2 "Logical Structure"
+.pp
+Logically,
+domains are organized into a tree.
+There need not be a host actually associated
+with each level in the tree \*-
+for example,
+there will be no host associated with the name
+.q UUCP.
+Similarly,
+an organization might group names together for administrative reasons;
+for example,
+the name
+.(l
+CAD.research.BigCorp.UUCP
+.)l
+might not actually have a host representing
+.q research.
+.pp
+However,
+it may frequently be convenient to have a host
+or hosts
+that
+.q represent
+a domain.
+For example,
+if a single host exists that
+represents
+Berkeley,
+then mail from outside Berkeley
+can forward mail to that host
+for further resolution
+without knowing Berkeley's
+(rather volatile)
+topology.
+This is not unlike the operation
+of the telephone network.
+.pp
+This may also be useful
+inside certain large domains.
+For example,
+at Berkeley it may be presumed
+that most hosts know about other hosts
+inside the Berkeley domain.
+But if they process an address
+that is unknown,
+they can pass it
+.q upstairs
+for further examination.
+Thus as new hosts are added
+only one host
+(the domain master)
+.i must
+be updated immediately;
+other hosts can be updated as convenient.
+.pp
+Ideally this name resolution process
+would be performed by a name server
+(e.g., [Su82b])
+to avoid unnecessary copying
+of the message.
+However,
+in a batch network
+such as UUCP
+this could result in unnecessary delays.
+.sh 1 "COMPARISON WITH DELIVERMAIL"
+.pp
+.i Sendmail
+is an outgrowth of
+.i delivermail .
+The primary differences are:
+.np
+Configuration information is not compiled in.
+This change simplifies many of the problems
+of moving to other machines.
+It also allows easy debugging of new mailers.
+.np
+Address parsing is more flexible.
+For example,
+.i delivermail
+only supported one gateway to any network,
+whereas
+.i sendmail
+can be sensitive to host names
+and reroute to different gateways.
+.np
+Forwarding and
+:include:
+features eliminate the requirement that the system alias file
+be writable by any user
+(or that an update program be written,
+or that the system administration make all changes).
+.np
+.i Sendmail
+supports message batching across networks
+when a message is being sent to multiple recipients.
+.np
+A mail queue is provided in
+.i sendmail.
+Mail that cannot be delivered immediately
+but can potentially be delivered later
+is stored in this queue for a later retry.
+The queue also provides a buffer against system crashes;
+after the message has been collected
+it may be reliably redelivered
+even if the system crashes during the initial delivery.
+.np
+.i Sendmail
+uses the networking support provided by 4.2BSD
+to provide a direct interface networks such as the ARPANET
+and/or Ethernet
+using SMTP (the Simple Mail Transfer Protocol)
+over a TCP/IP connection.
+.+c
+.ce
+REFERENCES
+.nr ii 1.5i
+.ip [Crocker77]
+Crocker, D. H.,
+Vittal, J. J.,
+Pogran, K. T.,
+and
+Henderson, D. A. Jr.,
+.ul
+Standard for the Format of ARPA Network Text Messages.
+RFC 733,
+NIC 41952.
+In [Feinler78].
+November 1977.
+.ip [Crocker82]
+Crocker, D. H.,
+.ul
+Standard for the Format of Arpa Internet Text Messages.
+RFC 822.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1982.
+.ip [Feinler78]
+Feinler, E.,
+and
+Postel, J.
+(eds.),
+.ul
+ARPANET Protocol Handbook.
+NIC 7104,
+Network Information Center,
+SRI International,
+Menlo Park, California.
+1978.
+.ip [Nowitz78]
+Nowitz, D. A.,
+and
+Lesk, M. E.,
+.ul
+A Dial-Up Network of UNIX Systems.
+Bell Laboratories.
+In
+UNIX Programmer's Manual, Seventh Edition,
+Volume 2.
+August, 1978.
+.ip [Schmidt79]
+Schmidt, E.,
+.ul
+An Introduction to the Berkeley Network.
+University of California, Berkeley California.
+1979.
+.ip [Shoens79]
+Shoens, K.,
+.ul
+Mail Reference Manual.
+University of California, Berkeley.
+In UNIX Programmer's Manual,
+Seventh Edition,
+Volume 2C.
+December 1979.
+.ip [Solomon81]
+Solomon, M.,
+Landweber, L.,
+and
+Neuhengen, D.,
+.ul
+The Design of the CSNET Name Server.
+CS-DN-2.
+University of Wisconsin,
+Madison.
+October 1981.
+.ip [Su82a]
+Su, Zaw-Sing,
+and
+Postel, Jon,
+.ul
+The Domain Naming Convention for Internet User Applications.
+RFC819.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+August 1982.
+.ip [Su82b]
+Su, Zaw-Sing,
+.ul
+A Distributed System for Internet Name Service.
+RFC830.
+Network Information Center,
+SRI International,
+Menlo Park, California.
+October 1982.
diff --git a/usr.sbin/sendmail/mailstats/Makefile b/usr.sbin/sendmail/mailstats/Makefile
new file mode 100644
index 00000000000..d6a04f0bdc1
--- /dev/null
+++ b/usr.sbin/sendmail/mailstats/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+PROG= mailstats
+CFLAGS+=-I${.CURDIR}/../src
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/mailstats/mailstats.c b/usr.sbin/sendmail/mailstats/mailstats.c
new file mode 100644
index 00000000000..1e11b014cd0
--- /dev/null
+++ b/usr.sbin/sendmail/mailstats/mailstats.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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[] = "@(#)mailstats.c 8.3 (Berkeley) 12/27/93";
+#endif /* not lint */
+
+#include <sendmail.h>
+#include <mailstats.h>
+#include <pathnames.h>
+
+#define MNAMELEN 20 /* max length of mailer name */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ struct statistics stat;
+ register int i;
+ int mno;
+ int ch, fd;
+ char *sfile;
+ char *cfile;
+ FILE *cfp;
+ bool mnames;
+ long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0;
+ char mtable[MAXMAILERS][MNAMELEN+1];
+ char sfilebuf[100];
+ char buf[MAXLINE];
+ extern char *ctime();
+
+ cfile = _PATH_SENDMAILCF;
+ sfile = NULL;
+ mnames = TRUE;
+ while ((ch = getopt(argc, argv, "C:f:o")) != EOF)
+ {
+ switch (ch)
+ {
+ case 'C':
+ cfile = optarg;
+ break;
+
+ case 'f':
+ sfile = optarg;
+ break;
+
+ case 'o':
+ mnames = FALSE;
+ break;
+
+ case '?':
+ default:
+ usage:
+ fputs("usage: mailstats [-C cffile] [-f stfile]\n", stderr);
+ exit(EX_USAGE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ goto usage;
+
+ if ((cfp = fopen(cfile, "r")) == NULL)
+ {
+ fprintf(stderr, "mailstats: ");
+ perror(cfile);
+ exit(EX_NOINPUT);
+ }
+
+ mno = 0;
+ (void) strcpy(mtable[mno++], "prog");
+ (void) strcpy(mtable[mno++], "*file*");
+ (void) strcpy(mtable[mno++], "*include*");
+
+ while (fgets(buf, sizeof(buf), cfp) != NULL)
+ {
+ register char *b;
+ char *s;
+ register char *m;
+
+ b = buf;
+ switch (*b++)
+ {
+ case 'M': /* mailer definition */
+ break;
+
+ case 'O': /* option -- see if .st file */
+ if (*b++ != 'S')
+ continue;
+
+ /* yep -- save this */
+ strcpy(sfilebuf, b);
+ b = strchr(sfilebuf, '\n');
+ if (b != NULL)
+ *b = '\0';
+ if (sfile == NULL)
+ sfile = sfilebuf;
+
+ default:
+ continue;
+ }
+
+ if (mno >= MAXMAILERS)
+ {
+ fprintf(stderr,
+ "Too many mailers defined, %d max.\n",
+ MAXMAILERS);
+ exit(EX_SOFTWARE);
+ }
+ m = mtable[mno];
+ s = m + MNAMELEN; /* is [MNAMELEN+1] */
+ while (*b != ',' && !isspace(*b) && *b != '\0' && m < s)
+ *m++ = *b++;
+ *m = '\0';
+ for (i = 0; i < mno; i++)
+ {
+ if (strcmp(mtable[i], mtable[mno]) == 0)
+ break;
+ }
+ if (i == mno)
+ mno++;
+ }
+ (void) fclose(cfp);
+ for (; mno < MAXMAILERS; mno++)
+ mtable[mno][0]='\0';
+
+ if (sfile == NULL)
+ {
+ fprintf(stderr, "mailstats: no statistics file located\n");
+ exit (EX_OSFILE);
+ }
+
+ if ((fd = open(sfile, O_RDONLY)) < 0) {
+ fputs("mailstats: ", stderr);
+ perror(sfile);
+ exit(EX_NOINPUT);
+ }
+ if (read(fd, &stat, sizeof(stat)) != sizeof(stat) ||
+ stat.stat_size != sizeof(stat))
+ {
+ fputs("mailstats: file size changed.\n", stderr);
+ exit(EX_OSERR);
+ }
+
+ printf("Statistics from %s", ctime(&stat.stat_itime));
+ printf(" M msgsfr bytes_from msgsto bytes_to%s\n",
+ mnames ? " Mailer" : "");
+ for (i = 0; i < MAXMAILERS; i++)
+ {
+ if (stat.stat_nf[i] || stat.stat_nt[i])
+ {
+ printf("%2d %6ld %10ldK %6ld %10ldK", i,
+ stat.stat_nf[i], stat.stat_bf[i],
+ stat.stat_nt[i], stat.stat_bt[i]);
+ if (mnames)
+ printf(" %s", mtable[i]);
+ printf("\n");
+ frmsgs += stat.stat_nf[i];
+ frbytes += stat.stat_bf[i];
+ tomsgs += stat.stat_nt[i];
+ tobytes += stat.stat_bt[i];
+ }
+ }
+ printf("========================================\n");
+ printf(" T %6ld %10ldK %6ld %10ldK\n",
+ frmsgs, frbytes, tomsgs, tobytes);
+ exit(EX_OK);
+}
diff --git a/usr.sbin/sendmail/makemap/Makefile b/usr.sbin/sendmail/makemap/Makefile
new file mode 100644
index 00000000000..a8592fec10a
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+PROG= makemap
+MAN= makemap.8
+CFLAGS+=-I${.CURDIR}/../src -DNDBM -DNEWDB
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/makemap/makemap.8 b/usr.sbin/sendmail/makemap/makemap.8
new file mode 100644
index 00000000000..2ee45c2dd86
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/makemap.8
@@ -0,0 +1,128 @@
+.\" Copyright (c) 1988, 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.
+.\"
+.\" @(#)makemap.8 8.2 (Berkeley) 9/22/93
+.\"
+.Dd November 16, 1992
+.Dt MAKEMAP 8
+.Os BSD 4.4
+.Sh NAME
+.Nm makemap
+.Nd create database maps for sendmail
+.Sh SYNOPSIS
+.Nm
+.Op Fl N
+.Op Fl f
+.Op Fl o
+.Op Fl r
+.Op Fl v
+.Ar maptype
+.Ar mapname
+.Sh DESCRIPTION
+.Nm
+creates the database maps used by the keyed map lookups in
+.Xr sendmail 8 .
+It reads input from the standard input
+and outputs them to the indicated
+.Ar mapname .
+.Pp
+Depending on how it is compiled,
+.Nm
+handles up to three different database formats,
+selected using the
+.Ar maptype
+parameter.
+They may be
+.Bl -tag -width Fl
+.It Li dbm
+DBM format maps.
+This requires the
+.Xr ndbm 3
+library.
+.It Li btree
+B-Tree format maps.
+This requires the new Berkeley
+.Xr db 3
+library.
+.It Li hash
+Hash format maps.
+This also requires the
+.Xr db 3
+library.
+.El
+.Pp
+In all cases,
+.Nm
+reads lines from the standard input consisting of two
+words separated by white space.
+The first is the database key,
+the second is the value.
+The value may contain
+``%\fIn\fP''
+strings to indicated parameter substitution.
+Literal parentheses should be doubled
+(``%%'').
+Blank lines and lines beginning with ``#'' are ignored.
+.Ss Flags
+.Bl -tag -width Fl
+.It Fl N
+Include the null byte that terminates strings
+in the map.
+This must match the \-N flag in the sendmail.cf
+``K'' line.
+.It Fl f
+Normally all upper case letters in the key
+are folded to lower case.
+This flag disables that behaviour.
+This is intended to mesh with the
+\-f flag in the
+\fBK\fP
+line in sendmail.cf.
+The value is never case folded.
+.It Fl o
+Append to an old file.
+This allows you to augment an existing file.
+.It Fl r
+Allow replacement of existing keys.
+Normally
+.Nm
+complains if you repeat a key,
+and does not do the insert.
+.It Fl v
+Verbosely print what it is doing.
+.El
+.Sh SEE ALSO
+.Xr sendmail 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/usr.sbin/sendmail/makemap/makemap.c b/usr.sbin/sendmail/makemap/makemap.c
new file mode 100644
index 00000000000..a676cd7f43b
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/makemap.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 1992 Eric P. Allman.
+ * Copyright (c) 1992, 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 sccsid[] = "@(#)makemap.c 8.6.1.1 (Berkeley) 3/6/95";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <ctype.h>
+#include <string.h>
+#include "useful.h"
+#include "conf.h"
+
+#ifdef NDBM
+#include <ndbm.h>
+#endif
+
+#ifdef NEWDB
+#include <db.h>
+#endif
+
+enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN };
+
+union dbent
+{
+#ifdef NDBM
+ datum dbm;
+#endif
+#ifdef NEWDB
+ DBT db;
+#endif
+ struct
+ {
+ char *data;
+ size_t size;
+ } xx;
+};
+
+#define BUFSIZE 1024
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ bool inclnull = FALSE;
+ bool notrunc = FALSE;
+ bool allowreplace = FALSE;
+ bool verbose = FALSE;
+ bool foldcase = TRUE;
+ int exitstat;
+ int opt;
+ char *typename;
+ char *mapname;
+ char *ext;
+ int lineno;
+ int st;
+ int mode;
+ enum type type;
+ union
+ {
+#ifdef NDBM
+ DBM *dbm;
+#endif
+#ifdef NEWDB
+ DB *db;
+#endif
+ void *dbx;
+ } dbp;
+ union dbent key, val;
+ char ibuf[BUFSIZE];
+ char fbuf[MAXNAME];
+ extern char *optarg;
+ extern int optind;
+
+ progname = argv[0];
+
+ while ((opt = getopt(argc, argv, "Nforv")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'N':
+ inclnull = TRUE;
+ break;
+
+ case 'f':
+ foldcase = FALSE;
+ break;
+
+ case 'o':
+ notrunc = TRUE;
+ break;
+
+ case 'r':
+ allowreplace = TRUE;
+ break;
+
+ case 'v':
+ verbose = TRUE;
+ break;
+
+ default:
+ type = T_ERR;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 2)
+ type = T_ERR;
+ else
+ {
+ typename = argv[0];
+ mapname = argv[1];
+ ext = NULL;
+
+ if (strcmp(typename, "dbm") == 0)
+ {
+ type = T_DBM;
+ }
+ else if (strcmp(typename, "btree") == 0)
+ {
+ type = T_BTREE;
+ ext = ".db";
+ }
+ else if (strcmp(typename, "hash") == 0)
+ {
+ type = T_HASH;
+ ext = ".db";
+ }
+ else
+ type = T_UNKNOWN;
+ }
+
+ switch (type)
+ {
+ case T_ERR:
+ fprintf(stderr, "Usage: %s [-N] [-o] [-v] type mapname\n", progname);
+ exit(EX_USAGE);
+
+ case T_UNKNOWN:
+ fprintf(stderr, "%s: Unknown database type %s\n",
+ progname, typename);
+ exit(EX_USAGE);
+
+#ifndef NDBM
+ case T_DBM:
+#endif
+#ifndef NEWDB
+ case T_BTREE:
+ case T_HASH:
+#endif
+ fprintf(stderr, "%s: Type %s not supported in this version\n",
+ progname, typename);
+ exit(EX_UNAVAILABLE);
+ }
+
+ /*
+ ** Adjust file names.
+ */
+
+ if (ext != NULL)
+ {
+ int el, fl;
+
+ el = strlen(ext);
+ fl = strlen(mapname);
+ if (fl < el || strcmp(&mapname[fl - el], ext) != 0)
+ {
+ strcpy(fbuf, mapname);
+ strcat(fbuf, ext);
+ mapname = fbuf;
+ }
+ }
+
+ /*
+ ** Create the database.
+ */
+
+ mode = O_RDWR;
+ if (!notrunc)
+ mode |= O_CREAT|O_TRUNC;
+ switch (type)
+ {
+#ifdef NDBM
+ case T_DBM:
+ dbp.dbm = dbm_open(mapname, mode, 0644);
+ break;
+#endif
+
+#ifdef NEWDB
+ case T_HASH:
+ dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL);
+ if (dbp.db != NULL)
+ (void) (*dbp.db->sync)(dbp.db, 0);
+ break;
+
+ case T_BTREE:
+ dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
+ if (dbp.db != NULL)
+ (void) (*dbp.db->sync)(dbp.db, 0);
+ break;
+#endif
+
+ default:
+ fprintf(stderr, "%s: internal error: type %d\n", progname, type);
+ exit(EX_SOFTWARE);
+ }
+
+ if (dbp.dbx == NULL)
+ {
+ fprintf(stderr, "%s: cannot create type %s map %s\n",
+ progname, typename, mapname);
+ exit(EX_CANTCREAT);
+ }
+
+ /*
+ ** Copy the data
+ */
+
+ lineno = 0;
+ exitstat = EX_OK;
+ while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
+ {
+ register char *p;
+
+ lineno++;
+
+ /*
+ ** Parse the line.
+ */
+
+ p = strchr(ibuf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ else if (!feof(stdin))
+ {
+ fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n",
+ progname, mapname, lineno, sizeof ibuf);
+ continue;
+ }
+
+ if (ibuf[0] == '\0' || ibuf[0] == '#')
+ continue;
+ if (isspace(ibuf[0]))
+ {
+ fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n",
+ progname, mapname, lineno);
+ continue;
+ }
+ key.xx.data = ibuf;
+ for (p = ibuf; *p != '\0' && !isspace(*p); p++)
+ {
+ if (foldcase && isupper(*p))
+ *p = tolower(*p);
+ }
+ key.xx.size = p - key.xx.data;
+ if (inclnull)
+ key.xx.size++;
+ if (*p != '\0')
+ *p++ = '\0';
+ while (isspace(*p))
+ p++;
+ if (*p == '\0')
+ {
+ fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n",
+ progname, mapname, lineno, key.xx.data);
+ continue;
+ }
+ val.xx.data = p;
+ val.xx.size = strlen(p);
+ if (inclnull)
+ val.xx.size++;
+
+ /*
+ ** Do the database insert.
+ */
+
+ if (verbose)
+ {
+ printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data);
+ }
+
+ switch (type)
+ {
+#ifdef NDBM
+ case T_DBM:
+ st = dbm_store(dbp.dbm, key.dbm, val.dbm,
+ allowreplace ? DBM_REPLACE : DBM_INSERT);
+ break;
+#endif
+
+#ifdef NEWDB
+ case T_BTREE:
+ case T_HASH:
+ st = (*dbp.db->put)(dbp.db, &key.db, &val.db,
+ allowreplace ? 0 : R_NOOVERWRITE);
+ break;
+#endif
+ }
+
+ if (st < 0)
+ {
+ fprintf(stderr, "%s: %s: line %d: key %s: put error\n",
+ progname, mapname, lineno, key.xx.data);
+ perror(mapname);
+ exitstat = EX_IOERR;
+ }
+ else if (st > 0)
+ {
+ fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n",
+ progname, mapname, lineno, key.xx.data);
+ }
+ }
+
+ /*
+ ** Now close the database.
+ */
+
+ switch (type)
+ {
+#ifdef NDBM
+ case T_DBM:
+ dbm_close(dbp.dbm);
+ break;
+#endif
+
+#ifdef NEWDB
+ case T_HASH:
+ case T_BTREE:
+ if ((*dbp.db->close)(dbp.db) < 0)
+ {
+ fprintf(stderr, "%s: %s: error on close\n",
+ progname, mapname);
+ perror(mapname);
+ exitstat = EX_IOERR;
+ }
+#endif
+ }
+
+ exit (exitstat);
+}
diff --git a/usr.sbin/sendmail/praliases/Makefile b/usr.sbin/sendmail/praliases/Makefile
new file mode 100644
index 00000000000..621bea8f66f
--- /dev/null
+++ b/usr.sbin/sendmail/praliases/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+PROG= praliases
+CFLAGS+=-I${.CURDIR}/../src
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/praliases/praliases.c b/usr.sbin/sendmail/praliases/praliases.c
new file mode 100644
index 00000000000..2c22279205e
--- /dev/null
+++ b/usr.sbin/sendmail/praliases/praliases.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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[] = "@(#)praliases.c 8.3 (Berkeley) 3/6/94";
+#endif /* not lint */
+
+#include <ndbm.h>
+#include <sendmail.h>
+#ifdef NEWDB
+#include <db.h>
+#endif
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ DBM *dbp;
+ datum content, key;
+ char *filename;
+ int ch;
+#ifdef NEWDB
+ const DB *db;
+ DBT newdbkey, newdbcontent;
+ char buf[MAXNAME];
+#endif
+
+ filename = "/etc/aliases";
+ while ((ch = getopt(argc, argv, "f:")) != EOF)
+ switch((char)ch) {
+ case 'f':
+ filename = optarg;
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: praliases [-f file]\n");
+ exit(EX_USAGE);
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef NEWDB
+ (void) strcpy(buf, filename);
+ (void) strcat(buf, ".db");
+ if (db = dbopen(buf, O_RDONLY, 0444 , DB_HASH, NULL)) {
+ if (!argc) {
+ while(!db->seq(db, &newdbkey, &newdbcontent, R_NEXT))
+ printf("%.*s:%.*s\n",
+ newdbkey.size, newdbkey.data,
+ newdbcontent.size, newdbcontent.data);
+ }
+ else for (; *argv; ++argv) {
+ newdbkey.data = *argv;
+ newdbkey.size = strlen(*argv) + 1;
+ if (!db->get(db, &newdbkey, &newdbcontent, 0))
+ printf("%s:%.*s\n", newdbkey.data,
+ newdbcontent.size, newdbcontent.data);
+ else
+ printf("%s: No such key\n",
+ newdbkey.data);
+ }
+ }
+ else {
+#endif
+ if ((dbp = dbm_open(filename, O_RDONLY, 0)) == NULL) {
+ (void)fprintf(stderr,
+ "praliases: %s: %s\n", filename, strerror(errno));
+ exit(EX_OSFILE);
+ }
+ if (!argc)
+ for (key = dbm_firstkey(dbp);
+ key.dptr != NULL; key = dbm_nextkey(dbp)) {
+ content = dbm_fetch(dbp, key);
+ (void)printf("%.*s:%.*s\n",
+ key.dsize, key.dptr,
+ content.dsize, content.dptr);
+ }
+ else for (; *argv; ++argv) {
+ key.dptr = *argv;
+ key.dsize = strlen(*argv) + 1;
+ content = dbm_fetch(dbp, key);
+ if (!content.dptr)
+ (void)printf("%s: No such key\n", key.dptr);
+ else
+ (void)printf("%s:%.*s\n", key.dptr,
+ content.dsize, content.dptr);
+ }
+#ifdef NEWDB
+ }
+#endif
+ exit(EX_OK);
+}
diff --git a/usr.sbin/sendmail/src/Makefile b/usr.sbin/sendmail/src/Makefile
new file mode 100644
index 00000000000..aa843bbe4a8
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile
@@ -0,0 +1,42 @@
+#
+# NetBSD Makefile
+#
+# @(#)Makefile.NetBSD 8.1 (Berkeley) 2/26/94
+# @Id: Makefile.NetBSD,v 1.3 1994/02/01 05:33:44 glass Exp $
+#
+
+PROG= sendmail
+
+# define the database format to use for aliases et al. Can be -DNEWDB (for
+# the new BSD database package -- this is preferred) or -DNDBM for the NDBM
+# database package. The old putrescent V7 DBM package is no longer
+# supported.
+# You can define both NEWDB and NDBM during a transition period; old
+# databases are read, but the new format will be used on any rebuilds. On
+# really gnarly systems, you can set this to null; it will crawl like a high
+# spiral snail, but it will work.
+DBMDEF= -DNEWDB -DNIS
+
+CFLAGS+=-I${.CURDIR} ${DBMDEF} -DNETISO
+
+SRCS= alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \
+ deliver.c domain.c envelope.c err.c headers.c macro.c main.c map.c \
+ mci.c parseaddr.c queue.c readcf.c recipient.c savemail.c srvrsmtp.c \
+ stab.c stats.c sysexits.c trace.c udb.c usersmtp.c \
+ util.c version.c
+MAN= aliases.5 mailq.1 newaliases.1 sendmail.8
+LINKS= /usr/sbin/sendmail /usr/bin/newaliases \
+ /usr/sbin/sendmail /usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINMODE=4555
+
+beforeinstall:
+# install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+# ${DESTDIR}/etc/sendmail.fc
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${DESTDIR}/var/log/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/sendmail.hf \
+ ${DESTDIR}/usr/share/misc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/src/Makefile.BSD44 b/usr.sbin/sendmail/src/Makefile.BSD44
new file mode 100644
index 00000000000..ebeacd01622
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.BSD44
@@ -0,0 +1,46 @@
+#
+# NetBSD Makefile
+#
+# @(#)Makefile.NetBSD 8.1 (Berkeley) 2/26/94
+# @Id: Makefile.NetBSD,v 1.3 1994/02/01 05:33:44 glass Exp $
+#
+
+PROG= sendmail
+
+# define the database format to use for aliases et al. Can be -DNEWDB (for
+# the new BSD database package -- this is preferred) or -DNDBM for the NDBM
+# database package. The old putrescent V7 DBM package is no longer
+# supported.
+# You can define both NEWDB and NDBM during a transition period; old
+# databases are read, but the new format will be used on any rebuilds. On
+# really gnarly systems, you can set this to null; it will crawl like a high
+# spiral snail, but it will work.
+DBMDEF= -DNEWDB -DNIS
+
+#nasty warning about gcc 2.4.x caused bugs
+CFLAGS=-I${.CURDIR} ${DBMDEF} -DNETISO
+#CFLAGS+=-I${.CURDIR} ${DBMDEF} -DNETISO
+
+SRCS= alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \
+ deliver.c domain.c envelope.c err.c headers.c macro.c main.c map.c \
+ mci.c parseaddr.c queue.c readcf.c recipient.c savemail.c srvrsmtp.c \
+ stab.c stats.c sysexits.c trace.c udb.c usersmtp.c \
+ util.c version.c
+MAN1= mailq.0 newaliases.0
+MAN5= aliases.0
+MAN8= sendmail.0
+LINKS= /usr/sbin/sendmail /usr/bin/newaliases \
+ /usr/sbin/sendmail /usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINMODE=4555
+
+beforeinstall:
+# install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+# ${DESTDIR}/etc/sendmail.fc
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${DESTDIR}/var/log/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/sendmail.hf \
+ ${DESTDIR}/usr/share/misc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/src/Makefile.NetBSD b/usr.sbin/sendmail/src/Makefile.NetBSD
new file mode 100644
index 00000000000..aa843bbe4a8
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.NetBSD
@@ -0,0 +1,42 @@
+#
+# NetBSD Makefile
+#
+# @(#)Makefile.NetBSD 8.1 (Berkeley) 2/26/94
+# @Id: Makefile.NetBSD,v 1.3 1994/02/01 05:33:44 glass Exp $
+#
+
+PROG= sendmail
+
+# define the database format to use for aliases et al. Can be -DNEWDB (for
+# the new BSD database package -- this is preferred) or -DNDBM for the NDBM
+# database package. The old putrescent V7 DBM package is no longer
+# supported.
+# You can define both NEWDB and NDBM during a transition period; old
+# databases are read, but the new format will be used on any rebuilds. On
+# really gnarly systems, you can set this to null; it will crawl like a high
+# spiral snail, but it will work.
+DBMDEF= -DNEWDB -DNIS
+
+CFLAGS+=-I${.CURDIR} ${DBMDEF} -DNETISO
+
+SRCS= alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \
+ deliver.c domain.c envelope.c err.c headers.c macro.c main.c map.c \
+ mci.c parseaddr.c queue.c readcf.c recipient.c savemail.c srvrsmtp.c \
+ stab.c stats.c sysexits.c trace.c udb.c usersmtp.c \
+ util.c version.c
+MAN= aliases.5 mailq.1 newaliases.1 sendmail.8
+LINKS= /usr/sbin/sendmail /usr/bin/newaliases \
+ /usr/sbin/sendmail /usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINMODE=4555
+
+beforeinstall:
+# install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+# ${DESTDIR}/etc/sendmail.fc
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${DESTDIR}/var/log/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/sendmail.hf \
+ ${DESTDIR}/usr/share/misc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/src/READ_ME b/usr.sbin/sendmail/src/READ_ME
new file mode 100644
index 00000000000..ace0d3ab9bb
--- /dev/null
+++ b/usr.sbin/sendmail/src/READ_ME
@@ -0,0 +1,883 @@
+# Copyright (c) 1983 Eric P. Allman
+# Copyright (c) 1988 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.
+#
+# @(#)READ_ME 8.61.1.1 (Berkeley) 3/5/95
+#
+
+This directory contains the source files for sendmail.
+
+For detailed instructions, please read the document ../doc/op.me:
+
+ eqn ../doc/op.me | pic | ditroff -me
+
+The Makefile is for the new (4.4BSD) Berkeley make and uses syntax
+that is not recognized by older makes. It also has assumptions
+about the 4.4 file system layout built in. See below for details
+about other Makefiles.
+
+There is also a Makefile.dist which is much less clever, but works on
+the old traditional make. You can use this using:
+
+ make -f Makefile.dist
+
+**************************************************
+** Read below for more details of Makefiles. **
+**************************************************
+
+There is also a shell script (makesendmail) that tries to be clever
+about using object subdirectories. It's pretty straightforward, and
+may help if you share a source tree among different architectures.
+
+**************************************************************************
+** IMPORTANT: DO NOT USE OPTIMIZATION (``-O'') IF YOU ARE RUNNING **
+** GCC 2.4.x or 2.5.x. THERE IS A BUG IN THE GCC OPTIMIZER THAT **
+** CAUSES SENDMAIL COMPILES TO FAIL MISERABLY. **
+**************************************************************************
+
+Jim Wilson of Cygnus believes he has found the problem -- it will
+probably be fixed in GCC 2.5.6 -- but until this is verified, be
+very suspicious of gcc -O.
+
+**************************************************************************
+** IMPORTANT: Read the appropriate paragraphs in the section on **
+** ``Operating System and Compile Quirks''. **
+**************************************************************************
+
+
++-----------+
+| MAKEFILES |
++-----------+
+
+The "Makefile"s in these directories are from 4.4 BSD, and hence
+really only work properly if you are on a 4.4 system. In particular,
+they use new syntax that will not be recognized on old make programs,
+and some of them do things like ``.include ../../Makefile.inc'' to
+pick up some system defines. If you are getting sendmail separately,
+these files won't be included in the distribution, as they are
+outside of the sendmail tree.
+
+Instead, you should use one of the other Makefiles, such as
+Makefile.SunOS for a SunOS system, and so forth. These should
+work with the version of make that is appropriate for that
+system.
+
+There are a bunch of other Makefiles for other systems with names
+like Makefile.HPUX for an HP-UX system. They use the version of
+make that is native for that system. These are the Makefiles that
+I use, and they have "Berkeley quirks" in them. I can't guarantee
+that they will work unmodified in your environment. Many of them
+include -I/usr/sww/include/db and -L/usr/sww/lib -- this is Berkeley's
+location (the ``Software Warehouse'') for the new database libraries,
+described below. You don't have to remove these definitions if you
+don't have these directories.
+
+Please look for an appropriate Makefile before you start trying to
+compile with Makefile or Makefile.dist.
+
+If you want to port the new Berkeley make, you can get it from
+ftp.uu.net in the directory /systems/unix/bsd-sources/usr.bin/make.
+Diffs and instructions for building this version of make under
+SunOS 4.1.x are available on ftp.css.itd.umich.edu in
+/pub/systems/sun/Net2-make.sun4.diff.Z. Diffs and instructions
+for building this version of make under IBM AIX 3.2.4 are available
+on ftp.uni-stuttgart.de in /sw/src/patches/bsd-make-rus-patches.
+Paul Southworth <pauls@umich.edu> published a description of porting
+this make in comp.unix.bsd.
+
+The complete text of the Makefile.inc that is in the parent of the
+sendmail directory is:
+
+ # @(#)Makefile.inc 8.1 (Berkeley) 6/6/93
+
+ BINDIR?= /usr/sbin
+
+
++----------------------+
+| DATABASE DEFINITIONS |
++----------------------+
+
+There are several database formats that can be used for the alias files
+and for general maps. When used for alias files they interact in an
+attempt to be back compatible.
+
+The three options are NEWDB (the new Berkeley DB package), NDBM (the
+older DBM implementation -- the very old V7 implementation is no
+longer supported), and NIS (Network Information Services). Used alone
+these just include the support they indicate. [If you are using NEWDB,
+get the latest version from FTP.CS.Berkeley.EDU in /ucb/4bsd. DO NOT
+use the version from the Net2 distribution! However, if you are on
+BSD/386 or 386BSD-based systems, use the one that already exists
+on your system. You may need to #define OLD_NEWDB 1 to do this.]
+
+[NOTE WELL: it is CRITICAL that you remove ndbm.o from libdb.a and
+ndbm.h from the appropriate include directories if you want to get
+ndbm support. These files OVERRIDE calls to ndbm routines -- in
+particular, if you leave ndbm.h in, you can find yourself using
+the new db package even if you don't define NEWDB.]
+
+If NEWDB and NDBM are defined (but not NIS), then sendmail will read
+NDBM format alias files, but the next time a newaliases is run the
+format will be converted to NEWDB; that format will be used forever
+more. This is intended as a transition feature. [Note however that
+the NEWDB library also catches and maps NDBM calls; you will have to
+back out this feature to get this to work. See ``Quirks'' section
+below for details.]
+
+If all three are defined, sendmail operates as described above, and also
+looks for the file /var/yp/Makefile. If it exists, newaliases will
+build BOTH the NEWDB and NDBM format alias files. However, it will
+only use the NEWDB file; the NDBM format file is used only by the
+NIS subsystem.
+
+If NDBM and NIS are defined (regardless of the definition of NEWDB
+or the existance of /var/yp/Makefile), sendmail adds the special
+tokens "YP_LAST_MODIFIED" and "YP_MASTER_NAME", both of which are
+required if the NDBM file is to be used as an NIS map.
+
+All of -DNEWDB, -DNDBM, and -DNIS are normally defined in the DBMDEF
+line in the Makefile.
+
+
++---------------+
+| COMPILE FLAGS |
++---------------+
+
+Whereever possible, I try to make sendmail pull in the correct
+compilation options needed to compile on various environments based on
+automatically defined symbols. Some machines don't seem to have useful
+symbols availble, requiring the following compilation flags in the
+Makefile:
+
+SOLARIS Define this if you are running Solaris 2.0 or higher.
+SOLARIS_2_3 Define this if you are running Solaris 2.3 or higher.
+SUNOS403 Define this if you are running SunOS 4.0.3.
+NeXT Define this if you are on a NeXT box. (This one may
+ be pre-defined for you.) There are other hacks you
+ have to make -- see below.
+_AIX3 Define this if you are IBM AIX 3.x.
+RISCOS Define this if you are running RISC/os from MIPS.
+IRIX Define this if you are running IRIX from SGI.
+_SCO_unix_ Define this if you are on SCO UNIX.
+_SCO_unix_4_2 Define this if you are on SCO Open Server 3.2v4.
+
+If you are a system that sendmail has already been ported to, you
+probably won't have to touch these. But if you are porting, you may
+have to tweak the following compilation flags in conf.h in order to
+get it to compile and link properly:
+
+SYSTEM5 Adjust for System V (not necessarily Release 4).
+SYS5SIGNALS Use System V signal semantics -- the signal handler
+ is automatically dropped when the signal is caught.
+ If this is not set, use POSIX/BSD semantics, where the
+ signal handler stays in force until an exec or an
+ explicit delete. Implied by SYSTEM5.
+SYS5SETPGRP Use System V setpgrp() semantics. Implied by SYSTEM5.
+HASFLOCK Set this if you prefer to use the flock(2) system call
+ rather than using fcntl-based locking. Fcntl locking
+ has some semantic gotchas, but many vendor systems
+ also interface it to lockd(8) to do NFS-style locking.
+ For this reason, this should not be set unless you
+ don't have an alternative.
+HASUNAME Set if you have the "uname" system call. Implied by
+ SYSTEM5.
+HASUNSETENV Define this if your system library has the "unsetenv"
+ subroutine.
+HASSETSID Define this if you have the setsid(2) system call. This
+ is implied if your system appears to be POSIX compliant.
+HASINITGROUPS Define this if you have the initgroups(3) routine.
+HASSETVBUF Define this if you have the setvbuf(3) library call.
+ If you don't, setlinebuf will be used instead. This
+ defaults on if your compiler defines __STDC__.
+HASSETREUID Define this if you have setreuid(2) ***AND*** root can
+ use setreuid to change to an arbitrary user. This second
+ condition is not satisfied on AIX 3.x. You may find that
+ your system has setresuid(2), (for example, on HP-UX) in
+ which case you will also have to #define setreuid(r, e)
+ to be the appropriate call. Some systems (such as Solaris)
+ have a compatibility routine that doesn't work properly,
+ but may have "saved user ids" properly implemented so you
+ can ``#define setreuid(r, e) seteuid(e)'' and have it work.
+ The important thing is that you have a call that will set
+ the effective uid independently of the real or saved uid
+ and be able to set the effective uid back again when done.
+ There's a test program in ../test/t_setreuid.c that will
+ try things on your system. Setting this improves the
+ security, since sendmail doesn't have to read .forward
+ and :include: files as root. There are certain attacks
+ that may be unpreventable without this call.
+HASLSTAT Define this if you have symbolic links (and thus the
+ lstat(2) system call). This improves security. Unlike
+ most other options, this one is on by default, so you
+ need to #undef it in conf.h if you don't have symbolic
+ links (these days everyone does).
+NEEDGETOPT Define this if you need a reimplementation of getopt(3).
+ On some systems, getopt does very odd things if called
+ to scan the arguments twice. This flag will ask sendmail
+ to compile in a local version of getopt that works
+ properly.
+NEEDSTRTOL Define this if your standard C library does not define
+ strtol(3). This will compile in a local version.
+NEEDVPRINTF Define this if your standard C library does not define
+ vprintf(3). Note that the resulting fake implementation
+ is not very elegant and may not even work on some
+ architectures.
+NEEDFSYNC Define this if your standard C library does not define
+ fsync(2). This will try to simulate the operation using
+ fcntl(2); if that is not available it does nothing, which
+ isn't great, but at least it compiles and runs.
+HASGETUSERSHELL Define this to 1 if you have getusershell(3) in your
+ standard C library. If this is not defined, or is defined
+ to be 0, sendmail will scan the /etc/shells file (no
+ NIS-style support, defaults to /bin/sh and /bin/csh if
+ that file does not exist) to get a list of unrestricted
+ user shells. This is used to determine whether users
+ are allowed to forward their mail to a program or a file.
+GIDSET_T The type of entries in a gidset passed as the second
+ argument to getgroups(2). Historically this has been an
+ int, so this is the default, but some systems (such as
+ IRIX) pass it as a gid_t, which is an unsigned short.
+ This will make a difference, so it is important to get
+ this right! However, it is only an issue if you have
+ group sets.
+SLEEP_T The type returned by the system sleep() function.
+ Defaults to "unsigned int". Don't worry about this
+ if you don't have compilation problems.
+ARBPTR_T The type of an arbitrary pointer -- defaults to "void *".
+ If you are an very old compiler you may need to define
+ this to be "char *".
+LA_TYPE The type of load average your kernel supports. These
+ can be one of:
+ LA_ZERO (1) -- it always returns the load average as
+ "zero" (and does so on all architectures).
+ LA_SUBR (4) if you have the getloadavg(3) routine,
+ LA_MACH (5) to use MACH-style load averages (calls
+ processor_set_info()),
+ LA_PROCSTR (7) to read /proc/loadavg and interpret it
+ as a string representing a floating-point
+ number (Linux-style),
+ LA_FLOAT (3) if you read kmem and interpret the value
+ as a floating point number,
+ LA_INT (2) to interpret as a long integer,
+ LA_SHORT (6) to interpret as a short integer.
+ These last three have several other parameters that they
+ try to divine: the name of your kernel, the name of the
+ variable in the kernel to examine, the number of bits of
+ precision in a fixed point load average, and so forth.
+ In desperation, use LA_ZERO. The actual code is in
+ conf.c -- it can be tweaked if you are brave.
+SFS_TYPE Encodes how your kernel can locate the amount of free
+ space on a disk partition. This can be set to SFS_NONE
+ (0) if you have no way of getting this information,
+ SFS_USTAT (1) if you have the ustat(2) system call,
+ SFS_4ARGS (2) if you have a four-argument statfs(2)
+ system call (and the include file is <sys/statfs.h>),
+ and SFS_VFS (3), SFS_MOUNT (4), SFS_STATFS (5) or
+ SFS_STATVFS (6) if you have the two-argument statfs(2)
+ system call, with includes in <sys/vfs.h>, <sys/mount.h>,
+ <sys/statfs.h>, or <sys/statvfs.h> respectively. The
+ default if nothing is defined is SFS_NONE.
+ERRLIST_PREDEFINED
+ If set, assumes that some header file defines sys_errlist.
+ This may be needed if you get type conflicts on this
+ variable -- otherwise don't worry about it.
+WAITUNION The wait(2) routine takes a "union wait" argument instead
+ of an integer argument. This is for compatibility with
+ old versions of BSD.
+SCANF You can set this to extend the F command to accept a
+ scanf string -- this gives you a primitive parser for
+ class definitions -- BUT it can make you vulnerable to
+ core dumps if the target file is poorly formed.
+SYSLOG_BUFSIZE You can define this to be the size of the buffer that
+ syslog accepts. If it is not defined, it assumes a
+ 1024-byte buffer. If the buffer is very small (under
+ 256 bytes) the log message format changes -- each
+ e-mail message will log many more messages, since it
+ will log each piece of information as a separate line
+ in syslog.
+BROKEN_RES_SEARCH
+ On Ultrix (and maybe other systems?) if you use the
+ res_search routine with an unknown host name, it returns
+ -1 but sets h_errno to 0 instead of HOST_NOT_FOUND. If
+ you set this, sendmail considers 0 to be the same as
+ HOST_NOT_FOUND.
+
+
++-----------------------+
+| COMPILE-TIME FEATURES |
++-----------------------+
+
+There are a bunch of features that you can decide to compile in, such
+as selecting various database packages and special protocol support.
+Several are assumed based on other compilation flags -- if you want to
+"un-assume" something, you probably need to edit conf.h. Compilation
+flags that add support for special features include:
+
+NDBM Include support for "new" DBM library for aliases and maps.
+ Normally defined in the Makefile.
+NEWDB Include support for Berkeley "db" package (hash & btree)
+ for aliases and maps. Normally defined in the Makefile.
+OLD_NEWDB If non-zero, the version of NEWDB you have is the old
+ one that does not include the "fd" call. This call was
+ added in version 1.5 of the Berkeley DB code. If you
+ use -DOLD_NEWDB=0 it forces you to use the new interface.
+NIS Define this to get NIS (YP) support for aliases and maps.
+ Normally defined in the Makefile.
+USERDB Include support for the User Information Database. Implied
+ by NEWDB in conf.h.
+IDENTPROTO Define this as 1 to get IDENT (RFC 1413) protocol support.
+ This is assumed unless you are running on Ultrix or
+ HP-UX, both of which have a problem in the UDP
+ implementation. You can define it to be 0 to explicitly
+ turn off IDENT protocol support.
+MIME Include support for MIME-encapsulated error messages.
+LOG Set this to get syslog(3) support. Defined by default
+ in conf.h. You want this if at all possible.
+NETINET Set this to get TCP/IP support. Defined by default
+ in conf.h. You probably want this.
+NETISO Define this to get ISO networking support.
+SMTP Define this to get the SMTP code. Implied by NETINET
+ or NETISO.
+NAMED_BIND Define this to get DNS (name daemon) support, including
+ MX support. The specs you must use this if you run
+ SMTP. Defined by default in conf.h.
+QUEUE Define this to get queueing code. Implied by NETINET
+ or NETISO; required by SMTP. This gives you other good
+ stuff -- it should be on.
+DAEMON Define this to get general network support. Implied by
+ NETINET or NETISO. Defined by default in conf.h. You
+ almost certainly want it on.
+MATCHGECOS Permit fuzzy matching of user names against the full
+ name (GECOS) field in the /etc/passwd file. This should
+ probably be on, since you can disable it from the config
+ file if you want to. Defined by default in conf.h.
+SETPROCTITLE Try to set the string printed by "ps" to something
+ informative about what sendmail is doing. Defined by
+ default in conf.h.
+
+
++---------------------+
+| DNS/RESOLVER ISSUES |
++---------------------+
+
+Many systems have old versions of the resolver library. At a minimum,
+you should be running BIND 4.8.3; older versions may compile, but they
+have known bugs that should give you pause.
+
+Common problems in old versions include "undefined" errors for
+dn_skipname.
+
+Some people have had a problem with BIND 4.9; it uses some routines
+that it expects to be externally defined such as strerror(). It may
+help to link with "-l44bsd" to solve this problem.
+
+!PLEASE! be sure to link with the same version of the resolver as
+the header files you used -- some people have used the 4.9 headers
+and linked with BIND 4.8 or vice versa, and it doesn't work.
+Unfortunately, it doesn't fail in an obvious way -- things just
+subtly don't work.
+
+
++-------------------------------------+
+| OPERATING SYSTEM AND COMPILE QUIRKS |
++-------------------------------------+
+
+GCC 2.5.x problems *** IMPORTANT ***
+ Date: Mon, 29 Nov 93 19:08:44 PST
+ From: wilson@cygnus.com (Jim Wilson)
+ Message-Id: <9311300308.AA04608@cygnus.com>
+ To: kenner@vlsi1.ultra.nyu.edu
+ Subject: [cattelan@thebarn.com: gcc 2.5.4-2.5.5 -O bug]
+ Cc: cattelan@thebarn.com, rms@gnu.ai.mit.edu, sendmail@cs.berkeley.edu
+
+ This fixes a problem that occurs when gcc 2.5.5 is used to compile
+ sendmail 8.6.4 with optimization on a sparc.
+
+ Mon Nov 29 19:00:14 1993 Jim Wilson (wilson@sphagnum.cygnus.com)
+
+ * reload.c (find_reloads_toplev): Replace obsolete reference to
+ BYTE_LOADS_*_EXTEND with LOAD_EXTEND_OP.
+
+ *** clean-ss-931128/reload.c Sun Nov 14 16:20:01 1993
+ --- ss-931128/reload.c Mon Nov 29 18:52:55 1993
+ *************** find_reloads_toplev (x, opnum, type, ind
+ *** 3888,3894 ****
+ force a reload in that case. So we should not do anything here. */
+
+ else if (regno >= FIRST_PSEUDO_REGISTER
+ ! #if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+ && (GET_MODE_SIZE (GET_MODE (x))
+ <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ #endif
+ --- 3888,3894 ----
+ force a reload in that case. So we should not do anything here. */
+
+ else if (regno >= FIRST_PSEUDO_REGISTER
+ ! #ifdef LOAD_EXTEND_OP
+ && (GET_MODE_SIZE (GET_MODE (x))
+ <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ #endif
+
+
+SunOS 4.x (Solaris 1.x)
+ You may have to use -lresolv on SunOS. However, beware that
+ this links in a new version of gethostbyname that does not
+ understand NIS, so you must have all of your hosts in DNS.
+
+ Some people have reported problems with the SunOS version of
+ -lresolv and/or in.named, and suggest that you get a newer
+ version. The symptoms are delays when you connect to the
+ SMTP server on a SunOS machine or having your domain added to
+ addresses inappropriately. There is a version of BIND
+ version 4.9 on gatekeeper.DEC.COM in pub/BSD/bind/4.9.
+
+ There is substantial disagreement about whether you can make
+ this work with resolv+, which allows you to specify a search-path
+ of services. Some people report that it works fine, others
+ claim it doesn't work at all (including causing sendmail to
+ drop core when it tries to do multiple resolv+ lookups for a
+ single job). I haven't tried resolv+, as we use DNS exclusively.
+
+ Should you want to try resolv+, it is on ftp.uu.net in
+ /networking/ip/dns.
+
+Solaris 2.x (SunOS 5.x)
+ To compile for Solaris, be sure you use -DSOLARIS.
+
+ To the best of my knowledge, Solaris does not have the
+ gethostbyname problem described above. However, it does
+ have another one:
+
+ From a correspondent:
+
+ For solaris 2.2, I have
+
+ hosts: files dns
+
+ in /etc/nsswitch.conf and /etc/hosts has to have the fully
+ qualified host name. I think "files" has to be before "dns"
+ in /etc/nsswitch.conf during bootup.
+
+ From another correspondent:
+
+ When running sendmail under Solaris, the gethostbyname()
+ hack in conf.c which should perform proper canonicalization
+ of host names could fail. Result: the host name is not
+ canonicalized despite the hack, and you'll have to define $j
+ and $m in sendmail.cf somewhere.
+
+ The reason could be that /etc/nsswitch.conf is improperly
+ configured (at least from sendmail's point of view). For
+ example, the line
+
+ hosts: files nisplus dns
+
+ will make gethostbyname() look in /etc/hosts first, then ask
+ nisplus, then dns. However, if /etc/hosts does not contain
+ the full canonicalized hostname, then no amount of
+ gethostbyname()s will work.
+
+ Solution (or rather, a workaround): Ask nisplus first, then
+ dns, then local files:
+
+ hosts: nisplus dns [NOTFOUND=return] files
+
+ The Solaris "syslog" function is apparently limited to something
+ about 90 characters because of a kernel limitation. If you have
+ source code, you can probably up this number. You can get patches
+ that fix this problem: the patch ids are:
+
+ Solaris 2.1 100834
+ Solaris 2.2 100999
+ Solaris 2.3 101318
+
+ Be sure you have the appropriate patch installed or you won't
+ see system logging.
+
+OSF/1
+ If you are compiling on OSF/1 (DEC Alpha), you must use
+ -L/usr/shlib (otherwise it core dumps on startup). You may also
+ need -mld to get the nlist() function, although some versions
+ apparently don't need this.
+
+ Also, the enclosed makefile removed /usr/sbin/smtpd; if you need
+ it, just create the link to the sendmail binary.
+
+IRIX
+ The header files on SGI IRIX are completely prototyped, and as
+ a result you can sometimes get some warning messages during
+ compilation. These can be ignored. There are two errors in
+ deliver only if you are using gcc, both of the form ``warning:
+ passing arg N of `execve' from incompatible pointer type''.
+ Also, if you compile with -DNIS, you will get a complaint
+ about a declaration of struct dom_binding in a prototype
+ when compiling map.c; this is not important because the
+ function being prototyped is not used in that file.
+
+NeXT
+ If you are compiling on NeXT, you will have to create an empty
+ file "unistd.h" and create a file "dirent.h" containing:
+
+ #include <sys/dir.h>
+ #define dirent direct
+
+ (The Makefile.NeXT should try to do both of these for you.)
+
+ Apparently, there is a bug in getservbyname on Nextstep 3.0
+ that causes it to fail under some circumstances with the
+ message "SYSERR: service "smtp" unknown" logged. You should
+ be able to work around this by including the line:
+
+ OOPort=25
+
+ in your .cf file.
+
+ You may have to use -DNeXT.
+
+BSDI (BSD/386) 1.0, NetBSD 0.9, FreeBSD 1.0
+ The "m4" from BSDI won't handle the config files properly.
+ I haven't had a chance to test this myself.
+
+ The M4 shipped in FreeBSD and NetBSD 0.9 don't handle the config
+ files properly. One must use either GNU m4 1.1 or the PD-M4
+ recently posted in comp.os.386bsd.bugs (and maybe others).
+ NetBSD-current includes the PD-M4 (as stated in the NetBSD file
+ CHANGES).
+
+ FreeBSD 1.0 RELEASE has uname(2) now. Use -DUSEUNAME in order to
+ use it (look into Makefile.FreeBSD). NetBSD-current may have
+ it too but it has not been verified.
+
+ You cannot port the latest version of the Berkeley db library
+ and use it with sendmail without recompiling the world. This
+ is because C library routines use the older version which have
+ incompatible header files -- the result is that it can't read
+ other system files, such as /etc/passwd, unless you use the
+ new db format throughout your system. You should normally just
+ use the version of db supplied in your release. You may need
+ to use -DOLD_NEWDB=1 to make this work -- this turns off some
+ new interface calls (for file locking) that are not in older
+ versions of db. You'll get compile errors if you need this
+ flag and don't have it set.
+
+4.3BSD
+ If you are running a "virgin" version of 4.3BSD, you'll have
+ a very old resolver and be missing some header files. The
+ header files are simple -- create empty versions and everything
+ will work fine. For the resolver you should really port a new
+ version (4.8.3 or later) of the resolver; 4.9 is available on
+ gatekeeper.DEC.COM in pub/BSD/bind/4.9. If you are really
+ determined to continue to use your old, buggy version (or as
+ a shortcut to get sendmail working -- I'm sure you have the
+ best intentions to port a modern version of BIND), you can
+ copy ../contrib/oldbind.compat.c into src and add
+ oldbind.compat.o to OBJADD in the Makefile.
+
+A/UX
+ Date: Tue, 12 Oct 1993 18:28:28 -0400 (EDT)
+ From: "Eric C. Hagberg" <hagberg@med.cornell.edu>
+ Subject: Fix for A/UX ndbm
+
+ I guess this isn't really a sendmail bug, however, it is something
+ that A/UX users should be aware of when compiling sendmail 8.6.
+
+ Apparently, the calls that sendmail is using to the ndbm routines
+ in A/UX 3.0.x contain calls to "broken" routines, in that the
+ aliases database will break when it gets "just a little big"
+ (sorry I don't have exact numbers here, but it broke somewhere
+ around 20-25 aliases for me.), making all aliases non-functional
+ after exceeding this point.
+
+ What I did was to get the gnu-dbm-1.6 package, compile it, and
+ then re-compile sendmail with "-lgdbm", "-DNDBM", and using the
+ ndbm.h header file that comes with the gnu-package. This makes
+ things behave properly.
+
+ I suppose porting the New Berkeley db package is another route,
+ however, I made a quick attempt at it, and found it difficult
+ (not easy at least); the gnu-dbm package "configured" and
+ compiled easily.
+
+DG/UX
+ Apparently, /bin/mail doesn't work properly for delivery on
+ DG/UX -- the person who has this working, Douglas Anderson
+ <dlander@afterlife.ncsc.mil>, used procmail instead.
+
+Apollo DomainOS
+ If you are compiling on Apollo, you will have to create an empty
+ file "unistd.h" and create a file "dirent.h" containing:
+
+ #include <sys/dir.h>
+ #define dirent direct
+
+ (The Makefile.DomainOS will attempt to do both of these for you.)
+
+HP-UX 8.00
+ Date: Mon, 24 Jan 1994 13:25:45 +0200
+ From: Kimmo Suominen <Kimmo.Suominen@lut.fi>
+ Subject: 8.6.5 w/ HP-UX 8.00 on s300
+
+ Just compiled and fought with sendmail 8.6.5 on a HP9000/360 (ie. a
+ series 300 machine) running HP-UX 8.00.
+
+ I was getting segmentation fault when delivering to a local user.
+ With debugging I saw it was faulting when doing _free@libc... *sigh*
+ It seems the new implementation of malloc on s300 is buggy as of 8.0,
+ so I tried out the one in -lmalloc (malloc(3X)). With that it seems
+ to work just dandy.
+
+ When linking, you will get the following error:
+
+ ld: multiply defined symbol _freespace in file /usr/lib/libmalloc.a
+
+ but you can just ignore it. You might want to add this info to the
+ README file for the future...
+
+Linux
+ Something broke between versions 0.99.13 and 0.99.14 of Linux:
+ the flock() system call gives errors. If you are running .14,
+ you must not use flock. You can do this with -DHASFLOCK=0.
+
+ Around the inclusion of bind-4.9.3 & linux libc-4.6.20, the
+ initialization of the _res structure changed. If /etc/hosts.conf
+ was configured as "hosts, bind" the resolver code could return
+ "Name server failure" errors. This is supposedly fixed in
+ later versions of libc (>= 4.6.29?), and later versions of
+ sendmail (> 8.6.10) try to work around the problem.
+
+ Some older versions (< 4.6.20?) of the libc/include files conflict
+ with sendmail's version of cdefs.h. Deleting sendmail's version
+ on those systems should be non-harmful, and new versions don't care.
+
+AIX
+ This version of sendmail does not support MB, MG, and MR resource
+ records, which are supported by AIX sendmail.
+
+RISC/os
+ RISC/os from MIPS is a merged AT&T/Berkeley system. When you
+ compile on that platform you will get duplicate definitions
+ on many files. You can ignore these.
+
+System V Release 4 Based Systems
+ There is a single Makefile that is intended for all SVR4-based
+ systems (called Makefile.SVR4). It defines __svr4__, which is
+ predefined by some compilers. If your compiler already defines
+ this compile variable, you can delete the definition from the
+ Makefile.
+
+ It's been tested on Dell Issue 2.2.
+
+DELL SVR4
+ Date: Mon, 06 Dec 1993 10:42:29 EST
+ From: "Kimmo Suominen" <kim@grendel.lut.fi>
+ Message-ID: <2d0352f9.lento29@lento29.UUCP>
+ To: eric@cs.berkeley.edu
+ Cc: sendmail@cs.berkeley.edu
+ Subject: Notes for DELL SVR4
+
+ Eric,
+
+ Here are some notes for compiling Sendmail 8.6.4 on DELL SVR4. I ran
+ across these things when helping out some people who contacted me by
+ e-mail.
+
+ 1) Use gcc 2.4.5 (or later?). Dell distributes gcc 2.1 with their
+ Issue 2.2 Unix. It is too old, and gives you problems with
+ clock.c, because sigset_t won't get defined in <sys/signal.h>.
+ This is due to a problematic protection rule in there, and is
+ fixed with gcc 2.4.5.
+
+ 2) If you don't use the new Berkeley DB (-DNEWDB), then you need
+ to add "-lc -lucb" to the libraries to link with. This is because
+ the -ldbm distributed by Dell needs the bcopy, bcmp and bzero
+ functions. It is important that you specify both libraries in
+ the given order to be sure you only get the BSTRING functions
+ from the UCB library (and not the signal routines etc.).
+
+ 3) Don't leave out "-lelf" even if compiling with "-lc -lucb".
+ The UCB library also has another copy of the nlist routines,
+ but we do want the ones from "-lelf".
+
+ If anyone needs a compiled gcc 2.4.5 and/or a ported DB library, they
+ can use anonymous ftp to fetch them from lut.fi in the /kim directory.
+ They are copies of what I use on grendel.lut.fi, and offering them
+ does not imply that I would also support them. I have sent the DB
+ port for SVR4 back to Keith Bostic for inclusion in the official
+ distribution, but I haven't heard anything from him as of today.
+
+ - gcc-2.4.5-svr4.tar.gz (gcc 2.4.5 and the corresponding libg++)
+ - db-1.72.tar.gz (with source, objects and a installed copy)
+
+ Cheers
+ + Kim
+ --
+ * Kimmo.Suominen@lut.fi * SysVr4 enthusiast at GRENDEL.LUT.FI *
+ * KIM@FINFILES.BITNET * Postmaster and Hostmaster at LUT.FI *
+ * + 358 200 865 718 * Unix area moderator at NIC.FUNET.FI *
+
+
+Non-DNS based sites
+ This version of sendmail always tries to connect to the Domain
+ Name System (DNS) to resolve names, regardless of the setting
+ of the `I' option. On most systems that are not running DNS,
+ this will fail quickly and sendmail will continue, but on some
+ systems it has a long timeout. If you have this problem, you
+ will have to recompile without NAMED_BIND. Some people have
+ claimed that they have successfully used "OI+USEVC" to force
+ sendmail to use a virtual circuit -- this will always time out
+ quickly, but also tells sendmail that a failed connection
+ should requeue the message (probably not what you intended).
+ A future release of sendmail will correct this problem.
+
+Both NEWDB and NDBM
+ If you use both -DNDBM and -DNEWDB, you must delete the module
+ ndbm.o from libdb.a and delete the file "ndbm.h" from the files
+ that get installed (that is, use the OLD ndbm.h, not the new
+ ndbm.h). This compatibility module maps ndbm calls into DB
+ calls, and breaks things rather badly.
+
+GNU getopt
+ I'm told that GNU getopt has a problem in that it gets confused
+ by the double call. Use the version in conf.c instead.
+
+BIND 4.9.2 and Ultrix
+ If you are running on Ultrix, be sure you read the conf/Info.Ultrix
+ carefully -- there is information in there that you need to know
+ in order to avoid errors of the form:
+
+ /lib/libc.a(gethostent.o): sethostent: multiply defined
+ /lib/libc.a(gethostent.o): endhostent: multiply defined
+ /lib/libc.a(gethostent.o): gethostbyname: multiply defined
+ /lib/libc.a(gethostent.o): gethostbyaddr: multiply defined
+
+ during the link stage.
+
+
++--------------+
+| MANUAL PAGES |
++--------------+
+
+The manual pages have been written against the -mandoc macros
+instead of the -man macros. The latest version of groff has them
+included. You can also get a copy from FTP.UU.NET in directory
+/systems/unix/bsd-sources/share/tmac.
+
+
++-----------------+
+| DEBUGGING HOOKS |
++-----------------+
+
+As of 8.6.5, sendmail daemons will catch a SIGUSR1 signal and log
+some debugging output (logged at LOG_DEBUG severity). The
+information dumped is:
+
+ * The value of the $j macro.
+ * A warning if $j is not in the set $=w.
+ * A list of the open file descriptors.
+ * The contents of the connection cache.
+ * If ruleset 89 is defined, it is evaluated and the results printed.
+
+This allows you to get information regarding the runtime state of the
+daemon on the fly. This should not be done too frequently, since
+the process of rewriting may lose memory which will not be recovered.
+Also, ruleset 89 may call non-reentrant routines, so there is a small
+non-zero probability that this will cause other problems. It is
+really only for debugging serious problems.
+
+A typical formulation of ruleset 89 would be:
+
+ R$* $@ $>0 some test address
+
+
++-----------------------------+
+| DESCRIPTION OF SOURCE FILES |
++-----------------------------+
+
+The following list describes the files in this directory:
+
+Makefile The makefile used here; this version only works with
+ the new Berkeley make.
+Makefile.dist A trimmed down version of the makefile that works with
+ the old make.
+READ_ME This file.
+TRACEFLAGS My own personal list of the trace flags -- not guaranteed
+ to be particularly up to date.
+alias.c Does name aliasing in all forms.
+arpadate.c A subroutine which creates ARPANET standard dates.
+clock.c Routines to implement real-time oriented functions
+ in sendmail -- e.g., timeouts.
+collect.c The routine that actually reads the mail into a temp
+ file. It also does a certain amount of parsing of
+ the header, etc.
+conf.c The configuration file. This contains information
+ that is presumed to be quite static and non-
+ controversial, or code compiled in for efficiency
+ reasons. Most of the configuration is in sendmail.cf.
+conf.h Configuration that must be known everywhere.
+convtime.c A routine to sanely process times.
+daemon.c Routines to implement daemon mode. This version is
+ specifically for Berkeley 4.1 IPC.
+deliver.c Routines to deliver mail.
+domain.c Routines that interface with DNS (the Domain Name
+ System).
+err.c Routines to print error messages.
+envelope.c Routines to manipulate the envelope structure.
+headers.c Routines to process message headers.
+macro.c The macro expander. This is used internally to
+ insert information from the configuration file.
+main.c The main routine to sendmail. This file also
+ contains some miscellaneous routines.
+map.c Support for database maps.
+mci.c Routines that handle mail connection information caching.
+parseaddr.c The routines which do address parsing.
+queue.c Routines to implement message queueing.
+readcf.c The routine that reads the configuration file and
+ translates it to internal form.
+recipient.c Routines that manipulate the recipient list.
+savemail.c Routines which save the letter on processing errors.
+sendmail.h Main header file for sendmail.
+srvrsmtp.c Routines to implement server SMTP.
+stab.c Routines to manage the symbol table.
+stats.c Routines to collect and post the statistics.
+sysexits.c List of error messages associated with error codes
+ in sysexits.h.
+trace.c The trace package. These routines allow setting and
+ testing of trace flags with a high granularity.
+udb.c The user database interface module.
+usersmtp.c Routines to implement user SMTP.
+util.c Some general purpose routines used by sendmail.
+version.c The version number and information about this
+ version of sendmail. Theoretically, this gets
+ modified on every change.
+
+Eric Allman
+
+(Version 8.61.1.1, last update 3/5/95 12:52:16)
diff --git a/usr.sbin/sendmail/src/TRACEFLAGS b/usr.sbin/sendmail/src/TRACEFLAGS
new file mode 100644
index 00000000000..f05c219c871
--- /dev/null
+++ b/usr.sbin/sendmail/src/TRACEFLAGS
@@ -0,0 +1,64 @@
+0, 1 main.c main skip background fork
+0, 4 main.c main canonical name, UUCP node name, a.k.a.s
+0, 15 main.c main print configuration
+0, 44 util.c printav print address of each string
+1 main.c main print from person
+2 main.c finis
+3 conf.c getla
+4 conf.c enoughspace
+5 clock.c setevent, clrevent, tick
+6 savemail.c savemail, returntosender
+7 queue.c queuename
+8 domain.c getmxrr, getcanonname
+9 daemon.c getauthinfo IDENT protocol
+9 daemon.c maphostname
+10 deliver.c deliver
+11 deliver.c openmailer, mailfile
+12 parseaddr.c remotename
+13 deliver.c sendall, sendenvelope
+14 headers.c commaize
+15 daemon.c getrequests
+16 daemon.c makeconnection
+17 deliver.c hostsignature
+17 domain.c mxrand
+18 usersmtp.c reply, smtpmessage, smtpinit, smtpmailfrom
+19 srvrsmtp.c smtp
+20 parseaddr.c parseaddr
+21 parseaddr.c rewrite
+22 parseaddr.c prescan
+24 parseaddr.c buildaddr, allocaddr
+25 recipient.c sendtolist
+26 recipient.c recipient
+27 alias.c alias
+27 alias.c readaliases
+27 alias.c forward
+27 recipient.c include
+28 udb.c udbexpand, udbsender
+29 parseaddr.c maplocaluser
+29 recipient.c recipient (local users), finduser
+30 collect.c collect
+30 collect.c eatfrom
+31 headers.c chompheader
+32 headers.c eatheader
+33 headers.c crackaddr
+34 headers.c putheader
+35 macro.c expand, define
+36 stab.c stab
+37 readcf.c (many)
+38 map.c initmaps
+39 map.c map_rewrite
+40 queue.c queueup, orderq, dowork
+41 queue.c orderq
+42 mci.c mci_get
+45 envelope.c setsender
+46 envelope.c openxscript
+49 conf.c checkcompat
+50 envelope.c dropenvelope
+51 queue.c unlockqueue
+52 main.c disconnect
+53 util.c xfclose
+54 err.c putoutmsg
+55 conf.c lockfile
+59 Extended Load Average implementation from Christophe Wolfhugel
+60 map.c
+91 mci.c syslogging of MCI cache information
diff --git a/usr.sbin/sendmail/src/alias.c b/usr.sbin/sendmail/src/alias.c
new file mode 100644
index 00000000000..9952db53fd4
--- /dev/null
+++ b/usr.sbin/sendmail/src/alias.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+# include "sendmail.h"
+# include <pwd.h>
+
+#ifndef lint
+static char sccsid[] = "@(#)alias.c 8.25 (Berkeley) 4/14/94";
+#endif /* not lint */
+
+
+MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */
+int NAliasDBs; /* number of alias databases */
+ /*
+** ALIAS -- Compute aliases.
+**
+** Scans the alias file for an alias for the given address.
+** If found, it arranges to deliver to the alias list instead.
+** Uses libdbm database if -DDBM.
+**
+** Parameters:
+** a -- address to alias.
+** sendq -- a pointer to the head of the send queue
+** to put the aliases in.
+** e -- the current envelope.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Aliases found are expanded.
+**
+** Deficiencies:
+** It should complain about names that are aliased to
+** nothing.
+*/
+
+alias(a, sendq, e)
+ register ADDRESS *a;
+ ADDRESS **sendq;
+ register ENVELOPE *e;
+{
+ register char *p;
+ int naliases;
+ char *owner;
+ char obuf[MAXNAME + 6];
+ extern char *aliaslookup();
+
+ if (tTd(27, 1))
+ printf("alias(%s)\n", a->q_paddr);
+
+ /* don't realias already aliased names */
+ if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
+ return;
+
+ if (NoAlias)
+ return;
+
+ e->e_to = a->q_paddr;
+
+ /*
+ ** Look up this name
+ */
+
+ p = aliaslookup(a->q_user, e);
+ if (p == NULL)
+ return;
+
+ /*
+ ** Match on Alias.
+ ** Deliver to the target list.
+ */
+
+ if (tTd(27, 1))
+ printf("%s (%s, %s) aliased to %s\n",
+ a->q_paddr, a->q_host, a->q_user, p);
+ if (bitset(EF_VRFYONLY, e->e_flags))
+ {
+ a->q_flags |= QVERIFIED;
+ e->e_nrcpts++;
+ return;
+ }
+ message("aliased to %s", p);
+#ifdef LOG
+ if (LogLevel > 9)
+ syslog(LOG_INFO, "%s: alias %s => %s",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id,
+ a->q_paddr, p);
+#endif
+ a->q_flags &= ~QSELFREF;
+ AliasLevel++;
+ naliases = sendtolist(p, a, sendq, e);
+ AliasLevel--;
+ if (!bitset(QSELFREF, a->q_flags))
+ {
+ if (tTd(27, 5))
+ {
+ printf("alias: QDONTSEND ");
+ printaddr(a, FALSE);
+ }
+ a->q_flags |= QDONTSEND;
+ }
+
+ /*
+ ** Look for owner of alias
+ */
+
+ (void) strcpy(obuf, "owner-");
+ if (strncmp(a->q_user, "owner-", 6) == 0)
+ (void) strcat(obuf, "owner");
+ else
+ (void) strcat(obuf, a->q_user);
+ if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
+ makelower(obuf);
+ owner = aliaslookup(obuf, e);
+ if (owner == NULL)
+ return;
+
+ /* reflect owner into envelope sender */
+ if (strpbrk(owner, ",:/|\"") != NULL)
+ owner = obuf;
+ a->q_owner = newstr(owner);
+
+ /* announce delivery to this alias; NORECEIPT bit set later */
+ if (e->e_xfp != NULL)
+ {
+ fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
+ a->q_paddr);
+ e->e_flags |= EF_SENDRECEIPT;
+ }
+}
+ /*
+** ALIASLOOKUP -- look up a name in the alias file.
+**
+** Parameters:
+** name -- the name to look up.
+**
+** Returns:
+** the value of name.
+** NULL if unknown.
+**
+** Side Effects:
+** none.
+**
+** Warnings:
+** The return value will be trashed across calls.
+*/
+
+char *
+aliaslookup(name, e)
+ char *name;
+ ENVELOPE *e;
+{
+ register int dbno;
+ register MAP *map;
+ register char *p;
+
+ for (dbno = 0; dbno < NAliasDBs; dbno++)
+ {
+ auto int stat;
+
+ map = AliasDB[dbno];
+ if (!bitset(MF_OPEN, map->map_mflags))
+ continue;
+ p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
+ if (p != NULL)
+ return p;
+ }
+ return NULL;
+}
+ /*
+** SETALIAS -- set up an alias map
+**
+** Called when reading configuration file.
+**
+** Parameters:
+** spec -- the alias specification
+**
+** Returns:
+** none.
+*/
+
+setalias(spec)
+ char *spec;
+{
+ register char *p;
+ register MAP *map;
+ char *class;
+ STAB *s;
+
+ if (tTd(27, 8))
+ printf("setalias(%s)\n", spec);
+
+ for (p = spec; p != NULL; )
+ {
+ char aname[50];
+
+ while (isspace(*p))
+ p++;
+ if (*p == '\0')
+ break;
+ spec = p;
+
+ if (NAliasDBs >= MAXALIASDB)
+ {
+ syserr("Too many alias databases defined, %d max", MAXALIASDB);
+ return;
+ }
+ (void) sprintf(aname, "Alias%d", NAliasDBs);
+ s = stab(aname, ST_MAP, ST_ENTER);
+ map = &s->s_map;
+ AliasDB[NAliasDBs] = map;
+ bzero(map, sizeof *map);
+
+ p = strpbrk(p, " ,/:");
+ if (p != NULL && *p == ':')
+ {
+ /* map name */
+ *p++ = '\0';
+ class = spec;
+ spec = p;
+ }
+ else
+ {
+ class = "implicit";
+ map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
+ }
+
+ /* find end of spec */
+ if (p != NULL)
+ p = strchr(p, ',');
+ if (p != NULL)
+ *p++ = '\0';
+
+ /* look up class */
+ s = stab(class, ST_MAPCLASS, ST_FIND);
+ if (s == NULL)
+ {
+ if (tTd(27, 1))
+ printf("Unknown alias class %s\n", class);
+ }
+ else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
+ {
+ syserr("setalias: map class %s can't handle aliases",
+ class);
+ }
+ else
+ {
+ map->map_class = &s->s_mapclass;
+ if (map->map_class->map_parse(map, spec))
+ {
+ map->map_mflags |= MF_VALID|MF_ALIAS;
+ NAliasDBs++;
+ }
+ }
+ }
+}
+ /*
+** ALIASWAIT -- wait for distinguished @:@ token to appear.
+**
+** This can decide to reopen or rebuild the alias file
+**
+** Parameters:
+** map -- a pointer to the map descriptor for this alias file.
+** ext -- the filename extension (e.g., ".db") for the
+** database file.
+** isopen -- if set, the database is already open, and we
+** should check for validity; otherwise, we are
+** just checking to see if it should be created.
+**
+** Returns:
+** TRUE -- if the database is open when we return.
+** FALSE -- if the database is closed when we return.
+*/
+
+bool
+aliaswait(map, ext, isopen)
+ MAP *map;
+ char *ext;
+ int isopen;
+{
+ bool attimeout = FALSE;
+ time_t mtime;
+ struct stat stb;
+ char buf[MAXNAME];
+
+ if (tTd(27, 3))
+ printf("aliaswait(%s:%s)\n",
+ map->map_class->map_cname, map->map_file);
+ if (bitset(MF_ALIASWAIT, map->map_mflags))
+ return isopen;
+ map->map_mflags |= MF_ALIASWAIT;
+
+ if (SafeAlias > 0)
+ {
+ auto int st;
+ time_t toolong = curtime() + SafeAlias;
+ unsigned int sleeptime = 2;
+
+ while (isopen &&
+ map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
+ {
+ if (curtime() > toolong)
+ {
+ /* we timed out */
+ attimeout = TRUE;
+ break;
+ }
+
+ /*
+ ** Close and re-open the alias database in case
+ ** the one is mv'ed instead of cp'ed in.
+ */
+
+ if (tTd(27, 2))
+ printf("aliaswait: sleeping for %d seconds\n",
+ sleeptime);
+
+ map->map_class->map_close(map);
+ sleep(sleeptime);
+ sleeptime *= 2;
+ if (sleeptime > 60)
+ sleeptime = 60;
+ isopen = map->map_class->map_open(map, O_RDONLY);
+ }
+ }
+
+ /* see if we need to go into auto-rebuild mode */
+ if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
+ {
+ if (tTd(27, 3))
+ printf("aliaswait: not rebuildable\n");
+ map->map_mflags &= ~MF_ALIASWAIT;
+ return isopen;
+ }
+ if (stat(map->map_file, &stb) < 0)
+ {
+ if (tTd(27, 3))
+ printf("aliaswait: no source file\n");
+ map->map_mflags &= ~MF_ALIASWAIT;
+ return isopen;
+ }
+ mtime = stb.st_mtime;
+ (void) strcpy(buf, map->map_file);
+ if (ext != NULL)
+ (void) strcat(buf, ext);
+ if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
+ {
+ /* database is out of date */
+ if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
+ {
+ message("auto-rebuilding alias database %s", buf);
+ if (isopen)
+ map->map_class->map_close(map);
+ rebuildaliases(map, TRUE);
+ isopen = map->map_class->map_open(map, O_RDONLY);
+ }
+ else
+ {
+#ifdef LOG
+ if (LogLevel > 3)
+ syslog(LOG_INFO, "alias database %s out of date",
+ buf);
+#endif /* LOG */
+ message("Warning: alias database %s out of date", buf);
+ }
+ }
+ map->map_mflags &= ~MF_ALIASWAIT;
+ return isopen;
+}
+ /*
+** REBUILDALIASES -- rebuild the alias database.
+**
+** Parameters:
+** map -- the database to rebuild.
+** automatic -- set if this was automatically generated.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Reads the text version of the database, builds the
+** DBM or DB version.
+*/
+
+rebuildaliases(map, automatic)
+ register MAP *map;
+ bool automatic;
+{
+ FILE *af;
+ bool nolock = FALSE;
+ sigfunc_t oldsigint;
+
+ if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
+ return;
+
+ /* try to lock the source file */
+ if ((af = fopen(map->map_file, "r+")) == NULL)
+ {
+ if ((errno != EACCES && errno != EROFS) || automatic ||
+ (af = fopen(map->map_file, "r")) == NULL)
+ {
+ int saveerr = errno;
+
+ if (tTd(27, 1))
+ printf("Can't open %s: %s\n",
+ map->map_file, errstring(saveerr));
+ if (!automatic)
+ message("newaliases: cannot open %s: %s",
+ map->map_file, errstring(saveerr));
+ errno = 0;
+ return;
+ }
+ nolock = TRUE;
+ message("warning: cannot lock %s: %s",
+ map->map_file, errstring(errno));
+ }
+
+ /* see if someone else is rebuilding the alias file */
+ if (!nolock &&
+ !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
+ {
+ /* yes, they are -- wait until done */
+ message("Alias file %s is already being rebuilt",
+ map->map_file);
+ if (OpMode != MD_INITALIAS)
+ {
+ /* wait for other rebuild to complete */
+ (void) lockfile(fileno(af), map->map_file, NULL,
+ LOCK_EX);
+ }
+ (void) xfclose(af, "rebuildaliases1", map->map_file);
+ errno = 0;
+ return;
+ }
+
+ oldsigint = setsignal(SIGINT, SIG_IGN);
+
+ if (map->map_class->map_open(map, O_RDWR))
+ {
+#ifdef LOG
+ if (LogLevel > 7)
+ {
+ syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
+ map->map_file, automatic ? "auto" : "",
+ username());
+ }
+#endif /* LOG */
+ map->map_mflags |= MF_OPEN|MF_WRITABLE;
+ readaliases(map, af, automatic);
+ }
+ else
+ {
+ if (tTd(27, 1))
+ printf("Can't create database for %s: %s\n",
+ map->map_file, errstring(errno));
+ if (!automatic)
+ syserr("Cannot create database for alias file %s",
+ map->map_file);
+ }
+
+ /* close the file, thus releasing locks */
+ xfclose(af, "rebuildaliases2", map->map_file);
+
+ /* add distinguished entries and close the database */
+ if (bitset(MF_OPEN, map->map_mflags))
+ map->map_class->map_close(map);
+
+ /* restore the old signal */
+ (void) setsignal(SIGINT, oldsigint);
+}
+ /*
+** READALIASES -- read and process the alias file.
+**
+** This routine implements the part of initaliases that occurs
+** when we are not going to use the DBM stuff.
+**
+** Parameters:
+** map -- the alias database descriptor.
+** af -- file to read the aliases from.
+** automatic -- set if this was an automatic rebuild.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Reads aliasfile into the symbol table.
+** Optionally, builds the .dir & .pag files.
+*/
+
+readaliases(map, af, automatic)
+ register MAP *map;
+ FILE *af;
+ int automatic;
+{
+ register char *p;
+ char *rhs;
+ bool skipping;
+ long naliases, bytes, longest;
+ ADDRESS al, bl;
+ char line[BUFSIZ];
+
+ /*
+ ** Read and interpret lines
+ */
+
+ FileName = map->map_file;
+ LineNumber = 0;
+ naliases = bytes = longest = 0;
+ skipping = FALSE;
+ while (fgets(line, sizeof (line), af) != NULL)
+ {
+ int lhssize, rhssize;
+
+ LineNumber++;
+ p = strchr(line, '\n');
+ if (p != NULL)
+ *p = '\0';
+ switch (line[0])
+ {
+ case '#':
+ case '\0':
+ skipping = FALSE;
+ continue;
+
+ case ' ':
+ case '\t':
+ if (!skipping)
+ syserr("554 Non-continuation line starts with space");
+ skipping = TRUE;
+ continue;
+ }
+ skipping = FALSE;
+
+ /*
+ ** Process the LHS
+ ** Find the colon separator, and parse the address.
+ ** It should resolve to a local name -- this will
+ ** be checked later (we want to optionally do
+ ** parsing of the RHS first to maximize error
+ ** detection).
+ */
+
+ for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
+ continue;
+ if (*p++ != ':')
+ {
+ syserr("554 missing colon");
+ continue;
+ }
+ if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
+ {
+ syserr("554 %.40s... illegal alias name", line);
+ continue;
+ }
+
+ /*
+ ** Process the RHS.
+ ** 'al' is the internal form of the LHS address.
+ ** 'p' points to the text of the RHS.
+ */
+
+ while (isascii(*p) && isspace(*p))
+ p++;
+ rhs = p;
+ for (;;)
+ {
+ register char c;
+ register char *nlp;
+
+ nlp = &p[strlen(p)];
+ if (nlp[-1] == '\n')
+ *--nlp = '\0';
+
+ if (CheckAliases)
+ {
+ /* do parsing & compression of addresses */
+ while (*p != '\0')
+ {
+ auto char *delimptr;
+
+ while ((isascii(*p) && isspace(*p)) ||
+ *p == ',')
+ p++;
+ if (*p == '\0')
+ break;
+ if (parseaddr(p, &bl, RF_COPYNONE, ',',
+ &delimptr, CurEnv) == NULL)
+ usrerr("553 %s... bad address", p);
+ p = delimptr;
+ }
+ }
+ else
+ {
+ p = nlp;
+ }
+
+ /* see if there should be a continuation line */
+ c = fgetc(af);
+ if (!feof(af))
+ (void) ungetc(c, af);
+ if (c != ' ' && c != '\t')
+ break;
+
+ /* read continuation line */
+ if (fgets(p, sizeof line - (p - line), af) == NULL)
+ break;
+ LineNumber++;
+
+ /* check for line overflow */
+ if (strchr(p, '\n') == NULL)
+ {
+ usrerr("554 alias too long");
+ break;
+ }
+ }
+ if (al.q_mailer != LocalMailer)
+ {
+ syserr("554 %s... cannot alias non-local names",
+ al.q_paddr);
+ continue;
+ }
+
+ /*
+ ** Insert alias into symbol table or DBM file
+ */
+
+ if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
+ makelower(al.q_user);
+
+ lhssize = strlen(al.q_user);
+ rhssize = strlen(rhs);
+ map->map_class->map_store(map, al.q_user, rhs);
+
+ if (al.q_paddr != NULL)
+ free(al.q_paddr);
+ if (al.q_host != NULL)
+ free(al.q_host);
+ if (al.q_user != NULL)
+ free(al.q_user);
+
+ /* statistics */
+ naliases++;
+ bytes += lhssize + rhssize;
+ if (rhssize > longest)
+ longest = rhssize;
+ }
+
+ CurEnv->e_to = NULL;
+ FileName = NULL;
+ if (Verbose || !automatic)
+ message("%s: %d aliases, longest %d bytes, %d bytes total",
+ map->map_file, naliases, longest, bytes);
+# ifdef LOG
+ if (LogLevel > 7)
+ syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
+ map->map_file, naliases, longest, bytes);
+# endif /* LOG */
+}
+ /*
+** FORWARD -- Try to forward mail
+**
+** This is similar but not identical to aliasing.
+**
+** Parameters:
+** user -- the name of the user who's mail we would like
+** to forward to. It must have been verified --
+** i.e., the q_home field must have been filled
+** in.
+** sendq -- a pointer to the head of the send queue to
+** put this user's aliases in.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** New names are added to send queues.
+*/
+
+forward(user, sendq, e)
+ ADDRESS *user;
+ ADDRESS **sendq;
+ register ENVELOPE *e;
+{
+ char *pp;
+ char *ep;
+
+ if (tTd(27, 1))
+ printf("forward(%s)\n", user->q_paddr);
+
+ if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
+ return;
+ if (user->q_home == NULL)
+ {
+ syserr("554 forward: no home");
+ user->q_home = "/nosuchdirectory";
+ }
+
+ /* good address -- look for .forward file in home */
+ define('z', user->q_home, e);
+ define('u', user->q_user, e);
+ define('h', user->q_host, e);
+ if (ForwardPath == NULL)
+ ForwardPath = newstr("\201z/.forward");
+
+ for (pp = ForwardPath; pp != NULL; pp = ep)
+ {
+ int err;
+ char buf[MAXPATHLEN+1];
+
+ ep = strchr(pp, ':');
+ if (ep != NULL)
+ *ep = '\0';
+ expand(pp, buf, &buf[sizeof buf - 1], e);
+ if (ep != NULL)
+ *ep++ = ':';
+ if (tTd(27, 3))
+ printf("forward: trying %s\n", buf);
+
+ err = include(buf, TRUE, user, sendq, e);
+ if (err == 0)
+ break;
+ else if (transienterror(err))
+ {
+ /* we have to suspend this message */
+ if (tTd(27, 2))
+ printf("forward: transient error on %s\n", buf);
+#ifdef LOG
+ if (LogLevel > 2)
+ syslog(LOG_ERR, "%s: forward %s: transient error: %s",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id,
+ buf, errstring(err));
+#endif
+ message("%s: %s: message queued", buf, errstring(err));
+ user->q_flags |= QQUEUEUP;
+ return;
+ }
+ }
+}
diff --git a/usr.sbin/sendmail/src/aliases b/usr.sbin/sendmail/src/aliases
new file mode 100644
index 00000000000..7540eeae3f6
--- /dev/null
+++ b/usr.sbin/sendmail/src/aliases
@@ -0,0 +1,53 @@
+#
+# @(#)aliases 8.2 (Berkeley) 3/5/94
+#
+# Aliases in this file will NOT be expanded in the header from
+# Mail, but WILL be visible over networks or from /bin/mail.
+#
+# >>>>>>>>>> The program "newaliases" must be run after
+# >> NOTE >> this file is updated for any changes to
+# >>>>>>>>>> show through to sendmail.
+#
+
+# Basic system aliases -- these MUST be present.
+MAILER-DAEMON: postmaster
+postmaster: root
+
+# General redirections for pseudo accounts.
+bin: root
+daemon: root
+games: root
+ingres: root
+nobody: root
+system: root
+toor: root
+uucp: root
+
+# Well-known aliases.
+manager: root
+dumper: root
+operator: root
+
+# trap decode to catch security attacks
+decode: root
+
+# OFFICIAL CSRG/BUG ADDRESSES
+
+# Ftp maintainer.
+ftp: ftp-bugs
+ftp-bugs: bigbug@cs.berkeley.edu
+
+# Distribution office.
+bsd-dist: bsd-dist@cs.berkeley.edu
+
+# Fortune maintainer.
+fortune: fortune@cs.berkeley.edu
+
+# Termcap maintainer.
+termcap: termcap@cs.berkeley.edu
+
+# General bug address.
+ucb-fixes: bigbug@cs.berkeley.edu
+ucb-fixes-request: bigbug@cs.berkeley.edu
+bugs: bugs@cs.berkeley.edu
+# END OFFICIAL BUG ADDRESSES
diff --git a/usr.sbin/sendmail/src/aliases.5 b/usr.sbin/sendmail/src/aliases.5
new file mode 100644
index 00000000000..f40f64de10b
--- /dev/null
+++ b/usr.sbin/sendmail/src/aliases.5
@@ -0,0 +1,106 @@
+.\" Copyright (c) 1985, 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.
+.\"
+.\" @(#)aliases.5 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt ALIASES 5
+.Os BSD 4
+.Sh NAME
+.Nm aliases
+.Nd aliases file for sendmail
+.Sh SYNOPSIS
+.Nm aliases
+.Sh DESCRIPTION
+This file describes user
+.Tn ID
+aliases used by
+.Pa /usr/sbin/sendmail .
+The file resides in
+.Pa /etc
+and
+is formatted as a series of lines of the form
+.Bd -filled -offset indent
+name: name_1, name2, name_3, . . .
+.Ed
+.Pp
+The
+.Em name
+is the name to alias, and the
+.Em name_n
+are the aliases for that name.
+Lines beginning with white space are continuation lines.
+Lines beginning with
+.Ql #
+are comments.
+.Pp
+Aliasing occurs only on local names.
+Loops can not occur, since no message will be sent to any person more than once.
+.Pp
+After aliasing has been done, local and valid recipients who have a
+.Dq Pa .forward
+file in their home directory have messages forwarded to the
+list of users defined in that file.
+.Pp
+This is only the raw data file; the actual aliasing information is
+placed into a binary format in the file
+.Pa /etc/aliases.db
+using the program
+.Xr newaliases 1 .
+A
+.Xr newaliases
+command should be executed each time the aliases file is changed for the
+change to take effect.
+.Sh SEE ALSO
+.Xr newaliases 1 ,
+.Xr dbopen 3 ,
+.Xr dbm 3 ,
+.Xr sendmail 8
+.Rs
+.%T "SENDMAIL Installation and Operation Guide"
+.Re
+.Rs
+.%T "SENDMAIL An Internetwork Mail Router"
+.Re
+.Sh BUGS
+If you have compiled
+.Xr sendmail
+with DBM support instead of NEWDB,
+you may have encountered problems in
+.Xr dbm 3
+restricting a single alias to about 1000 bytes of information.
+You can get longer aliases by ``chaining''; that is, make the last name in
+the alias be a dummy name which is a continuation alias.
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/sendmail/src/arpadate.c b/usr.sbin/sendmail/src/arpadate.c
new file mode 100644
index 00000000000..d3f9ac574a6
--- /dev/null
+++ b/usr.sbin/sendmail/src/arpadate.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)arpadate.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** ARPADATE -- Create date in ARPANET format
+**
+** Parameters:
+** ud -- unix style date string. if NULL, one is created.
+**
+** Returns:
+** pointer to an ARPANET date field
+**
+** Side Effects:
+** none
+**
+** WARNING:
+** date is stored in a local buffer -- subsequent
+** calls will overwrite.
+**
+** Bugs:
+** Timezone is computed from local time, rather than
+** from whereever (and whenever) the message was sent.
+** To do better is very hard.
+**
+** Some sites are now inserting the timezone into the
+** local date. This routine should figure out what
+** the format is and work appropriately.
+*/
+
+char *
+arpadate(ud)
+ register char *ud;
+{
+ register char *p;
+ register char *q;
+ register int off;
+ register int i;
+ register struct tm *lt;
+ time_t t;
+ struct tm gmt;
+ static char b[40];
+
+ /*
+ ** Get current time.
+ ** This will be used if a null argument is passed and
+ ** to resolve the timezone.
+ */
+
+ (void) time(&t);
+ if (ud == NULL)
+ ud = ctime(&t);
+
+ /*
+ ** Crack the UNIX date line in a singularly unoriginal way.
+ */
+
+ q = b;
+
+ p = &ud[0]; /* Mon */
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = ',';
+ *q++ = ' ';
+
+ p = &ud[8]; /* 16 */
+ if (*p == ' ')
+ p++;
+ else
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = ' ';
+
+ p = &ud[4]; /* Sep */
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = ' ';
+
+ p = &ud[20]; /* 1979 */
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = ' ';
+
+ p = &ud[11]; /* 01:03:52 */
+ for (i = 8; i > 0; i--)
+ *q++ = *p++;
+
+ /*
+ * should really get the timezone from the time in "ud" (which
+ * is only different if a non-null arg was passed which is different
+ * from the current time), but for all practical purposes, returning
+ * the current local zone will do (its all that is ever needed).
+ */
+ gmt = *gmtime(&t);
+ lt = localtime(&t);
+
+ off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
+
+ /* assume that offset isn't more than a day ... */
+ if (lt->tm_year < gmt.tm_year)
+ off -= 24 * 60;
+ else if (lt->tm_year > gmt.tm_year)
+ off += 24 * 60;
+ else if (lt->tm_yday < gmt.tm_yday)
+ off -= 24 * 60;
+ else if (lt->tm_yday > gmt.tm_yday)
+ off += 24 * 60;
+
+ *q++ = ' ';
+ if (off == 0) {
+ *q++ = 'G';
+ *q++ = 'M';
+ *q++ = 'T';
+ } else {
+ if (off < 0) {
+ off = -off;
+ *q++ = '-';
+ } else
+ *q++ = '+';
+
+ if (off >= 24*60) /* should be impossible */
+ off = 23*60+59; /* if not, insert silly value */
+
+ *q++ = (off / 600) + '0';
+ *q++ = (off / 60) % 10 + '0';
+ off %= 60;
+ *q++ = (off / 10) + '0';
+ *q++ = (off % 10) + '0';
+ }
+ *q = '\0';
+
+ return (b);
+}
diff --git a/usr.sbin/sendmail/src/cdefs.h b/usr.sbin/sendmail/src/cdefs.h
new file mode 100644
index 00000000000..e586cbfaf7c
--- /dev/null
+++ b/usr.sbin/sendmail/src/cdefs.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Berkeley Software Design, Inc.
+ *
+ * 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.
+ *
+ * @(#)cdefs.h 8.8 (Berkeley) 1/9/95
+ */
+
+#ifndef _CDEFS_H_
+#define _CDEFS_H_
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
+ * in between its arguments. __CONCAT can also concatenate double-quoted
+ * strings produced by the __STRING macro, but this only works with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#define __CONCAT(x,y) x ## y
+#define __STRING(x) #x
+
+#define __const const /* define reserved names to standard */
+#define __signed signed
+#define __volatile volatile
+#if defined(__cplusplus)
+#define __inline inline /* convert to C++ keyword */
+#else
+#ifndef __GNUC__
+#define __inline /* delete GCC keyword */
+#endif /* !__GNUC__ */
+#endif /* !__cplusplus */
+
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+
+#ifndef __GNUC__
+#define __const /* delete pseudo-ANSI C keywords */
+#define __inline
+#define __signed
+#define __volatile
+/*
+ * In non-ANSI C environments, new programs will want ANSI-only C keywords
+ * deleted from the program and old programs will want them left alone.
+ * When using a compiler other than gcc, programs using the ANSI C keywords
+ * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
+ * When using "gcc -traditional", we assume that this is the intent; if
+ * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
+ */
+#ifndef NO_ANSI_KEYWORDS
+#define const /* delete ANSI C keywords */
+#define inline
+#define signed
+#define volatile
+#endif
+#endif /* !__GNUC__ */
+#endif /* !(__STDC__ || __cplusplus) */
+
+/*
+ * GCC1 and some versions of GCC2 declare dead (non-returning) and
+ * pure (no side effects) functions using "volatile" and "const";
+ * unfortunately, these then cause warnings under "-ansi -pedantic".
+ * GCC2 uses a new, peculiar __attribute__((attrs)) style. All of
+ * these work for GNU C++ (modulo a slight glitch in the C++ grammar
+ * in the distribution version of 2.5.5).
+ */
+#if !defined(__GNUC__) || __GNUC__ < 2 || \
+ (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define __dead __volatile
+#define __pure __const
+#endif
+#endif
+
+/* Delete pseudo-keywords wherever they are not available or needed. */
+#ifndef __dead
+#define __dead
+#define __pure
+#endif
+
+#endif /* !_CDEFS_H_ */
diff --git a/usr.sbin/sendmail/src/clock.c b/usr.sbin/sendmail/src/clock.c
new file mode 100644
index 00000000000..45ef1c2782c
--- /dev/null
+++ b/usr.sbin/sendmail/src/clock.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)clock.c 8.8 (Berkeley) 1/12/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+# ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+# endif
+
+/*
+** SETEVENT -- set an event to happen at a specific time.
+**
+** Events are stored in a sorted list for fast processing.
+** An event only applies to the process that set it.
+**
+** Parameters:
+** intvl -- intvl until next event occurs.
+** func -- function to call on event.
+** arg -- argument to func on event.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+static void tick __P((int));
+
+EVENT *
+setevent(intvl, func, arg)
+ time_t intvl;
+ int (*func)();
+ int arg;
+{
+ register EVENT **evp;
+ register EVENT *ev;
+ auto time_t now;
+
+ if (intvl <= 0)
+ {
+ syserr("554 setevent: intvl=%ld\n", intvl);
+ return (NULL);
+ }
+
+ (void) setsignal(SIGALRM, SIG_IGN);
+ (void) time(&now);
+
+ /* search event queue for correct position */
+ for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
+ {
+ if (ev->ev_time >= now + intvl)
+ break;
+ }
+
+ /* insert new event */
+ ev = (EVENT *) xalloc(sizeof *ev);
+ ev->ev_time = now + intvl;
+ ev->ev_func = func;
+ ev->ev_arg = arg;
+ ev->ev_pid = getpid();
+ ev->ev_link = *evp;
+ *evp = ev;
+
+ if (tTd(5, 5))
+ printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
+ intvl, now + intvl, func, arg, ev);
+
+ tick(0);
+ return (ev);
+}
+ /*
+** CLREVENT -- remove an event from the event queue.
+**
+** Parameters:
+** ev -- pointer to event to remove.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** arranges for event ev to not happen.
+*/
+
+clrevent(ev)
+ register EVENT *ev;
+{
+ register EVENT **evp;
+
+ if (tTd(5, 5))
+ printf("clrevent: ev=%x\n", ev);
+ if (ev == NULL)
+ return;
+
+ /* find the parent event */
+ (void) setsignal(SIGALRM, SIG_IGN);
+ for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
+ {
+ if (*evp == ev)
+ break;
+ }
+
+ /* now remove it */
+ if (*evp != NULL)
+ {
+ *evp = ev->ev_link;
+ free((char *) ev);
+ }
+
+ /* restore clocks and pick up anything spare */
+ tick(0);
+}
+ /*
+** TICK -- take a clock tick
+**
+** Called by the alarm clock. This routine runs events as needed.
+**
+** Parameters:
+** One that is ignored; for compatibility with signal handlers.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** calls the next function in EventQueue.
+*/
+
+static void
+tick(arg)
+ int arg;
+{
+ register time_t now;
+ register EVENT *ev;
+ int mypid = getpid();
+ int olderrno = errno;
+#ifdef SIG_UNBLOCK
+ sigset_t ss;
+#endif
+
+ (void) setsignal(SIGALRM, SIG_IGN);
+ (void) alarm(0);
+ now = curtime();
+
+ if (tTd(5, 4))
+ printf("tick: now=%ld\n", now);
+
+ while ((ev = EventQueue) != NULL &&
+ (ev->ev_time <= now || ev->ev_pid != mypid))
+ {
+ int (*f)();
+ int arg;
+ int pid;
+
+ /* process the event on the top of the queue */
+ ev = EventQueue;
+ EventQueue = EventQueue->ev_link;
+ if (tTd(5, 6))
+ printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev,
+ ev->ev_func, ev->ev_arg, ev->ev_pid);
+
+ /* we must be careful in here because ev_func may not return */
+ f = ev->ev_func;
+ arg = ev->ev_arg;
+ pid = ev->ev_pid;
+ free((char *) ev);
+ if (pid != getpid())
+ continue;
+ if (EventQueue != NULL)
+ {
+ if (EventQueue->ev_time > now)
+ (void) alarm((unsigned) (EventQueue->ev_time - now));
+ else
+ (void) alarm(3);
+ }
+
+ /* restore signals so that we can take ticks while in ev_func */
+ (void) setsignal(SIGALRM, tick);
+#ifdef SIG_UNBLOCK
+ /* unblock SIGALRM signal */
+ sigemptyset(&ss);
+ sigaddset(&ss, SIGALRM);
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);
+#else
+#ifdef SIGVTALRM
+ /* reset 4.2bsd signal mask to allow future alarms */
+ (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM));
+#endif /* SIGVTALRM */
+#endif /* SIG_UNBLOCK */
+
+ /* call ev_func */
+ errno = olderrno;
+ (*f)(arg);
+ (void) alarm(0);
+ now = curtime();
+ }
+ (void) setsignal(SIGALRM, tick);
+ if (EventQueue != NULL)
+ (void) alarm((unsigned) (EventQueue->ev_time - now));
+ errno = olderrno;
+}
+ /*
+** SLEEP -- a version of sleep that works with this stuff
+**
+** Because sleep uses the alarm facility, I must reimplement
+** it here.
+**
+** Parameters:
+** intvl -- time to sleep.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** waits for intvl time. However, other events can
+** be run during that interval.
+*/
+
+static bool SleepDone;
+static int endsleep();
+
+#ifndef SLEEP_T
+# define SLEEP_T unsigned int
+#endif
+
+SLEEP_T
+sleep(intvl)
+ unsigned int intvl;
+{
+ if (intvl == 0)
+ return;
+ SleepDone = FALSE;
+ (void) setevent((time_t) intvl, endsleep, 0);
+ while (!SleepDone)
+ pause();
+}
+
+static
+endsleep()
+{
+ SleepDone = TRUE;
+}
diff --git a/usr.sbin/sendmail/src/collect.c b/usr.sbin/sendmail/src/collect.c
new file mode 100644
index 00000000000..b77f6e985e3
--- /dev/null
+++ b/usr.sbin/sendmail/src/collect.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)collect.c 8.14 (Berkeley) 4/18/94";
+#endif /* not lint */
+
+# include <errno.h>
+# include "sendmail.h"
+
+/*
+** COLLECT -- read & parse message header & make temp file.
+**
+** Creates a temporary file name and copies the standard
+** input to that file. Leading UNIX-style "From" lines are
+** stripped off (after important information is extracted).
+**
+** Parameters:
+** smtpmode -- if set, we are running SMTP: give an RFC821
+** style message to say we are ready to collect
+** input, and never ignore a single dot to mean
+** end of message.
+** requeueflag -- this message will be requeued later, so
+** don't do final processing on it.
+** e -- the current envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Temp file is created and filled.
+** The from person may be set.
+*/
+
+char *CollectErrorMessage;
+bool CollectErrno;
+
+collect(smtpmode, requeueflag, e)
+ bool smtpmode;
+ bool requeueflag;
+ register ENVELOPE *e;
+{
+ register FILE *tf;
+ bool ignrdot = smtpmode ? FALSE : IgnrDot;
+ char buf[MAXLINE], buf2[MAXLINE];
+ register char *workbuf, *freebuf;
+ bool inputerr = FALSE;
+ extern char *hvalue();
+ extern bool isheader(), flusheol();
+
+ CollectErrorMessage = NULL;
+ CollectErrno = 0;
+
+ /*
+ ** Create the temp file name and create the file.
+ */
+
+ e->e_df = queuename(e, 'd');
+ e->e_df = newstr(e->e_df);
+ if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL)
+ {
+ syserr("Cannot create %s", e->e_df);
+ NoReturn = TRUE;
+ finis();
+ }
+
+ /*
+ ** Tell ARPANET to go ahead.
+ */
+
+ if (smtpmode)
+ message("354 Enter mail, end with \".\" on a line by itself");
+
+ /* set global timer to monitor progress */
+ sfgetset(TimeOuts.to_datablock);
+
+ /*
+ ** Try to read a UNIX-style From line
+ */
+
+ if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+ "initial message read") == NULL)
+ goto readerr;
+ fixcrlf(buf, FALSE);
+# ifndef NOTUNIX
+ if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
+ {
+ if (!flusheol(buf, InChannel))
+ goto readerr;
+ eatfrom(buf, e);
+ if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+ "message header read") == NULL)
+ goto readerr;
+ fixcrlf(buf, FALSE);
+ }
+# endif /* NOTUNIX */
+
+ /*
+ ** Copy InChannel to temp file & do message editing.
+ ** To keep certain mailers from getting confused,
+ ** and to keep the output clean, lines that look
+ ** like UNIX "From" lines are deleted in the header.
+ */
+
+ workbuf = buf; /* `workbuf' contains a header field */
+ freebuf = buf2; /* `freebuf' can be used for read-ahead */
+ for (;;)
+ {
+ char *curbuf;
+ int curbuffree;
+ register int curbuflen;
+ char *p;
+
+ /* first, see if the header is over */
+ if (!isheader(workbuf))
+ {
+ fixcrlf(workbuf, TRUE);
+ break;
+ }
+
+ /* if the line is too long, throw the rest away */
+ if (!flusheol(workbuf, InChannel))
+ goto readerr;
+
+ /* it's okay to toss '\n' now (flusheol() needed it) */
+ fixcrlf(workbuf, TRUE);
+
+ curbuf = workbuf;
+ curbuflen = strlen(curbuf);
+ curbuffree = MAXLINE - curbuflen;
+ p = curbuf + curbuflen;
+
+ /* get the rest of this field */
+ for (;;)
+ {
+ int clen;
+
+ if (sfgets(freebuf, MAXLINE, InChannel,
+ TimeOuts.to_datablock,
+ "message header read") == NULL)
+ {
+ freebuf[0] = '\0';
+ break;
+ }
+
+ /* is this a continuation line? */
+ if (*freebuf != ' ' && *freebuf != '\t')
+ break;
+
+ if (!flusheol(freebuf, InChannel))
+ goto readerr;
+
+ fixcrlf(freebuf, TRUE);
+ clen = strlen(freebuf) + 1;
+
+ /* if insufficient room, dynamically allocate buffer */
+ if (clen >= curbuffree)
+ {
+ /* reallocate buffer */
+ int nbuflen = ((p - curbuf) + clen) * 2;
+ char *nbuf = xalloc(nbuflen);
+
+ p = nbuf + curbuflen;
+ curbuffree = nbuflen - curbuflen;
+ bcopy(curbuf, nbuf, curbuflen);
+ if (curbuf != buf && curbuf != buf2)
+ free(curbuf);
+ curbuf = nbuf;
+ }
+ *p++ = '\n';
+ bcopy(freebuf, p, clen - 1);
+ p += clen - 1;
+ curbuffree -= clen;
+ curbuflen += clen;
+ }
+ *p++ = '\0';
+
+ e->e_msgsize += curbuflen;
+
+ /*
+ ** The working buffer now becomes the free buffer, since
+ ** the free buffer contains a new header field.
+ **
+ ** This is premature, since we still havent called
+ ** chompheader() to process the field we just created
+ ** (so the call to chompheader() will use `freebuf').
+ ** This convolution is necessary so that if we break out
+ ** of the loop due to H_EOH, `workbuf' will always be
+ ** the next unprocessed buffer.
+ */
+
+ {
+ register char *tmp = workbuf;
+ workbuf = freebuf;
+ freebuf = tmp;
+ }
+
+ /*
+ ** Snarf header away.
+ */
+
+ if (bitset(H_EOH, chompheader(curbuf, FALSE, e)))
+ break;
+
+ /*
+ ** If the buffer was dynamically allocated, free it.
+ */
+
+ if (curbuf != buf && curbuf != buf2)
+ free(curbuf);
+ }
+
+ if (tTd(30, 1))
+ printf("EOH\n");
+
+ if (*workbuf == '\0')
+ {
+ /* throw away a blank line */
+ if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+ "message separator read") == NULL)
+ goto readerr;
+ }
+ else if (workbuf == buf2) /* guarantee `buf' contains data */
+ (void) strcpy(buf, buf2);
+
+ /*
+ ** Collect the body of the message.
+ */
+
+ for (;;)
+ {
+ register char *bp = buf;
+
+ fixcrlf(buf, TRUE);
+
+ /* check for end-of-message */
+ if (!ignrdot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
+ break;
+
+ /* check for transparent dot */
+ if ((OpMode == MD_SMTP || OpMode == MD_DAEMON) &&
+ bp[0] == '.' && bp[1] == '.')
+ bp++;
+
+ /*
+ ** Figure message length, output the line to the temp
+ ** file, and insert a newline if missing.
+ */
+
+ e->e_msgsize += strlen(bp) + 1;
+ fputs(bp, tf);
+ fputs("\n", tf);
+ if (ferror(tf))
+ tferror(tf, e);
+ if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+ "message body read") == NULL)
+ goto readerr;
+ }
+
+ if (feof(InChannel) || ferror(InChannel))
+ {
+readerr:
+ if (tTd(30, 1))
+ printf("collect: read error\n");
+ inputerr = TRUE;
+ }
+
+ /* reset global timer */
+ sfgetset((time_t) 0);
+
+ if (fflush(tf) != 0)
+ tferror(tf, e);
+ if (fsync(fileno(tf)) < 0 || fclose(tf) < 0)
+ {
+ tferror(tf, e);
+ finis();
+ }
+
+ if (CollectErrorMessage != NULL && Errors <= 0)
+ {
+ if (CollectErrno != 0)
+ {
+ errno = CollectErrno;
+ syserr(CollectErrorMessage, e->e_df);
+ finis();
+ }
+ usrerr(CollectErrorMessage);
+ }
+ else if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+ {
+ /* An EOF when running SMTP is an error */
+ char *host;
+ char *problem;
+
+ host = RealHostName;
+ if (host == NULL)
+ host = "localhost";
+
+ if (feof(InChannel))
+ problem = "unexpected close";
+ else if (ferror(InChannel))
+ problem = "I/O error";
+ else
+ problem = "read timeout";
+# ifdef LOG
+ if (LogLevel > 0 && feof(InChannel))
+ syslog(LOG_NOTICE,
+ "collect: %s on connection from %s, sender=%s: %s\n",
+ problem, host, e->e_from.q_paddr, errstring(errno));
+# endif
+ if (feof(InChannel))
+ usrerr("451 collect: %s on connection from %s, from=%s",
+ problem, host, e->e_from.q_paddr);
+ else
+ syserr("451 collect: %s on connection from %s, from=%s",
+ problem, host, e->e_from.q_paddr);
+
+ /* don't return an error indication */
+ e->e_to = NULL;
+ e->e_flags &= ~EF_FATALERRS;
+ e->e_flags |= EF_CLRQUEUE;
+
+ /* and don't try to deliver the partial message either */
+ if (InChild)
+ ExitStat = EX_QUIT;
+ finis();
+ }
+
+ /*
+ ** Find out some information from the headers.
+ ** Examples are who is the from person & the date.
+ */
+
+ eatheader(e, !requeueflag);
+
+ /* collect statistics */
+ if (OpMode != MD_VERIFY)
+ markstats(e, (ADDRESS *) NULL);
+
+ /*
+ ** Add an Apparently-To: line if we have no recipient lines.
+ */
+
+ if (hvalue("to", e) == NULL && hvalue("cc", e) == NULL &&
+ hvalue("bcc", e) == NULL && hvalue("apparently-to", e) == NULL)
+ {
+ register ADDRESS *q;
+
+ /* create an Apparently-To: field */
+ /* that or reject the message.... */
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (q->q_alias != NULL)
+ continue;
+ if (tTd(30, 3))
+ printf("Adding Apparently-To: %s\n", q->q_paddr);
+ addheader("Apparently-To", q->q_paddr, e);
+ }
+ }
+
+ /* check for message too large */
+ if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
+ {
+ usrerr("552 Message exceeds maximum fixed size (%ld)",
+ MaxMessageSize);
+ }
+
+ if ((e->e_dfp = fopen(e->e_df, "r")) == NULL)
+ {
+ /* we haven't acked receipt yet, so just chuck this */
+ syserr("Cannot reopen %s", e->e_df);
+ finis();
+ }
+}
+ /*
+** FLUSHEOL -- if not at EOL, throw away rest of input line.
+**
+** Parameters:
+** buf -- last line read in (checked for '\n'),
+** fp -- file to be read from.
+**
+** Returns:
+** FALSE on error from sfgets(), TRUE otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+flusheol(buf, fp)
+ char *buf;
+ FILE *fp;
+{
+ register char *p = buf;
+ char junkbuf[MAXLINE];
+
+ while (strchr(p, '\n') == NULL)
+ {
+ CollectErrorMessage = "553 header line too long";
+ CollectErrno = 0;
+ if (sfgets(junkbuf, MAXLINE, fp, TimeOuts.to_datablock,
+ "long line flush") == NULL)
+ return (FALSE);
+ p = junkbuf;
+ }
+
+ return (TRUE);
+}
+ /*
+** TFERROR -- signal error on writing the temporary file.
+**
+** Parameters:
+** tf -- the file pointer for the temporary file.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Gives an error message.
+** Arranges for following output to go elsewhere.
+*/
+
+tferror(tf, e)
+ FILE *tf;
+ register ENVELOPE *e;
+{
+ CollectErrno = errno;
+ if (errno == ENOSPC)
+ {
+ struct stat st;
+ long avail;
+ long bsize;
+
+ NoReturn = TRUE;
+ if (fstat(fileno(tf), &st) < 0)
+ st.st_size = 0;
+ (void) freopen(e->e_df, "w", tf);
+ if (st.st_size <= 0)
+ fprintf(tf, "\n*** Mail could not be accepted");
+ else if (sizeof st.st_size > sizeof (long))
+ fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n",
+ st.st_size);
+ else
+ fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n",
+ st.st_size);
+ fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
+ MyHostName);
+ avail = freespace(QueueDir, &bsize);
+ if (avail > 0)
+ {
+ if (bsize > 1024)
+ avail *= bsize / 1024;
+ else if (bsize < 1024)
+ avail /= 1024 / bsize;
+ fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
+ avail);
+ }
+ CollectErrorMessage = "452 Out of disk space for temp file";
+ }
+ else
+ {
+ CollectErrorMessage = "cannot write message body to disk (%s)";
+ }
+ (void) freopen("/dev/null", "w", tf);
+}
+ /*
+** EATFROM -- chew up a UNIX style from line and process
+**
+** This does indeed make some assumptions about the format
+** of UNIX messages.
+**
+** Parameters:
+** fm -- the from line.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** extracts what information it can from the header,
+** such as the date.
+*/
+
+# ifndef NOTUNIX
+
+char *DowList[] =
+{
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
+};
+
+char *MonthList[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ NULL
+};
+
+eatfrom(fm, e)
+ char *fm;
+ register ENVELOPE *e;
+{
+ register char *p;
+ register char **dt;
+
+ if (tTd(30, 2))
+ printf("eatfrom(%s)\n", fm);
+
+ /* find the date part */
+ p = fm;
+ while (*p != '\0')
+ {
+ /* skip a word */
+ while (*p != '\0' && *p != ' ')
+ p++;
+ while (*p == ' ')
+ p++;
+ if (!(isascii(*p) && isupper(*p)) ||
+ p[3] != ' ' || p[13] != ':' || p[16] != ':')
+ continue;
+
+ /* we have a possible date */
+ for (dt = DowList; *dt != NULL; dt++)
+ if (strncmp(*dt, p, 3) == 0)
+ break;
+ if (*dt == NULL)
+ continue;
+
+ for (dt = MonthList; *dt != NULL; dt++)
+ if (strncmp(*dt, &p[4], 3) == 0)
+ break;
+ if (*dt != NULL)
+ break;
+ }
+
+ if (*p != '\0')
+ {
+ char *q;
+ extern char *arpadate();
+
+ /* we have found a date */
+ q = xalloc(25);
+ (void) strncpy(q, p, 25);
+ q[24] = '\0';
+ q = arpadate(q);
+ define('a', newstr(q), e);
+ }
+}
+
+# endif /* NOTUNIX */
diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c
new file mode 100644
index 00000000000..5559a741d15
--- /dev/null
+++ b/usr.sbin/sendmail/src/conf.c
@@ -0,0 +1,2387 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)conf.c 8.89.1.3 (Berkeley) 3/7/95";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include "pathnames.h"
+# include <sys/ioctl.h>
+# include <sys/param.h>
+# include <netdb.h>
+# include <pwd.h>
+
+/*
+** CONF.C -- Sendmail Configuration Tables.
+**
+** Defines the configuration of this installation.
+**
+** Configuration Variables:
+** HdrInfo -- a table describing well-known header fields.
+** Each entry has the field name and some flags,
+** which are described in sendmail.h.
+**
+** Notes:
+** I have tried to put almost all the reasonable
+** configuration information into the configuration
+** file read at runtime. My intent is that anything
+** here is a function of the version of UNIX you
+** are running, or is really static -- for example
+** the headers are a superset of widely used
+** protocols. If you find yourself playing with
+** this file too much, you may be making a mistake!
+*/
+
+
+
+
+/*
+** Header info table
+** Final (null) entry contains the flags used for any other field.
+**
+** Not all of these are actually handled specially by sendmail
+** at this time. They are included as placeholders, to let
+** you know that "someday" I intend to have sendmail do
+** something with them.
+*/
+
+struct hdrinfo HdrInfo[] =
+{
+ /* originator fields, most to least significant */
+ "resent-sender", H_FROM|H_RESENT,
+ "resent-from", H_FROM|H_RESENT,
+ "resent-reply-to", H_FROM|H_RESENT,
+ "sender", H_FROM,
+ "from", H_FROM,
+ "reply-to", H_FROM,
+ "full-name", H_ACHECK,
+ "return-receipt-to", H_FROM|H_RECEIPTTO,
+ "errors-to", H_FROM|H_ERRORSTO,
+
+ /* destination fields */
+ "to", H_RCPT,
+ "resent-to", H_RCPT|H_RESENT,
+ "cc", H_RCPT,
+ "resent-cc", H_RCPT|H_RESENT,
+ "bcc", H_RCPT|H_ACHECK,
+ "resent-bcc", H_RCPT|H_ACHECK|H_RESENT,
+ "apparently-to", H_RCPT,
+
+ /* message identification and control */
+ "message-id", 0,
+ "resent-message-id", H_RESENT,
+ "message", H_EOH,
+ "text", H_EOH,
+
+ /* date fields */
+ "date", 0,
+ "resent-date", H_RESENT,
+
+ /* trace fields */
+ "received", H_TRACE|H_FORCE,
+ "x400-received", H_TRACE|H_FORCE,
+ "via", H_TRACE|H_FORCE,
+ "mail-from", H_TRACE|H_FORCE,
+
+ /* miscellaneous fields */
+ "comments", H_FORCE,
+ "return-path", H_FORCE|H_ACHECK,
+
+ NULL, 0,
+};
+
+
+
+/*
+** Location of system files/databases/etc.
+*/
+
+char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */
+
+
+
+/*
+** Privacy values
+*/
+
+struct prival PrivacyValues[] =
+{
+ "public", PRIV_PUBLIC,
+ "needmailhelo", PRIV_NEEDMAILHELO,
+ "needexpnhelo", PRIV_NEEDEXPNHELO,
+ "needvrfyhelo", PRIV_NEEDVRFYHELO,
+ "noexpn", PRIV_NOEXPN,
+ "novrfy", PRIV_NOVRFY,
+ "restrictmailq", PRIV_RESTRICTMAILQ,
+ "restrictqrun", PRIV_RESTRICTQRUN,
+ "authwarnings", PRIV_AUTHWARNINGS,
+ "noreceipts", PRIV_NORECEIPTS,
+ "goaway", PRIV_GOAWAY,
+ NULL, 0,
+};
+
+
+
+/*
+** Miscellaneous stuff.
+*/
+
+int DtableSize = 50; /* max open files; reset in 4.2bsd */
+
+
+/*
+** Following should be config parameters (and probably will be in
+** future releases). In the meantime, setting these is considered
+** unsupported, and is intentionally undocumented.
+*/
+
+#ifdef BROKENSMTPPEERS
+bool BrokenSmtpPeers = TRUE; /* set if you have broken SMTP peers */
+#else
+bool BrokenSmtpPeers = FALSE; /* set if you have broken SMTP peers */
+#endif
+#ifdef NOLOOPBACKCHECK
+bool CheckLoopBack = FALSE; /* set to check HELO loopback */
+#else
+bool CheckLoopBack = TRUE; /* set to check HELO loopback */
+#endif
+
+ /*
+** SETDEFAULTS -- set default values
+**
+** Because of the way freezing is done, these must be initialized
+** using direct code.
+**
+** Parameters:
+** e -- the default envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Initializes a bunch of global variables to their
+** default values.
+*/
+
+#define DAYS * 24 * 60 * 60
+
+setdefaults(e)
+ register ENVELOPE *e;
+{
+ SpaceSub = ' '; /* option B */
+ QueueLA = 8; /* option x */
+ RefuseLA = 12; /* option X */
+ WkRecipFact = 30000L; /* option y */
+ WkClassFact = 1800L; /* option z */
+ WkTimeFact = 90000L; /* option Z */
+ QueueFactor = WkRecipFact * 20; /* option q */
+ FileMode = (RealUid != geteuid()) ? 0644 : 0600;
+ /* option F */
+ DefUid = 1; /* option u */
+ DefGid = 1; /* option g */
+ CheckpointInterval = 10; /* option C */
+ MaxHopCount = 25; /* option h */
+ e->e_sendmode = SM_FORK; /* option d */
+ e->e_errormode = EM_PRINT; /* option e */
+ SevenBit = FALSE; /* option 7 */
+ MaxMciCache = 1; /* option k */
+ MciCacheTimeout = 300; /* option K */
+ LogLevel = 9; /* option L */
+ settimeouts(NULL); /* option r */
+ TimeOuts.to_q_return = 5 DAYS; /* option T */
+ TimeOuts.to_q_warning = 0; /* option T */
+ PrivacyFlags = 0; /* option p */
+ setdefuser();
+ setupmaps();
+ setupmailers();
+}
+
+
+/*
+** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
+*/
+
+setdefuser()
+{
+ struct passwd *defpwent;
+ static char defuserbuf[40];
+
+ DefUser = defuserbuf;
+ if ((defpwent = getpwuid(DefUid)) != NULL)
+ strcpy(defuserbuf, defpwent->pw_name);
+ else
+ strcpy(defuserbuf, "nobody");
+}
+ /*
+** HOST_MAP_INIT -- initialize host class structures
+*/
+
+bool host_map_init __P((MAP *map, char *args));
+
+bool
+host_map_init(map, args)
+ MAP *map;
+ char *args;
+{
+ register char *p = args;
+
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'a':
+ map->map_app = ++p;
+ break;
+ }
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ if (map->map_app != NULL)
+ map->map_app = newstr(map->map_app);
+ return TRUE;
+}
+ /*
+** SETUPMAILERS -- initialize default mailers
+*/
+
+setupmailers()
+{
+ char buf[100];
+
+ strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
+ makemailer(buf);
+
+ strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE");
+ makemailer(buf);
+
+ strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
+ makemailer(buf);
+}
+ /*
+** SETUPMAPS -- set up map classes
+*/
+
+#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
+ { \
+ extern bool parse __P((MAP *, char *)); \
+ extern bool open __P((MAP *, int)); \
+ extern void close __P((MAP *)); \
+ extern char *lookup __P((MAP *, char *, char **, int *)); \
+ extern void store __P((MAP *, char *, char *)); \
+ s = stab(name, ST_MAPCLASS, ST_ENTER); \
+ s->s_mapclass.map_cname = name; \
+ s->s_mapclass.map_ext = ext; \
+ s->s_mapclass.map_cflags = flags; \
+ s->s_mapclass.map_parse = parse; \
+ s->s_mapclass.map_open = open; \
+ s->s_mapclass.map_close = close; \
+ s->s_mapclass.map_lookup = lookup; \
+ s->s_mapclass.map_store = store; \
+ }
+
+setupmaps()
+{
+ register STAB *s;
+
+#ifdef NEWDB
+ MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, hash_map_open, db_map_close,
+ db_map_lookup, db_map_store);
+ MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, bt_map_open, db_map_close,
+ db_map_lookup, db_map_store);
+#endif
+
+#ifdef NDBM
+ MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, ndbm_map_open, ndbm_map_close,
+ ndbm_map_lookup, ndbm_map_store);
+#endif
+
+#ifdef NIS
+ MAPDEF("nis", NULL, MCF_ALIASOK,
+ map_parseargs, nis_map_open, nis_map_close,
+ nis_map_lookup, nis_map_store);
+#endif
+
+ MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
+ map_parseargs, stab_map_open, stab_map_close,
+ stab_map_lookup, stab_map_store);
+
+ MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
+ map_parseargs, impl_map_open, impl_map_close,
+ impl_map_lookup, impl_map_store);
+
+ /* host DNS lookup */
+ MAPDEF("host", NULL, 0,
+ host_map_init, null_map_open, null_map_close,
+ host_map_lookup, null_map_store);
+
+ /* dequote map */
+ MAPDEF("dequote", NULL, 0,
+ dequote_init, null_map_open, null_map_close,
+ dequote_map, null_map_store);
+
+#if 0
+# ifdef USERDB
+ /* user database */
+ MAPDEF("udb", ".db", 0,
+ udb_map_parse, null_map_open, null_map_close,
+ udb_map_lookup, null_map_store);
+# endif
+#endif
+}
+
+#undef MAPDEF
+ /*
+** USERNAME -- return the user id of the logged in user.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** The login name of the logged in user.
+**
+** Side Effects:
+** none.
+**
+** Notes:
+** The return value is statically allocated.
+*/
+
+char *
+username()
+{
+ static char *myname = NULL;
+ extern char *getlogin();
+ register struct passwd *pw;
+
+ /* cache the result */
+ if (myname == NULL)
+ {
+ myname = getlogin();
+ if (myname == NULL || myname[0] == '\0')
+ {
+ pw = getpwuid(RealUid);
+ if (pw != NULL)
+ myname = newstr(pw->pw_name);
+ }
+ else
+ {
+ uid_t uid = RealUid;
+
+ myname = newstr(myname);
+ if ((pw = getpwnam(myname)) == NULL ||
+ (uid != 0 && uid != pw->pw_uid))
+ {
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ myname = newstr(pw->pw_name);
+ }
+ }
+ if (myname == NULL || myname[0] == '\0')
+ {
+ syserr("554 Who are you?");
+ myname = "postmaster";
+ }
+ }
+
+ return (myname);
+}
+ /*
+** TTYPATH -- Get the path of the user's tty
+**
+** Returns the pathname of the user's tty. Returns NULL if
+** the user is not logged in or if s/he has write permission
+** denied.
+**
+** Parameters:
+** none
+**
+** Returns:
+** pathname of the user's tty.
+** NULL if not logged in or write permission denied.
+**
+** Side Effects:
+** none.
+**
+** WARNING:
+** Return value is in a local buffer.
+**
+** Called By:
+** savemail
+*/
+
+char *
+ttypath()
+{
+ struct stat stbuf;
+ register char *pathn;
+ extern char *ttyname();
+ extern char *getlogin();
+
+ /* compute the pathname of the controlling tty */
+ if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
+ (pathn = ttyname(0)) == NULL)
+ {
+ errno = 0;
+ return (NULL);
+ }
+
+ /* see if we have write permission */
+ if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
+ {
+ errno = 0;
+ return (NULL);
+ }
+
+ /* see if the user is logged in */
+ if (getlogin() == NULL)
+ return (NULL);
+
+ /* looks good */
+ return (pathn);
+}
+ /*
+** CHECKCOMPAT -- check for From and To person compatible.
+**
+** This routine can be supplied on a per-installation basis
+** to determine whether a person is allowed to send a message.
+** This allows restriction of certain types of internet
+** forwarding or registration of users.
+**
+** If the hosts are found to be incompatible, an error
+** message should be given using "usrerr" and 0 should
+** be returned.
+**
+** 'NoReturn' can be set to suppress the return-to-sender
+** function; this should be done on huge messages.
+**
+** Parameters:
+** to -- the person being sent to.
+**
+** Returns:
+** an exit status
+**
+** Side Effects:
+** none (unless you include the usrerr stuff)
+*/
+
+checkcompat(to, e)
+ register ADDRESS *to;
+ register ENVELOPE *e;
+{
+# ifdef lint
+ if (to == NULL)
+ to++;
+# endif /* lint */
+
+ if (tTd(49, 1))
+ printf("checkcompat(to=%s, from=%s)\n",
+ to->q_paddr, e->e_from.q_paddr);
+
+# ifdef EXAMPLE_CODE
+ /* this code is intended as an example only */
+ register STAB *s;
+
+ s = stab("arpa", ST_MAILER, ST_FIND);
+ if (s != NULL && e->e_from.q_mailer != LocalMailer &&
+ to->q_mailer == s->s_mailer)
+ {
+ usrerr("553 No ARPA mail through this machine: see your system administration");
+ /* NoReturn = TRUE; to supress return copy */
+ return (EX_UNAVAILABLE);
+ }
+# endif /* EXAMPLE_CODE */
+ return (EX_OK);
+}
+ /*
+** SETSIGNAL -- set a signal handler
+**
+** This is essentially old BSD "signal(3)".
+*/
+
+sigfunc_t
+setsignal(sig, handler)
+ int sig;
+ sigfunc_t handler;
+{
+#if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
+ return signal(sig, handler);
+#else
+ struct sigaction n, o;
+
+ bzero(&n, sizeof n);
+ n.sa_handler = handler;
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+#endif
+}
+ /*
+** HOLDSIGS -- arrange to hold all signals
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Arranges that signals are held.
+*/
+
+holdsigs()
+{
+}
+ /*
+** RLSESIGS -- arrange to release all signals
+**
+** This undoes the effect of holdsigs.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Arranges that signals are released.
+*/
+
+rlsesigs()
+{
+}
+ /*
+** INIT_MD -- do machine dependent initializations
+**
+** Systems that have global modes that should be set should do
+** them here rather than in main.
+*/
+
+#ifdef _AUX_SOURCE
+# include <compat.h>
+#endif
+
+init_md(argc, argv)
+ int argc;
+ char **argv;
+{
+#ifdef _AUX_SOURCE
+ setcompat(getcompat() | COMPAT_BSDPROT);
+#endif
+}
+ /*
+** GETLA -- get the current load average
+**
+** This code stolen from la.c.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** The current load average as an integer.
+**
+** Side Effects:
+** none.
+*/
+
+/* try to guess what style of load average we have */
+#define LA_ZERO 1 /* always return load average as zero */
+#define LA_INT 2 /* read kmem for avenrun; interpret as long */
+#define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
+#define LA_SUBR 4 /* call getloadavg */
+#define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */
+#define LA_SHORT 6 /* read kmem for avenrun; interpret as short */
+#define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */
+
+/* do guesses based on general OS type */
+#ifndef LA_TYPE
+# define LA_TYPE LA_ZERO
+#endif
+
+#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
+
+#include <nlist.h>
+
+#ifndef LA_AVENRUN
+# ifdef SYSTEM5
+# define LA_AVENRUN "avenrun"
+# else
+# define LA_AVENRUN "_avenrun"
+# endif
+#endif
+
+/* _PATH_UNIX should be defined in <paths.h> */
+#ifndef _PATH_UNIX
+# if defined(SYSTEM5)
+# define _PATH_UNIX "/unix"
+# else
+# define _PATH_UNIX "/vmunix"
+# endif
+#endif
+
+struct nlist Nl[] =
+{
+ { LA_AVENRUN },
+#define X_AVENRUN 0
+ { 0 },
+};
+
+#ifndef FSHIFT
+# if defined(unixpc)
+# define FSHIFT 5
+# endif
+
+# if defined(__alpha) || defined(IRIX)
+# define FSHIFT 10
+# endif
+#endif
+
+#ifndef FSHIFT
+# define FSHIFT 8
+#endif
+
+#ifndef FSCALE
+# define FSCALE (1 << FSHIFT)
+#endif
+
+getla()
+{
+ static int kmem = -1;
+#if LA_TYPE == LA_INT
+ long avenrun[3];
+#else
+# if LA_TYPE == LA_SHORT
+ short avenrun[3];
+# else
+ double avenrun[3];
+# endif
+#endif
+ extern off_t lseek();
+ extern int errno;
+
+ if (kmem < 0)
+ {
+ kmem = open("/dev/kmem", 0, 0);
+ if (kmem < 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: open(/dev/kmem): %s\n",
+ errstring(errno));
+ return (-1);
+ }
+ (void) fcntl(kmem, F_SETFD, 1);
+ if (nlist(_PATH_UNIX, Nl) < 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: nlist(%s): %s\n", _PATH_UNIX,
+ errstring(errno));
+ return (-1);
+ }
+ if (Nl[X_AVENRUN].n_value == 0)
+ {
+ if (tTd(3, 1))
+ printf("getla: nlist(%s, %s) ==> 0\n",
+ _PATH_UNIX, LA_AVENRUN);
+ return (-1);
+ }
+#ifdef IRIX
+ Nl[X_AVENRUN].n_value &= 0x7fffffff;
+#endif
+ }
+ if (tTd(3, 20))
+ printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
+ if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
+ read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
+ {
+ /* thank you Ian */
+ if (tTd(3, 1))
+ printf("getla: lseek or read: %s\n", errstring(errno));
+ return (-1);
+ }
+#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
+ if (tTd(3, 5))
+ {
+ printf("getla: avenrun = %d", avenrun[0]);
+ if (tTd(3, 15))
+ printf(", %d, %d", avenrun[1], avenrun[2]);
+ printf("\n");
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
+ return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
+#else
+ if (tTd(3, 5))
+ {
+ printf("getla: avenrun = %g", avenrun[0]);
+ if (tTd(3, 15))
+ printf(", %g, %g", avenrun[1], avenrun[2]);
+ printf("\n");
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] +0.5));
+ return ((int) (avenrun[0] + 0.5));
+#endif
+}
+
+#else
+#if LA_TYPE == LA_SUBR
+
+#ifdef DGUX
+
+#include <sys/dg_sys_info.h>
+
+int getla()
+{
+ struct dg_sys_info_load_info load_info;
+
+ dg_sys_info((long *)&load_info,
+ DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
+
+ return((int) (load_info.one_minute + 0.5));
+}
+
+#else
+
+getla()
+{
+ double avenrun[3];
+
+ if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
+ {
+ if (tTd(3, 1))
+ perror("getla: getloadavg failed:");
+ return (-1);
+ }
+ if (tTd(3, 1))
+ printf("getla: %d\n", (int) (avenrun[0] +0.5));
+ return ((int) (avenrun[0] + 0.5));
+}
+
+#endif /* DGUX */
+#else
+#if LA_TYPE == LA_MACH
+
+/*
+** This has been tested on NEXTSTEP release 2.1/3.X.
+*/
+
+#if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
+# include <mach/mach.h>
+#else
+# include <mach.h>
+#endif
+
+getla()
+{
+ processor_set_t default_set;
+ kern_return_t error;
+ unsigned int info_count;
+ struct processor_set_basic_info info;
+ host_t host;
+
+ error = processor_set_default(host_self(), &default_set);
+ if (error != KERN_SUCCESS)
+ return -1;
+ info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
+ if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
+ &host, (processor_set_info_t)&info,
+ &info_count) != KERN_SUCCESS)
+ {
+ return -1;
+ }
+ return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
+}
+
+
+#else
+#if LA_TYPE == LA_PROCSTR
+
+/*
+** Read /proc/loadavg for the load average. This is assumed to be
+** in a format like "0.15 0.12 0.06".
+**
+** Initially intended for Linux. This has been in the kernel
+** since at least 0.99.15.
+*/
+
+# ifndef _PATH_LOADAVG
+# define _PATH_LOADAVG "/proc/loadavg"
+# endif
+
+int
+getla()
+{
+ double avenrun;
+ register int result;
+ FILE *fp;
+
+ fp = fopen(_PATH_LOADAVG, "r");
+ if (fp == NULL)
+ {
+ if (tTd(3, 1))
+ printf("getla: fopen(%s): %s\n",
+ _PATH_LOADAVG, errstring(errno));
+ return -1;
+ }
+ result = fscanf(fp, "%lf", &avenrun);
+ fclose(fp);
+ if (result != 1)
+ {
+ if (tTd(3, 1))
+ printf("getla: fscanf() = %d: %s\n",
+ result, errstring(errno));
+ return -1;
+ }
+
+ if (tTd(3, 1))
+ printf("getla(): %.2f\n", avenrun);
+
+ return ((int) (avenrun + 0.5));
+}
+
+#else
+
+getla()
+{
+ if (tTd(3, 1))
+ printf("getla: ZERO\n");
+ return (0);
+}
+
+#endif
+#endif
+#endif
+#endif
+
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Many and varied...
+ */
+
+/* Non Apollo stuff removed by Don Lewis 11/15/93 */
+#ifndef lint
+static char rcsid[] = "@(#)Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp ";
+#endif /* !lint */
+
+#ifdef apollo
+# undef volatile
+# include <apollo/base.h>
+
+/* ARGSUSED */
+int getloadavg( call_data )
+ caddr_t call_data; /* pointer to (double) return value */
+{
+ double *avenrun = (double *) call_data;
+ int i;
+ status_$t st;
+ long loadav[3];
+ proc1_$get_loadav(loadav, &st);
+ *avenrun = loadav[0] / (double) (1 << 16);
+ return(0);
+}
+# endif /* apollo */
+ /*
+** SHOULDQUEUE -- should this message be queued or sent?
+**
+** Compares the message cost to the load average to decide.
+**
+** Parameters:
+** pri -- the priority of the message in question.
+** ctime -- the message creation time.
+**
+** Returns:
+** TRUE -- if this message should be queued up for the
+** time being.
+** FALSE -- if the load is low enough to send this message.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+shouldqueue(pri, ctime)
+ long pri;
+ time_t ctime;
+{
+ if (CurrentLA < QueueLA)
+ return (FALSE);
+ if (CurrentLA >= RefuseLA)
+ return (TRUE);
+ return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
+}
+ /*
+** REFUSECONNECTIONS -- decide if connections should be refused
+**
+** Parameters:
+** none.
+**
+** Returns:
+** TRUE if incoming SMTP connections should be refused
+** (for now).
+** FALSE if we should accept new work.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+refuseconnections()
+{
+#ifdef XLA
+ if (!xla_smtp_ok())
+ return TRUE;
+#endif
+
+ /* this is probably too simplistic */
+ return (CurrentLA >= RefuseLA);
+}
+ /*
+** SETPROCTITLE -- set process title for ps
+**
+** Parameters:
+** fmt -- a printf style format string.
+** a, b, c -- possible parameters to fmt.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Clobbers argv of our main procedure so ps(1) will
+** display the title.
+*/
+
+#ifdef SETPROCTITLE
+# ifdef HASSETPROCTITLE
+ *** ERROR *** Cannot have both SETPROCTITLE and HASSETPROCTITLE defined
+# endif
+# ifdef __hpux
+# include <sys/pstat.h>
+# endif
+# ifdef BSD4_4
+# include <machine/vmparam.h>
+# include <sys/exec.h>
+# ifdef __bsdi__
+# undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */
+# define PROCTITLEPAD '\0'
+# endif
+# ifdef PS_STRINGS
+# define SETPROC_STATIC static
+# endif
+# endif
+# ifndef SETPROC_STATIC
+# define SETPROC_STATIC
+# endif
+#endif
+
+#ifndef PROCTITLEPAD
+# define PROCTITLEPAD ' '
+#endif
+
+#ifndef HASSETPROCTITLE
+
+/*VARARGS1*/
+#ifdef __STDC__
+setproctitle(char *fmt, ...)
+#else
+setproctitle(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+# ifdef SETPROCTITLE
+ register char *p;
+ register int i;
+ SETPROC_STATIC char buf[MAXLINE];
+ VA_LOCAL_DECL
+# ifdef __hpux
+ union pstun pst;
+# endif
+ extern char **Argv;
+ extern char *LastArgv;
+
+ p = buf;
+
+ /* print sendmail: heading for grep */
+ (void) strcpy(p, "sendmail: ");
+ p += strlen(p);
+
+ /* print the argument string */
+ VA_START(fmt);
+ (void) vsprintf(p, fmt, ap);
+ VA_END;
+
+ i = strlen(buf);
+
+# ifdef __hpux
+ pst.pst_command = buf;
+ pstat(PSTAT_SETCMD, pst, i, 0, 0);
+# else
+# ifdef PS_STRINGS
+ PS_STRINGS->ps_nargvstr = 1;
+ PS_STRINGS->ps_argvstr = buf;
+# else
+ if (i > LastArgv - Argv[0] - 2)
+ {
+ i = LastArgv - Argv[0] - 2;
+ buf[i] = '\0';
+ }
+ (void) strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while (p < LastArgv)
+ *p++ = PROCTITLEPAD;
+# endif
+# endif
+# endif /* SETPROCTITLE */
+}
+
+#endif
+ /*
+** REAPCHILD -- pick up the body of my child, lest it become a zombie
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Picks up extant zombies.
+*/
+
+void
+reapchild()
+{
+ int olderrno = errno;
+# ifdef HASWAITPID
+ auto int status;
+ int count;
+ int pid;
+
+ count = 0;
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ if (count++ > 1000)
+ {
+#ifdef LOG
+ syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
+ pid, status);
+#endif
+ break;
+ }
+ }
+# else
+# ifdef WNOHANG
+ union wait status;
+
+ while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
+ continue;
+# else /* WNOHANG */
+ auto int status;
+
+ while (wait(&status) > 0)
+ continue;
+# endif /* WNOHANG */
+# endif
+# ifdef SYS5SIGNALS
+ (void) setsignal(SIGCHLD, reapchild);
+# endif
+ errno = olderrno;
+}
+ /*
+** UNSETENV -- remove a variable from the environment
+**
+** Not needed on newer systems.
+**
+** Parameters:
+** name -- the string name of the environment variable to be
+** deleted from the current environment.
+**
+** Returns:
+** none.
+**
+** Globals:
+** environ -- a pointer to the current environment.
+**
+** Side Effects:
+** Modifies environ.
+*/
+
+#ifndef HASUNSETENV
+
+void
+unsetenv(name)
+ char *name;
+{
+ extern char **environ;
+ register char **pp;
+ int len = strlen(name);
+
+ for (pp = environ; *pp != NULL; pp++)
+ {
+ if (strncmp(name, *pp, len) == 0 &&
+ ((*pp)[len] == '=' || (*pp)[len] == '\0'))
+ break;
+ }
+
+ for (; *pp != NULL; pp++)
+ *pp = pp[1];
+}
+
+#endif
+ /*
+** GETDTABLESIZE -- return number of file descriptors
+**
+** Only on non-BSD systems
+**
+** Parameters:
+** none
+**
+** Returns:
+** size of file descriptor table
+**
+** Side Effects:
+** none
+*/
+
+#ifdef SOLARIS
+# include <sys/resource.h>
+#endif
+
+int
+getdtsize()
+{
+#ifdef RLIMIT_NOFILE
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
+ return rl.rlim_cur;
+#endif
+
+# ifdef HASGETDTABLESIZE
+ return getdtablesize();
+# else
+# ifdef _SC_OPEN_MAX
+ return sysconf(_SC_OPEN_MAX);
+# else
+ return NOFILE;
+# endif
+# endif
+}
+ /*
+** UNAME -- get the UUCP name of this system.
+*/
+
+#ifndef HASUNAME
+
+int
+uname(name)
+ struct utsname *name;
+{
+ FILE *file;
+ char *n;
+
+ name->nodename[0] = '\0';
+
+ /* try /etc/whoami -- one line with the node name */
+ if ((file = fopen("/etc/whoami", "r")) != NULL)
+ {
+ (void) fgets(name->nodename, NODE_LENGTH + 1, file);
+ (void) fclose(file);
+ n = strchr(name->nodename, '\n');
+ if (n != NULL)
+ *n = '\0';
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+
+ /* try /usr/include/whoami.h -- has a #define somewhere */
+ if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
+ {
+ char buf[MAXLINE];
+
+ while (fgets(buf, MAXLINE, file) != NULL)
+ if (sscanf(buf, "#define sysname \"%*[^\"]\"",
+ NODE_LENGTH, name->nodename) > 0)
+ break;
+ (void) fclose(file);
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+
+#ifdef TRUST_POPEN
+ /*
+ ** Popen is known to have security holes.
+ */
+
+ /* try uuname -l to return local name */
+ if ((file = popen("uuname -l", "r")) != NULL)
+ {
+ (void) fgets(name, NODE_LENGTH + 1, file);
+ (void) pclose(file);
+ n = strchr(name, '\n');
+ if (n != NULL)
+ *n = '\0';
+ if (name->nodename[0] != '\0')
+ return (0);
+ }
+#endif
+
+ return (-1);
+}
+#endif /* HASUNAME */
+ /*
+** INITGROUPS -- initialize groups
+**
+** Stub implementation for System V style systems
+*/
+
+#ifndef HASINITGROUPS
+
+initgroups(name, basegid)
+ char *name;
+ int basegid;
+{
+ return 0;
+}
+
+#endif
+ /*
+** SETSID -- set session id (for non-POSIX systems)
+*/
+
+#ifndef HASSETSID
+
+pid_t
+setsid __P ((void))
+{
+#ifdef TIOCNOTTY
+ int fd;
+
+ fd = open("/dev/tty", O_RDWR, 0);
+ if (fd >= 0)
+ {
+ (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
+ (void) close(fd);
+ }
+#endif /* TIOCNOTTY */
+# ifdef SYS5SETPGRP
+ return setpgrp();
+# else
+ return setpgid(0, getpid());
+# endif
+}
+
+#endif
+ /*
+** FSYNC -- dummy fsync
+*/
+
+#ifdef NEEDFSYNC
+
+fsync(fd)
+ int fd;
+{
+# ifdef O_SYNC
+ return fcntl(fd, F_SETFL, O_SYNC);
+# else
+ /* nothing we can do */
+ return 0;
+# endif
+}
+
+#endif
+ /*
+** DGUX_INET_ADDR -- inet_addr for DG/UX
+**
+** Data General DG/UX version of inet_addr returns a struct in_addr
+** instead of a long. This patches things.
+*/
+
+#ifdef DGUX
+
+#undef inet_addr
+
+long
+dgux_inet_addr(host)
+ char *host;
+{
+ struct in_addr haddr;
+
+ haddr = inet_addr(host);
+ return haddr.s_addr;
+}
+
+#endif
+ /*
+** GETOPT -- for old systems or systems with bogus implementations
+*/
+
+#ifdef NEEDGETOPT
+
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+
+/*
+** this version hacked to add `atend' flag to allow state machine
+** to reset if invoked by the program to scan args for a 2nd time
+*/
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+/*
+ * get option letter from argument vector
+ */
+#ifdef _CONVEX_SOURCE
+extern int optind, opterr;
+#else
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+#endif
+int optopt = 0; /* character checked for validity */
+char *optarg = NULL; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define EMSG ""
+#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
+ fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
+
+getopt(nargc,nargv,ostr)
+ int nargc;
+ char *const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ static char atend = 0;
+ register char *oli; /* option letter list index */
+
+ if (atend) {
+ atend = 0;
+ place = EMSG;
+ }
+ if(!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
+ atend++;
+ return(EOF);
+ }
+ if (*place == '-') { /* found "--" */
+ ++optind;
+ atend++;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
+ if (!*place) ++optind;
+ tell(": illegal option -- ");
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place) ++optind;
+ }
+ else { /* need an argument */
+ if (*place) optarg = place; /* no white space */
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ tell(": option requires an argument -- ");
+ }
+ else optarg = nargv[optind]; /* white space */
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
+
+#endif
+ /*
+** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
+*/
+
+#ifdef NEEDVPRINTF
+
+#define MAXARG 16
+
+vfprintf(fp, fmt, ap)
+ FILE * fp;
+ char * fmt;
+ char ** ap;
+{
+ char * bp[MAXARG];
+ int i = 0;
+
+ while (*ap && i < MAXARG)
+ bp[i++] = *ap++;
+ fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
+ bp[4], bp[5], bp[6], bp[7],
+ bp[8], bp[9], bp[10], bp[11],
+ bp[12], bp[13], bp[14], bp[15]);
+}
+
+vsprintf(s, fmt, ap)
+ char * s;
+ char * fmt;
+ char ** ap;
+{
+ char * bp[MAXARG];
+ int i = 0;
+
+ while (*ap && i < MAXARG)
+ bp[i++] = *ap++;
+ sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
+ bp[4], bp[5], bp[6], bp[7],
+ bp[8], bp[9], bp[10], bp[11],
+ bp[12], bp[13], bp[14], bp[15]);
+}
+
+#endif
+ /*
+** USERSHELLOK -- tell if a user's shell is ok for unrestricted use
+**
+** Parameters:
+** shell -- the user's shell from /etc/passwd
+**
+** Returns:
+** TRUE -- if it is ok to use this for unrestricted access.
+** FALSE -- if the shell is restricted.
+*/
+
+#if !HASGETUSERSHELL
+
+# ifndef _PATH_SHELLS
+# define _PATH_SHELLS "/etc/shells"
+# endif
+
+char *DefaultUserShells[] =
+{
+ "/bin/sh",
+ "/usr/bin/sh",
+ "/bin/csh",
+ "/usr/bin/csh",
+#ifdef __hpux
+ "/bin/rsh",
+ "/bin/ksh",
+ "/bin/rksh",
+ "/bin/pam",
+ "/usr/bin/keysh",
+ "/bin/posix/sh",
+#endif
+ NULL
+};
+
+#endif
+
+#define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/"
+
+bool
+usershellok(shell)
+ char *shell;
+{
+#if HASGETUSERSHELL
+ register char *p;
+ extern char *getusershell();
+
+ if (shell == NULL || shell[0] == '\0')
+ return TRUE;
+
+ setusershell();
+ while ((p = getusershell()) != NULL)
+ if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
+ break;
+ endusershell();
+ return p != NULL;
+#else
+ register FILE *shellf;
+ char buf[MAXLINE];
+
+ if (shell == NULL || shell[0] == '\0')
+ return TRUE;
+
+ shellf = fopen(_PATH_SHELLS, "r");
+ if (shellf == NULL)
+ {
+ /* no /etc/shells; see if it is one of the std shells */
+ char **d;
+
+ for (d = DefaultUserShells; *d != NULL; d++)
+ {
+ if (strcmp(shell, *d) == 0)
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ while (fgets(buf, sizeof buf, shellf) != NULL)
+ {
+ register char *p, *q;
+
+ p = buf;
+ while (*p != '\0' && *p != '#' && *p != '/')
+ p++;
+ if (*p == '#' || *p == '\0')
+ continue;
+ q = p;
+ while (*p != '\0' && *p != '#' && !isspace(*p))
+ p++;
+ *p = '\0';
+ if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
+ {
+ fclose(shellf);
+ return TRUE;
+ }
+ }
+ fclose(shellf);
+ return FALSE;
+#endif
+}
+ /*
+** FREESPACE -- see how much free space is on the queue filesystem
+**
+** Only implemented if you have statfs.
+**
+** Parameters:
+** dir -- the directory in question.
+** bsize -- a variable into which the filesystem
+** block size is stored.
+**
+** Returns:
+** The number of bytes free on the queue filesystem.
+** -1 if the statfs call fails.
+**
+** Side effects:
+** Puts the filesystem block size into bsize.
+*/
+
+/* statfs types */
+#define SFS_NONE 0 /* no statfs implementation */
+#define SFS_USTAT 1 /* use ustat */
+#define SFS_4ARGS 2 /* use four-argument statfs call */
+#define SFS_VFS 3 /* use <sys/vfs.h> implementation */
+#define SFS_MOUNT 4 /* use <sys/mount.h> implementation */
+#define SFS_STATFS 5 /* use <sys/statfs.h> implementation */
+#define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */
+
+#ifndef SFS_TYPE
+# define SFS_TYPE SFS_NONE
+#endif
+
+#if SFS_TYPE == SFS_USTAT
+# include <ustat.h>
+#endif
+#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
+# include <sys/statfs.h>
+#endif
+#if SFS_TYPE == SFS_VFS
+# include <sys/vfs.h>
+#endif
+#if SFS_TYPE == SFS_MOUNT
+# include <sys/mount.h>
+#endif
+#if SFS_TYPE == SFS_STATVFS
+# include <sys/statvfs.h>
+#endif
+
+long
+freespace(dir, bsize)
+ char *dir;
+ long *bsize;
+{
+#if SFS_TYPE != SFS_NONE
+# if SFS_TYPE == SFS_USTAT
+ struct ustat fs;
+ struct stat statbuf;
+# define FSBLOCKSIZE DEV_BSIZE
+# define f_bavail f_tfree
+# else
+# if defined(ultrix)
+ struct fs_data fs;
+# define f_bavail fd_bfreen
+# define FSBLOCKSIZE fs.fd_bsize
+# else
+# if SFS_TYPE == SFS_STATVFS
+ struct statvfs fs;
+# define FSBLOCKSIZE fs.f_bsize
+# else
+ struct statfs fs;
+# define FSBLOCKSIZE fs.f_bsize
+# if defined(_SCO_unix_) || defined(IRIX) || defined(apollo)
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+# endif
+ extern int errno;
+
+# if SFS_TYPE == SFS_USTAT
+ if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
+# else
+# if SFS_TYPE == SFS_4ARGS
+ if (statfs(dir, &fs, sizeof fs, 0) == 0)
+# else
+# if defined(ultrix)
+ if (statfs(dir, &fs) > 0)
+# else
+ if (statfs(dir, &fs) == 0)
+# endif
+# endif
+# endif
+ {
+ if (bsize != NULL)
+ *bsize = FSBLOCKSIZE;
+ return (fs.f_bavail);
+ }
+#endif
+ return (-1);
+}
+ /*
+** ENOUGHSPACE -- check to see if there is enough free space on the queue fs
+**
+** Only implemented if you have statfs.
+**
+** Parameters:
+** msize -- the size to check against. If zero, we don't yet
+** know how big the message will be, so just check for
+** a "reasonable" amount.
+**
+** Returns:
+** TRUE if there is enough space.
+** FALSE otherwise.
+*/
+
+bool
+enoughspace(msize)
+ long msize;
+{
+ long bfree, bsize;
+
+ if (MinBlocksFree <= 0 && msize <= 0)
+ {
+ if (tTd(4, 80))
+ printf("enoughspace: no threshold\n");
+ return TRUE;
+ }
+
+ if ((bfree = freespace(QueueDir, &bsize)) >= 0)
+ {
+ if (tTd(4, 80))
+ printf("enoughspace: bavail=%ld, need=%ld\n",
+ bfree, msize);
+
+ /* convert msize to block count */
+ msize = msize / bsize + 1;
+ if (MinBlocksFree >= 0)
+ msize += MinBlocksFree;
+
+ if (bfree < msize)
+ {
+#ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_ALERT,
+ "%s: low on space (have %ld, %s needs %ld in %s)",
+ CurEnv->e_id, bfree,
+ CurHostName, msize, QueueDir);
+#endif
+ return FALSE;
+ }
+ }
+ else if (tTd(4, 80))
+ printf("enoughspace failure: min=%ld, need=%ld: %s\n",
+ MinBlocksFree, msize, errstring(errno));
+ return TRUE;
+}
+ /*
+** TRANSIENTERROR -- tell if an error code indicates a transient failure
+**
+** This looks at an errno value and tells if this is likely to
+** go away if retried later.
+**
+** Parameters:
+** err -- the errno code to classify.
+**
+** Returns:
+** TRUE if this is probably transient.
+** FALSE otherwise.
+*/
+
+bool
+transienterror(err)
+ int err;
+{
+ switch (err)
+ {
+ case EIO: /* I/O error */
+ case ENXIO: /* Device not configured */
+ case EAGAIN: /* Resource temporarily unavailable */
+ case ENOMEM: /* Cannot allocate memory */
+ case ENODEV: /* Operation not supported by device */
+ case ENFILE: /* Too many open files in system */
+ case EMFILE: /* Too many open files */
+ case ENOSPC: /* No space left on device */
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: /* Connection timed out */
+#endif
+#ifdef ESTALE
+ case ESTALE: /* Stale NFS file handle */
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: /* Network is down */
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: /* Network is unreachable */
+#endif
+#ifdef ENETRESET
+ case ENETRESET: /* Network dropped connection on reset */
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: /* Software caused connection abort */
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: /* Connection reset by peer */
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS: /* No buffer space available */
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: /* Can't send after socket shutdown */
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: /* Connection refused */
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: /* Host is down */
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: /* No route to host */
+#endif
+#ifdef EDQUOT
+ case EDQUOT: /* Disc quota exceeded */
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: /* Too many processes */
+#endif
+#ifdef EUSERS
+ case EUSERS: /* Too many users */
+#endif
+#ifdef EDEADLK
+ case EDEADLK: /* Resource deadlock avoided */
+#endif
+#ifdef EISCONN
+ case EISCONN: /* Socket already connected */
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: /* Operation now in progress */
+#endif
+#ifdef EALREADY
+ case EALREADY: /* Operation already in progress */
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: /* Address already in use */
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: /* Can't assign requested address */
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: /* (Apollo) file locked */
+#endif
+#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
+ case ENOSR: /* Out of streams resources */
+#endif
+ return TRUE;
+ }
+
+ /* nope, must be permanent */
+ return FALSE;
+}
+ /*
+** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
+**
+** Parameters:
+** fd -- the file descriptor of the file.
+** filename -- the file name (for error messages).
+** ext -- the filename extension.
+** type -- type of the lock. Bits can be:
+** LOCK_EX -- exclusive lock.
+** LOCK_NB -- non-blocking.
+**
+** Returns:
+** TRUE if the lock was acquired.
+** FALSE otherwise.
+*/
+
+bool
+lockfile(fd, filename, ext, type)
+ int fd;
+ char *filename;
+ char *ext;
+ int type;
+{
+# if !HASFLOCK
+ int action;
+ struct flock lfd;
+
+ if (ext == NULL)
+ ext = "";
+
+ bzero(&lfd, sizeof lfd);
+ if (bitset(LOCK_UN, type))
+ lfd.l_type = F_UNLCK;
+ else if (bitset(LOCK_EX, type))
+ lfd.l_type = F_WRLCK;
+ else
+ lfd.l_type = F_RDLCK;
+
+ if (bitset(LOCK_NB, type))
+ action = F_SETLK;
+ else
+ action = F_SETLKW;
+
+ if (tTd(55, 60))
+ printf("lockfile(%s%s, action=%d, type=%d): ",
+ filename, ext, action, lfd.l_type);
+
+ if (fcntl(fd, action, &lfd) >= 0)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (tTd(55, 60))
+ printf("(%s) ", errstring(errno));
+
+ /*
+ ** On SunOS, if you are testing using -oQ/tmp/mqueue or
+ ** -oA/tmp/aliases or anything like that, and /tmp is mounted
+ ** as type "tmp" (that is, served from swap space), the
+ ** previous fcntl will fail with "Invalid argument" errors.
+ ** Since this is fairly common during testing, we will assume
+ ** that this indicates that the lock is successfully grabbed.
+ */
+
+ if (errno == EINVAL)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
+ {
+ int omode = -1;
+# ifdef F_GETFL
+ int oerrno = errno;
+
+ (void) fcntl(fd, F_GETFL, &omode);
+ errno = oerrno;
+# endif
+ syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
+ filename, ext, fd, type, omode, geteuid());
+ }
+# else
+ if (ext == NULL)
+ ext = "";
+
+ if (tTd(55, 60))
+ printf("lockfile(%s%s, type=%o): ", filename, ext, type);
+
+ if (flock(fd, type) >= 0)
+ {
+ if (tTd(55, 60))
+ printf("SUCCESS\n");
+ return TRUE;
+ }
+
+ if (tTd(55, 60))
+ printf("(%s) ", errstring(errno));
+
+ if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
+ {
+ int omode = -1;
+# ifdef F_GETFL
+ int oerrno = errno;
+
+ (void) fcntl(fd, F_GETFL, &omode);
+ errno = oerrno;
+# endif
+ syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
+ filename, ext, fd, type, omode, geteuid());
+ }
+# endif
+ if (tTd(55, 60))
+ printf("FAIL\n");
+ return FALSE;
+}
+ /*
+** CHOWNSAFE -- tell if chown is "safe" (executable only by root)
+**
+** Parameters:
+** fd -- the file descriptor to check.
+**
+** Returns:
+** TRUE -- if only root can chown the file to an arbitrary
+** user.
+** FALSE -- if an arbitrary user can give away a file.
+*/
+
+bool
+chownsafe(fd)
+ int fd;
+{
+#ifdef __hpux
+ char *s;
+ int tfd;
+ uid_t o_uid, o_euid;
+ gid_t o_gid, o_egid;
+ bool rval;
+ struct stat stbuf;
+
+ o_uid = getuid();
+ o_euid = geteuid();
+ o_gid = getgid();
+ o_egid = getegid();
+ fstat(fd, &stbuf);
+ setresuid(stbuf.st_uid, stbuf.st_uid, -1);
+ setresgid(stbuf.st_gid, stbuf.st_gid, -1);
+ s = tmpnam(NULL);
+ tfd = open(s, O_RDONLY|O_CREAT, 0600);
+ rval = fchown(tfd, DefUid, DefGid) != 0;
+ close(tfd);
+ unlink(s);
+ setreuid(o_uid, o_euid);
+ setresgid(o_gid, o_egid, -1);
+ return rval;
+#else
+# ifdef _POSIX_CHOWN_RESTRICTED
+# if _POSIX_CHOWN_RESTRICTED == -1
+ return FALSE;
+# else
+ return TRUE;
+# endif
+# else
+# ifdef _PC_CHOWN_RESTRICTED
+ return fpathconf(fd, _PC_CHOWN_RESTRICTED) > 0;
+# else
+# ifdef BSD
+ return TRUE;
+# else
+ return FALSE;
+# endif
+# endif
+# endif
+#endif
+}
+ /*
+** GETCFNAME -- return the name of the .cf file.
+**
+** Some systems (e.g., NeXT) determine this dynamically.
+*/
+
+char *
+getcfname()
+{
+ if (ConfFile != NULL)
+ return ConfFile;
+#ifdef NETINFO
+ {
+ extern char *ni_propval();
+ char *cflocation;
+
+ cflocation = ni_propval("/locations/sendmail", "sendmail.cf");
+ if (cflocation != NULL)
+ return cflocation;
+ }
+#endif
+ return _PATH_SENDMAILCF;
+}
+ /*
+** SETVENDOR -- process vendor code from V configuration line
+**
+** Parameters:
+** vendor -- string representation of vendor.
+**
+** Returns:
+** TRUE -- if ok.
+** FALSE -- if vendor code could not be processed.
+**
+** Side Effects:
+** It is reasonable to set mode flags here to tweak
+** processing in other parts of the code if necessary.
+** For example, if you are a vendor that uses $%y to
+** indicate YP lookups, you could enable that here.
+*/
+
+bool
+setvendor(vendor)
+ char *vendor;
+{
+ if (strcasecmp(vendor, "Berkeley") == 0)
+ return TRUE;
+
+ /* add vendor extensions here */
+
+ return FALSE;
+}
+ /*
+** STRTOL -- convert string to long integer
+**
+** For systems that don't have it in the C library.
+**
+** This is taken verbatim from the 4.4-Lite C library.
+*/
+
+#ifdef NEEDSTRTOL
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+
+long
+strtol(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+
+#endif
+ /*
+** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
+**
+** Solaris versions prior through 2.3 don't properly deliver a
+** canonical h_name field. This tries to work around it.
+*/
+
+#ifdef SOLARIS
+
+extern int h_errno;
+
+struct hostent *
+solaris_gethostbyname(name)
+ const char *name;
+{
+# ifdef SOLARIS_2_3
+ static struct hostent hp;
+ static char buf[1000];
+ extern struct hostent *_switch_gethostbyname_r();
+
+ return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
+# else
+ extern struct hostent *__switch_gethostbyname();
+
+ return __switch_gethostbyname(name);
+# endif
+}
+
+struct hostent *
+solaris_gethostbyaddr(addr, len, type)
+ const char *addr;
+ int len;
+ int type;
+{
+# ifdef SOLARIS_2_3
+ static struct hostent hp;
+ static char buf[1000];
+ extern struct hostent *_switch_gethostbyaddr_r();
+
+ return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
+# else
+ extern struct hostent *__switch_gethostbyaddr();
+
+ return __switch_gethostbyaddr(addr, len, type);
+# endif
+}
+
+#endif
+ /*
+** NI_PROPVAL -- netinfo property value lookup routine
+**
+** Parameters:
+** directory -- the Netinfo directory name.
+** propname -- the Netinfo property name.
+**
+** Returns:
+** NULL -- if:
+** 1. the directory is not found
+** 2. the property name is not found
+** 3. the property contains multiple values
+** 4. some error occured
+** else -- the location of the config file.
+**
+** Notes:
+** Caller should free the return value of ni_proval
+*/
+
+#ifdef NETINFO
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN "."
+# define PARENT_NETINFO_DOMAIN ".."
+# define MAX_NI_LEVELS 256
+
+char *
+ni_propval(directory, propname)
+ char *directory;
+ char *propname;
+{
+ char *propval = NULL;
+ int i;
+ void *ni = NULL;
+ void *lastni = NULL;
+ ni_status nis;
+ ni_id nid;
+ ni_namelist ninl;
+
+ /*
+ ** If the passed directory and property name are found
+ ** in one of netinfo domains we need to search (starting
+ ** from the local domain moving all the way back to the
+ ** root domain) set propval to the property's value
+ ** and return it.
+ */
+
+ for (i = 0; i < MAX_NI_LEVELS; ++i)
+ {
+ if (i == 0)
+ {
+ nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+ }
+ else
+ {
+ if (lastni != NULL)
+ ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+ }
+
+ /*
+ ** Don't bother if we didn't get a handle on a
+ ** proper domain. This is not necessarily an error.
+ ** We would get a positive ni_status if, for instance
+ ** we never found the directory or property and tried
+ ** to open the parent of the root domain!
+ */
+
+ if (nis != 0)
+ break;
+
+ /*
+ ** Find the path to the server information.
+ */
+
+ if (ni_pathsearch(ni, &nid, directory) != 0)
+ continue;
+
+ /*
+ ** Find "host" information.
+ */
+
+ if (ni_lookupprop(ni, &nid, propname, &ninl) != 0)
+ continue;
+
+ /*
+ ** If there's only one name in
+ ** the list, assume we've got
+ ** what we want.
+ */
+
+ if (ninl.ni_namelist_len == 1)
+ {
+ propval = ni_name_dup(ninl.ni_namelist_val[0]);
+ break;
+ }
+ }
+
+ /*
+ ** Clean up.
+ */
+
+ if (ni != NULL)
+ ni_free(ni);
+ if (lastni != NULL && ni != lastni)
+ ni_free(lastni);
+
+ return propval;
+}
+
+#endif /* NETINFO */
+ /*
+** HARD_SYSLOG -- call syslog repeatedly until it works
+**
+** Needed on HP-UX, which apparently doesn't guarantee that
+** syslog succeeds during interrupt handlers.
+*/
+
+#ifdef __hpux
+
+# define MAXSYSLOGTRIES 100
+# undef syslog
+
+# ifdef __STDC__
+hard_syslog(int pri, char *msg, ...)
+# else
+hard_syslog(pri, msg, va_alist)
+ int pri;
+ char *msg;
+ va_dcl
+# endif
+{
+ int i;
+ char buf[SYSLOG_BUFSIZE * 2];
+ VA_LOCAL_DECL;
+
+ VA_START(msg);
+ vsprintf(buf, msg, ap);
+ VA_END;
+
+ for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; )
+ continue;
+}
+
+#endif
diff --git a/usr.sbin/sendmail/src/conf.h b/usr.sbin/sendmail/src/conf.h
new file mode 100644
index 00000000000..62344c39e15
--- /dev/null
+++ b/usr.sbin/sendmail/src/conf.h
@@ -0,0 +1,1197 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ *
+ * @(#)conf.h 8.104 (Berkeley) 4/17/94
+ */
+
+/*
+** CONF.H -- All user-configurable parameters for sendmail
+*/
+
+# include <sys/param.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/file.h>
+# include <sys/wait.h>
+# include <fcntl.h>
+# include <signal.h>
+
+/**********************************************************************
+** Table sizes, etc....
+** There shouldn't be much need to change these....
+**********************************************************************/
+
+# define MAXLINE 2048 /* max line length */
+# define MAXNAME 256 /* max length of a name */
+# define MAXPV 40 /* max # of parms to mailers */
+# define MAXATOM 200 /* max atoms per address */
+# define MAXMAILERS 25 /* maximum mailers known to system */
+# define MAXRWSETS 100 /* max # of sets of rewriting rules */
+# define MAXPRIORITIES 25 /* max values for Precedence: field */
+# define MAXMXHOSTS 20 /* max # of MX records */
+# define SMTPLINELIM 990 /* maximum SMTP line length */
+# define MAXKEY 128 /* maximum size of a database key */
+# define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */
+# define MAXUSERENVIRON 100 /* max envars saved, must be >= 3 */
+# define MAXALIASDB 12 /* max # of alias databases */
+
+# ifndef QUEUESIZE
+# define QUEUESIZE 1000 /* max # of jobs per queue run */
+# endif
+
+/**********************************************************************
+** Compilation options.
+**
+** #define these if they are available; comment them out otherwise.
+**********************************************************************/
+
+# define LOG 1 /* enable logging */
+# define UGLYUUCP 1 /* output ugly UUCP From lines */
+# define NETUNIX 1 /* include unix domain support */
+# define NETINET 1 /* include internet support */
+# define SETPROCTITLE 1 /* munge argv to display current status */
+# define MATCHGECOS 1 /* match user names from gecos field */
+# define XDEBUG 1 /* enable extended debugging */
+# ifdef NEWDB
+# define USERDB 1 /* look in user database (requires NEWDB) */
+# endif
+
+/**********************************************************************
+** 0/1 Compilation options.
+** #define these to 1 if they are available;
+** #define them to 0 otherwise.
+**********************************************************************/
+
+# ifndef NAMED_BIND
+# define NAMED_BIND 1 /* use Berkeley Internet Domain Server */
+# endif
+
+/*
+** Most systems have symbolic links today, so default them on. You
+** can turn them off by #undef'ing this below.
+*/
+
+# define HASLSTAT 1 /* has lstat(2) call */
+
+/*
+** General "standard C" defines.
+**
+** These may be undone later, to cope with systems that claim to
+** be Standard C but aren't. Gcc is the biggest offender -- it
+** doesn't realize that the library is part of the language.
+**
+** Life would be much easier if we could get rid of this sort
+** of bozo problems.
+*/
+
+#ifdef __STDC__
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+#endif
+
+/**********************************************************************
+** Operating system configuration.
+**
+** Unless you are porting to a new OS, you shouldn't have to
+** change these.
+**********************************************************************/
+
+/*
+** Per-Operating System defines
+*/
+
+
+/*
+** HP-UX -- tested for 8.07, 9.00, and 9.01.
+*/
+
+# ifdef __hpux
+/* avoid m_flags conflict between db.h & sys/sysmacros.h on HP 300 */
+# undef m_flags
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define setreuid(r, e) setresuid(r, e, -1)
+# define LA_TYPE LA_FLOAT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define GIDSET_T gid_t
+# define _PATH_UNIX "/hp-ux"
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
+# endif
+# define syslog hard_syslog
+# ifdef __STDC__
+extern int syslog(int, char *, ...);
+# endif
+# endif
+
+
+/*
+** IBM AIX 3.x -- actually tested for 3.2.3
+*/
+
+# ifdef _AIX3
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define FORK fork /* no vfork primitive available */
+# undef SETPROCTITLE /* setproctitle confuses AIX */
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# endif
+
+
+/*
+** Silicon Graphics IRIX
+**
+** Compiles on 4.0.1.
+*/
+
+# ifdef IRIX
+# define SYSTEM5 1 /* this is a System-V derived system */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define FORK fork /* no vfork primitive available */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define setpgid BSDsetpgrp
+# define GIDSET_T gid_t
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define LA_TYPE LA_INT
+# endif
+
+
+/*
+** SunOS and Solaris
+**
+** Tested on SunOS 4.1.x (a.k.a. Solaris 1.1.x) and
+** Solaris 2.2 (a.k.a. SunOS 5.2).
+*/
+
+#if defined(sun) && !defined(BSD)
+
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
+# define LA_TYPE LA_INT
+
+# ifdef SOLARIS_2_3
+# define SOLARIS
+# endif
+
+# ifdef SOLARIS
+ /* Solaris 2.x (a.k.a. SunOS 5.x) */
+# ifndef __svr4__
+# define __svr4__ /* use all System V Releae 4 defines below */
+# endif
+# include <sys/time.h>
+# define gethostbyname solaris_gethostbyname /* get working version */
+# define gethostbyaddr solaris_gethostbyaddr /* get working version */
+# define GIDSET_T gid_t
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/kernel/unix"
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/etc/mail/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
+# endif
+
+# else
+ /* SunOS 4.0.3 or 4.1.x */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# include <vfork.h>
+
+# ifdef SUNOS403
+ /* special tweaking for SunOS 4.0.3 */
+# include <malloc.h>
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# undef WIFEXITED
+# undef WEXITSTATUS
+# undef HASUNAME
+# define setpgid setpgrp
+typedef int pid_t;
+extern char *getenv();
+
+# else
+ /* 4.1.x specifics */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+
+# endif
+# endif
+#endif
+
+/*
+** DG/UX
+**
+** Tested on 5.4.2
+*/
+
+#ifdef DGUX
+# define SYSTEM5 1
+# define LA_TYPE LA_SUBR
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+# undef SETPROCTITLE
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+
+/* these include files must be included early on DG/UX */
+# include <netinet/in.h>
+# include <arpa/inet.h>
+
+# define inet_addr dgux_inet_addr
+extern long dgux_inet_addr();
+#endif
+
+
+/*
+** Digital Ultrix 4.2A or 4.3
+**
+** Apparently, fcntl locking is broken on 4.2A, in that locks are
+** not dropped when the process exits. This causes major problems,
+** so flock is the only alternative.
+*/
+
+#ifdef ultrix
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
+# ifdef vax
+# define LA_TYPE LA_FLOAT
+# else
+# define LA_TYPE LA_INT
+# define LA_AVENRUN "avenrun"
+# endif
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+#endif
+
+
+/*
+** OSF/1 (tested on Alpha)
+*/
+
+#ifdef __osf__
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define LA_TYPE LA_INT
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# endif
+#endif
+
+
+/*
+** NeXTstep
+*/
+
+#ifdef NeXT
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define sleep sleepX
+# define setpgid setpgrp
+# ifndef LA_TYPE
+# define LA_TYPE LA_MACH
+# endif
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifndef _POSIX_SOURCE
+typedef int pid_t;
+# undef WEXITSTATUS
+# undef WIFEXITED
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/etc/sendmail/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail/sendmail.pid"
+# endif
+#endif
+
+
+/*
+** 4.4 BSD
+**
+** See also BSD defines.
+*/
+
+#ifdef BSD4_4
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+#endif
+
+
+/*
+** BSD/386 (all versions)
+** From Tony Sanders, BSDI
+*/
+
+#ifdef __bsdi__
+# define HASUNSETENV 1 /* has the unsetenv(3) call */
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif
+# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312
+ /* version 1.1 or later */
+# define HASSETPROCTITLE 1 /* setproctitle is in libc */
+# undef SETPROCTITLE /* so don't redefine it in conf.c */
+# else
+ /* version 1.0 or earlier */
+# ifndef OLD_NEWDB
+# define OLD_NEWDB 1 /* old version of newdb library */
+# endif
+# endif
+#endif
+
+
+
+/*
+** 386BSD / FreeBSD 1.0E / NetBSD (all architectures, all versions)
+**
+** 4.3BSD clone, closer to 4.4BSD
+**
+** See also BSD defines.
+*/
+
+#if defined(__386BSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+# define HASUNAME 1
+#endif
+#if defined(__NetBSD__) && ((NetBSD > 199307) || (NetBSD0_9 > 1))
+# undef SETPROCTITLE
+# define HASSETPROCTITLE
+# define setreuid(r,e) __setreuid(r,e)
+# define GIDSET_T gid_t
+#endif
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+#endif
+
+
+/*
+** Mach386
+**
+** For mt Xinu's Mach386 system.
+*/
+
+#if defined(MACH) && defined(i386)
+# define MACH386 1
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
+# define NEEDSTRTOL 1 /* need the strtol() function */
+# define setpgid setpgrp
+# ifndef LA_TYPE
+# define LA_TYPE LA_FLOAT
+# endif
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# undef HASSETVBUF /* don't actually have setvbuf(3) */
+# undef WEXITSTATUS
+# undef WIFEXITED
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif
+#endif
+
+
+/*
+** 4.3 BSD -- this is for very old systems
+**
+** Should work for mt Xinu MORE/BSD and Mips UMIPS-BSD 2.1.
+**
+** You'll also have to install a new resolver library.
+** I don't guarantee that support for this environment is complete.
+*/
+
+#if defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd)
+# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
+# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
+# define ARBPTR_T char *
+# define setpgid setpgrp
+# ifndef LA_TYPE
+# define LA_TYPE LA_FLOAT
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+# undef WEXITSTATUS
+# undef WIFEXITED
+typedef short pid_t;
+extern int errno;
+#endif
+
+
+/*
+** SCO Unix
+**
+** This includes two parts -- the first is for SCO Open Server 3.2v4
+** (contributed by Philippe Brand <phb@colombo.telesys-innov.fr>).
+** The second is, I believe, for an older version.
+*/
+
+#ifdef _SCO_unix_4_2
+# define _SCO_unix_
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
+# define _PATH_UNIX "/unix"
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif
+#endif
+
+#ifdef _SCO_unix_
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define FORK fork
+# define MAXPATHLEN PATHSIZE
+# define LA_TYPE LA_SHORT
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# undef NETUNIX /* no unix domain socket support */
+#endif
+
+
+/*
+** ConvexOS 11.0 and later
+**
+** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this
+** works on 9.1 as well.
+*/
+
+#ifdef _CONVEX_SOURCE
+# define BSD 1 /* include all the BSD defines */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETSID 1 /* has POSIX setsid(2) call */
+# define NEEDGETOPT 1 /* need replacement for getopt(3) */
+# define LA_TYPE LA_FLOAT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef S_IREAD
+# define S_IREAD _S_IREAD
+# define S_IWRITE _S_IWRITE
+# define S_IEXEC _S_IEXEC
+# define S_IFMT _S_IFMT
+# define S_IFCHR _S_IFCHR
+# define S_IFBLK _S_IFBLK
+# endif
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+#endif
+
+
+/*
+** RISC/os 4.52
+**
+** Gives a ton of warning messages, but otherwise compiles.
+*/
+
+#ifdef RISCOS
+
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
+# define LA_TYPE LA_INT
+# define LA_AVENRUN "avenrun"
+# define _PATH_UNIX "/unix"
+# undef WIFEXITED
+
+# define setpgid setpgrp
+
+extern int errno;
+typedef int pid_t;
+#define SIGFUNC_DEFINED
+typedef int (*sigfunc_t)();
+extern char *getenv();
+extern void *malloc();
+
+#endif
+
+
+/*
+** Linux 0.99pl10 and above...
+**
+** Thanks to, in reverse order of contact:
+**
+** John Kennedy <warlock@csuchico.edu>
+** Florian La Roche <rzsfl@rz.uni-sb.de>
+** Karl London <karl@borg.demon.co.uk>
+**
+** Last compiled against: [03/02/94 @ 05:34 PM (Wednesday)]
+** sendmail 8.6.6.b9 named 4.9.2-931205-p1 db-1.73
+** gcc 2.5.8 libc.so.4.5.19
+** slackware 1.1.2 linux 0.99.15
+*/
+
+#ifdef __linux__
+# define BSD 1 /* include BSD defines */
+# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define GIDSET_T gid_t /* from <linux/types.h> */
+# ifndef LA_TYPE
+# define LA_TYPE LA_PROCSTR
+# endif
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */
+# include <sys/sysmacros.h>
+# undef atol /* wounded in <stdlib.h> */
+#endif
+
+
+/*
+** DELL SVR4 Issue 2.2, and others
+** From Kimmo Suominen <kim@grendel.lut.fi>
+**
+** It's on #ifdef DELL_SVR4 because Solaris also gets __svr4__
+** defined, and the definitions conflict.
+**
+** Peter Wemm <peter@perth.DIALix.oz.au> claims that the setreuid
+** trick works on DELL 2.2 (SVR4.0/386 version 4.0) and ESIX 4.0.3A
+** (SVR4.0/386 version 3.0).
+*/
+
+#ifdef DELL_SVR4
+ /* no changes necessary */
+ /* see general __svr4__ defines below */
+#endif
+
+
+/*
+** Apple A/UX 3.0
+*/
+
+#ifdef _AUX_SOURCE
+# include <sys/sysmacros.h>
+# define BSD /* has BSD routines */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# define SIGFUNC_DEFINED /* sigfunc_t already defined */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+# define FORK fork
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef LA_TYPE
+# define LA_TYPE LA_ZERO
+# endif
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# undef WIFEXITED
+# undef WEXITSTATUS
+#endif
+
+
+/*
+** Encore UMAX V
+**
+** Not extensively tested.
+*/
+
+#ifdef UMAXV
+# include <limits.h>
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
+# define FORK fork /* no vfork(2) primitive available */
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define MAXPATHLEN PATH_MAX
+extern struct passwd *getpwent(), *getpwnam(), *getpwuid();
+extern struct group *getgrent(), *getgrnam(), *getgrgid();
+# undef WIFEXITED
+# undef WEXITSTATUS
+#endif
+
+
+/*
+** Stardent Titan 3000 running TitanOS 4.2.
+**
+** Must be compiled in "cc -43" mode.
+**
+** From Kate Hedstrom <kate@ahab.rutgers.edu>.
+**
+** Note the tweaking below after the BSD defines are set.
+*/
+
+#ifdef titan
+# define setpgid setpgrp
+typedef int pid_t;
+# undef WIFEXITED
+# undef WEXITSTATUS
+#endif
+
+
+/*
+** Sequent DYNIX 3.2.0
+**
+** From Jim Davis <jdavis@cs.arizona.edu>.
+*/
+
+#ifdef sequent
+
+# define BSD 1
+# define HASUNSETENV 1
+# define BSD4_3 1 /* to get signal() in conf.c */
+# define WAITUNION 1
+# define LA_TYPE LA_FLOAT
+# ifdef _POSIX_VERSION
+# undef _POSIX_VERSION /* set in <unistd.h> */
+# endif
+# undef HASSETVBUF /* don't actually have setvbuf(3) */
+# define setpgid setpgrp
+
+/* Have to redefine WIFEXITED to take an int, to work with waitfor() */
+# undef WIFEXITED
+# define WIFEXITED(s) (((union wait*)&(s))->w_stopval != WSTOPPED && \
+ ((union wait*)&(s))->w_termsig == 0)
+# define WEXITSTATUS(s) (((union wait*)&(s))->w_retcode)
+typedef int pid_t;
+# define isgraph(c) (isprint(c) && (c != ' '))
+
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/dynix"
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+
+#endif
+
+
+/*
+** Sequent DYNIX/ptx v2.0 (and higher)
+**
+** For DYNIX/ptx v1.x, undefine HASSETREUID.
+**
+** From Tim Wright <timw@sequent.com>.
+*/
+
+#ifdef _SEQUENT_
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASSETSID 1 /* has POSIX setsid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define GIDSET_T gid_t
+# define LA_TYPE LA_INT
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# undef SETPROCTITLE
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif
+#endif
+
+
+/*
+** Cray Unicos
+**
+** Ported by David L. Kensiski, Sterling Sofware <kensiski@nas.nasa.gov>
+*/
+
+#ifdef UNICOS
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define MAXPATHLEN PATHSIZE
+# define LA_TYPE LA_ZERO
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+#endif
+
+
+/*
+** Apollo DomainOS
+**
+** From Todd Martin <tmartint@tus.ssi1.com> & Don Lewis <gdonl@gv.ssi1.com>
+**
+** 15 Jan 1994
+**
+*/
+
+#ifdef apollo
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(2) call */
+# undef SETPROCTITLE
+# define LA_TYPE LA_SUBR /* use getloadavg.c */
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/lib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif
+# undef S_IFSOCK /* S_IFSOCK and S_IFIFO are the same */
+# undef S_IFIFO
+# define S_IFIFO 0010000
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif
+#endif
+
+
+/*
+** UnixWare
+**
+** From Evan Champion <evanc@spatial.synapse.org>.
+*/
+
+#ifdef UNIXWARE
+# define SYSTEM5 1
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# endif
+# define GIDSET_T int
+# define SLEEP_T int
+# define SFS_TYPE SFS_STATVFS
+# define LA_TYPE LA_ZERO
+# undef WIFEXITED
+# undef WEXITSTATUS
+# define _PATH_UNIX "/unix"
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/ucblib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif
+# define SYSLOG_BUFSIZE 128
+#endif
+
+
+/*
+** Intergraph CLIX 3.1
+**
+** From Paul Southworth <pauls@locust.cic.net>
+*/
+
+#ifdef CLIX
+# define SYSTEM5 1 /* looks like System V */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# endif
+# define DEV_BSIZE 512 /* device block size not defined */
+# define GIDSET_T gid_t
+# undef LOG /* syslog not available */
+# define NEEDFSYNC 1 /* no fsync in system library */
+# define GETSHORT _getshort
+#endif
+
+
+/*
+** NCR 3000 Series (SysVr4)
+**
+** From From: Kevin Darcy <kevin@tech.mis.cfc.com>.
+*/
+
+#ifdef NCR3000
+# define __svr4__
+# undef BSD
+# define LA_AVENRUN "avenrun"
+#endif
+
+
+
+
+
+/**********************************************************************
+** End of Per-Operating System defines
+**********************************************************************/
+
+/**********************************************************************
+** More general defines
+**********************************************************************/
+
+/* general BSD defines */
+#ifdef BSD
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(2) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif
+#endif
+
+/* general System V Release 4 defines */
+#ifdef __svr4__
+# define SYSTEM5 1
+# define HASSETREUID 1 /* has seteuid(2) call & working saved uids */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# endif
+# define setreuid(r, e) seteuid(e)
+
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/unix"
+# endif
+# ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/usr/ucblib/sendmail.cf"
+# endif
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 128
+# endif
+#endif
+
+/* general System V defines */
+#ifdef SYSTEM5
+# include <sys/sysmacros.h>
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# ifndef LA_TYPE
+# define LA_TYPE LA_INT /* assume integer load average */
+# endif
+# ifndef SFS_TYPE
+# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
+# endif
+# define bcopy(s, d, l) (memmove((d), (s), (l)))
+# define bzero(d, l) (memset((d), '\0', (l)))
+# define bcmp(s, d, l) (memcmp((s), (d), (l)))
+#endif
+
+/* general POSIX defines */
+#ifdef _POSIX_VERSION
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASWAITPID 1 /* has Posix waitpid(2) call */
+#endif
+
+/*
+** If no type for argument two of getgroups call is defined, assume
+** it's an integer -- unfortunately, there seem to be several choices
+** here.
+*/
+
+#ifndef GIDSET_T
+# define GIDSET_T int
+#endif
+
+/*
+** Tweaking for systems that (for example) claim to be BSD but
+** don't have all the standard BSD routines (boo hiss).
+*/
+
+#ifdef titan
+# undef HASINITGROUPS /* doesn't have initgroups(3) call */
+#endif
+
+
+/*
+** Due to a "feature" in some operating systems such as Ultrix 4.3 and
+** HPUX 8.0, if you receive a "No route to host" message (ICMP message
+** ICMP_UNREACH_HOST) on _any_ connection, all connections to that host
+** are closed. Some firewalls return this error if you try to connect
+** to the IDENT port (113), so you can't receive email from these hosts
+** on these systems. The firewall really should use a more specific
+** message such as ICMP_UNREACH_PROTOCOL or _PORT or _NET_PROHIB. If
+** not explicitly set to zero above, default it on.
+*/
+
+#ifndef IDENTPROTO
+# define IDENTPROTO 1 /* use IDENT proto (RFC 1413) */
+#endif
+
+#ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 1 /* libc has getusershell(3) call */
+#endif
+
+#ifndef HASFLOCK
+# define HASFLOCK 0 /* assume no flock(2) support */
+#endif
+
+#ifndef OLD_NEWDB
+# define OLD_NEWDB 0 /* assume newer version of newdb */
+#endif
+
+
+/**********************************************************************
+** Remaining definitions should never have to be changed. They are
+** primarily to provide back compatibility for older systems -- for
+** example, it includes some POSIX compatibility definitions
+**********************************************************************/
+
+/* System 5 compatibility */
+#ifndef S_ISREG
+# define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+# define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK)
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 020
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 002
+#endif
+
+/*
+** Older systems don't have this error code -- it should be in
+** /usr/include/sysexits.h.
+*/
+
+# ifndef EX_CONFIG
+# define EX_CONFIG 78 /* configuration error */
+# endif
+
+/* pseudo-code used in server SMTP */
+# define EX_QUIT 22 /* drop out of server immediately */
+
+
+/*
+** These are used in a few cases where we need some special
+** error codes, but where the system doesn't provide something
+** reasonable. They are printed in errstring.
+*/
+
+#ifndef E_PSEUDOBASE
+# define E_PSEUDOBASE 256
+#endif
+
+#define EOPENTIMEOUT (E_PSEUDOBASE + 0) /* timeout on open */
+#define E_DNSBASE (E_PSEUDOBASE + 20) /* base for DNS h_errno */
+
+/* type of arbitrary pointer */
+#ifndef ARBPTR_T
+# define ARBPTR_T void *
+#endif
+
+#ifndef __P
+# include "cdefs.h"
+#endif
+
+/*
+** Do some required dependencies
+*/
+
+#if defined(NETINET) || defined(NETISO)
+# define SMTP 1 /* enable user and server SMTP */
+# define QUEUE 1 /* enable queueing */
+# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */
+#endif
+
+
+/*
+** Arrange to use either varargs or stdargs
+*/
+
+# ifdef __STDC__
+
+# include <stdarg.h>
+
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap, f)
+# define VA_END va_end(ap)
+
+# else
+
+# include <varargs.h>
+
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap)
+# define VA_END va_end(ap)
+
+# endif
+
+#ifdef HASUNAME
+# include <sys/utsname.h>
+# ifdef newstr
+# undef newstr
+# endif
+#else /* ! HASUNAME */
+# define NODE_LENGTH 32
+struct utsname
+{
+ char nodename[NODE_LENGTH+1];
+};
+#endif /* HASUNAME */
+
+#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_)
+# define MAXHOSTNAMELEN 256
+#endif
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+# define SIGCHLD SIGCLD
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#ifndef LOCK_SH
+# define LOCK_SH 0x01 /* shared lock */
+# define LOCK_EX 0x02 /* exclusive lock */
+# define LOCK_NB 0x04 /* non-blocking lock */
+# define LOCK_UN 0x08 /* unlock */
+#endif
+
+#ifndef SIG_ERR
+# define SIG_ERR ((void (*)()) -1)
+#endif
+
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(st) (((st) >> 8) & 0377)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(st) (((st) & 0377) == 0)
+#endif
+
+#ifndef SIGFUNC_DEFINED
+typedef void (*sigfunc_t) __P((int));
+#endif
+
+/* size of syslog buffer */
+#ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024
+#endif
+
+/*
+** Size of tobuf (deliver.c)
+** Tweak this to match your syslog implementation. It will have to
+** allow for the extra information printed.
+*/
+
+#ifndef TOBUFSIZE
+# if (SYSLOG_BUFSIZE) > 512
+# define TOBUFSIZE (SYSLOG_BUFSIZE - 256)
+# else
+# define TOBUFSIZE 256
+# endif
+#endif
+
+/*
+** Size of prescan buffer.
+** Despite comments in the _sendmail_ book, this probably should
+** not be changed; there are some hard-to-define dependencies.
+*/
+
+# define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */
+/* fork routine -- set above using #ifdef _osname_ or in Makefile */
+# ifndef FORK
+# define FORK vfork /* function to call to fork mailer */
+# endif
+
+/*
+** If we are going to link scanf anyway, use it in readcf
+*/
+
+#if !defined(HASUNAME) && !defined(SCANF)
+# define SCANF 1
+#endif
diff --git a/usr.sbin/sendmail/src/convtime.c b/usr.sbin/sendmail/src/convtime.c
new file mode 100644
index 00000000000..109c30f5b96
--- /dev/null
+++ b/usr.sbin/sendmail/src/convtime.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)convtime.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** CONVTIME -- convert time
+**
+** Takes a time as an ascii string with a trailing character
+** giving units:
+** s -- seconds
+** m -- minutes
+** h -- hours
+** d -- days (default)
+** w -- weeks
+** For example, "3d12h" is three and a half days.
+**
+** Parameters:
+** p -- pointer to ascii time.
+** units -- default units if none specified.
+**
+** Returns:
+** time in seconds.
+**
+** Side Effects:
+** none.
+*/
+
+time_t
+convtime(p, units)
+ char *p;
+ char units;
+{
+ register time_t t, r;
+ register char c;
+
+ r = 0;
+ while (*p != '\0')
+ {
+ t = 0;
+ while ((c = *p++) != '\0' && isascii(c) && isdigit(c))
+ t = t * 10 + (c - '0');
+ if (c == '\0')
+ {
+ c = units;
+ p--;
+ }
+ switch (c)
+ {
+ case 'w': /* weeks */
+ t *= 7;
+
+ case 'd': /* days */
+ default:
+ t *= 24;
+
+ case 'h': /* hours */
+ t *= 60;
+
+ case 'm': /* minutes */
+ t *= 60;
+
+ case 's': /* seconds */
+ break;
+ }
+ r += t;
+ }
+
+ return (r);
+}
+ /*
+** PINTVL -- produce printable version of a time interval
+**
+** Parameters:
+** intvl -- the interval to be converted
+** brief -- if TRUE, print this in an extremely compact form
+** (basically used for logging).
+**
+** Returns:
+** A pointer to a string version of intvl suitable for
+** printing or framing.
+**
+** Side Effects:
+** none.
+**
+** Warning:
+** The string returned is in a static buffer.
+*/
+
+# define PLURAL(n) ((n) == 1 ? "" : "s")
+
+char *
+pintvl(intvl, brief)
+ time_t intvl;
+ bool brief;
+{
+ static char buf[256];
+ register char *p;
+ int wk, dy, hr, mi, se;
+
+ if (intvl == 0 && !brief)
+ return ("zero seconds");
+
+ /* decode the interval into weeks, days, hours, minutes, seconds */
+ se = intvl % 60;
+ intvl /= 60;
+ mi = intvl % 60;
+ intvl /= 60;
+ hr = intvl % 24;
+ intvl /= 24;
+ if (brief)
+ dy = intvl;
+ else
+ {
+ dy = intvl % 7;
+ intvl /= 7;
+ wk = intvl;
+ }
+
+ /* now turn it into a sexy form */
+ p = buf;
+ if (brief)
+ {
+ if (dy > 0)
+ {
+ (void) sprintf(p, "%d+", dy);
+ p += strlen(p);
+ }
+ (void) sprintf(p, "%02d:%02d:%02d", hr, mi, se);
+ return (buf);
+ }
+
+ /* use the verbose form */
+ if (wk > 0)
+ {
+ (void) sprintf(p, ", %d week%s", wk, PLURAL(wk));
+ p += strlen(p);
+ }
+ if (dy > 0)
+ {
+ (void) sprintf(p, ", %d day%s", dy, PLURAL(dy));
+ p += strlen(p);
+ }
+ if (hr > 0)
+ {
+ (void) sprintf(p, ", %d hour%s", hr, PLURAL(hr));
+ p += strlen(p);
+ }
+ if (mi > 0)
+ {
+ (void) sprintf(p, ", %d minute%s", mi, PLURAL(mi));
+ p += strlen(p);
+ }
+ if (se > 0)
+ {
+ (void) sprintf(p, ", %d second%s", se, PLURAL(se));
+ p += strlen(p);
+ }
+
+ return (buf + 2);
+}
diff --git a/usr.sbin/sendmail/src/daemon.c b/usr.sbin/sendmail/src/daemon.c
new file mode 100644
index 00000000000..9753d4c7b1c
--- /dev/null
+++ b/usr.sbin/sendmail/src/daemon.c
@@ -0,0 +1,1555 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+#include <errno.h>
+#include "sendmail.h"
+
+#ifndef lint
+#ifdef DAEMON
+static char sccsid[] = "@(#)daemon.c 8.48.1.5 (Berkeley) 3/28/95 (with daemon mode)";
+#else
+static char sccsid[] = "@(#)daemon.c 8.48.1.5 (Berkeley) 3/28/95 (without daemon mode)";
+#endif
+#endif /* not lint */
+
+#ifdef DAEMON
+
+# include <netdb.h>
+# include <arpa/inet.h>
+
+#if NAMED_BIND
+# include <arpa/nameser.h>
+# include <resolv.h>
+#endif
+
+/*
+** DAEMON.C -- routines to use when running as a daemon.
+**
+** This entire file is highly dependent on the 4.2 BSD
+** interprocess communication primitives. No attempt has
+** been made to make this file portable to Version 7,
+** Version 6, MPX files, etc. If you should try such a
+** thing yourself, I recommend chucking the entire file
+** and starting from scratch. Basic semantics are:
+**
+** getrequests()
+** Opens a port and initiates a connection.
+** Returns in a child. Must set InChannel and
+** OutChannel appropriately.
+** clrdaemon()
+** Close any open files associated with getting
+** the connection; this is used when running the queue,
+** etc., to avoid having extra file descriptors during
+** the queue run and to avoid confusing the network
+** code (if it cares).
+** makeconnection(host, port, outfile, infile, usesecureport)
+** Make a connection to the named host on the given
+** port. Set *outfile and *infile to the files
+** appropriate for communication. Returns zero on
+** success, else an exit status describing the
+** error.
+** host_map_lookup(map, hbuf, avp, pstat)
+** Convert the entry in hbuf into a canonical form.
+*/
+ /*
+** GETREQUESTS -- open mail IPC port and get requests.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Waits until some interesting activity occurs. When
+** it does, a child is created to process it, and the
+** parent waits for completion. Return from this
+** routine is always in the child. The file pointers
+** "InChannel" and "OutChannel" should be set to point
+** to the communication channel.
+*/
+
+int DaemonSocket = -1; /* fd describing socket */
+SOCKADDR DaemonAddr; /* socket for incoming */
+int ListenQueueSize = 10; /* size of listen queue */
+int TcpRcvBufferSize = 0; /* size of TCP receive buffer */
+int TcpSndBufferSize = 0; /* size of TCP send buffer */
+
+getrequests()
+{
+ int t;
+ bool refusingconnections = TRUE;
+ FILE *pidf;
+ int socksize;
+#ifdef XDEBUG
+ bool j_has_dot;
+#endif
+ extern void reapchild();
+
+ /*
+ ** Set up the address for the mailer.
+ */
+
+ if (DaemonAddr.sin.sin_family == 0)
+ DaemonAddr.sin.sin_family = AF_INET;
+ if (DaemonAddr.sin.sin_addr.s_addr == 0)
+ DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
+ if (DaemonAddr.sin.sin_port == 0)
+ {
+ register struct servent *sp;
+
+ sp = getservbyname("smtp", "tcp");
+ if (sp == NULL)
+ {
+ syserr("554 service \"smtp\" unknown");
+ DaemonAddr.sin.sin_port = htons(25);
+ }
+ else
+ DaemonAddr.sin.sin_port = sp->s_port;
+ }
+
+ /*
+ ** Try to actually open the connection.
+ */
+
+ if (tTd(15, 1))
+ printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
+
+ /* get a socket for the SMTP connection */
+ socksize = opendaemonsocket(TRUE);
+
+ (void) setsignal(SIGCHLD, reapchild);
+
+ /* write the pid to the log file for posterity */
+ pidf = fopen(PidFile, "w");
+ if (pidf != NULL)
+ {
+ extern char *CommandLineArgs;
+
+ /* write the process id on line 1 */
+ fprintf(pidf, "%d\n", getpid());
+
+ /* line 2 contains all command line flags */
+ fprintf(pidf, "%s\n", CommandLineArgs);
+
+ /* flush and close */
+ fclose(pidf);
+ }
+
+#ifdef XDEBUG
+ {
+ char jbuf[MAXHOSTNAMELEN];
+
+ expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+ j_has_dot = strchr(jbuf, '.') != NULL;
+ }
+#endif
+
+ if (tTd(15, 1))
+ printf("getrequests: %d\n", DaemonSocket);
+
+ for (;;)
+ {
+ register int pid;
+ auto int lotherend;
+ extern bool refuseconnections();
+
+ /* see if we are rejecting connections */
+ CurrentLA = getla();
+ if (refuseconnections())
+ {
+ if (DaemonSocket >= 0)
+ {
+ /* close socket so peer will fail quickly */
+ (void) close(DaemonSocket);
+ DaemonSocket = -1;
+ }
+ refusingconnections = TRUE;
+ setproctitle("rejecting connections: load average: %d",
+ CurrentLA);
+ sleep(15);
+ continue;
+ }
+
+ if (refusingconnections)
+ {
+ /* start listening again */
+ (void) opendaemonsocket(FALSE);
+ setproctitle("accepting connections");
+ refusingconnections = FALSE;
+ }
+
+#ifdef XDEBUG
+ /* check for disaster */
+ {
+ register STAB *s;
+ char jbuf[MAXHOSTNAMELEN];
+
+ expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+ if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL ||
+ !bitnset('w', s->s_class))
+ {
+ dumpstate("daemon lost $j");
+ syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog");
+ abort();
+ }
+ else if (j_has_dot && strchr(jbuf, '.') == NULL)
+ {
+ dumpstate("daemon $j lost dot");
+ syslog(LOG_ALERT, "daemon process $j lost dot; see syslog");
+ abort();
+ }
+ }
+#endif
+
+ /* wait for a connection */
+ do
+ {
+ errno = 0;
+ lotherend = socksize;
+ t = accept(DaemonSocket,
+ (struct sockaddr *)&RealHostAddr, &lotherend);
+ } while (t < 0 && errno == EINTR);
+ if (t < 0)
+ {
+ syserr("getrequests: accept");
+ sleep(5);
+ continue;
+ }
+
+ /*
+ ** Create a subprocess to process the mail.
+ */
+
+ if (tTd(15, 2))
+ printf("getrequests: forking (fd = %d)\n", t);
+
+ pid = fork();
+ if (pid < 0)
+ {
+ syserr("daemon: cannot fork");
+ sleep(10);
+ (void) close(t);
+ continue;
+ }
+
+ if (pid == 0)
+ {
+ char *p;
+ extern char *hostnamebyanyaddr();
+
+ /*
+ ** CHILD -- return to caller.
+ ** Collect verified idea of sending host.
+ ** Verify calling user id if possible here.
+ */
+
+ (void) setsignal(SIGCHLD, SIG_DFL);
+ DisConnected = FALSE;
+
+ setproctitle("startup with %s",
+ anynet_ntoa(&RealHostAddr));
+
+ /* determine host name */
+ p = hostnamebyanyaddr(&RealHostAddr);
+ RealHostName = newstr(p);
+ setproctitle("startup with %s", p);
+
+#ifdef LOG
+ if (LogLevel > 11)
+ {
+ /* log connection information */
+ syslog(LOG_INFO, "connect from %s (%s)",
+ RealHostName, anynet_ntoa(&RealHostAddr));
+ }
+#endif
+
+ (void) close(DaemonSocket);
+ if ((InChannel = fdopen(t, "r")) == NULL ||
+ (t = dup(t)) < 0 ||
+ (OutChannel = fdopen(t, "w")) == NULL)
+ {
+ syserr("cannot open SMTP server channel, fd=%d", t);
+ exit(0);
+ }
+
+ /* should we check for illegal connection here? XXX */
+#ifdef XLA
+ if (!xla_host_ok(RealHostName))
+ {
+ message("421 Too many SMTP sessions for this host");
+ exit(0);
+ }
+#endif
+
+ if (tTd(15, 2))
+ printf("getreq: returning\n");
+ return;
+ }
+
+ /* close the port so that others will hang (for a while) */
+ (void) close(t);
+ }
+ /*NOTREACHED*/
+}
+ /*
+** OPENDAEMONSOCKET -- open the SMTP socket
+**
+** Deals with setting all appropriate options. DaemonAddr must
+** be set up in advance.
+**
+** Parameters:
+** firsttime -- set if this is the initial open.
+**
+** Returns:
+** Size in bytes of the daemon socket addr.
+**
+** Side Effects:
+** Leaves DaemonSocket set to the open socket.
+** Exits if the socket cannot be created.
+*/
+
+#define MAXOPENTRIES 10 /* maximum number of tries to open connection */
+
+int
+opendaemonsocket(firsttime)
+ bool firsttime;
+{
+ int on = 1;
+ int socksize;
+ int ntries = 0;
+ int saveerrno;
+
+ if (tTd(15, 2))
+ printf("opendaemonsocket()\n");
+
+ do
+ {
+ if (ntries > 0)
+ sleep(5);
+ if (firsttime || DaemonSocket < 0)
+ {
+ DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
+ if (DaemonSocket < 0)
+ {
+ /* probably another daemon already */
+ saveerrno = errno;
+ syserr("opendaemonsocket: can't create server SMTP socket");
+ severe:
+# ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_ALERT, "problem creating SMTP socket");
+# endif /* LOG */
+ DaemonSocket = -1;
+ continue;
+ }
+
+ /* turn on network debugging? */
+ if (tTd(15, 101))
+ (void) setsockopt(DaemonSocket, SOL_SOCKET,
+ SO_DEBUG, (char *)&on,
+ sizeof on);
+
+ (void) setsockopt(DaemonSocket, SOL_SOCKET,
+ SO_REUSEADDR, (char *)&on, sizeof on);
+ (void) setsockopt(DaemonSocket, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof on);
+
+#ifdef SO_RCVBUF
+ if (TcpRcvBufferSize > 0)
+ {
+ if (setsockopt(DaemonSocket, SOL_SOCKET,
+ SO_RCVBUF,
+ (char *) &TcpRcvBufferSize,
+ sizeof(TcpRcvBufferSize)) < 0)
+ syserr("getrequests: setsockopt(SO_RCVBUF)");
+ }
+#endif
+
+ switch (DaemonAddr.sa.sa_family)
+ {
+# ifdef NETINET
+ case AF_INET:
+ socksize = sizeof DaemonAddr.sin;
+ break;
+# endif
+
+# ifdef NETISO
+ case AF_ISO:
+ socksize = sizeof DaemonAddr.siso;
+ break;
+# endif
+
+ default:
+ socksize = sizeof DaemonAddr;
+ break;
+ }
+
+ if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
+ {
+ saveerrno = errno;
+ syserr("getrequests: cannot bind");
+ (void) close(DaemonSocket);
+ goto severe;
+ }
+ }
+ if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
+ {
+ saveerrno = errno;
+ syserr("getrequests: cannot listen");
+ (void) close(DaemonSocket);
+ goto severe;
+ }
+ return socksize;
+ } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
+ finis();
+}
+ /*
+** CLRDAEMON -- reset the daemon connection
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** releases any resources used by the passive daemon.
+*/
+
+clrdaemon()
+{
+ if (DaemonSocket >= 0)
+ (void) close(DaemonSocket);
+ DaemonSocket = -1;
+}
+ /*
+** SETDAEMONOPTIONS -- set options for running the daemon
+**
+** Parameters:
+** p -- the options line.
+**
+** Returns:
+** none.
+*/
+
+setdaemonoptions(p)
+ register char *p;
+{
+ if (DaemonAddr.sa.sa_family == AF_UNSPEC)
+ DaemonAddr.sa.sa_family = AF_INET;
+
+ while (p != NULL)
+ {
+ register char *f;
+ register char *v;
+
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p == '\0')
+ break;
+ f = p;
+ p = strchr(p, ',');
+ if (p != NULL)
+ *p++ = '\0';
+ v = strchr(f, '=');
+ if (v == NULL)
+ continue;
+ while (isascii(*++v) && isspace(*v))
+ continue;
+
+ switch (*f)
+ {
+ case 'F': /* address family */
+ if (isascii(*v) && isdigit(*v))
+ DaemonAddr.sa.sa_family = atoi(v);
+#ifdef NETINET
+ else if (strcasecmp(v, "inet") == 0)
+ DaemonAddr.sa.sa_family = AF_INET;
+#endif
+#ifdef NETISO
+ else if (strcasecmp(v, "iso") == 0)
+ DaemonAddr.sa.sa_family = AF_ISO;
+#endif
+#ifdef NETNS
+ else if (strcasecmp(v, "ns") == 0)
+ DaemonAddr.sa.sa_family = AF_NS;
+#endif
+#ifdef NETX25
+ else if (strcasecmp(v, "x.25") == 0)
+ DaemonAddr.sa.sa_family = AF_CCITT;
+#endif
+ else
+ syserr("554 Unknown address family %s in Family=option", v);
+ break;
+
+ case 'A': /* address */
+ switch (DaemonAddr.sa.sa_family)
+ {
+#ifdef NETINET
+ case AF_INET:
+ if (isascii(*v) && isdigit(*v))
+ DaemonAddr.sin.sin_addr.s_addr = inet_network(v);
+ else
+ {
+ register struct netent *np;
+
+ np = getnetbyname(v);
+ if (np == NULL)
+ syserr("554 network \"%s\" unknown", v);
+ else
+ DaemonAddr.sin.sin_addr.s_addr = np->n_net;
+ }
+ break;
+#endif
+
+ default:
+ syserr("554 Address= option unsupported for family %d",
+ DaemonAddr.sa.sa_family);
+ break;
+ }
+ break;
+
+ case 'P': /* port */
+ switch (DaemonAddr.sa.sa_family)
+ {
+ short port;
+
+#ifdef NETINET
+ case AF_INET:
+ if (isascii(*v) && isdigit(*v))
+ DaemonAddr.sin.sin_port = htons(atoi(v));
+ else
+ {
+ register struct servent *sp;
+
+ sp = getservbyname(v, "tcp");
+ if (sp == NULL)
+ syserr("554 service \"%s\" unknown", v);
+ else
+ DaemonAddr.sin.sin_port = sp->s_port;
+ }
+ break;
+#endif
+
+#ifdef NETISO
+ case AF_ISO:
+ /* assume two byte transport selector */
+ if (isascii(*v) && isdigit(*v))
+ port = htons(atoi(v));
+ else
+ {
+ register struct servent *sp;
+
+ sp = getservbyname(v, "tcp");
+ if (sp == NULL)
+ syserr("554 service \"%s\" unknown", v);
+ else
+ port = sp->s_port;
+ }
+ bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
+ break;
+#endif
+
+ default:
+ syserr("554 Port= option unsupported for family %d",
+ DaemonAddr.sa.sa_family);
+ break;
+ }
+ break;
+
+ case 'L': /* listen queue size */
+ ListenQueueSize = atoi(v);
+ break;
+
+ case 'S': /* send buffer size */
+ TcpSndBufferSize = atoi(v);
+ break;
+
+ case 'R': /* receive buffer size */
+ TcpRcvBufferSize = atoi(v);
+ break;
+ }
+ }
+}
+ /*
+** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
+**
+** Parameters:
+** host -- the name of the host.
+** port -- the port number to connect to.
+** mci -- a pointer to the mail connection information
+** structure to be filled in.
+** usesecureport -- if set, use a low numbered (reserved)
+** port to provide some rudimentary authentication.
+**
+** Returns:
+** An exit code telling whether the connection could be
+** made and if not why not.
+**
+** Side Effects:
+** none.
+*/
+
+SOCKADDR CurHostAddr; /* address of current host */
+
+int
+makeconnection(host, port, mci, usesecureport)
+ char *host;
+ u_short port;
+ register MCI *mci;
+ bool usesecureport;
+{
+ register int i, s;
+ register struct hostent *hp = (struct hostent *)NULL;
+ SOCKADDR addr;
+ int sav_errno;
+ int addrlen;
+#if NAMED_BIND
+ extern int h_errno;
+#endif
+
+ /*
+ ** Set up the address for the mailer.
+ ** Accept "[a.b.c.d]" syntax for host name.
+ */
+
+#if NAMED_BIND
+ h_errno = 0;
+#endif
+ errno = 0;
+ bzero(&CurHostAddr, sizeof CurHostAddr);
+ SmtpPhase = mci->mci_phase = "initial connection";
+ CurHostName = host;
+
+ if (host[0] == '[')
+ {
+ register char *p = strchr(host, ']');
+
+ if (p != NULL)
+ {
+ *p = '\0';
+#ifdef NETINET
+ if (inet_aton(&host[1], &addr.sin.sin_addr) == 0)
+#endif
+ {
+ /* try it as a host name (avoid MX lookup) */
+ hp = gethostbyname(&host[1]);
+ if (hp == NULL && p[-1] == '.')
+ {
+ p[-1] = '\0';
+ hp = gethostbyname(&host[1]);
+ p[-1] = '.';
+ }
+ *p = ']';
+ goto gothostent;
+ }
+ *p = ']';
+ }
+ if (p == NULL)
+ {
+ usrerr("553 Invalid numeric domain spec \"%s\"", host);
+ return (EX_NOHOST);
+ }
+#ifdef NETINET
+ addr.sin.sin_family = AF_INET; /*XXX*/
+#endif
+ }
+ else
+ {
+ register char *p = &host[strlen(host) - 1];
+
+ hp = gethostbyname(host);
+ if (hp == NULL && *p == '.')
+ {
+ *p = '\0';
+ hp = gethostbyname(host);
+ *p = '.';
+ }
+gothostent:
+ if (hp == NULL)
+ {
+#if NAMED_BIND
+ if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
+ return (EX_TEMPFAIL);
+
+ /* if name server is specified, assume temp fail */
+ if (errno == ECONNREFUSED && UseNameServer)
+ return (EX_TEMPFAIL);
+#endif
+ return (EX_NOHOST);
+ }
+ addr.sa.sa_family = hp->h_addrtype;
+ switch (hp->h_addrtype)
+ {
+#ifdef NETINET
+ case AF_INET:
+ bcopy(hp->h_addr,
+ &addr.sin.sin_addr,
+ sizeof addr.sin.sin_addr);
+ break;
+#endif
+
+ default:
+ bcopy(hp->h_addr,
+ addr.sa.sa_data,
+ hp->h_length);
+ break;
+ }
+ i = 1;
+ }
+
+ /*
+ ** Determine the port number.
+ */
+
+ if (port != 0)
+ port = htons(port);
+ else
+ {
+ register struct servent *sp = getservbyname("smtp", "tcp");
+
+ if (sp == NULL)
+ {
+ syserr("554 makeconnection: service \"smtp\" unknown");
+ port = htons(25);
+ }
+ else
+ port = sp->s_port;
+ }
+
+ switch (addr.sa.sa_family)
+ {
+#ifdef NETINET
+ case AF_INET:
+ addr.sin.sin_port = port;
+ addrlen = sizeof (struct sockaddr_in);
+ break;
+#endif
+
+#ifdef NETISO
+ case AF_ISO:
+ /* assume two byte transport selector */
+ bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
+ addrlen = sizeof (struct sockaddr_iso);
+ break;
+#endif
+
+ default:
+ syserr("Can't connect to address family %d", addr.sa.sa_family);
+ return (EX_NOHOST);
+ }
+
+ /*
+ ** Try to actually open the connection.
+ */
+
+#ifdef XLA
+ /* if too many connections, don't bother trying */
+ if (!xla_noqueue_ok(host))
+ return EX_TEMPFAIL;
+#endif
+
+ for (;;)
+ {
+ if (tTd(16, 1))
+ printf("makeconnection (%s [%s])\n",
+ host, anynet_ntoa(&addr));
+
+ /* save for logging */
+ CurHostAddr = addr;
+
+ if (usesecureport)
+ {
+ int rport = IPPORT_RESERVED - 1;
+
+ s = rresvport(&rport);
+ }
+ else
+ {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ }
+ if (s < 0)
+ {
+ sav_errno = errno;
+ syserr("makeconnection: no socket");
+ goto failure;
+ }
+
+#ifdef SO_SNDBUF
+ if (TcpSndBufferSize > 0)
+ {
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+ (char *) &TcpSndBufferSize,
+ sizeof(TcpSndBufferSize)) < 0)
+ syserr("makeconnection: setsockopt(SO_SNDBUF)");
+ }
+#endif
+
+ if (tTd(16, 1))
+ printf("makeconnection: fd=%d\n", s);
+
+ /* turn on network debugging? */
+ if (tTd(16, 101))
+ {
+ int on = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof on);
+ }
+ if (CurEnv->e_xfp != NULL)
+ (void) fflush(CurEnv->e_xfp); /* for debugging */
+ errno = 0; /* for debugging */
+ if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
+ break;
+
+ /* couldn't connect.... figure out why */
+ sav_errno = errno;
+ (void) close(s);
+ if (hp && hp->h_addr_list[i])
+ {
+ if (tTd(16, 1))
+ printf("Connect failed (%s); trying new address....\n",
+ errstring(sav_errno));
+ switch (addr.sa.sa_family)
+ {
+#ifdef NETINET
+ case AF_INET:
+ bcopy(hp->h_addr_list[i++],
+ &addr.sin.sin_addr,
+ sizeof addr.sin.sin_addr);
+ break;
+#endif
+
+ default:
+ bcopy(hp->h_addr_list[i++],
+ addr.sa.sa_data,
+ hp->h_length);
+ break;
+ }
+ continue;
+ }
+
+ /* failure, decide if temporary or not */
+ failure:
+#ifdef XLA
+ xla_host_end(host);
+#endif
+ if (transienterror(sav_errno))
+ return EX_TEMPFAIL;
+ else
+ {
+ message("%s", errstring(sav_errno));
+ return (EX_UNAVAILABLE);
+ }
+ }
+
+ /* connection ok, put it into canonical form */
+ if ((mci->mci_out = fdopen(s, "w")) == NULL ||
+ (s = dup(s)) < 0 ||
+ (mci->mci_in = fdopen(s, "r")) == NULL)
+ {
+ syserr("cannot open SMTP client channel, fd=%d", s);
+ return EX_TEMPFAIL;
+ }
+
+ return (EX_OK);
+}
+ /*
+** MYHOSTNAME -- return the name of this host.
+**
+** Parameters:
+** hostbuf -- a place to return the name of this host.
+** size -- the size of hostbuf.
+**
+** Returns:
+** A list of aliases for this host.
+**
+** Side Effects:
+** Adds numeric codes to $=w.
+*/
+
+char **
+myhostname(hostbuf, size)
+ char hostbuf[];
+ int size;
+{
+ register struct hostent *hp;
+ extern struct hostent *gethostbyname();
+
+ if (gethostname(hostbuf, size) < 0)
+ {
+ (void) strcpy(hostbuf, "localhost");
+ }
+ hp = gethostbyname(hostbuf);
+ if (hp == NULL)
+ {
+ syserr("!My host name (%s) does not seem to exist!", hostbuf);
+ }
+ (void) strncpy(hostbuf, hp->h_name, size - 1);
+ hostbuf[size - 1] = '\0';
+
+#if NAMED_BIND
+ /* if still no dot, try DNS directly (i.e., avoid NIS problems) */
+ if (strchr(hostbuf, '.') == NULL)
+ {
+ extern bool getcanonname();
+ extern int h_errno;
+
+ /* try twice in case name server not yet started up */
+ if (!getcanonname(hostbuf, size, TRUE) &&
+ UseNameServer &&
+ (h_errno != TRY_AGAIN ||
+ (sleep(30), !getcanonname(hostbuf, size, TRUE))))
+ {
+ errno = h_errno + E_DNSBASE;
+ syserr("!My host name (%s) not known to DNS",
+ hostbuf);
+ }
+ }
+#endif
+
+ if (hp->h_addrtype == AF_INET && hp->h_length == 4)
+ {
+ register int i;
+
+ for (i = 0; hp->h_addr_list[i] != NULL; i++)
+ {
+ char ipbuf[100];
+
+ sprintf(ipbuf, "[%s]",
+ inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
+ setclass('w', ipbuf);
+ }
+ }
+
+ return (hp->h_aliases);
+}
+ /*
+** GETAUTHINFO -- get the real host name asociated with a file descriptor
+**
+** Uses RFC1413 protocol to try to get info from the other end.
+**
+** Parameters:
+** fd -- the descriptor
+**
+** Returns:
+** The user@host information associated with this descriptor.
+*/
+
+#if IDENTPROTO
+
+static jmp_buf CtxAuthTimeout;
+
+static
+authtimeout()
+{
+ longjmp(CtxAuthTimeout, 1);
+}
+
+#endif
+
+char *
+getauthinfo(fd)
+ int fd;
+{
+ int falen;
+ register char *p;
+#if IDENTPROTO
+ SOCKADDR la;
+ int lalen;
+ register struct servent *sp;
+ int s;
+ int i;
+ EVENT *ev;
+ int nleft;
+ char ibuf[MAXNAME + 1];
+#endif
+ static char hbuf[MAXNAME * 2 + 2];
+ extern char *hostnamebyanyaddr();
+ extern char RealUserName[]; /* main.c */
+
+ falen = sizeof RealHostAddr;
+ if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 ||
+ RealHostAddr.sa.sa_family == 0)
+ {
+ (void) sprintf(hbuf, "%s@localhost", RealUserName);
+ if (tTd(9, 1))
+ printf("getauthinfo: %s\n", hbuf);
+ return hbuf;
+ }
+
+ if (RealHostName == NULL)
+ {
+ /* translate that to a host name */
+ RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
+ }
+
+#if IDENTPROTO
+ if (TimeOuts.to_ident == 0)
+ goto noident;
+
+ lalen = sizeof la;
+ if (RealHostAddr.sa.sa_family != AF_INET ||
+ getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
+ la.sa.sa_family != AF_INET)
+ {
+ /* no ident info */
+ goto noident;
+ }
+
+ /* create ident query */
+ (void) sprintf(ibuf, "%d,%d\r\n",
+ ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
+
+ /* create local address */
+ la.sin.sin_port = 0;
+
+ /* create foreign address */
+ sp = getservbyname("auth", "tcp");
+ if (sp != NULL)
+ RealHostAddr.sin.sin_port = sp->s_port;
+ else
+ RealHostAddr.sin.sin_port = htons(113);
+
+ s = -1;
+ if (setjmp(CtxAuthTimeout) != 0)
+ {
+ if (s >= 0)
+ (void) close(s);
+ goto noident;
+ }
+
+ /* put a timeout around the whole thing */
+ ev = setevent(TimeOuts.to_ident, authtimeout, 0);
+
+ /* connect to foreign IDENT server using same address as SMTP socket */
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ {
+ clrevent(ev);
+ goto noident;
+ }
+ if (bind(s, &la.sa, sizeof la.sin) < 0 ||
+ connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
+ {
+ goto closeident;
+ }
+
+ if (tTd(9, 10))
+ printf("getauthinfo: sent %s", ibuf);
+
+ /* send query */
+ if (write(s, ibuf, strlen(ibuf)) < 0)
+ goto closeident;
+
+ /* get result */
+ p = &ibuf[0];
+ nleft = sizeof ibuf - 1;
+ while ((i = read(s, p, nleft)) > 0)
+ {
+ p += i;
+ nleft -= i;
+ }
+ (void) close(s);
+ clrevent(ev);
+ if (i < 0 || p == &ibuf[0])
+ goto noident;
+
+ if (*--p == '\n' && *--p == '\r')
+ p--;
+ *++p = '\0';
+
+ if (tTd(9, 3))
+ printf("getauthinfo: got %s\n", ibuf);
+
+ /* parse result */
+ p = strchr(ibuf, ':');
+ if (p == NULL)
+ {
+ /* malformed response */
+ goto noident;
+ }
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ if (strncasecmp(p, "userid", 6) != 0)
+ {
+ /* presumably an error string */
+ goto noident;
+ }
+ p += 6;
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p++ != ':')
+ {
+ /* either useridxx or malformed response */
+ goto noident;
+ }
+
+ /* p now points to the OSTYPE field */
+ p = strchr(p, ':');
+ if (p == NULL)
+ {
+ /* malformed response */
+ goto noident;
+ }
+
+ /* 1413 says don't do this -- but it's broken otherwise */
+ while (isascii(*++p) && isspace(*p))
+ continue;
+
+ /* p now points to the authenticated name -- copy carefully */
+ cleanstrcpy(hbuf, p, MAXNAME);
+ i = strlen(hbuf);
+ hbuf[i++] = '@';
+ strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName);
+ goto finish;
+
+closeident:
+ (void) close(s);
+ clrevent(ev);
+
+#endif /* IDENTPROTO */
+
+noident:
+ if (RealHostName == NULL)
+ {
+ if (tTd(9, 1))
+ printf("getauthinfo: NULL\n");
+ return NULL;
+ }
+ (void) strcpy(hbuf, RealHostName);
+
+finish:
+ if (RealHostName != NULL && RealHostName[0] != '[')
+ {
+ p = &hbuf[strlen(hbuf)];
+ (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
+ }
+ if (tTd(9, 1))
+ printf("getauthinfo: %s\n", hbuf);
+ return hbuf;
+}
+ /*
+** HOST_MAP_LOOKUP -- turn a hostname into canonical form
+**
+** Parameters:
+** map -- a pointer to this map (unused).
+** name -- the (presumably unqualified) hostname.
+** av -- unused -- for compatibility with other mapping
+** functions.
+** statp -- an exit status (out parameter) -- set to
+** EX_TEMPFAIL if the name server is unavailable.
+**
+** Returns:
+** The mapping, if found.
+** NULL if no mapping found.
+**
+** Side Effects:
+** Looks up the host specified in hbuf. If it is not
+** the canonical name for that host, return the canonical
+** name.
+*/
+
+char *
+host_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ register struct hostent *hp;
+ struct in_addr in_addr;
+ char *cp;
+ int i;
+ register STAB *s;
+ char hbuf[MAXNAME];
+ extern struct hostent *gethostbyaddr();
+#if NAMED_BIND
+ extern int h_errno;
+#endif
+
+ /*
+ ** See if we have already looked up this name. If so, just
+ ** return it.
+ */
+
+ s = stab(name, ST_NAMECANON, ST_ENTER);
+ if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
+ {
+ if (tTd(9, 1))
+ printf("host_map_lookup(%s) => CACHE %s\n",
+ name, s->s_namecanon.nc_cname);
+ errno = s->s_namecanon.nc_errno;
+#if NAMED_BIND
+ h_errno = s->s_namecanon.nc_herrno;
+#endif
+ *statp = s->s_namecanon.nc_stat;
+ if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL)
+ {
+ sprintf(hbuf, "%s: Name server timeout",
+ shortenstring(name, 33));
+ CurEnv->e_message = newstr(hbuf);
+ }
+ return s->s_namecanon.nc_cname;
+ }
+
+ /*
+ ** If first character is a bracket, then it is an address
+ ** lookup. Address is copied into a temporary buffer to
+ ** strip the brackets and to preserve name if address is
+ ** unknown.
+ */
+
+ if (*name != '[')
+ {
+ extern bool getcanonname();
+
+ if (tTd(9, 1))
+ printf("host_map_lookup(%s) => ", name);
+ s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
+ (void) strcpy(hbuf, name);
+ if (getcanonname(hbuf, sizeof hbuf - 1, TRUE))
+ {
+ if (tTd(9, 1))
+ printf("%s\n", hbuf);
+ cp = map_rewrite(map, hbuf, strlen(hbuf), av);
+ s->s_namecanon.nc_cname = newstr(cp);
+ return cp;
+ }
+ else
+ {
+ register struct hostent *hp;
+
+ s->s_namecanon.nc_errno = errno;
+#if NAMED_BIND
+ s->s_namecanon.nc_herrno = h_errno;
+ if (tTd(9, 1))
+ printf("FAIL (%d)\n", h_errno);
+ switch (h_errno)
+ {
+ case TRY_AGAIN:
+ if (UseNameServer)
+ {
+ sprintf(hbuf, "%s: Name server timeout",
+ shortenstring(name, 33));
+ message("%s", hbuf);
+ if (CurEnv->e_message == NULL)
+ CurEnv->e_message = newstr(hbuf);
+ }
+ *statp = EX_TEMPFAIL;
+ break;
+
+ case HOST_NOT_FOUND:
+ *statp = EX_NOHOST;
+ break;
+
+ case NO_RECOVERY:
+ *statp = EX_SOFTWARE;
+ break;
+
+ default:
+ *statp = EX_UNAVAILABLE;
+ break;
+ }
+#else
+ if (tTd(9, 1))
+ printf("FAIL\n");
+ *statp = EX_NOHOST;
+#endif
+ s->s_namecanon.nc_stat = *statp;
+ if (*statp != EX_TEMPFAIL || UseNameServer)
+ return NULL;
+
+ /*
+ ** Try to look it up in /etc/hosts
+ */
+
+ hp = gethostbyname(name);
+ if (hp == NULL)
+ {
+ /* no dice there either */
+ s->s_namecanon.nc_stat = *statp = EX_NOHOST;
+ return NULL;
+ }
+
+ s->s_namecanon.nc_stat = *statp = EX_OK;
+ cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
+ s->s_namecanon.nc_cname = newstr(cp);
+ return cp;
+ }
+ }
+ if ((cp = strchr(name, ']')) == NULL)
+ return (NULL);
+ *cp = '\0';
+ (void) inet_aton(&name[1], &in_addr);
+
+ /* nope -- ask the name server */
+ hp = gethostbyaddr((char *)&in_addr, sizeof(in_addr), AF_INET);
+ s->s_namecanon.nc_errno = errno;
+#if NAMED_BIND
+ s->s_namecanon.nc_herrno = h_errno;
+#endif
+ s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
+ if (hp == NULL)
+ {
+ s->s_namecanon.nc_stat = *statp = EX_NOHOST;
+ return (NULL);
+ }
+
+ /* found a match -- copy out */
+ cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
+ s->s_namecanon.nc_stat = *statp = EX_OK;
+ s->s_namecanon.nc_cname = newstr(cp);
+ return cp;
+}
+ /*
+** ANYNET_NTOA -- convert a network address to printable form.
+**
+** Parameters:
+** sap -- a pointer to a sockaddr structure.
+**
+** Returns:
+** A printable version of that sockaddr.
+*/
+
+char *
+anynet_ntoa(sap)
+ register SOCKADDR *sap;
+{
+ register char *bp;
+ register char *ap;
+ int l;
+ static char buf[100];
+
+ /* check for null/zero family */
+ if (sap == NULL)
+ return "NULLADDR";
+ if (sap->sa.sa_family == 0)
+ return "0";
+
+ switch (sap->sa.sa_family)
+ {
+#ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/
+#ifdef NETUNIX
+ case AF_UNIX:
+ if (sap->sunix.sun_path[0] != '\0')
+ sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path);
+ else
+ sprintf(buf, "[UNIX: localhost]");
+ return buf;
+#endif
+#endif
+
+#ifdef NETINET
+ case AF_INET:
+ return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
+#endif
+
+ default:
+ /* this case is only to ensure syntactic correctness */
+ break;
+ }
+
+ /* unknown family -- just dump bytes */
+ (void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
+ bp = &buf[strlen(buf)];
+ ap = sap->sa.sa_data;
+ for (l = sizeof sap->sa.sa_data; --l >= 0; )
+ {
+ (void) sprintf(bp, "%02x:", *ap++ & 0377);
+ bp += 3;
+ }
+ *--bp = '\0';
+ return buf;
+}
+ /*
+** HOSTNAMEBYANYADDR -- return name of host based on address
+**
+** Parameters:
+** sap -- SOCKADDR pointer
+**
+** Returns:
+** text representation of host name.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+hostnamebyanyaddr(sap)
+ register SOCKADDR *sap;
+{
+ register struct hostent *hp;
+ int saveretry;
+
+#if NAMED_BIND
+ /* shorten name server timeout to avoid higher level timeouts */
+ saveretry = _res.retry;
+ _res.retry = 3;
+#endif /* NAMED_BIND */
+
+ switch (sap->sa.sa_family)
+ {
+#ifdef NETINET
+ case AF_INET:
+ hp = gethostbyaddr((char *) &sap->sin.sin_addr,
+ sizeof sap->sin.sin_addr,
+ AF_INET);
+ break;
+#endif
+
+#ifdef NETISO
+ case AF_ISO:
+ hp = gethostbyaddr((char *) &sap->siso.siso_addr,
+ sizeof sap->siso.siso_addr,
+ AF_ISO);
+ break;
+#endif
+
+#ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/
+ case AF_UNIX:
+ hp = NULL;
+ break;
+#endif
+
+ default:
+ hp = gethostbyaddr(sap->sa.sa_data,
+ sizeof sap->sa.sa_data,
+ sap->sa.sa_family);
+ break;
+ }
+
+#if NAMED_BIND
+ _res.retry = saveretry;
+#endif /* NAMED_BIND */
+
+ if (hp != NULL)
+ return hp->h_name;
+ else
+ {
+ /* produce a dotted quad */
+ static char buf[512];
+
+ (void) sprintf(buf, "[%s]", anynet_ntoa(sap));
+ return buf;
+ }
+}
+
+# else /* DAEMON */
+/* code for systems without sophisticated networking */
+
+/*
+** MYHOSTNAME -- stub version for case of no daemon code.
+**
+** Can't convert to upper case here because might be a UUCP name.
+**
+** Mark, you can change this to be anything you want......
+*/
+
+char **
+myhostname(hostbuf, size)
+ char hostbuf[];
+ int size;
+{
+ register FILE *f;
+
+ hostbuf[0] = '\0';
+ f = fopen("/usr/include/whoami", "r");
+ if (f != NULL)
+ {
+ (void) fgets(hostbuf, size, f);
+ fixcrlf(hostbuf, TRUE);
+ (void) fclose(f);
+ }
+ return (NULL);
+}
+ /*
+** GETAUTHINFO -- get the real host name asociated with a file descriptor
+**
+** Parameters:
+** fd -- the descriptor
+**
+** Returns:
+** The host name associated with this descriptor, if it can
+** be determined.
+** NULL otherwise.
+**
+** Side Effects:
+** none
+*/
+
+char *
+getauthinfo(fd)
+ int fd;
+{
+ return NULL;
+}
+ /*
+** MAPHOSTNAME -- turn a hostname into canonical form
+**
+** Parameters:
+** map -- a pointer to the database map.
+** name -- a buffer containing a hostname.
+** avp -- a pointer to a (cf file defined) argument vector.
+** statp -- an exit status (out parameter).
+**
+** Returns:
+** mapped host name
+** FALSE otherwise.
+**
+** Side Effects:
+** Looks up the host specified in name. If it is not
+** the canonical name for that host, replace it with
+** the canonical name. If the name is unknown, or it
+** is already the canonical name, leave it unchanged.
+*/
+
+/*ARGSUSED*/
+char *
+host_map_lookup(map, name, avp, statp)
+ MAP *map;
+ char *name;
+ char **avp;
+ char *statp;
+{
+ register struct hostent *hp;
+
+ hp = gethostbyname(name);
+ if (hp != NULL)
+ return hp->h_name;
+ *statp = EX_NOHOST;
+ return NULL;
+}
+
+#endif /* DAEMON */
diff --git a/usr.sbin/sendmail/src/deliver.c b/usr.sbin/sendmail/src/deliver.c
new file mode 100644
index 00000000000..99e09f60289
--- /dev/null
+++ b/usr.sbin/sendmail/src/deliver.c
@@ -0,0 +1,2437 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)deliver.c 8.84.1.4 (Berkeley) 3/28/95";
+#endif /* not lint */
+
+#include "sendmail.h"
+#include <netdb.h>
+#include <errno.h>
+#if NAMED_BIND
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+extern int h_errno;
+#endif
+
+extern char SmtpError[];
+
+/*
+** SENDALL -- actually send all the messages.
+**
+** Parameters:
+** e -- the envelope to send.
+** mode -- the delivery mode to use. If SM_DEFAULT, use
+** the current e->e_sendmode.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Scans the send lists and sends everything it finds.
+** Delivers any appropriate error messages.
+** If we are running in a non-interactive mode, takes the
+** appropriate action.
+*/
+
+sendall(e, mode)
+ ENVELOPE *e;
+ char mode;
+{
+ register ADDRESS *q;
+ char *owner;
+ int otherowners;
+ register ENVELOPE *ee;
+ ENVELOPE *splitenv = NULL;
+ bool announcequeueup;
+
+ /*
+ ** If we have had global, fatal errors, don't bother sending
+ ** the message at all if we are in SMTP mode. Local errors
+ ** (e.g., a single address failing) will still cause the other
+ ** addresses to be sent.
+ */
+
+ if (bitset(EF_FATALERRS, e->e_flags) &&
+ (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+ {
+ e->e_flags |= EF_CLRQUEUE;
+ return;
+ }
+
+ /* determine actual delivery mode */
+ CurrentLA = getla();
+ if (mode == SM_DEFAULT)
+ {
+ mode = e->e_sendmode;
+ if (mode != SM_VERIFY &&
+ shouldqueue(e->e_msgpriority, e->e_ctime))
+ mode = SM_QUEUE;
+ announcequeueup = mode == SM_QUEUE;
+ }
+ else
+ announcequeueup = FALSE;
+
+ if (tTd(13, 1))
+ {
+ printf("\n===== SENDALL: mode %c, id %s, e_from ",
+ mode, e->e_id);
+ printaddr(&e->e_from, FALSE);
+ printf("sendqueue:\n");
+ printaddr(e->e_sendqueue, TRUE);
+ }
+
+ /*
+ ** Do any preprocessing necessary for the mode we are running.
+ ** Check to make sure the hop count is reasonable.
+ ** Delete sends to the sender in mailing lists.
+ */
+
+ CurEnv = e;
+
+ if (e->e_hopcount > MaxHopCount)
+ {
+ errno = 0;
+ queueup(e, TRUE, announcequeueup);
+ e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
+ syserr("554 too many hops %d (%d max): from %s via %s, to %s",
+ e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
+ RealHostName == NULL ? "localhost" : RealHostName,
+ e->e_sendqueue->q_paddr);
+ return;
+ }
+
+ /*
+ ** Do sender deletion.
+ **
+ ** If the sender has the QQUEUEUP flag set, skip this.
+ ** This can happen if the name server is hosed when you
+ ** are trying to send mail. The result is that the sender
+ ** is instantiated in the queue as a recipient.
+ */
+
+ if (!bitset(EF_METOO, e->e_flags) &&
+ !bitset(QQUEUEUP, e->e_from.q_flags))
+ {
+ if (tTd(13, 5))
+ {
+ printf("sendall: QDONTSEND ");
+ printaddr(&e->e_from, FALSE);
+ }
+ e->e_from.q_flags |= QDONTSEND;
+ (void) recipient(&e->e_from, &e->e_sendqueue, e);
+ }
+
+ /*
+ ** Handle alias owners.
+ **
+ ** We scan up the q_alias chain looking for owners.
+ ** We discard owners that are the same as the return path.
+ */
+
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ register struct address *a;
+
+ for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
+ continue;
+ if (a != NULL)
+ q->q_owner = a->q_owner;
+
+ if (q->q_owner != NULL &&
+ !bitset(QDONTSEND, q->q_flags) &&
+ strcmp(q->q_owner, e->e_from.q_paddr) == 0)
+ q->q_owner = NULL;
+ }
+
+ owner = "";
+ otherowners = 1;
+ while (owner != NULL && otherowners > 0)
+ {
+ owner = NULL;
+ otherowners = 0;
+
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QDONTSEND, q->q_flags))
+ continue;
+
+ if (q->q_owner != NULL)
+ {
+ if (owner == NULL)
+ owner = q->q_owner;
+ else if (owner != q->q_owner)
+ {
+ if (strcmp(owner, q->q_owner) == 0)
+ {
+ /* make future comparisons cheap */
+ q->q_owner = owner;
+ }
+ else
+ {
+ otherowners++;
+ }
+ owner = q->q_owner;
+ }
+ }
+ else
+ {
+ otherowners++;
+ }
+ }
+
+ if (owner != NULL && otherowners > 0)
+ {
+ extern HDR *copyheader();
+ extern ADDRESS *copyqueue();
+
+ /*
+ ** Split this envelope into two.
+ */
+
+ ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE));
+ *ee = *e;
+ ee->e_id = NULL;
+ (void) queuename(ee, '\0');
+
+ if (tTd(13, 1))
+ printf("sendall: split %s into %s\n",
+ e->e_id, ee->e_id);
+
+ ee->e_header = copyheader(e->e_header);
+ ee->e_sendqueue = copyqueue(e->e_sendqueue);
+ ee->e_errorqueue = copyqueue(e->e_errorqueue);
+ ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT);
+ ee->e_flags |= EF_NORECEIPT;
+ setsender(owner, ee, NULL, TRUE);
+ if (tTd(13, 5))
+ {
+ printf("sendall(split): QDONTSEND ");
+ printaddr(&ee->e_from, FALSE);
+ }
+ ee->e_from.q_flags |= QDONTSEND;
+ ee->e_dfp = NULL;
+ ee->e_xfp = NULL;
+ ee->e_df = NULL;
+ ee->e_errormode = EM_MAIL;
+ ee->e_sibling = splitenv;
+ splitenv = ee;
+
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ if (q->q_owner == owner)
+ {
+ q->q_flags |= QDONTSEND;
+ q->q_flags &= ~QQUEUEUP;
+ }
+ for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
+ if (q->q_owner != owner)
+ {
+ q->q_flags |= QDONTSEND;
+ q->q_flags &= ~QQUEUEUP;
+ }
+
+ if (e->e_df != NULL && mode != SM_VERIFY)
+ {
+ ee->e_dfp = NULL;
+ ee->e_df = queuename(ee, 'd');
+ ee->e_df = newstr(ee->e_df);
+ if (link(e->e_df, ee->e_df) < 0)
+ {
+ syserr("sendall: link(%s, %s)",
+ e->e_df, ee->e_df);
+ }
+ }
+#ifdef LOG
+ if (LogLevel > 4)
+ syslog(LOG_INFO, "%s: clone %s, owner=%s",
+ ee->e_id, e->e_id, owner);
+#endif
+ }
+ }
+
+ if (owner != NULL)
+ {
+ setsender(owner, e, NULL, TRUE);
+ if (tTd(13, 5))
+ {
+ printf("sendall(owner): QDONTSEND ");
+ printaddr(&e->e_from, FALSE);
+ }
+ e->e_from.q_flags |= QDONTSEND;
+ e->e_errormode = EM_MAIL;
+ e->e_flags |= EF_NORECEIPT;
+ }
+
+# ifdef QUEUE
+ if ((mode == SM_QUEUE || mode == SM_FORK ||
+ (mode != SM_VERIFY && SuperSafe)) &&
+ !bitset(EF_INQUEUE, e->e_flags))
+ {
+ /* be sure everything is instantiated in the queue */
+ queueup(e, TRUE, announcequeueup);
+ for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
+ queueup(ee, TRUE, announcequeueup);
+ }
+#endif /* QUEUE */
+
+ if (splitenv != NULL)
+ {
+ if (tTd(13, 1))
+ {
+ printf("\nsendall: Split queue; remaining queue:\n");
+ printaddr(e->e_sendqueue, TRUE);
+ }
+
+ for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
+ {
+ CurEnv = ee;
+ if (mode != SM_VERIFY)
+ openxscript(ee);
+ sendenvelope(ee, mode);
+ dropenvelope(ee);
+ }
+
+ CurEnv = e;
+ }
+ sendenvelope(e, mode);
+}
+
+sendenvelope(e, mode)
+ register ENVELOPE *e;
+ char mode;
+{
+ bool oldverbose;
+ int pid;
+ register ADDRESS *q;
+ char *qf;
+ char *id;
+
+ /*
+ ** If we have had global, fatal errors, don't bother sending
+ ** the message at all if we are in SMTP mode. Local errors
+ ** (e.g., a single address failing) will still cause the other
+ ** addresses to be sent.
+ */
+
+ if (bitset(EF_FATALERRS, e->e_flags) &&
+ (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+ {
+ e->e_flags |= EF_CLRQUEUE;
+ return;
+ }
+
+ oldverbose = Verbose;
+ switch (mode)
+ {
+ case SM_VERIFY:
+ Verbose = TRUE;
+ break;
+
+ case SM_QUEUE:
+ queueonly:
+ e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
+ return;
+
+ case SM_FORK:
+ if (e->e_xfp != NULL)
+ (void) fflush(e->e_xfp);
+
+# if !HASFLOCK
+ /*
+ ** Since fcntl locking has the interesting semantic that
+ ** the lock is owned by a process, not by an open file
+ ** descriptor, we have to flush this to the queue, and
+ ** then restart from scratch in the child.
+ */
+
+ /* save id for future use */
+ id = e->e_id;
+
+ /* now drop the envelope in the parent */
+ e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
+ dropenvelope(e);
+
+ /* and reacquire in the child */
+ (void) dowork(id, TRUE, FALSE, e);
+
+ return;
+
+# else /* HASFLOCK */
+
+ pid = fork();
+ if (pid < 0)
+ {
+ goto queueonly;
+ }
+ else if (pid > 0)
+ {
+ /* be sure we leave the temp files to our child */
+ /* can't call unlockqueue to avoid unlink of xfp */
+ if (e->e_lockfp != NULL)
+ (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp");
+ e->e_lockfp = NULL;
+
+ /* close any random open files in the envelope */
+ closexscript(e);
+ if (e->e_dfp != NULL)
+ (void) xfclose(e->e_dfp, "sendenvelope", e->e_df);
+ e->e_dfp = NULL;
+ e->e_id = e->e_df = NULL;
+
+ /* catch intermediate zombie */
+ (void) waitfor(pid);
+ return;
+ }
+
+ /* double fork to avoid zombies */
+ pid = fork();
+ if (pid > 0)
+ exit(EX_OK);
+
+ /* be sure we are immune from the terminal */
+ disconnect(1, e);
+
+ /* prevent parent from waiting if there was an error */
+ if (pid < 0)
+ {
+ e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
+ finis();
+ }
+
+ /*
+ ** Close any cached connections.
+ **
+ ** We don't send the QUIT protocol because the parent
+ ** still knows about the connection.
+ **
+ ** This should only happen when delivering an error
+ ** message.
+ */
+
+ mci_flush(FALSE, NULL);
+
+# endif /* HASFLOCK */
+
+ break;
+ }
+
+ /*
+ ** Run through the list and send everything.
+ **
+ ** Set EF_GLOBALERRS so that error messages during delivery
+ ** result in returned mail.
+ */
+
+ e->e_nsent = 0;
+ e->e_flags |= EF_GLOBALERRS;
+
+ /* now run through the queue */
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+#ifdef XDEBUG
+ char wbuf[MAXNAME + 20];
+
+ (void) sprintf(wbuf, "sendall(%s)", q->q_paddr);
+ checkfd012(wbuf);
+#endif
+ if (mode == SM_VERIFY)
+ {
+ e->e_to = q->q_paddr;
+ if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
+ {
+ if (q->q_host != NULL && q->q_host[0] != '\0')
+ message("deliverable: mailer %s, host %s, user %s",
+ q->q_mailer->m_name,
+ q->q_host,
+ q->q_user);
+ else
+ message("deliverable: mailer %s, user %s",
+ q->q_mailer->m_name,
+ q->q_user);
+ }
+ }
+ else if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
+ {
+# ifdef QUEUE
+ /*
+ ** Checkpoint the send list every few addresses
+ */
+
+ if (e->e_nsent >= CheckpointInterval)
+ {
+ queueup(e, TRUE, FALSE);
+ e->e_nsent = 0;
+ }
+# endif /* QUEUE */
+ (void) deliver(e, q);
+ }
+ }
+ Verbose = oldverbose;
+
+#ifdef XDEBUG
+ checkfd012("end of sendenvelope");
+#endif
+
+ if (mode == SM_FORK)
+ finis();
+}
+ /*
+** DOFORK -- do a fork, retrying a couple of times on failure.
+**
+** This MUST be a macro, since after a vfork we are running
+** two processes on the same stack!!!
+**
+** Parameters:
+** none.
+**
+** Returns:
+** From a macro??? You've got to be kidding!
+**
+** Side Effects:
+** Modifies the ==> LOCAL <== variable 'pid', leaving:
+** pid of child in parent, zero in child.
+** -1 on unrecoverable error.
+**
+** Notes:
+** I'm awfully sorry this looks so awful. That's
+** vfork for you.....
+*/
+
+# define NFORKTRIES 5
+
+# ifndef FORK
+# define FORK fork
+# endif
+
+# define DOFORK(fORKfN) \
+{\
+ register int i;\
+\
+ for (i = NFORKTRIES; --i >= 0; )\
+ {\
+ pid = fORKfN();\
+ if (pid >= 0)\
+ break;\
+ if (i > 0)\
+ sleep((unsigned) NFORKTRIES - i);\
+ }\
+}
+ /*
+** DOFORK -- simple fork interface to DOFORK.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** pid of child in parent.
+** zero in child.
+** -1 on error.
+**
+** Side Effects:
+** returns twice, once in parent and once in child.
+*/
+
+dofork()
+{
+ register int pid;
+
+ DOFORK(fork);
+ return (pid);
+}
+ /*
+** DELIVER -- Deliver a message to a list of addresses.
+**
+** This routine delivers to everyone on the same host as the
+** user on the head of the list. It is clever about mailers
+** that don't handle multiple users. It is NOT guaranteed
+** that it will deliver to all these addresses however -- so
+** deliver should be called once for each address on the
+** list.
+**
+** Parameters:
+** e -- the envelope to deliver.
+** firstto -- head of the address list to deliver to.
+**
+** Returns:
+** zero -- successfully delivered.
+** else -- some failure, see ExitStat for more info.
+**
+** Side Effects:
+** The standard input is passed off to someone.
+*/
+
+deliver(e, firstto)
+ register ENVELOPE *e;
+ ADDRESS *firstto;
+{
+ char *host; /* host being sent to */
+ char *user; /* user being sent to */
+ char **pvp;
+ register char **mvp;
+ register char *p;
+ register MAILER *m; /* mailer for this recipient */
+ ADDRESS *ctladdr;
+ register MCI *mci;
+ register ADDRESS *to = firstto;
+ bool clever = FALSE; /* running user smtp to this mailer */
+ ADDRESS *tochain = NULL; /* chain of users in this mailer call */
+ int rcode; /* response code */
+ char *firstsig; /* signature of firstto */
+ int pid;
+ char *curhost;
+ int mpvect[2];
+ int rpvect[2];
+ char *pv[MAXPV+1];
+ char tobuf[TOBUFSIZE]; /* text line of to people */
+ char buf[MAXNAME];
+ char rpathbuf[MAXNAME]; /* translated return path */
+ extern int checkcompat();
+
+ errno = 0;
+ if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))
+ return (0);
+
+#if NAMED_BIND
+ /* unless interactive, try twice, over a minute */
+ if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
+ {
+ _res.retrans = 30;
+ _res.retry = 2;
+ }
+#endif
+
+ m = to->q_mailer;
+ host = to->q_host;
+ CurEnv = e; /* just in case */
+ e->e_statmsg = NULL;
+ SmtpError[0] = '\0';
+
+ if (tTd(10, 1))
+ printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
+ e->e_id, m->m_name, host, to->q_user);
+ if (tTd(10, 100))
+ printopenfds(FALSE);
+
+ /*
+ ** If this mailer is expensive, and if we don't want to make
+ ** connections now, just mark these addresses and return.
+ ** This is useful if we want to batch connections to
+ ** reduce load. This will cause the messages to be
+ ** queued up, and a daemon will come along to send the
+ ** messages later.
+ ** This should be on a per-mailer basis.
+ */
+
+ if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)
+ {
+ for (; to != NULL; to = to->q_next)
+ {
+ if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||
+ to->q_mailer != m)
+ continue;
+ to->q_flags |= QQUEUEUP;
+ e->e_to = to->q_paddr;
+ message("queued");
+ if (LogLevel > 8)
+ logdelivery(m, NULL, "queued", NULL, e);
+ }
+ e->e_to = NULL;
+ return (0);
+ }
+
+ /*
+ ** Do initial argv setup.
+ ** Insert the mailer name. Notice that $x expansion is
+ ** NOT done on the mailer name. Then, if the mailer has
+ ** a picky -f flag, we insert it as appropriate. This
+ ** code does not check for 'pv' overflow; this places a
+ ** manifest lower limit of 4 for MAXPV.
+ ** The from address rewrite is expected to make
+ ** the address relative to the other end.
+ */
+
+ /* rewrite from address, using rewriting rules */
+ rcode = EX_OK;
+ (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m,
+ RF_SENDERADDR|RF_CANONICAL,
+ &rcode, e));
+ define('g', rpathbuf, e); /* translated return path */
+ define('h', host, e); /* to host */
+ Errors = 0;
+ pvp = pv;
+ *pvp++ = m->m_argv[0];
+
+ /* insert -f or -r flag as appropriate */
+ if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))
+ {
+ if (bitnset(M_FOPT, m->m_flags))
+ *pvp++ = "-f";
+ else
+ *pvp++ = "-r";
+ *pvp++ = newstr(rpathbuf);
+ }
+
+ /*
+ ** Append the other fixed parts of the argv. These run
+ ** up to the first entry containing "$u". There can only
+ ** be one of these, and there are only a few more slots
+ ** in the pv after it.
+ */
+
+ for (mvp = m->m_argv; (p = *++mvp) != NULL; )
+ {
+ /* can't use strchr here because of sign extension problems */
+ while (*p != '\0')
+ {
+ if ((*p++ & 0377) == MACROEXPAND)
+ {
+ if (*p == 'u')
+ break;
+ }
+ }
+
+ if (*p != '\0')
+ break;
+
+ /* this entry is safe -- go ahead and process it */
+ expand(*mvp, buf, &buf[sizeof buf - 1], e);
+ *pvp++ = newstr(buf);
+ if (pvp >= &pv[MAXPV - 3])
+ {
+ syserr("554 Too many parameters to %s before $u", pv[0]);
+ return (-1);
+ }
+ }
+
+ /*
+ ** If we have no substitution for the user name in the argument
+ ** list, we know that we must supply the names otherwise -- and
+ ** SMTP is the answer!!
+ */
+
+ if (*mvp == NULL)
+ {
+ /* running SMTP */
+# ifdef SMTP
+ clever = TRUE;
+ *pvp = NULL;
+# else /* SMTP */
+ /* oops! we don't implement SMTP */
+ syserr("554 SMTP style mailer not implemented");
+ return (EX_SOFTWARE);
+# endif /* SMTP */
+ }
+
+ /*
+ ** At this point *mvp points to the argument with $u. We
+ ** run through our address list and append all the addresses
+ ** we can. If we run out of space, do not fret! We can
+ ** always send another copy later.
+ */
+
+ tobuf[0] = '\0';
+ e->e_to = tobuf;
+ ctladdr = NULL;
+ firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e);
+ for (; to != NULL; to = to->q_next)
+ {
+ /* avoid sending multiple recipients to dumb mailers */
+ if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
+ break;
+
+ /* if already sent or not for this host, don't send */
+ if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||
+ to->q_mailer != firstto->q_mailer ||
+ strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0)
+ continue;
+
+ /* avoid overflowing tobuf */
+ if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
+ break;
+
+ if (tTd(10, 1))
+ {
+ printf("\nsend to ");
+ printaddr(to, FALSE);
+ }
+
+ /* compute effective uid/gid when sending */
+ /* XXX perhaps this should be to->q_mailer != LocalMailer ?? */
+ /* XXX perhaps it should be a mailer flag? */
+ if (to->q_mailer == ProgMailer || to->q_mailer == FileMailer)
+ ctladdr = getctladdr(to);
+
+ user = to->q_user;
+ e->e_to = to->q_paddr;
+ if (tTd(10, 5))
+ {
+ printf("deliver: QDONTSEND ");
+ printaddr(to, FALSE);
+ }
+ to->q_flags |= QDONTSEND;
+
+ /*
+ ** Check to see that these people are allowed to
+ ** talk to each other.
+ */
+
+ if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
+ {
+ NoReturn = TRUE;
+ usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
+ giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e);
+ continue;
+ }
+ rcode = checkcompat(to, e);
+ if (rcode != EX_OK)
+ {
+ markfailure(e, to, rcode);
+ giveresponse(rcode, m, NULL, ctladdr, e);
+ continue;
+ }
+
+ /*
+ ** Strip quote bits from names if the mailer is dumb
+ ** about them.
+ */
+
+ if (bitnset(M_STRIPQ, m->m_flags))
+ {
+ stripquotes(user);
+ stripquotes(host);
+ }
+
+ /* hack attack -- delivermail compatibility */
+ if (m == ProgMailer && *user == '|')
+ user++;
+
+ /*
+ ** If an error message has already been given, don't
+ ** bother to send to this address.
+ **
+ ** >>>>>>>>>> This clause assumes that the local mailer
+ ** >> NOTE >> cannot do any further aliasing; that
+ ** >>>>>>>>>> function is subsumed by sendmail.
+ */
+
+ if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
+ continue;
+
+ /* save statistics.... */
+ markstats(e, to);
+
+ /*
+ ** See if this user name is "special".
+ ** If the user name has a slash in it, assume that this
+ ** is a file -- send it off without further ado. Note
+ ** that this type of addresses is not processed along
+ ** with the others, so we fudge on the To person.
+ */
+
+ if (m == FileMailer)
+ {
+ rcode = mailfile(user, ctladdr, e);
+ giveresponse(rcode, m, NULL, ctladdr, e);
+ if (rcode == EX_OK)
+ to->q_flags |= QSENT;
+ continue;
+ }
+
+ /*
+ ** Address is verified -- add this user to mailer
+ ** argv, and add it to the print list of recipients.
+ */
+
+ /* link together the chain of recipients */
+ to->q_tchain = tochain;
+ tochain = to;
+
+ /* create list of users for error messages */
+ (void) strcat(tobuf, ",");
+ (void) strcat(tobuf, to->q_paddr);
+ define('u', user, e); /* to user */
+ p = to->q_home;
+ if (p == NULL && ctladdr != NULL)
+ p = ctladdr->q_home;
+ define('z', p, e); /* user's home */
+
+ /*
+ ** Expand out this user into argument list.
+ */
+
+ if (!clever)
+ {
+ expand(*mvp, buf, &buf[sizeof buf - 1], e);
+ *pvp++ = newstr(buf);
+ if (pvp >= &pv[MAXPV - 2])
+ {
+ /* allow some space for trailing parms */
+ break;
+ }
+ }
+ }
+
+ /* see if any addresses still exist */
+ if (tobuf[0] == '\0')
+ {
+ define('g', (char *) NULL, e);
+ return (0);
+ }
+
+ /* print out messages as full list */
+ e->e_to = tobuf + 1;
+
+ /*
+ ** Fill out any parameters after the $u parameter.
+ */
+
+ while (!clever && *++mvp != NULL)
+ {
+ expand(*mvp, buf, &buf[sizeof buf - 1], e);
+ *pvp++ = newstr(buf);
+ if (pvp >= &pv[MAXPV])
+ syserr("554 deliver: pv overflow after $u for %s", pv[0]);
+ }
+ *pvp++ = NULL;
+
+ /*
+ ** Call the mailer.
+ ** The argument vector gets built, pipes
+ ** are created as necessary, and we fork & exec as
+ ** appropriate.
+ ** If we are running SMTP, we just need to clean up.
+ */
+
+ /*XXX this seems a bit wierd */
+ if (ctladdr == NULL && m != ProgMailer &&
+ bitset(QGOODUID, e->e_from.q_flags))
+ ctladdr = &e->e_from;
+
+#if NAMED_BIND
+ if (ConfigLevel < 2)
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
+#endif
+
+ if (tTd(11, 1))
+ {
+ printf("openmailer:");
+ printav(pv);
+ }
+ errno = 0;
+
+ CurHostName = m->m_mailer;
+
+ /*
+ ** Deal with the special case of mail handled through an IPC
+ ** connection.
+ ** In this case we don't actually fork. We must be
+ ** running SMTP for this to work. We will return a
+ ** zero pid to indicate that we are running IPC.
+ ** We also handle a debug version that just talks to stdin/out.
+ */
+
+ curhost = NULL;
+ SmtpPhase = NULL;
+ mci = NULL;
+
+#ifdef XDEBUG
+ {
+ char wbuf[MAXLINE];
+
+ /* make absolutely certain 0, 1, and 2 are in use */
+ sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name);
+ checkfd012(wbuf);
+ }
+#endif
+
+ /* check for Local Person Communication -- not for mortals!!! */
+ if (strcmp(m->m_mailer, "[LPC]") == 0)
+ {
+ mci = (MCI *) xalloc(sizeof *mci);
+ bzero((char *) mci, sizeof *mci);
+ mci->mci_in = stdin;
+ mci->mci_out = stdout;
+ mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
+ mci->mci_mailer = m;
+ }
+ else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
+ strcmp(m->m_mailer, "[TCP]") == 0)
+ {
+#ifdef DAEMON
+ register int i;
+ register u_short port;
+
+ if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
+ {
+ syserr("null host name for %s mailer", m->m_mailer);
+ rcode = EX_CONFIG;
+ goto give_up;
+ }
+
+ CurHostName = pv[1];
+ curhost = hostsignature(m, pv[1], e);
+
+ if (curhost == NULL || curhost[0] == '\0')
+ {
+ syserr("null host signature for %s", pv[1]);
+ rcode = EX_CONFIG;
+ goto give_up;
+ }
+
+ if (!clever)
+ {
+ syserr("554 non-clever IPC");
+ rcode = EX_CONFIG;
+ goto give_up;
+ }
+ if (pv[2] != NULL)
+ port = atoi(pv[2]);
+ else
+ port = 0;
+tryhost:
+ while (*curhost != '\0')
+ {
+ register char *p;
+ static char hostbuf[MAXNAME];
+
+ /* pull the next host from the signature */
+ p = strchr(curhost, ':');
+ if (p == NULL)
+ p = &curhost[strlen(curhost)];
+ if (p == curhost)
+ {
+ syserr("deliver: null host name in signature");
+ curhost++;
+ continue;
+ }
+ strncpy(hostbuf, curhost, p - curhost);
+ hostbuf[p - curhost] = '\0';
+ if (*p != '\0')
+ p++;
+ curhost = p;
+
+ /* see if we already know that this host is fried */
+ CurHostName = hostbuf;
+ mci = mci_get(hostbuf, m);
+ if (mci->mci_state != MCIS_CLOSED)
+ {
+ if (tTd(11, 1))
+ {
+ printf("openmailer: ");
+ mci_dump(mci, FALSE);
+ }
+ CurHostName = mci->mci_host;
+ break;
+ }
+ mci->mci_mailer = m;
+ if (mci->mci_exitstat != EX_OK)
+ continue;
+
+ /* try the connection */
+ setproctitle("%s %s: %s", e->e_id, hostbuf, "user open");
+ message("Connecting to %s (%s)...",
+ hostbuf, m->m_name);
+ i = makeconnection(hostbuf, port, mci,
+ bitnset(M_SECURE_PORT, m->m_flags));
+ mci->mci_exitstat = i;
+ mci->mci_errno = errno;
+#if NAMED_BIND
+ mci->mci_herrno = h_errno;
+#endif
+ if (i == EX_OK)
+ {
+ mci->mci_state = MCIS_OPENING;
+ mci_cache(mci);
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d == CONNECT %s\n",
+ getpid(), hostbuf);
+ break;
+ }
+ else if (tTd(11, 1))
+ printf("openmailer: makeconnection => stat=%d, errno=%d\n",
+ i, errno);
+
+ /* enter status of this host */
+ setstat(i);
+
+ /* should print some message here for -v mode */
+ }
+ if (mci == NULL)
+ {
+ syserr("deliver: no host name");
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+ mci->mci_pid = 0;
+#else /* no DAEMON */
+ syserr("554 openmailer: no IPC");
+ if (tTd(11, 1))
+ printf("openmailer: NULL\n");
+ rcode = EX_UNAVAILABLE;
+ goto give_up;
+#endif /* DAEMON */
+ }
+ else
+ {
+ if (TrafficLogFile != NULL)
+ {
+ char **av;
+
+ fprintf(TrafficLogFile, "%05d === EXEC", getpid());
+ for (av = pv; *av != NULL; av++)
+ fprintf(TrafficLogFile, " %s", *av);
+ fprintf(TrafficLogFile, "\n");
+ }
+
+ /* create a pipe to shove the mail through */
+ if (pipe(mpvect) < 0)
+ {
+ syserr("%s... openmailer(%s): pipe (to mailer)",
+ e->e_to, m->m_name);
+ if (tTd(11, 1))
+ printf("openmailer: NULL\n");
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+
+ /* if this mailer speaks smtp, create a return pipe */
+ if (clever && pipe(rpvect) < 0)
+ {
+ syserr("%s... openmailer(%s): pipe (from mailer)",
+ e->e_to, m->m_name);
+ (void) close(mpvect[0]);
+ (void) close(mpvect[1]);
+ if (tTd(11, 1))
+ printf("openmailer: NULL\n");
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+
+ /*
+ ** Actually fork the mailer process.
+ ** DOFORK is clever about retrying.
+ **
+ ** Dispose of SIGCHLD signal catchers that may be laying
+ ** around so that endmail will get it.
+ */
+
+ if (e->e_xfp != NULL)
+ (void) fflush(e->e_xfp); /* for debugging */
+ (void) fflush(stdout);
+# ifdef SIGCHLD
+ (void) setsignal(SIGCHLD, SIG_DFL);
+# endif /* SIGCHLD */
+ DOFORK(FORK);
+ /* pid is set by DOFORK */
+ if (pid < 0)
+ {
+ /* failure */
+ syserr("%s... openmailer(%s): cannot fork",
+ e->e_to, m->m_name);
+ (void) close(mpvect[0]);
+ (void) close(mpvect[1]);
+ if (clever)
+ {
+ (void) close(rpvect[0]);
+ (void) close(rpvect[1]);
+ }
+ if (tTd(11, 1))
+ printf("openmailer: NULL\n");
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+ else if (pid == 0)
+ {
+ int i;
+ int saveerrno;
+ char **ep;
+ char *env[MAXUSERENVIRON];
+ extern char **environ;
+ extern int DtableSize;
+
+ if (e->e_lockfp != NULL)
+ (void) close(fileno(e->e_lockfp));
+
+ /* child -- set up input & exec mailer */
+ (void) setsignal(SIGINT, SIG_IGN);
+ (void) setsignal(SIGHUP, SIG_IGN);
+ (void) setsignal(SIGTERM, SIG_DFL);
+
+ /* reset user and group */
+ if (!bitnset(M_RESTR, m->m_flags))
+ {
+ if (ctladdr == NULL || ctladdr->q_uid == 0)
+ {
+ (void) initgroups(DefUser, DefGid);
+ (void) setgid(DefGid);
+ (void) setuid(DefUid);
+ }
+ else
+ {
+ (void) initgroups(ctladdr->q_ruser?
+ ctladdr->q_ruser: ctladdr->q_user,
+ ctladdr->q_gid);
+ (void) setgid(ctladdr->q_gid);
+ (void) setuid(ctladdr->q_uid);
+ }
+ }
+
+ if (tTd(11, 2))
+ printf("openmailer: running as r/euid=%d/%d\n",
+ getuid(), geteuid());
+
+ /* move into some "safe" directory */
+ if (m->m_execdir != NULL)
+ {
+ char *p, *q;
+ char buf[MAXLINE];
+
+ for (p = m->m_execdir; p != NULL; p = q)
+ {
+ q = strchr(p, ':');
+ if (q != NULL)
+ *q = '\0';
+ expand(p, buf, &buf[sizeof buf] - 1, e);
+ if (q != NULL)
+ *q++ = ':';
+ if (tTd(11, 20))
+ printf("openmailer: trydir %s\n",
+ buf);
+ if (buf[0] != '\0' && chdir(buf) >= 0)
+ break;
+ }
+ }
+
+ /* arrange to filter std & diag output of command */
+ if (clever)
+ {
+ (void) close(rpvect[0]);
+ if (dup2(rpvect[1], STDOUT_FILENO) < 0)
+ {
+ syserr("%s... openmailer(%s): cannot dup pipe %d for stdout",
+ e->e_to, m->m_name, rpvect[1]);
+ _exit(EX_OSERR);
+ }
+ (void) close(rpvect[1]);
+ }
+ else if (OpMode == MD_SMTP || OpMode == MD_DAEMON ||
+ HoldErrs || DisConnected)
+ {
+ /* put mailer output in transcript */
+ if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0)
+ {
+ syserr("%s... openmailer(%s): cannot dup xscript %d for stdout",
+ e->e_to, m->m_name,
+ fileno(e->e_xfp));
+ _exit(EX_OSERR);
+ }
+ }
+ if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
+ {
+ syserr("%s... openmailer(%s): cannot dup stdout for stderr",
+ e->e_to, m->m_name);
+ _exit(EX_OSERR);
+ }
+
+ /* arrange to get standard input */
+ (void) close(mpvect[1]);
+ if (dup2(mpvect[0], STDIN_FILENO) < 0)
+ {
+ syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
+ e->e_to, m->m_name, mpvect[0]);
+ _exit(EX_OSERR);
+ }
+ (void) close(mpvect[0]);
+
+ /* arrange for all the files to be closed */
+ for (i = 3; i < DtableSize; i++)
+ {
+ register int j;
+
+ if ((j = fcntl(i, F_GETFD, 0)) != -1)
+ (void) fcntl(i, F_SETFD, j | 1);
+ }
+
+ /*
+ ** Set up the mailer environment
+ ** TZ is timezone information.
+ ** SYSTYPE is Apollo software sys type (required).
+ ** ISP is Apollo hardware system type (required).
+ */
+
+ i = 0;
+ env[i++] = "AGENT=sendmail";
+ for (ep = environ; *ep != NULL; ep++)
+ {
+ if (strncmp(*ep, "TZ=", 3) == 0 ||
+ strncmp(*ep, "ISP=", 4) == 0 ||
+ strncmp(*ep, "SYSTYPE=", 8) == 0)
+ env[i++] = *ep;
+ }
+ env[i++] = NULL;
+
+ /* run disconnected from terminal */
+ (void) setsid();
+
+ /* try to execute the mailer */
+ execve(m->m_mailer, pv, env);
+ saveerrno = errno;
+ syserr("Cannot exec %s", m->m_mailer);
+ if (m == LocalMailer || transienterror(saveerrno))
+ _exit(EX_OSERR);
+ _exit(EX_UNAVAILABLE);
+ }
+
+ /*
+ ** Set up return value.
+ */
+
+ mci = (MCI *) xalloc(sizeof *mci);
+ bzero((char *) mci, sizeof *mci);
+ mci->mci_mailer = m;
+ mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
+ mci->mci_pid = pid;
+ (void) close(mpvect[0]);
+ mci->mci_out = fdopen(mpvect[1], "w");
+ if (mci->mci_out == NULL)
+ {
+ syserr("deliver: cannot create mailer output channel, fd=%d",
+ mpvect[1]);
+ (void) close(mpvect[1]);
+ if (clever)
+ {
+ (void) close(rpvect[0]);
+ (void) close(rpvect[1]);
+ }
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+ if (clever)
+ {
+ (void) close(rpvect[1]);
+ mci->mci_in = fdopen(rpvect[0], "r");
+ if (mci->mci_in == NULL)
+ {
+ syserr("deliver: cannot create mailer input channel, fd=%d",
+ mpvect[1]);
+ (void) close(rpvect[0]);
+ fclose(mci->mci_out);
+ mci->mci_out = NULL;
+ rcode = EX_OSERR;
+ goto give_up;
+ }
+ }
+ else
+ {
+ mci->mci_flags |= MCIF_TEMP;
+ mci->mci_in = NULL;
+ }
+ }
+
+ /*
+ ** If we are in SMTP opening state, send initial protocol.
+ */
+
+ if (clever && mci->mci_state != MCIS_CLOSED)
+ {
+ smtpinit(m, mci, e);
+ }
+ if (tTd(11, 1))
+ {
+ printf("openmailer: ");
+ mci_dump(mci, FALSE);
+ }
+
+ if (mci->mci_state != MCIS_OPEN)
+ {
+ /* couldn't open the mailer */
+ rcode = mci->mci_exitstat;
+ errno = mci->mci_errno;
+#if NAMED_BIND
+ h_errno = mci->mci_herrno;
+#endif
+ if (rcode == EX_OK)
+ {
+ /* shouldn't happen */
+ syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s",
+ rcode, mci->mci_state, firstsig);
+ rcode = EX_SOFTWARE;
+ }
+ else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0')
+ {
+ /* try next MX site */
+ goto tryhost;
+ }
+ }
+ else if (!clever)
+ {
+ /*
+ ** Format and send message.
+ */
+
+ putfromline(mci, e);
+ (*e->e_puthdr)(mci, e);
+ putline("\n", mci);
+ (*e->e_putbody)(mci, e, NULL);
+
+ /* get the exit status */
+ rcode = endmailer(mci, e, pv);
+ }
+ else
+#ifdef SMTP
+ {
+ /*
+ ** Send the MAIL FROM: protocol
+ */
+
+ rcode = smtpmailfrom(m, mci, e);
+ if (rcode == EX_OK)
+ {
+ register char *t = tobuf;
+ register int i;
+
+ /* send the recipient list */
+ tobuf[0] = '\0';
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ {
+ e->e_to = to->q_paddr;
+ if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
+ {
+ markfailure(e, to, i);
+ giveresponse(i, m, mci, ctladdr, e);
+ }
+ else
+ {
+ *t++ = ',';
+ for (p = to->q_paddr; *p; *t++ = *p++)
+ continue;
+ *t = '\0';
+ }
+ }
+
+ /* now send the data */
+ if (tobuf[0] == '\0')
+ {
+ rcode = EX_OK;
+ e->e_to = NULL;
+ if (bitset(MCIF_CACHED, mci->mci_flags))
+ smtprset(m, mci, e);
+ }
+ else
+ {
+ e->e_to = tobuf + 1;
+ rcode = smtpdata(m, mci, e);
+ }
+
+ /* now close the connection */
+ if (!bitset(MCIF_CACHED, mci->mci_flags))
+ smtpquit(m, mci, e);
+ }
+ if (rcode != EX_OK && curhost != NULL && *curhost != '\0')
+ {
+ /* try next MX site */
+ goto tryhost;
+ }
+ }
+#else /* not SMTP */
+ {
+ syserr("554 deliver: need SMTP compiled to use clever mailer");
+ rcode = EX_CONFIG;
+ goto give_up;
+ }
+#endif /* SMTP */
+#if NAMED_BIND
+ if (ConfigLevel < 2)
+ _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
+#endif
+
+ /* arrange a return receipt if requested */
+ if (rcode == EX_OK && e->e_receiptto != NULL &&
+ bitnset(M_LOCALMAILER, m->m_flags))
+ {
+ e->e_flags |= EF_SENDRECEIPT;
+ /* do we want to send back more info? */
+ }
+
+ /*
+ ** Do final status disposal.
+ ** We check for something in tobuf for the SMTP case.
+ ** If we got a temporary failure, arrange to queue the
+ ** addressees.
+ */
+
+ give_up:
+ if (tobuf[0] != '\0')
+ giveresponse(rcode, m, mci, ctladdr, e);
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ {
+ if (rcode != EX_OK)
+ markfailure(e, to, rcode);
+ else
+ {
+ to->q_flags |= QSENT;
+ e->e_nsent++;
+ if (e->e_receiptto != NULL &&
+ bitnset(M_LOCALMAILER, m->m_flags))
+ {
+ fprintf(e->e_xfp, "%s... Successfully delivered\n",
+ to->q_paddr);
+ }
+ }
+ }
+
+ /*
+ ** Restore state and return.
+ */
+
+#ifdef XDEBUG
+ {
+ char wbuf[MAXLINE];
+
+ /* make absolutely certain 0, 1, and 2 are in use */
+ sprintf(wbuf, "%s... end of deliver(%s)",
+ e->e_to == NULL ? "NO-TO-LIST" : e->e_to,
+ m->m_name);
+ checkfd012(wbuf);
+ }
+#endif
+
+ errno = 0;
+ define('g', (char *) NULL, e);
+ return (rcode);
+}
+ /*
+** MARKFAILURE -- mark a failure on a specific address.
+**
+** Parameters:
+** e -- the envelope we are sending.
+** q -- the address to mark.
+** rcode -- the code signifying the particular failure.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** marks the address (and possibly the envelope) with the
+** failure so that an error will be returned or
+** the message will be queued, as appropriate.
+*/
+
+markfailure(e, q, rcode)
+ register ENVELOPE *e;
+ register ADDRESS *q;
+ int rcode;
+{
+ char buf[MAXLINE];
+
+ switch (rcode)
+ {
+ case EX_OK:
+ break;
+
+ case EX_TEMPFAIL:
+ case EX_IOERR:
+ case EX_OSERR:
+ q->q_flags |= QQUEUEUP;
+ break;
+
+ default:
+ q->q_flags |= QBADADDR;
+ break;
+ }
+}
+ /*
+** ENDMAILER -- Wait for mailer to terminate.
+**
+** We should never get fatal errors (e.g., segmentation
+** violation), so we report those specially. For other
+** errors, we choose a status message (into statmsg),
+** and if it represents an error, we print it.
+**
+** Parameters:
+** pid -- pid of mailer.
+** e -- the current envelope.
+** pv -- the parameter vector that invoked the mailer
+** (for error messages).
+**
+** Returns:
+** exit code of mailer.
+**
+** Side Effects:
+** none.
+*/
+
+endmailer(mci, e, pv)
+ register MCI *mci;
+ register ENVELOPE *e;
+ char **pv;
+{
+ int st;
+
+ /* close any connections */
+ if (mci->mci_in != NULL)
+ (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in");
+ if (mci->mci_out != NULL)
+ (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out");
+ mci->mci_in = mci->mci_out = NULL;
+ mci->mci_state = MCIS_CLOSED;
+
+ /* in the IPC case there is nothing to wait for */
+ if (mci->mci_pid == 0)
+ return (EX_OK);
+
+ /* wait for the mailer process to die and collect status */
+ st = waitfor(mci->mci_pid);
+ if (st == -1)
+ {
+ syserr("endmailer %s: wait", pv[0]);
+ return (EX_SOFTWARE);
+ }
+
+ if (WIFEXITED(st))
+ {
+ /* normal death -- return status */
+ return (WEXITSTATUS(st));
+ }
+
+ /* it died a horrid death */
+ syserr("451 mailer %s died with signal %o",
+ mci->mci_mailer->m_name, st);
+
+ /* log the arguments */
+ if (pv != NULL && e->e_xfp != NULL)
+ {
+ register char **av;
+
+ fprintf(e->e_xfp, "Arguments:");
+ for (av = pv; *av != NULL; av++)
+ fprintf(e->e_xfp, " %s", *av);
+ fprintf(e->e_xfp, "\n");
+ }
+
+ ExitStat = EX_TEMPFAIL;
+ return (EX_TEMPFAIL);
+}
+ /*
+** GIVERESPONSE -- Interpret an error response from a mailer
+**
+** Parameters:
+** stat -- the status code from the mailer (high byte
+** only; core dumps must have been taken care of
+** already).
+** m -- the mailer info for this mailer.
+** mci -- the mailer connection info -- can be NULL if the
+** response is given before the connection is made.
+** ctladdr -- the controlling address for the recipient
+** address(es).
+** e -- the current envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Errors may be incremented.
+** ExitStat may be set.
+*/
+
+giveresponse(stat, m, mci, ctladdr, e)
+ int stat;
+ register MAILER *m;
+ register MCI *mci;
+ ADDRESS *ctladdr;
+ ENVELOPE *e;
+{
+ register const char *statmsg;
+ extern char *SysExMsg[];
+ register int i;
+ extern int N_SysEx;
+ char buf[MAXLINE];
+
+ /*
+ ** Compute status message from code.
+ */
+
+ i = stat - EX__BASE;
+ if (stat == 0)
+ {
+ statmsg = "250 Sent";
+ if (e->e_statmsg != NULL)
+ {
+ (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg);
+ statmsg = buf;
+ }
+ }
+ else if (i < 0 || i > N_SysEx)
+ {
+ (void) sprintf(buf, "554 unknown mailer error %d", stat);
+ stat = EX_UNAVAILABLE;
+ statmsg = buf;
+ }
+ else if (stat == EX_TEMPFAIL)
+ {
+ (void) strcpy(buf, SysExMsg[i] + 1);
+#if NAMED_BIND
+ if (h_errno == TRY_AGAIN)
+ statmsg = errstring(h_errno+E_DNSBASE);
+ else
+#endif
+ {
+ if (errno != 0)
+ statmsg = errstring(errno);
+ else
+ {
+#ifdef SMTP
+ statmsg = SmtpError;
+#else /* SMTP */
+ statmsg = NULL;
+#endif /* SMTP */
+ }
+ }
+ if (statmsg != NULL && statmsg[0] != '\0')
+ {
+ (void) strcat(buf, ": ");
+ (void) strcat(buf, statmsg);
+ }
+ statmsg = buf;
+ }
+#if NAMED_BIND
+ else if (stat == EX_NOHOST && h_errno != 0)
+ {
+ statmsg = errstring(h_errno + E_DNSBASE);
+ (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg);
+ statmsg = buf;
+ }
+#endif
+ else
+ {
+ statmsg = SysExMsg[i];
+ if (*statmsg++ == ':')
+ {
+ (void) sprintf(buf, "%s: %s", statmsg, errstring(errno));
+ statmsg = buf;
+ }
+ }
+
+ /*
+ ** Print the message as appropriate
+ */
+
+ if (stat == EX_OK || stat == EX_TEMPFAIL)
+ {
+ extern char MsgBuf[];
+
+ message("%s", &statmsg[4]);
+ if (stat == EX_TEMPFAIL && e->e_xfp != NULL)
+ fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
+ }
+ else
+ {
+ char mbuf[8];
+
+ Errors++;
+ sprintf(mbuf, "%.3s %%s", statmsg);
+ usrerr(mbuf, &statmsg[4]);
+ }
+
+ /*
+ ** Final cleanup.
+ ** Log a record of the transaction. Compute the new
+ ** ExitStat -- if we already had an error, stick with
+ ** that.
+ */
+
+ if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6))
+ logdelivery(m, mci, &statmsg[4], ctladdr, e);
+
+ if (tTd(11, 2))
+ printf("giveresponse: stat=%d, e->e_message=%s\n",
+ stat, e->e_message == NULL ? "<NULL>" : e->e_message);
+
+ if (stat != EX_TEMPFAIL)
+ setstat(stat);
+ if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL))
+ {
+ if (e->e_message != NULL)
+ free(e->e_message);
+ e->e_message = newstr(&statmsg[4]);
+ }
+ errno = 0;
+#if NAMED_BIND
+ h_errno = 0;
+#endif
+}
+ /*
+** LOGDELIVERY -- log the delivery in the system log
+**
+** Care is taken to avoid logging lines that are too long, because
+** some versions of syslog have an unfortunate proclivity for core
+** dumping. This is a hack, to be sure, that is at best empirical.
+**
+** Parameters:
+** m -- the mailer info. Can be NULL for initial queue.
+** mci -- the mailer connection info -- can be NULL if the
+** log is occuring when no connection is active.
+** stat -- the message to print for the status.
+** ctladdr -- the controlling address for the to list.
+** e -- the current envelope.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** none
+*/
+
+logdelivery(m, mci, stat, ctladdr, e)
+ MAILER *m;
+ register MCI *mci;
+ char *stat;
+ ADDRESS *ctladdr;
+ register ENVELOPE *e;
+{
+# ifdef LOG
+ register char *bp;
+ register char *p;
+ int l;
+ char buf[512];
+
+# if (SYSLOG_BUFSIZE) >= 256
+ bp = buf;
+ if (ctladdr != NULL)
+ {
+ strcpy(bp, ", ctladdr=");
+ strcat(bp, shortenstring(ctladdr->q_paddr, 83));
+ bp += strlen(bp);
+ if (bitset(QGOODUID, ctladdr->q_flags))
+ {
+ (void) sprintf(bp, " (%d/%d)",
+ ctladdr->q_uid, ctladdr->q_gid);
+ bp += strlen(bp);
+ }
+ }
+
+ (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+ bp += strlen(bp);
+
+ if (m != NULL)
+ {
+ (void) strcpy(bp, ", mailer=");
+ (void) strcat(bp, m->m_name);
+ bp += strlen(bp);
+ }
+
+ if (mci != NULL && mci->mci_host != NULL)
+ {
+# ifdef DAEMON
+ extern SOCKADDR CurHostAddr;
+# endif
+
+ (void) strcpy(bp, ", relay=");
+ (void) strcat(bp, mci->mci_host);
+
+# ifdef DAEMON
+ (void) strcat(bp, " [");
+ (void) strcat(bp, anynet_ntoa(&CurHostAddr));
+ (void) strcat(bp, "]");
+# endif
+ }
+ else if (strcmp(stat, "queued") != 0)
+ {
+ char *p = macvalue('h', e);
+
+ if (p != NULL && p[0] != '\0')
+ {
+ (void) strcpy(bp, ", relay=");
+ (void) strcat(bp, p);
+ }
+ }
+ bp += strlen(bp);
+
+#define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4)
+#if (STATLEN) < 63
+# undef STATLEN
+# define STATLEN 63
+#endif
+#if (STATLEN) > 203
+# undef STATLEN
+# define STATLEN 203
+#endif
+
+ if ((bp - buf) > (sizeof buf - ((STATLEN) + 20)))
+ {
+ /* desperation move -- truncate data */
+ bp = buf + sizeof buf - ((STATLEN) + 17);
+ strcpy(bp, "...");
+ bp += 3;
+ }
+
+ (void) strcpy(bp, ", stat=");
+ bp += strlen(bp);
+
+ (void) strcpy(bp, shortenstring(stat, (STATLEN)));
+
+ l = SYSLOG_BUFSIZE - 100 - strlen(buf);
+ p = e->e_to;
+ while (strlen(p) >= l)
+ {
+ register char *q = strchr(p + l, ',');
+
+ if (q == NULL)
+ break;
+ syslog(LOG_INFO, "%s: to=%.*s [more]%s",
+ e->e_id, ++q - p, p, buf);
+ p = q;
+ }
+ syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf);
+
+# else /* we have a very short log buffer size */
+
+ l = SYSLOG_BUFSIZE - 85;
+ p = e->e_to;
+ while (strlen(p) >= l)
+ {
+ register char *q = strchr(p + l, ',');
+
+ if (q == NULL)
+ break;
+ syslog(LOG_INFO, "%s: to=%.*s [more]",
+ e->e_id, ++q - p, p);
+ p = q;
+ }
+ syslog(LOG_INFO, "%s: to=%s", e->e_id, p);
+
+ if (ctladdr != NULL)
+ {
+ bp = buf;
+ strcpy(buf, "ctladdr=");
+ bp += strlen(buf);
+ strcpy(bp, shortenstring(ctladdr->q_paddr, 83));
+ bp += strlen(buf);
+ if (bitset(QGOODUID, ctladdr->q_flags))
+ {
+ (void) sprintf(bp, " (%d/%d)",
+ ctladdr->q_uid, ctladdr->q_gid);
+ bp += strlen(bp);
+ }
+ syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+ }
+ bp = buf;
+ sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE));
+ bp += strlen(bp);
+
+ if (m != NULL)
+ {
+ sprintf(bp, ", mailer=%s", m->m_name);
+ bp += strlen(bp);
+ }
+ syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+
+ buf[0] = '\0';
+ if (mci != NULL && mci->mci_host != NULL)
+ {
+# ifdef DAEMON
+ extern SOCKADDR CurHostAddr;
+# endif
+
+ sprintf(buf, "relay=%s", mci->mci_host);
+
+# ifdef DAEMON
+ (void) strcat(buf, " [");
+ (void) strcat(buf, anynet_ntoa(&CurHostAddr));
+ (void) strcat(buf, "]");
+# endif
+ }
+ else if (strcmp(stat, "queued") != 0)
+ {
+ char *p = macvalue('h', e);
+
+ if (p != NULL && p[0] != '\0')
+ sprintf(buf, "relay=%s", p);
+ }
+ if (buf[0] != '\0')
+ syslog(LOG_INFO, "%s: %s", e->e_id, buf);
+
+ syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63));
+# endif /* short log buffer */
+# endif /* LOG */
+}
+ /*
+** PUTFROMLINE -- output a UNIX-style from line (or whatever)
+**
+** This can be made an arbitrary message separator by changing $l
+**
+** One of the ugliest hacks seen by human eyes is contained herein:
+** UUCP wants those stupid "remote from <host>" lines. Why oh why
+** does a well-meaning programmer such as myself have to deal with
+** this kind of antique garbage????
+**
+** Parameters:
+** mci -- the connection information.
+** e -- the envelope.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** outputs some text to fp.
+*/
+
+putfromline(mci, e)
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ char *template = "\201l\n";
+ char buf[MAXLINE];
+
+ if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
+ return;
+
+# ifdef UGLYUUCP
+ if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
+ {
+ char *bang;
+ char xbuf[MAXLINE];
+
+ expand("\201g", buf, &buf[sizeof buf - 1], e);
+ bang = strchr(buf, '!');
+ if (bang == NULL)
+ {
+ errno = 0;
+ syserr("554 No ! in UUCP From address! (%s given)", buf);
+ }
+ else
+ {
+ *bang++ = '\0';
+ (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf);
+ template = xbuf;
+ }
+ }
+# endif /* UGLYUUCP */
+ expand(template, buf, &buf[sizeof buf - 1], e);
+ putline(buf, mci);
+}
+ /*
+** PUTBODY -- put the body of a message.
+**
+** Parameters:
+** mci -- the connection information.
+** e -- the envelope to put out.
+** separator -- if non-NULL, a message separator that must
+** not be permitted in the resulting message.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** The message is written onto fp.
+*/
+
+putbody(mci, e, separator)
+ register MCI *mci;
+ register ENVELOPE *e;
+ char *separator;
+{
+ char buf[MAXLINE];
+
+ /*
+ ** Output the body of the message
+ */
+
+ if (e->e_dfp == NULL)
+ {
+ if (e->e_df != NULL)
+ {
+ e->e_dfp = fopen(e->e_df, "r");
+ if (e->e_dfp == NULL)
+ syserr("putbody: Cannot open %s for %s from %s",
+ e->e_df, e->e_to, e->e_from.q_paddr);
+ }
+ else
+ putline("<<< No Message Collected >>>", mci);
+ }
+ if (e->e_dfp != NULL)
+ {
+ rewind(e->e_dfp);
+ while (!ferror(mci->mci_out) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ {
+ if (buf[0] == 'F' &&
+ bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
+ strncmp(buf, "From ", 5) == 0)
+ (void) putc('>', mci->mci_out);
+ if (buf[0] == '-' && buf[1] == '-' && separator != NULL)
+ {
+ /* possible separator */
+ int sl = strlen(separator);
+
+ if (strncmp(&buf[2], separator, sl) == 0)
+ (void) putc(' ', mci->mci_out);
+ }
+ putline(buf, mci);
+ }
+
+ if (ferror(e->e_dfp))
+ {
+ syserr("putbody: %s: read error", e->e_df);
+ ExitStat = EX_IOERR;
+ }
+ }
+
+ /* some mailers want extra blank line at end of message */
+ if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
+ buf[0] != '\0' && buf[0] != '\n')
+ putline("", mci);
+
+ (void) fflush(mci->mci_out);
+ if (ferror(mci->mci_out) && errno != EPIPE)
+ {
+ syserr("putbody: write error");
+ ExitStat = EX_IOERR;
+ }
+ errno = 0;
+}
+ /*
+** MAILFILE -- Send a message to a file.
+**
+** If the file has the setuid/setgid bits set, but NO execute
+** bits, sendmail will try to become the owner of that file
+** rather than the real user. Obviously, this only works if
+** sendmail runs as root.
+**
+** This could be done as a subordinate mailer, except that it
+** is used implicitly to save messages in ~/dead.letter. We
+** view this as being sufficiently important as to include it
+** here. For example, if the system is dying, we shouldn't have
+** to create another process plus some pipes to save the message.
+**
+** Parameters:
+** filename -- the name of the file to send to.
+** ctladdr -- the controlling address header -- includes
+** the userid/groupid to be when sending.
+**
+** Returns:
+** The exit code associated with the operation.
+**
+** Side Effects:
+** none.
+*/
+
+mailfile(filename, ctladdr, e)
+ char *filename;
+ ADDRESS *ctladdr;
+ register ENVELOPE *e;
+{
+ register FILE *f;
+ register int pid;
+ int mode;
+
+ if (tTd(11, 1))
+ {
+ printf("mailfile %s\n ctladdr=", filename);
+ printaddr(ctladdr, FALSE);
+ }
+
+ if (e->e_xfp != NULL)
+ fflush(e->e_xfp);
+
+ /*
+ ** Fork so we can change permissions here.
+ ** Note that we MUST use fork, not vfork, because of
+ ** the complications of calling subroutines, etc.
+ */
+
+ DOFORK(fork);
+
+ if (pid < 0)
+ return (EX_OSERR);
+ else if (pid == 0)
+ {
+ /* child -- actually write to file */
+ struct stat stb;
+ struct stat fsb;
+ MCI mcibuf;
+ int oflags = O_WRONLY|O_APPEND;
+
+ if (e->e_lockfp != NULL)
+ {
+ fclose(e->e_lockfp);
+ e->e_lockfp = NULL;
+ }
+
+ (void) setsignal(SIGINT, SIG_DFL);
+ (void) setsignal(SIGHUP, SIG_DFL);
+ (void) setsignal(SIGTERM, SIG_DFL);
+ (void) umask(OldUmask);
+
+ if (stat(filename, &stb) < 0)
+ {
+ stb.st_mode = FileMode;
+ oflags |= O_CREAT|O_EXCL;
+ }
+ else if (bitset(0111, stb.st_mode))
+ exit(EX_CANTCREAT);
+ mode = stb.st_mode;
+
+ /* limit the errors to those actually caused in the child */
+ errno = 0;
+ ExitStat = EX_OK;
+
+ if (ctladdr != NULL)
+ {
+ /* ignore setuid and setgid bits */
+ mode &= ~(S_ISGID|S_ISUID);
+ }
+
+ /* we have to open the dfile BEFORE setuid */
+ if (e->e_dfp == NULL && e->e_df != NULL)
+ {
+ e->e_dfp = fopen(e->e_df, "r");
+ if (e->e_dfp == NULL)
+ {
+ syserr("mailfile: Cannot open %s for %s from %s",
+ e->e_df, e->e_to, e->e_from.q_paddr);
+ }
+ }
+
+ if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0)
+ {
+ if (ctladdr == NULL || ctladdr->q_uid == 0)
+ {
+ (void) initgroups(DefUser, DefGid);
+ }
+ else
+ {
+ (void) initgroups(ctladdr->q_ruser ?
+ ctladdr->q_ruser : ctladdr->q_user,
+ ctladdr->q_gid);
+ }
+ }
+ if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0)
+ {
+ if (ctladdr == NULL || ctladdr->q_uid == 0)
+ (void) setuid(DefUid);
+ else
+ (void) setuid(ctladdr->q_uid);
+ }
+ FileName = filename;
+ LineNumber = 0;
+ f = dfopen(filename, oflags, FileMode);
+ if (f == NULL)
+ {
+ message("554 cannot open: %s", errstring(errno));
+ exit(EX_CANTCREAT);
+ }
+ if (fstat(fileno(f), &fsb) < 0 ||
+ !bitset(O_CREAT, oflags) &&
+ (stb.st_nlink != fsb.st_nlink ||
+ stb.st_dev != fsb.st_dev ||
+ stb.st_ino != fsb.st_ino ||
+ stb.st_uid != fsb.st_uid))
+ {
+ message("554 cannot write: file changed after open");
+ exit(EX_CANTCREAT);
+ }
+
+ bzero(&mcibuf, sizeof mcibuf);
+ mcibuf.mci_mailer = FileMailer;
+ mcibuf.mci_out = f;
+ if (bitnset(M_7BITS, FileMailer->m_flags))
+ mcibuf.mci_flags |= MCIF_7BIT;
+
+ putfromline(&mcibuf, e);
+ (*e->e_puthdr)(&mcibuf, e);
+ putline("\n", &mcibuf);
+ (*e->e_putbody)(&mcibuf, e, NULL);
+ putline("\n", &mcibuf);
+ if (ferror(f))
+ {
+ message("451 I/O error: %s", errstring(errno));
+ setstat(EX_IOERR);
+ }
+ (void) xfclose(f, "mailfile", filename);
+ (void) fflush(stdout);
+
+ /* reset ISUID & ISGID bits for paranoid systems */
+ (void) chmod(filename, (int) stb.st_mode);
+ exit(ExitStat);
+ /*NOTREACHED*/
+ }
+ else
+ {
+ /* parent -- wait for exit status */
+ int st;
+
+ st = waitfor(pid);
+ if (WIFEXITED(st))
+ return (WEXITSTATUS(st));
+ else
+ {
+ syserr("child died on signal %d", st);
+ return (EX_UNAVAILABLE);
+ }
+ /*NOTREACHED*/
+ }
+}
+ /*
+** HOSTSIGNATURE -- return the "signature" for a host.
+**
+** The signature describes how we are going to send this -- it
+** can be just the hostname (for non-Internet hosts) or can be
+** an ordered list of MX hosts.
+**
+** Parameters:
+** m -- the mailer describing this host.
+** host -- the host name.
+** e -- the current envelope.
+**
+** Returns:
+** The signature for this host.
+**
+** Side Effects:
+** Can tweak the symbol table.
+*/
+
+char *
+hostsignature(m, host, e)
+ register MAILER *m;
+ char *host;
+ ENVELOPE *e;
+{
+ register char *p;
+ register STAB *s;
+ int i;
+ int len;
+#if NAMED_BIND
+ int nmx;
+ auto int rcode;
+ char *hp;
+ char *endp;
+ int oldoptions;
+ char *mxhosts[MAXMXHOSTS + 1];
+#endif
+
+ /*
+ ** Check to see if this uses IPC -- if not, it can't have MX records.
+ */
+
+ p = m->m_mailer;
+ if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0)
+ {
+ /* just an ordinary mailer */
+ return host;
+ }
+
+ /*
+ ** Look it up in the symbol table.
+ */
+
+ s = stab(host, ST_HOSTSIG, ST_ENTER);
+ if (s->s_hostsig != NULL)
+ return s->s_hostsig;
+
+ /*
+ ** Not already there -- create a signature.
+ */
+
+#if NAMED_BIND
+ if (ConfigLevel < 2)
+ {
+ oldoptions = _res.options;
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
+ }
+
+ for (hp = host; hp != NULL; hp = endp)
+ {
+ endp = strchr(hp, ':');
+ if (endp != NULL)
+ *endp = '\0';
+
+ nmx = getmxrr(hp, mxhosts, TRUE, &rcode);
+
+ if (nmx <= 0)
+ {
+ register MCI *mci;
+
+ /* update the connection info for this host */
+ mci = mci_get(hp, m);
+ mci->mci_exitstat = rcode;
+ mci->mci_errno = errno;
+#if NAMED_BIND
+ mci->mci_herrno = h_errno;
+#endif
+
+ /* and return the original host name as the signature */
+ nmx = 1;
+ mxhosts[0] = hp;
+ }
+
+ len = 0;
+ for (i = 0; i < nmx; i++)
+ {
+ len += strlen(mxhosts[i]) + 1;
+ }
+ if (s->s_hostsig != NULL)
+ len += strlen(s->s_hostsig) + 1;
+ p = xalloc(len);
+ if (s->s_hostsig != NULL)
+ {
+ (void) strcpy(p, s->s_hostsig);
+ free(s->s_hostsig);
+ s->s_hostsig = p;
+ p += strlen(p);
+ *p++ = ':';
+ }
+ else
+ s->s_hostsig = p;
+ for (i = 0; i < nmx; i++)
+ {
+ if (i != 0)
+ *p++ = ':';
+ strcpy(p, mxhosts[i]);
+ p += strlen(p);
+ }
+ if (endp != NULL)
+ *endp++ = ':';
+ }
+ makelower(s->s_hostsig);
+ if (ConfigLevel < 2)
+ _res.options = oldoptions;
+#else
+ /* not using BIND -- the signature is just the host name */
+ s->s_hostsig = host;
+#endif
+ if (tTd(17, 1))
+ printf("hostsignature(%s) = %s\n", host, s->s_hostsig);
+ return s->s_hostsig;
+}
diff --git a/usr.sbin/sendmail/src/domain.c b/usr.sbin/sendmail/src/domain.c
new file mode 100644
index 00000000000..913b6f0f62c
--- /dev/null
+++ b/usr.sbin/sendmail/src/domain.c
@@ -0,0 +1,771 @@
+/*
+ * Copyright (c) 1986 Eric P. Allman
+ * 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.
+ */
+
+#include "sendmail.h"
+
+#ifndef lint
+#if NAMED_BIND
+static char sccsid[] = "@(#)domain.c 8.19.1.1 (Berkeley) 3/6/95 (with name server)";
+#else
+static char sccsid[] = "@(#)domain.c 8.19.1.1 (Berkeley) 3/6/95 (without name server)";
+#endif
+#endif /* not lint */
+
+#if NAMED_BIND
+
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+
+typedef union
+{
+ HEADER qb1;
+ char qb2[PACKETSZ];
+} querybuf;
+
+static char MXHostBuf[MAXMXHOSTS*PACKETSZ];
+
+#ifndef MAXDNSRCH
+#define MAXDNSRCH 6 /* number of possible domains to search */
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef NO_DATA
+# define NO_DATA NO_ADDRESS
+#endif
+
+#ifndef HEADERSZ
+# define HEADERSZ sizeof(HEADER)
+#endif
+
+/* don't use sizeof because sizeof(long) is different on 64-bit machines */
+#define SHORTSIZE 2 /* size of a short (really, must be 2) */
+#define LONGSIZE 4 /* size of a long (really, must be 4) */
+
+#define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
+ /*
+** GETMXRR -- get MX resource records for a domain
+**
+** Parameters:
+** host -- the name of the host to MX.
+** mxhosts -- a pointer to a return buffer of MX records.
+** droplocalhost -- If TRUE, all MX records less preferred
+** than the local host (as determined by $=w) will
+** be discarded.
+** rcode -- a pointer to an EX_ status code.
+**
+** Returns:
+** The number of MX records found.
+** -1 if there is an internal failure.
+** If no MX records are found, mxhosts[0] is set to host
+** and 1 is returned.
+*/
+
+getmxrr(host, mxhosts, droplocalhost, rcode)
+ char *host;
+ char **mxhosts;
+ bool droplocalhost;
+ int *rcode;
+{
+ extern int h_errno;
+ register u_char *eom, *cp;
+ register int i, j, n;
+ int nmx = 0;
+ register char *bp;
+ HEADER *hp;
+ querybuf answer;
+ int ancount, qdcount, buflen;
+ bool seenlocal = FALSE;
+ u_short pref, localpref, type;
+ char *fallbackMX = FallBackMX;
+ static bool firsttime = TRUE;
+ STAB *st;
+ bool trycanon = FALSE;
+ u_short prefer[MAXMXHOSTS];
+ int weight[MAXMXHOSTS];
+ extern bool getcanonname();
+
+ if (tTd(8, 2))
+ printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost);
+
+ if (fallbackMX != NULL)
+ {
+ if (firsttime && res_query(FallBackMX, C_IN, T_A,
+ (char *) &answer, sizeof answer) < 0)
+ {
+ /* this entry is bogus */
+ fallbackMX = FallBackMX = NULL;
+ }
+ else if (droplocalhost &&
+ (st = stab(fallbackMX, ST_CLASS, ST_FIND)) != NULL &&
+ bitnset('w', st->s_class))
+ {
+ /* don't use fallback for this pass */
+ fallbackMX = NULL;
+ }
+ firsttime = FALSE;
+ }
+
+ /* efficiency hack -- numeric or non-MX lookups */
+ if (host[0] == '[')
+ goto punt;
+
+ errno = 0;
+ n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer));
+ if (n < 0)
+ {
+ if (tTd(8, 1))
+ printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
+ (host == NULL) ? "<NULL>" : host, errno, h_errno);
+ switch (h_errno)
+ {
+ case NO_DATA:
+ trycanon = TRUE;
+ /* fall through */
+
+ case NO_RECOVERY:
+ /* no MX data on this host */
+ goto punt;
+
+ case HOST_NOT_FOUND:
+#ifdef BROKEN_RES_SEARCH
+ /* Ultrix resolver returns failure w/ h_errno=0 */
+ case 0:
+#endif
+ /* the host just doesn't exist */
+ *rcode = EX_NOHOST;
+
+ if (!UseNameServer)
+ {
+ /* might exist in /etc/hosts */
+ goto punt;
+ }
+ break;
+
+ case TRY_AGAIN:
+ /* couldn't connect to the name server */
+ if (!UseNameServer && errno == ECONNREFUSED)
+ goto punt;
+
+ /* it might come up later; better queue it up */
+ *rcode = EX_TEMPFAIL;
+ break;
+
+ default:
+ syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n",
+ host, h_errno);
+ *rcode = EX_OSERR;
+ break;
+ }
+
+ /* irreconcilable differences */
+ return (-1);
+ }
+
+ /* find first satisfactory answer */
+ hp = (HEADER *)&answer;
+ cp = (u_char *)&answer + HEADERSZ;
+ eom = (u_char *)&answer + n;
+ for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
+ if ((n = dn_skipname(cp, eom)) < 0)
+ goto punt;
+ buflen = sizeof(MXHostBuf) - 1;
+ bp = MXHostBuf;
+ ancount = ntohs(hp->ancount);
+ while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
+ {
+ if ((n = dn_expand((u_char *)&answer,
+ eom, cp, (u_char *)bp, buflen)) < 0)
+ break;
+ cp += n;
+ GETSHORT(type, cp);
+ cp += SHORTSIZE + LONGSIZE;
+ GETSHORT(n, cp);
+ if (type != T_MX)
+ {
+ if (tTd(8, 8) || _res.options & RES_DEBUG)
+ printf("unexpected answer type %d, size %d\n",
+ type, n);
+ cp += n;
+ continue;
+ }
+ GETSHORT(pref, cp);
+ if ((n = dn_expand((u_char *)&answer, eom, cp,
+ (u_char *)bp, buflen)) < 0)
+ break;
+ cp += n;
+ if (droplocalhost &&
+ (st = stab(bp, ST_CLASS, ST_FIND)) != NULL &&
+ bitnset('w', st->s_class))
+ {
+ if (tTd(8, 3))
+ printf("found localhost (%s) in MX list, pref=%d\n",
+ bp, pref);
+ if (!seenlocal || pref < localpref)
+ localpref = pref;
+ seenlocal = TRUE;
+ continue;
+ }
+ weight[nmx] = mxrand(bp);
+ prefer[nmx] = pref;
+ mxhosts[nmx++] = bp;
+ n = strlen(bp);
+ bp += n;
+ if (bp[-1] != '.')
+ {
+ *bp++ = '.';
+ n++;
+ }
+ *bp++ = '\0';
+ buflen -= n + 1;
+ }
+
+ /* sort the records */
+ for (i = 0; i < nmx; i++)
+ {
+ for (j = i + 1; j < nmx; j++)
+ {
+ if (prefer[i] > prefer[j] ||
+ (prefer[i] == prefer[j] && weight[i] > weight[j]))
+ {
+ register int temp;
+ register char *temp1;
+
+ temp = prefer[i];
+ prefer[i] = prefer[j];
+ prefer[j] = temp;
+ temp1 = mxhosts[i];
+ mxhosts[i] = mxhosts[j];
+ mxhosts[j] = temp1;
+ temp = weight[i];
+ weight[i] = weight[j];
+ weight[j] = temp;
+ }
+ }
+ if (seenlocal && prefer[i] >= localpref)
+ {
+ /* truncate higher preference part of list */
+ nmx = i;
+ }
+ }
+
+ if (nmx == 0)
+ {
+punt:
+ if (seenlocal &&
+ (!TryNullMXList || gethostbyname(host) == NULL))
+ {
+ /*
+ ** If we have deleted all MX entries, this is
+ ** an error -- we should NEVER send to a host that
+ ** has an MX, and this should have been caught
+ ** earlier in the config file.
+ **
+ ** Some sites prefer to go ahead and try the
+ ** A record anyway; that case is handled by
+ ** setting TryNullMXList. I believe this is a
+ ** bad idea, but it's up to you....
+ */
+
+ *rcode = EX_CONFIG;
+ syserr("MX list for %s points back to %s",
+ host, MyHostName);
+ return -1;
+ }
+ strcpy(MXHostBuf, host);
+ mxhosts[0] = MXHostBuf;
+ if (host[0] == '[')
+ {
+ register char *p;
+ struct in_addr junk;
+
+ /* this may be an MX suppression-style address */
+ p = strchr(MXHostBuf, ']');
+ if (p != NULL)
+ {
+ *p = '\0';
+ if (inet_aton(&MXHostBuf[1], &junk) != 0)
+ *p = ']';
+ else
+ {
+ trycanon = TRUE;
+ mxhosts[0]++;
+ }
+ }
+ }
+ if (trycanon &&
+ getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
+ {
+ bp = &MXHostBuf[strlen(MXHostBuf)];
+ if (bp[-1] != '.')
+ {
+ *bp++ = '.';
+ *bp = '\0';
+ }
+ }
+ nmx = 1;
+ }
+
+ /* if we have a default lowest preference, include that */
+ if (fallbackMX != NULL && !seenlocal)
+ mxhosts[nmx++] = fallbackMX;
+
+ return (nmx);
+}
+ /*
+** MXRAND -- create a randomizer for equal MX preferences
+**
+** If two MX hosts have equal preferences we want to randomize
+** the selection. But in order for signatures to be the same,
+** we need to randomize the same way each time. This function
+** computes a pseudo-random hash function from the host name.
+**
+** Parameters:
+** host -- the name of the host.
+**
+** Returns:
+** A random but repeatable value based on the host name.
+**
+** Side Effects:
+** none.
+*/
+
+mxrand(host)
+ register char *host;
+{
+ int hfunc;
+ static unsigned int seed;
+
+ if (seed == 0)
+ {
+ seed = (int) curtime() & 0xffff;
+ if (seed == 0)
+ seed++;
+ }
+
+ if (tTd(17, 9))
+ printf("mxrand(%s)", host);
+
+ hfunc = seed;
+ while (*host != '\0')
+ {
+ int c = *host++;
+
+ if (isascii(c) && isupper(c))
+ c = tolower(c);
+ hfunc = ((hfunc << 1) ^ c) % 2003;
+ }
+
+ hfunc &= 0xff;
+
+ if (tTd(17, 9))
+ printf(" = %d\n", hfunc);
+ return hfunc;
+}
+ /*
+** GETCANONNAME -- get the canonical name for named host
+**
+** This algorithm tries to be smart about wildcard MX records.
+** This is hard to do because DNS doesn't tell is if we matched
+** against a wildcard or a specific MX.
+**
+** We always prefer A & CNAME records, since these are presumed
+** to be specific.
+**
+** If we match an MX in one pass and lose it in the next, we use
+** the old one. For example, consider an MX matching *.FOO.BAR.COM.
+** A hostname bletch.foo.bar.com will match against this MX, but
+** will stop matching when we try bletch.bar.com -- so we know
+** that bletch.foo.bar.com must have been right. This fails if
+** there was also an MX record matching *.BAR.COM, but there are
+** some things that just can't be fixed.
+**
+** Parameters:
+** host -- a buffer containing the name of the host.
+** This is a value-result parameter.
+** hbsize -- the size of the host buffer.
+** trymx -- if set, try MX records as well as A and CNAME.
+**
+** Returns:
+** TRUE -- if the host matched.
+** FALSE -- otherwise.
+*/
+
+bool
+getcanonname(host, hbsize, trymx)
+ char *host;
+ int hbsize;
+ bool trymx;
+{
+ extern int h_errno;
+ register u_char *eom, *ap;
+ register char *cp;
+ register int n;
+ HEADER *hp;
+ querybuf answer;
+ int ancount, qdcount;
+ int ret;
+ char **domain;
+ int type;
+ char **dp;
+ char *mxmatch;
+ bool amatch;
+ bool gotmx;
+ int qtype;
+ int loopcnt;
+ char *xp;
+ char nbuf[MAX(PACKETSZ, MAXDNAME*2+2)];
+ char *searchlist[MAXDNSRCH+2];
+ extern char *gethostalias();
+
+ if (tTd(8, 2))
+ printf("getcanonname(%s)\n", host);
+
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return (FALSE);
+
+ /*
+ ** Initialize domain search list. If there is at least one
+ ** dot in the name, search the unmodified name first so we
+ ** find "vse.CS" in Czechoslovakia instead of in the local
+ ** domain (e.g., vse.CS.Berkeley.EDU).
+ **
+ ** Older versions of the resolver could create this
+ ** list by tearing apart the host name.
+ */
+
+ loopcnt = 0;
+cnameloop:
+ for (cp = host, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+
+ if (n == 0 && (xp = gethostalias(host)) != NULL)
+ {
+ if (loopcnt++ > MAXCNAMEDEPTH)
+ {
+ syserr("loop in ${HOSTALIASES} file");
+ }
+ else
+ {
+ strncpy(host, xp, hbsize);
+ host[hbsize - 1] = '\0';
+ goto cnameloop;
+ }
+ }
+
+ dp = searchlist;
+ if (n > 0)
+ *dp++ = "";
+ if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
+ {
+ for (domain = _res.dnsrch; *domain != NULL; )
+ *dp++ = *domain++;
+ }
+ else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
+ {
+ *dp++ = _res.defdname;
+ }
+ else if (*cp == '.')
+ {
+ *cp = '\0';
+ }
+ *dp = NULL;
+
+ /*
+ ** Now run through the search list for the name in question.
+ */
+
+ mxmatch = NULL;
+ qtype = T_ANY;
+
+ for (dp = searchlist; *dp != NULL; )
+ {
+ if (qtype == T_ANY)
+ gotmx = FALSE;
+ if (tTd(8, 5))
+ printf("getcanonname: trying %s.%s (%s)\n", host, *dp,
+ qtype == T_ANY ? "ANY" : qtype == T_A ? "A" :
+ qtype == T_MX ? "MX" : "???");
+ ret = res_querydomain(host, *dp, C_IN, qtype,
+ &answer, sizeof(answer));
+ if (ret <= 0)
+ {
+ if (tTd(8, 7))
+ printf("\tNO: errno=%d, h_errno=%d\n",
+ errno, h_errno);
+
+ if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
+ {
+ /* the name server seems to be down */
+ h_errno = TRY_AGAIN;
+ return FALSE;
+ }
+
+ if (h_errno != HOST_NOT_FOUND)
+ {
+ /* might have another type of interest */
+ if (qtype == T_ANY)
+ {
+ qtype = T_A;
+ continue;
+ }
+ else if (qtype == T_A && !gotmx && trymx)
+ {
+ qtype = T_MX;
+ continue;
+ }
+ }
+
+ if (mxmatch != NULL)
+ {
+ /* we matched before -- use that one */
+ break;
+ }
+
+ /* otherwise, try the next name */
+ dp++;
+ qtype = T_ANY;
+ continue;
+ }
+ else if (tTd(8, 7))
+ printf("\tYES\n");
+
+ /*
+ ** This might be a bogus match. Search for A or
+ ** CNAME records. If we don't have a matching
+ ** wild card MX record, we will accept MX as well.
+ */
+
+ hp = (HEADER *) &answer;
+ ap = (u_char *) &answer + HEADERSZ;
+ eom = (u_char *) &answer + ret;
+
+ /* skip question part of response -- we know what we asked */
+ for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
+ {
+ if ((ret = dn_skipname(ap, eom)) < 0)
+ {
+ if (tTd(8, 20))
+ printf("qdcount failure (%d)\n",
+ ntohs(hp->qdcount));
+ return FALSE; /* ???XXX??? */
+ }
+ }
+
+ amatch = FALSE;
+ for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
+ {
+ n = dn_expand((u_char *) &answer, eom, ap,
+ (u_char *) nbuf, sizeof nbuf);
+ if (n < 0)
+ break;
+ ap += n;
+ GETSHORT(type, ap);
+ ap += SHORTSIZE + LONGSIZE;
+ GETSHORT(n, ap);
+ switch (type)
+ {
+ case T_MX:
+ gotmx = TRUE;
+ if (**dp != '\0')
+ {
+ /* got a match -- save that info */
+ if (trymx && mxmatch == NULL)
+ mxmatch = *dp;
+ continue;
+ }
+
+ /* exact MX matches are as good as an A match */
+ /* fall through */
+
+ case T_A:
+ /* good show */
+ amatch = TRUE;
+
+ /* continue in case a CNAME also exists */
+ continue;
+
+ case T_CNAME:
+ if (loopcnt++ > MAXCNAMEDEPTH)
+ {
+ /*XXX should notify postmaster XXX*/
+ message("DNS failure: CNAME loop for %s",
+ host);
+ if (CurEnv->e_message == NULL)
+ {
+ char ebuf[MAXLINE];
+
+ sprintf(ebuf, "Deferred: DNS failure: CNAME loop for %s",
+ host);
+ CurEnv->e_message = newstr(ebuf);
+ }
+ h_errno = NO_RECOVERY;
+ return FALSE;
+ }
+
+ /* value points at name */
+ if ((ret = dn_expand((u_char *)&answer,
+ eom, ap, (u_char *)nbuf, sizeof(nbuf))) < 0)
+ break;
+ (void)strncpy(host, nbuf, hbsize); /* XXX */
+ host[hbsize - 1] = '\0';
+
+ /*
+ ** RFC 1034 section 3.6 specifies that CNAME
+ ** should point at the canonical name -- but
+ ** urges software to try again anyway.
+ */
+
+ goto cnameloop;
+
+ default:
+ /* not a record of interest */
+ continue;
+ }
+ }
+
+ if (amatch)
+ {
+ /* got an A record and no CNAME */
+ mxmatch = *dp;
+ break;
+ }
+
+ /*
+ ** If this was a T_ANY query, we may have the info but
+ ** need an explicit query. Try T_A, then T_MX.
+ */
+
+ if (qtype == T_ANY)
+ qtype = T_A;
+ else if (qtype == T_A && !gotmx && trymx)
+ qtype = T_MX;
+ else
+ {
+ /* really nothing in this domain; try the next */
+ qtype = T_ANY;
+ dp++;
+ }
+ }
+
+ if (mxmatch == NULL)
+ return FALSE;
+
+ /* create matching name and return */
+ (void) sprintf(nbuf, "%.*s%s%.*s", MAXDNAME, host,
+ *mxmatch == '\0' ? "" : ".",
+ MAXDNAME, mxmatch);
+ strncpy(host, nbuf, hbsize);
+ host[hbsize - 1] = '\0';
+ return TRUE;
+}
+
+
+char *
+gethostalias(host)
+ char *host;
+{
+ char *fname;
+ FILE *fp;
+ register char *p;
+ char buf[MAXLINE];
+ static char hbuf[MAXDNAME];
+
+ fname = getenv("HOSTALIASES");
+ if (fname == NULL || (fp = fopen(fname, "r")) == NULL)
+ return NULL;
+ setbuf(fp, NULL);
+ while (fgets(buf, sizeof buf, fp) != NULL)
+ {
+ for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++)
+ continue;
+ if (*p == 0)
+ {
+ /* syntax error */
+ continue;
+ }
+ *p++ = '\0';
+ if (strcasecmp(buf, host) == 0)
+ break;
+ }
+
+ if (feof(fp))
+ {
+ /* no match */
+ fclose(fp);
+ return NULL;
+ }
+
+ /* got a match; extract the equivalent name */
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ p++;
+ host = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ *p = '\0';
+ strncpy(hbuf, host, sizeof hbuf - 1);
+ hbuf[sizeof hbuf - 1] = '\0';
+ return hbuf;
+}
+
+
+#else /* not NAMED_BIND */
+
+#include <netdb.h>
+
+bool
+getcanonname(host, hbsize, trymx)
+ char *host;
+ int hbsize;
+ bool trymx;
+{
+ struct hostent *hp;
+
+ hp = gethostbyname(host);
+ if (hp == NULL)
+ return (FALSE);
+
+ if (strlen(hp->h_name) >= hbsize)
+ return (FALSE);
+
+ (void) strcpy(host, hp->h_name);
+ return (TRUE);
+}
+
+#endif /* not NAMED_BIND */
diff --git a/usr.sbin/sendmail/src/envelope.c b/usr.sbin/sendmail/src/envelope.c
new file mode 100644
index 00000000000..e8bb1e479fe
--- /dev/null
+++ b/usr.sbin/sendmail/src/envelope.c
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)envelope.c 8.34.1.1 (Berkeley) 2/28/95";
+#endif /* not lint */
+
+#include "sendmail.h"
+#include <pwd.h>
+
+/*
+** NEWENVELOPE -- allocate a new envelope
+**
+** Supports inheritance.
+**
+** Parameters:
+** e -- the new envelope to fill in.
+** parent -- the envelope to be the parent of e.
+**
+** Returns:
+** e.
+**
+** Side Effects:
+** none.
+*/
+
+ENVELOPE *
+newenvelope(e, parent)
+ register ENVELOPE *e;
+ register ENVELOPE *parent;
+{
+ extern putheader(), putbody();
+ extern ENVELOPE BlankEnvelope;
+
+ if (e == parent && e->e_parent != NULL)
+ parent = e->e_parent;
+ clearenvelope(e, TRUE);
+ if (e == CurEnv)
+ bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
+ else
+ bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
+ e->e_parent = parent;
+ e->e_ctime = curtime();
+ if (parent != NULL)
+ e->e_msgpriority = parent->e_msgsize;
+ e->e_puthdr = putheader;
+ e->e_putbody = putbody;
+ if (CurEnv->e_xfp != NULL)
+ (void) fflush(CurEnv->e_xfp);
+
+ return (e);
+}
+ /*
+** DROPENVELOPE -- deallocate an envelope.
+**
+** Parameters:
+** e -- the envelope to deallocate.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** housekeeping necessary to dispose of an envelope.
+** Unlocks this queue file.
+*/
+
+void
+dropenvelope(e)
+ register ENVELOPE *e;
+{
+ bool queueit = FALSE;
+ bool saveit = bitset(EF_FATALERRS, e->e_flags);
+ register ADDRESS *q;
+ char *id = e->e_id;
+ char buf[MAXLINE];
+
+ if (tTd(50, 1))
+ {
+ printf("dropenvelope %x: id=", e);
+ xputs(e->e_id);
+ printf(", flags=0x%x\n", e->e_flags);
+ if (tTd(50, 10))
+ {
+ printf("sendq=");
+ printaddr(e->e_sendqueue, TRUE);
+ }
+ }
+
+ /* we must have an id to remove disk files */
+ if (id == NULL)
+ return;
+
+#ifdef LOG
+ if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
+ logsender(e, NULL);
+ if (LogLevel > 84)
+ syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d",
+ id, e->e_flags, getpid());
+#endif /* LOG */
+ e->e_flags &= ~EF_LOGSENDER;
+
+ /* post statistics */
+ poststats(StatFile);
+
+ /*
+ ** Extract state information from dregs of send list.
+ */
+
+ e->e_flags &= ~EF_QUEUERUN;
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QQUEUEUP, q->q_flags))
+ queueit = TRUE;
+ if (!bitset(QDONTSEND, q->q_flags) &&
+ bitset(QBADADDR, q->q_flags))
+ {
+ if (q->q_owner == NULL &&
+ strcmp(e->e_from.q_paddr, "<>") != 0)
+ (void) sendtolist(e->e_from.q_paddr, NULL,
+ &e->e_errorqueue, e);
+ }
+ }
+
+ /*
+ ** See if the message timed out.
+ */
+
+ if (!queueit)
+ /* nothing to do */ ;
+ else if (curtime() > e->e_ctime + TimeOuts.to_q_return)
+ {
+ (void) sprintf(buf, "Cannot send message for %s",
+ pintvl(TimeOuts.to_q_return, FALSE));
+ if (e->e_message != NULL)
+ free(e->e_message);
+ e->e_message = newstr(buf);
+ message(buf);
+ e->e_flags |= EF_CLRQUEUE;
+ saveit = TRUE;
+ fprintf(e->e_xfp, "Message could not be delivered for %s\n",
+ pintvl(TimeOuts.to_q_return, FALSE));
+ fprintf(e->e_xfp, "Message will be deleted from queue\n");
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QQUEUEUP, q->q_flags))
+ q->q_flags |= QBADADDR;
+ }
+ }
+ else if (TimeOuts.to_q_warning > 0 &&
+ curtime() > e->e_ctime + TimeOuts.to_q_warning)
+ {
+ if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
+ e->e_class >= 0 &&
+ strcmp(e->e_from.q_paddr, "<>") != 0)
+ {
+ (void) sprintf(buf,
+ "warning: cannot send message for %s",
+ pintvl(TimeOuts.to_q_warning, FALSE));
+ if (e->e_message != NULL)
+ free(e->e_message);
+ e->e_message = newstr(buf);
+ message(buf);
+ e->e_flags |= EF_WARNING;
+ saveit = TRUE;
+ }
+ fprintf(e->e_xfp,
+ "Warning: message still undelivered after %s\n",
+ pintvl(TimeOuts.to_q_warning, FALSE));
+ fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
+ pintvl(TimeOuts.to_q_return, FALSE));
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QQUEUEUP, q->q_flags))
+ q->q_flags |= QREPORT;
+ }
+ }
+
+ /*
+ ** Send back return receipts as requested.
+ */
+
+ if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
+ && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
+ {
+ auto ADDRESS *rlist = NULL;
+
+ (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e);
+ (void) returntosender("Return receipt", rlist, FALSE, e);
+ e->e_flags &= ~EF_SENDRECEIPT;
+ }
+
+ /*
+ ** Arrange to send error messages if there are fatal errors.
+ */
+
+ if (saveit && e->e_errormode != EM_QUIET)
+ savemail(e);
+
+ /*
+ ** Arrange to send warning messages to postmaster as requested.
+ */
+
+ if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL &&
+ !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0)
+ {
+ auto ADDRESS *rlist = NULL;
+
+ (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, e);
+ (void) returntosender(e->e_message, rlist, FALSE, e);
+ }
+
+ /*
+ ** Instantiate or deinstantiate the queue.
+ */
+
+ if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
+ bitset(EF_CLRQUEUE, e->e_flags))
+ {
+ if (tTd(50, 1))
+ printf("\n===== Dropping [dq]f%s =====\n\n", e->e_id);
+ if (e->e_df != NULL)
+ xunlink(e->e_df);
+ xunlink(queuename(e, 'q'));
+
+#ifdef LOG
+ if (LogLevel > 10)
+ syslog(LOG_INFO, "%s: done", id);
+#endif
+ }
+ else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
+ {
+#ifdef QUEUE
+ queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE);
+#else /* QUEUE */
+ syserr("554 dropenvelope: queueup");
+#endif /* QUEUE */
+ }
+
+ /* now unlock the job */
+ closexscript(e);
+ unlockqueue(e);
+
+ /* make sure that this envelope is marked unused */
+ if (e->e_dfp != NULL)
+ (void) xfclose(e->e_dfp, "dropenvelope", e->e_df);
+ e->e_dfp = NULL;
+ e->e_id = e->e_df = NULL;
+}
+ /*
+** CLEARENVELOPE -- clear an envelope without unlocking
+**
+** This is normally used by a child process to get a clean
+** envelope without disturbing the parent.
+**
+** Parameters:
+** e -- the envelope to clear.
+** fullclear - if set, the current envelope is total
+** garbage and should be ignored; otherwise,
+** release any resources it may indicate.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Closes files associated with the envelope.
+** Marks the envelope as unallocated.
+*/
+
+void
+clearenvelope(e, fullclear)
+ register ENVELOPE *e;
+ bool fullclear;
+{
+ register HDR *bh;
+ register HDR **nhp;
+ extern ENVELOPE BlankEnvelope;
+
+ if (!fullclear)
+ {
+ /* clear out any file information */
+ if (e->e_xfp != NULL)
+ (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
+ if (e->e_dfp != NULL)
+ (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df);
+ e->e_xfp = e->e_dfp = NULL;
+ }
+
+ /* now clear out the data */
+ STRUCTCOPY(BlankEnvelope, *e);
+ if (Verbose)
+ e->e_sendmode = SM_DELIVER;
+ bh = BlankEnvelope.e_header;
+ nhp = &e->e_header;
+ while (bh != NULL)
+ {
+ *nhp = (HDR *) xalloc(sizeof *bh);
+ bcopy((char *) bh, (char *) *nhp, sizeof *bh);
+ bh = bh->h_link;
+ nhp = &(*nhp)->h_link;
+ }
+}
+ /*
+** INITSYS -- initialize instantiation of system
+**
+** In Daemon mode, this is done in the child.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Initializes the system macros, some global variables,
+** etc. In particular, the current time in various
+** forms is set.
+*/
+
+void
+initsys(e)
+ register ENVELOPE *e;
+{
+ char cbuf[5]; /* holds hop count */
+ char pbuf[10]; /* holds pid */
+#ifdef TTYNAME
+ static char ybuf[60]; /* holds tty id */
+ register char *p;
+#endif /* TTYNAME */
+ extern char *ttyname();
+ extern void settime();
+ extern char Version[];
+
+ /*
+ ** Give this envelope a reality.
+ ** I.e., an id, a transcript, and a creation time.
+ */
+
+ openxscript(e);
+ e->e_ctime = curtime();
+
+ /*
+ ** Set OutChannel to something useful if stdout isn't it.
+ ** This arranges that any extra stuff the mailer produces
+ ** gets sent back to the user on error (because it is
+ ** tucked away in the transcript).
+ */
+
+ if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
+ e->e_xfp != NULL)
+ OutChannel = e->e_xfp;
+
+ /*
+ ** Set up some basic system macros.
+ */
+
+ /* process id */
+ (void) sprintf(pbuf, "%d", getpid());
+ define('p', newstr(pbuf), e);
+
+ /* hop count */
+ (void) sprintf(cbuf, "%d", e->e_hopcount);
+ define('c', newstr(cbuf), e);
+
+ /* time as integer, unix time, arpa time */
+ settime(e);
+
+#ifdef TTYNAME
+ /* tty name */
+ if (macvalue('y', e) == NULL)
+ {
+ p = ttyname(2);
+ if (p != NULL)
+ {
+ if (strrchr(p, '/') != NULL)
+ p = strrchr(p, '/') + 1;
+ (void) strcpy(ybuf, p);
+ define('y', ybuf, e);
+ }
+ }
+#endif /* TTYNAME */
+}
+ /*
+** SETTIME -- set the current time.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets the various time macros -- $a, $b, $d, $t.
+*/
+
+void
+settime(e)
+ register ENVELOPE *e;
+{
+ register char *p;
+ auto time_t now;
+ char tbuf[20]; /* holds "current" time */
+ char dbuf[30]; /* holds ctime(tbuf) */
+ register struct tm *tm;
+ extern char *arpadate();
+ extern struct tm *gmtime();
+
+ now = curtime();
+ tm = gmtime(&now);
+ (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
+ tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+ define('t', newstr(tbuf), e);
+ (void) strcpy(dbuf, ctime(&now));
+ p = strchr(dbuf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ define('d', newstr(dbuf), e);
+ p = arpadate(dbuf);
+ p = newstr(p);
+ if (macvalue('a', e) == NULL)
+ define('a', p, e);
+ define('b', p, e);
+}
+ /*
+** OPENXSCRIPT -- Open transcript file
+**
+** Creates a transcript file for possible eventual mailing or
+** sending back.
+**
+** Parameters:
+** e -- the envelope to create the transcript in/for.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Creates the transcript file.
+*/
+
+#ifndef O_APPEND
+#define O_APPEND 0
+#endif
+
+void
+openxscript(e)
+ register ENVELOPE *e;
+{
+ register char *p;
+ int fd;
+
+ if (e->e_xfp != NULL)
+ return;
+ p = queuename(e, 'x');
+ fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (fd < 0)
+ {
+ syserr("Can't create transcript file %s", p);
+ fd = open("/dev/null", O_WRONLY, 0644);
+ if (fd < 0)
+ syserr("!Can't open /dev/null");
+ }
+ e->e_xfp = fdopen(fd, "a");
+ if (e->e_xfp == NULL)
+ {
+ syserr("!Can't create transcript stream %s", p);
+ }
+ if (tTd(46, 9))
+ {
+ printf("openxscript(%s):\n ", p);
+ dumpfd(fileno(e->e_xfp), TRUE, FALSE);
+ }
+}
+ /*
+** CLOSEXSCRIPT -- close the transcript file.
+**
+** Parameters:
+** e -- the envelope containing the transcript to close.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+void
+closexscript(e)
+ register ENVELOPE *e;
+{
+ if (e->e_xfp == NULL)
+ return;
+ (void) xfclose(e->e_xfp, "closexscript", e->e_id);
+ e->e_xfp = NULL;
+}
+ /*
+** SETSENDER -- set the person who this message is from
+**
+** Under certain circumstances allow the user to say who
+** s/he is (using -f or -r). These are:
+** 1. The user's uid is zero (root).
+** 2. The user's login name is in an approved list (typically
+** from a network server).
+** 3. The address the user is trying to claim has a
+** "!" character in it (since #2 doesn't do it for
+** us if we are dialing out for UUCP).
+** A better check to replace #3 would be if the
+** effective uid is "UUCP" -- this would require me
+** to rewrite getpwent to "grab" uucp as it went by,
+** make getname more nasty, do another passwd file
+** scan, or compile the UID of "UUCP" into the code,
+** all of which are reprehensible.
+**
+** Assuming all of these fail, we figure out something
+** ourselves.
+**
+** Parameters:
+** from -- the person we would like to believe this message
+** is from, as specified on the command line.
+** e -- the envelope in which we would like the sender set.
+** delimptr -- if non-NULL, set to the location of the
+** trailing delimiter.
+** internal -- set if this address is coming from an internal
+** source such as an owner alias.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sets sendmail's notion of who the from person is.
+*/
+
+void
+setsender(from, e, delimptr, internal)
+ char *from;
+ register ENVELOPE *e;
+ char **delimptr;
+ bool internal;
+{
+ register char **pvp;
+ char *realname = NULL;
+ register struct passwd *pw;
+ char delimchar;
+ char *bp;
+ char buf[MAXNAME + 2];
+ char pvpbuf[PSBUFSIZE];
+ extern struct passwd *getpwnam();
+ extern char *FullName;
+
+ if (tTd(45, 1))
+ printf("setsender(%s)\n", from == NULL ? "" : from);
+
+ /*
+ ** Figure out the real user executing us.
+ ** Username can return errno != 0 on non-errors.
+ */
+
+ if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
+ OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
+ realname = from;
+ if (realname == NULL || realname[0] == '\0')
+ realname = username();
+
+ if (ConfigLevel < 2)
+ SuprErrs = TRUE;
+
+ delimchar = internal ? '\0' : ' ';
+ e->e_from.q_flags = QBADADDR;
+ if (from == NULL ||
+ parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
+ delimchar, delimptr, e) == NULL ||
+ bitset(QBADADDR, e->e_from.q_flags) ||
+ e->e_from.q_mailer == ProgMailer ||
+ e->e_from.q_mailer == FileMailer ||
+ e->e_from.q_mailer == InclMailer)
+ {
+ /* log garbage addresses for traceback */
+# ifdef LOG
+ if (from != NULL && LogLevel > 2)
+ {
+ char *p;
+ char ebuf[MAXNAME * 2 + 2];
+
+ p = macvalue('_', e);
+ if (p == NULL)
+ {
+ char *host = RealHostName;
+ if (host == NULL)
+ host = MyHostName;
+ (void) sprintf(ebuf, "%s@%s", realname, host);
+ p = ebuf;
+ }
+ syslog(LOG_NOTICE,
+ "setsender: %s: invalid or unparseable, received from %s",
+ shortenstring(from, 83), p);
+ }
+# endif /* LOG */
+ if (from != NULL)
+ {
+ if (!bitset(QBADADDR, e->e_from.q_flags))
+ {
+ /* it was a bogus mailer in the from addr */
+ usrerr("553 Invalid sender address");
+ }
+ SuprErrs = TRUE;
+ }
+ if (from == realname ||
+ parseaddr(from = newstr(realname), &e->e_from,
+ RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
+ {
+ char nbuf[100];
+
+ SuprErrs = TRUE;
+ expand("\201n", nbuf, &nbuf[sizeof nbuf], e);
+ if (parseaddr(from = newstr(nbuf), &e->e_from,
+ RF_COPYALL, ' ', NULL, e) == NULL &&
+ parseaddr(from = "postmaster", &e->e_from,
+ RF_COPYALL, ' ', NULL, e) == NULL)
+ syserr("553 setsender: can't even parse postmaster!");
+ }
+ }
+ else
+ FromFlag = TRUE;
+ e->e_from.q_flags |= QDONTSEND;
+ if (tTd(45, 5))
+ {
+ printf("setsender: QDONTSEND ");
+ printaddr(&e->e_from, FALSE);
+ }
+ SuprErrs = FALSE;
+
+ pvp = NULL;
+ if (e->e_from.q_mailer == LocalMailer)
+ {
+# ifdef USERDB
+ register char *p;
+ extern char *udbsender();
+# endif
+
+ if (!internal)
+ {
+ /* if the user has given fullname already, don't redefine */
+ if (FullName == NULL)
+ FullName = macvalue('x', e);
+ if (FullName != NULL && FullName[0] == '\0')
+ FullName = NULL;
+
+# ifdef USERDB
+ p = udbsender(e->e_from.q_user);
+
+ if (p != NULL)
+ {
+ /*
+ ** We have an alternate address for the sender
+ */
+
+ pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL);
+ }
+# endif /* USERDB */
+ }
+
+ if ((pw = getpwnam(e->e_from.q_user)) != NULL)
+ {
+ /*
+ ** Process passwd file entry.
+ */
+
+ /* extract home directory */
+ if (strcmp(pw->pw_dir, "/") == 0)
+ e->e_from.q_home = newstr("");
+ else
+ e->e_from.q_home = newstr(pw->pw_dir);
+ define('z', e->e_from.q_home, e);
+
+ /* extract user and group id */
+ e->e_from.q_uid = pw->pw_uid;
+ e->e_from.q_gid = pw->pw_gid;
+ e->e_from.q_flags |= QGOODUID;
+
+ /* extract full name from passwd file */
+ if (FullName == NULL && pw->pw_gecos != NULL &&
+ strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
+ !internal)
+ {
+ buildfname(pw->pw_gecos, e->e_from.q_user, buf);
+ if (buf[0] != '\0')
+ FullName = newstr(buf);
+ }
+ }
+ if (FullName != NULL && !internal)
+ define('x', FullName, e);
+ }
+ else if (!internal && OpMode != MD_DAEMON)
+ {
+ if (e->e_from.q_home == NULL)
+ {
+ e->e_from.q_home = getenv("HOME");
+ if (e->e_from.q_home != NULL &&
+ strcmp(e->e_from.q_home, "/") == 0)
+ e->e_from.q_home++;
+ }
+ e->e_from.q_uid = RealUid;
+ e->e_from.q_gid = RealGid;
+ e->e_from.q_flags |= QGOODUID;
+ }
+
+ /*
+ ** Rewrite the from person to dispose of possible implicit
+ ** links in the net.
+ */
+
+ if (pvp == NULL)
+ pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL);
+ if (pvp == NULL)
+ {
+ /* don't need to give error -- prescan did that already */
+# ifdef LOG
+ if (LogLevel > 2)
+ syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
+# endif
+ finis();
+ }
+ (void) rewrite(pvp, 3, 0, e);
+ (void) rewrite(pvp, 1, 0, e);
+ (void) rewrite(pvp, 4, 0, e);
+ bp = buf + 1;
+ cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
+ if (*bp == '@')
+ {
+ /* heuristic: route-addr: add angle brackets */
+ strcat(bp, ">");
+ *--bp = '<';
+ }
+ e->e_sender = newstr(bp);
+ define('f', e->e_sender, e);
+
+ /* save the domain spec if this mailer wants it */
+ if (e->e_from.q_mailer != NULL &&
+ bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
+ {
+ extern char **copyplist();
+
+ while (*pvp != NULL && strcmp(*pvp, "@") != 0)
+ pvp++;
+ if (*pvp != NULL)
+ e->e_fromdomain = copyplist(pvp, TRUE);
+ }
+}
diff --git a/usr.sbin/sendmail/src/err.c b/usr.sbin/sendmail/src/err.c
new file mode 100644
index 00000000000..c6a87e9f30d
--- /dev/null
+++ b/usr.sbin/sendmail/src/err.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)err.c 8.27 (Berkeley) 4/18/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include <errno.h>
+# include <netdb.h>
+# include <pwd.h>
+
+/*
+** SYSERR -- Print error message.
+**
+** Prints an error message via printf to the diagnostic
+** output. If LOG is defined, it logs it also.
+**
+** If the first character of the syserr message is `!' it will
+** log this as an ALERT message and exit immediately. This can
+** leave queue files in an indeterminate state, so it should not
+** be used lightly.
+**
+** Parameters:
+** f -- the format string
+** a, b, c, d, e -- parameters
+**
+** Returns:
+** none
+** Through TopFrame if QuickAbort is set.
+**
+** Side Effects:
+** increments Errors.
+** sets ExitStat.
+*/
+
+char MsgBuf[BUFSIZ*2]; /* text of most recent message */
+
+static void fmtmsg();
+
+#if NAMED_BIND && !defined(NO_DATA)
+# define NO_DATA NO_ADDRESS
+#endif
+
+void
+/*VARARGS1*/
+#ifdef __STDC__
+syserr(const char *fmt, ...)
+#else
+syserr(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ register char *p;
+ int olderrno = errno;
+ bool panic;
+#ifdef LOG
+ char *uname;
+ struct passwd *pw;
+ char ubuf[80];
+#endif
+ VA_LOCAL_DECL
+
+ panic = *fmt == '!';
+ if (panic)
+ fmt++;
+
+ /* format and output the error message */
+ if (olderrno == 0)
+ p = "554";
+ else
+ p = "451";
+ VA_START(fmt);
+ fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
+ VA_END;
+ puterrmsg(MsgBuf);
+
+ /* determine exit status if not already set */
+ if (ExitStat == EX_OK)
+ {
+ if (olderrno == 0)
+ ExitStat = EX_SOFTWARE;
+ else
+ ExitStat = EX_OSERR;
+ if (tTd(54, 1))
+ printf("syserr: ExitStat = %d\n", ExitStat);
+ }
+
+# ifdef LOG
+ pw = getpwuid(getuid());
+ if (pw != NULL)
+ uname = pw->pw_name;
+ else
+ {
+ uname = ubuf;
+ sprintf(ubuf, "UID%d", getuid());
+ }
+
+ if (LogLevel > 0)
+ syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s",
+ CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
+ uname, &MsgBuf[4]);
+# endif /* LOG */
+ if (olderrno == EMFILE)
+ {
+ printopenfds(TRUE);
+ mci_dump_all(TRUE);
+ }
+ if (panic)
+ {
+#ifdef XLA
+ xla_all_end();
+#endif
+ exit(EX_OSERR);
+ }
+ errno = 0;
+ if (QuickAbort)
+ longjmp(TopFrame, 2);
+}
+ /*
+** USRERR -- Signal user error.
+**
+** This is much like syserr except it is for user errors.
+**
+** Parameters:
+** fmt, a, b, c, d -- printf strings
+**
+** Returns:
+** none
+** Through TopFrame if QuickAbort is set.
+**
+** Side Effects:
+** increments Errors.
+*/
+
+/*VARARGS1*/
+void
+#ifdef __STDC__
+usrerr(const char *fmt, ...)
+#else
+usrerr(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ VA_LOCAL_DECL
+
+ if (SuprErrs)
+ return;
+
+ VA_START(fmt);
+ fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
+ VA_END;
+ puterrmsg(MsgBuf);
+
+# ifdef LOG
+ if (LogLevel > 3 && LogUsrErrs)
+ syslog(LOG_NOTICE, "%s: %s",
+ CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
+ &MsgBuf[4]);
+# endif /* LOG */
+
+ if (QuickAbort)
+ longjmp(TopFrame, 1);
+}
+ /*
+** MESSAGE -- print message (not necessarily an error)
+**
+** Parameters:
+** msg -- the message (printf fmt) -- it can begin with
+** an SMTP reply code. If not, 050 is assumed.
+** a, b, c, d, e -- printf arguments
+**
+** Returns:
+** none
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS2*/
+void
+#ifdef __STDC__
+message(const char *msg, ...)
+#else
+message(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif
+{
+ VA_LOCAL_DECL
+
+ errno = 0;
+ VA_START(msg);
+ fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
+ VA_END;
+ putoutmsg(MsgBuf, FALSE);
+}
+ /*
+** NMESSAGE -- print message (not necessarily an error)
+**
+** Just like "message" except it never puts the to... tag on.
+**
+** Parameters:
+** num -- the default ARPANET error number (in ascii)
+** msg -- the message (printf fmt) -- if it begins
+** with three digits, this number overrides num.
+** a, b, c, d, e -- printf arguments
+**
+** Returns:
+** none
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS2*/
+void
+#ifdef __STDC__
+nmessage(const char *msg, ...)
+#else
+nmessage(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif
+{
+ VA_LOCAL_DECL
+
+ errno = 0;
+ VA_START(msg);
+ fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
+ VA_END;
+ putoutmsg(MsgBuf, FALSE);
+}
+ /*
+** PUTOUTMSG -- output error message to transcript and channel
+**
+** Parameters:
+** msg -- message to output (in SMTP format).
+** holdmsg -- if TRUE, don't output a copy of the message to
+** our output channel.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Outputs msg to the transcript.
+** If appropriate, outputs it to the channel.
+** Deletes SMTP reply code number as appropriate.
+*/
+
+putoutmsg(msg, holdmsg)
+ char *msg;
+ bool holdmsg;
+{
+ /* display for debugging */
+ if (tTd(54, 8))
+ printf("--- %s%s\n", msg, holdmsg ? " (held)" : "");
+
+ /* output to transcript if serious */
+ if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL)
+ fprintf(CurEnv->e_xfp, "%s\n", msg);
+
+ /* output to channel if appropriate */
+ if (holdmsg || (!Verbose && msg[0] == '0'))
+ return;
+
+ /* map warnings to something SMTP can handle */
+ if (msg[0] == '6')
+ msg[0] = '5';
+
+ (void) fflush(stdout);
+
+ /* if DisConnected, OutChannel now points to the transcript */
+ if (!DisConnected &&
+ (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
+ fprintf(OutChannel, "%s\r\n", msg);
+ else
+ fprintf(OutChannel, "%s\n", &msg[4]);
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(),
+ (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]);
+ if (msg[3] == ' ')
+ (void) fflush(OutChannel);
+ if (!ferror(OutChannel) || DisConnected)
+ return;
+
+ /*
+ ** Error on output -- if reporting lost channel, just ignore it.
+ ** Also, ignore errors from QUIT response (221 message) -- some
+ ** rude servers don't read result.
+ */
+
+ if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0)
+ return;
+
+ /* can't call syserr, 'cause we are using MsgBuf */
+ HoldErrs = TRUE;
+#ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_CRIT,
+ "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
+ CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
+ CurHostName == NULL ? "NO-HOST" : CurHostName,
+ msg, errstring(errno));
+#endif
+}
+ /*
+** PUTERRMSG -- like putoutmsg, but does special processing for error messages
+**
+** Parameters:
+** msg -- the message to output.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets the fatal error bit in the envelope as appropriate.
+*/
+
+puterrmsg(msg)
+ char *msg;
+{
+ char msgcode = msg[0];
+
+ /* output the message as usual */
+ putoutmsg(msg, HoldErrs);
+
+ /* signal the error */
+ Errors++;
+ if (msgcode == '6')
+ {
+ /* notify the postmaster */
+ CurEnv->e_flags |= EF_PM_NOTIFY;
+ }
+ else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
+ {
+ /* mark long-term fatal errors */
+ CurEnv->e_flags |= EF_FATALERRS;
+ }
+}
+ /*
+** FMTMSG -- format a message into buffer.
+**
+** Parameters:
+** eb -- error buffer to get result.
+** to -- the recipient tag for this message.
+** num -- arpanet error number.
+** en -- the error number to display.
+** fmt -- format of string.
+** a, b, c, d, e -- arguments.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+static void
+fmtmsg(eb, to, num, eno, fmt, ap)
+ register char *eb;
+ char *to;
+ char *num;
+ int eno;
+ char *fmt;
+ va_list ap;
+{
+ char del;
+ char *meb;
+
+ /* output the reply code */
+ if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
+ {
+ num = fmt;
+ fmt += 4;
+ }
+ if (num[3] == '-')
+ del = '-';
+ else
+ del = ' ';
+ (void) sprintf(eb, "%3.3s%c", num, del);
+ eb += 4;
+
+ /* output the file name and line number */
+ if (FileName != NULL)
+ {
+ (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
+ eb += strlen(eb);
+ }
+
+ /* output the "to" person */
+ if (to != NULL && to[0] != '\0')
+ {
+ (void) sprintf(eb, "%s... ", shortenstring(to, 203));
+ while (*eb != '\0')
+ *eb++ &= 0177;
+ }
+
+ meb = eb;
+
+ /* output the message */
+ (void) vsprintf(eb, fmt, ap);
+ while (*eb != '\0')
+ *eb++ &= 0177;
+
+ /* output the error code, if any */
+ if (eno != 0)
+ {
+ (void) sprintf(eb, ": %s", errstring(eno));
+ eb += strlen(eb);
+ }
+
+ if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4'))
+ {
+ if (CurEnv->e_message != NULL)
+ free(CurEnv->e_message);
+ CurEnv->e_message = newstr(meb);
+ }
+}
+ /*
+** ERRSTRING -- return string description of error code
+**
+** Parameters:
+** errnum -- the error number to translate
+**
+** Returns:
+** A string description of errnum.
+**
+** Side Effects:
+** none.
+*/
+
+const char *
+errstring(errnum)
+ int errnum;
+{
+ char *dnsmsg;
+ static char buf[MAXLINE];
+# ifndef ERRLIST_PREDEFINED
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+# endif
+# ifdef SMTP
+ extern char *SmtpPhase;
+# endif /* SMTP */
+
+ /*
+ ** Handle special network error codes.
+ **
+ ** These are 4.2/4.3bsd specific; they should be in daemon.c.
+ */
+
+ dnsmsg = NULL;
+ switch (errnum)
+ {
+# if defined(DAEMON) && defined(ETIMEDOUT)
+ case ETIMEDOUT:
+ case ECONNRESET:
+ (void) strcpy(buf, sys_errlist[errnum]);
+ if (SmtpPhase != NULL)
+ {
+ (void) strcat(buf, " during ");
+ (void) strcat(buf, SmtpPhase);
+ }
+ if (CurHostName != NULL)
+ {
+ (void) strcat(buf, " with ");
+ (void) strcat(buf, CurHostName);
+ }
+ return (buf);
+
+ case EHOSTDOWN:
+ if (CurHostName == NULL)
+ break;
+ (void) sprintf(buf, "Host %s is down", CurHostName);
+ return (buf);
+
+ case ECONNREFUSED:
+ if (CurHostName == NULL)
+ break;
+ (void) sprintf(buf, "Connection refused by %s", CurHostName);
+ return (buf);
+# endif
+
+ case EOPENTIMEOUT:
+ return "Timeout on file open";
+
+# if NAMED_BIND
+ case HOST_NOT_FOUND + E_DNSBASE:
+ dnsmsg = "host not found";
+ break;
+
+ case TRY_AGAIN + E_DNSBASE:
+ dnsmsg = "host name lookup failure";
+ break;
+
+ case NO_RECOVERY + E_DNSBASE:
+ dnsmsg = "non-recoverable error";
+ break;
+
+ case NO_DATA + E_DNSBASE:
+ dnsmsg = "no data known";
+ break;
+# endif
+
+ case EPERM:
+ /* SunOS gives "Not owner" -- this is the POSIX message */
+ return "Operation not permitted";
+ }
+
+ if (dnsmsg != NULL)
+ {
+ (void) strcpy(buf, "Name server: ");
+ if (CurHostName != NULL)
+ {
+ (void) strcat(buf, CurHostName);
+ (void) strcat(buf, ": ");
+ }
+ (void) strcat(buf, dnsmsg);
+ return buf;
+ }
+
+ if (errnum > 0 && errnum < sys_nerr)
+ return (sys_errlist[errnum]);
+
+ (void) sprintf(buf, "Error %d", errnum);
+ return (buf);
+}
diff --git a/usr.sbin/sendmail/src/headers.c b/usr.sbin/sendmail/src/headers.c
new file mode 100644
index 00000000000..8493e79cf7e
--- /dev/null
+++ b/usr.sbin/sendmail/src/headers.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)headers.c 8.32 (Berkeley) 4/14/94";
+#endif /* not lint */
+
+# include <errno.h>
+# include "sendmail.h"
+
+/*
+** CHOMPHEADER -- process and save a header line.
+**
+** Called by collect and by readcf to deal with header lines.
+**
+** Parameters:
+** line -- header as a text line.
+** def -- if set, this is a default value.
+** e -- the envelope including this header.
+**
+** Returns:
+** flags for this header.
+**
+** Side Effects:
+** The header is saved on the header list.
+** Contents of 'line' are destroyed.
+*/
+
+chompheader(line, def, e)
+ char *line;
+ bool def;
+ register ENVELOPE *e;
+{
+ register char *p;
+ register HDR *h;
+ HDR **hp;
+ char *fname;
+ char *fvalue;
+ struct hdrinfo *hi;
+ bool cond = FALSE;
+ BITMAP mopts;
+ char buf[MAXNAME];
+
+ if (tTd(31, 6))
+ printf("chompheader: %s\n", line);
+
+ /* strip off options */
+ clrbitmap(mopts);
+ p = line;
+ if (*p == '?')
+ {
+ /* have some */
+ register char *q = strchr(p + 1, *p);
+
+ if (q != NULL)
+ {
+ *q++ = '\0';
+ while (*++p != '\0')
+ setbitn(*p, mopts);
+ p = q;
+ }
+ else
+ usrerr("553 header syntax error, line \"%s\"", line);
+ cond = TRUE;
+ }
+
+ /* find canonical name */
+ fname = p;
+ while (isascii(*p) && isgraph(*p) && *p != ':')
+ p++;
+ fvalue = p;
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p++ != ':' || fname == fvalue)
+ {
+ syserr("553 header syntax error, line \"%s\"", line);
+ return (0);
+ }
+ *fvalue = '\0';
+ fvalue = p;
+
+ /* strip field value on front */
+ if (*fvalue == ' ')
+ fvalue++;
+
+ /* see if it is a known type */
+ for (hi = HdrInfo; hi->hi_field != NULL; hi++)
+ {
+ if (strcasecmp(hi->hi_field, fname) == 0)
+ break;
+ }
+
+ if (tTd(31, 9))
+ {
+ if (hi->hi_field == NULL)
+ printf("no header match\n");
+ else
+ printf("header match, hi_flags=%o\n", hi->hi_flags);
+ }
+
+ /* see if this is a resent message */
+ if (!def && bitset(H_RESENT, hi->hi_flags))
+ e->e_flags |= EF_RESENT;
+
+ /* if this means "end of header" quit now */
+ if (bitset(H_EOH, hi->hi_flags))
+ return (hi->hi_flags);
+
+ /*
+ ** Drop explicit From: if same as what we would generate.
+ ** This is to make MH (which doesn't always give a full name)
+ ** insert the full name information in all circumstances.
+ */
+
+ p = "resent-from";
+ if (!bitset(EF_RESENT, e->e_flags))
+ p += 7;
+ if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
+ {
+ if (tTd(31, 2))
+ {
+ printf("comparing header from (%s) against default (%s or %s)\n",
+ fvalue, e->e_from.q_paddr, e->e_from.q_user);
+ }
+ if (e->e_from.q_paddr != NULL &&
+ (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
+ strcmp(fvalue, e->e_from.q_user) == 0))
+ return (hi->hi_flags);
+#ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */
+#ifdef USERDB
+ else
+ {
+ auto ADDRESS a;
+ char *fancy;
+ bool oldSuprErrs = SuprErrs;
+ extern char *crackaddr();
+ extern char *udbsender();
+
+ /*
+ ** Try doing USERDB rewriting even on fully commented
+ ** names; this saves the "comment" information (such
+ ** as full name) and rewrites the electronic part.
+ **
+ ** XXX This code doesn't belong here -- parsing should
+ ** XXX not be done during collect() phase because
+ ** XXX error messages can confuse the SMTP phase.
+ ** XXX Setting SuprErrs is a crude hack around this
+ ** XXX problem.
+ */
+
+ if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
+ SuprErrs = TRUE;
+ fancy = crackaddr(fvalue);
+ if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL &&
+ a.q_mailer == LocalMailer &&
+ (p = udbsender(a.q_user)) != NULL)
+ {
+ char *oldg = macvalue('g', e);
+
+ define('g', p, e);
+ expand(fancy, buf, &buf[sizeof buf], e);
+ define('g', oldg, e);
+ fvalue = buf;
+ }
+ SuprErrs = oldSuprErrs;
+ }
+#endif
+#endif
+ }
+
+ /* delete default value for this header */
+ for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
+ {
+ if (strcasecmp(fname, h->h_field) == 0 &&
+ bitset(H_DEFAULT, h->h_flags) &&
+ !bitset(H_FORCE, h->h_flags))
+ h->h_value = NULL;
+ }
+
+ /* create a new node */
+ h = (HDR *) xalloc(sizeof *h);
+ h->h_field = newstr(fname);
+ h->h_value = newstr(fvalue);
+ h->h_link = NULL;
+ bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
+ *hp = h;
+ h->h_flags = hi->hi_flags;
+ if (def)
+ h->h_flags |= H_DEFAULT;
+ if (cond)
+ h->h_flags |= H_CHECK;
+
+ /* hack to see if this is a new format message */
+ if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
+ (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
+ strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
+ {
+ e->e_flags &= ~EF_OLDSTYLE;
+ }
+
+ return (h->h_flags);
+}
+ /*
+** ADDHEADER -- add a header entry to the end of the queue.
+**
+** This bypasses the special checking of chompheader.
+**
+** Parameters:
+** field -- the name of the header field.
+** value -- the value of the field.
+** e -- the envelope to add them to.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** adds the field on the list of headers for this envelope.
+*/
+
+addheader(field, value, e)
+ char *field;
+ char *value;
+ ENVELOPE *e;
+{
+ register HDR *h;
+ register struct hdrinfo *hi;
+ HDR **hp;
+
+ /* find info struct */
+ for (hi = HdrInfo; hi->hi_field != NULL; hi++)
+ {
+ if (strcasecmp(field, hi->hi_field) == 0)
+ break;
+ }
+
+ /* find current place in list -- keep back pointer? */
+ for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
+ {
+ if (strcasecmp(field, h->h_field) == 0)
+ break;
+ }
+
+ /* allocate space for new header */
+ h = (HDR *) xalloc(sizeof *h);
+ h->h_field = field;
+ h->h_value = newstr(value);
+ h->h_link = *hp;
+ h->h_flags = hi->hi_flags | H_DEFAULT;
+ clrbitmap(h->h_mflags);
+ *hp = h;
+}
+ /*
+** HVALUE -- return value of a header.
+**
+** Only "real" fields (i.e., ones that have not been supplied
+** as a default) are used.
+**
+** Parameters:
+** field -- the field name.
+** e -- the envelope containing the header.
+**
+** Returns:
+** pointer to the value part.
+** NULL if not found.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+hvalue(field, e)
+ char *field;
+ register ENVELOPE *e;
+{
+ register HDR *h;
+
+ for (h = e->e_header; h != NULL; h = h->h_link)
+ {
+ if (!bitset(H_DEFAULT, h->h_flags) &&
+ strcasecmp(h->h_field, field) == 0)
+ return (h->h_value);
+ }
+ return (NULL);
+}
+ /*
+** ISHEADER -- predicate telling if argument is a header.
+**
+** A line is a header if it has a single word followed by
+** optional white space followed by a colon.
+**
+** Parameters:
+** s -- string to check for possible headerness.
+**
+** Returns:
+** TRUE if s is a header.
+** FALSE otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+isheader(s)
+ register char *s;
+{
+ while (*s > ' ' && *s != ':' && *s != '\0')
+ s++;
+
+ /* following technically violates RFC822 */
+ while (isascii(*s) && isspace(*s))
+ s++;
+
+ return (*s == ':');
+}
+ /*
+** EATHEADER -- run through the stored header and extract info.
+**
+** Parameters:
+** e -- the envelope to process.
+** full -- if set, do full processing (e.g., compute
+** message priority).
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets a bunch of global variables from information
+** in the collected header.
+** Aborts the message if the hop count is exceeded.
+*/
+
+eatheader(e, full)
+ register ENVELOPE *e;
+ bool full;
+{
+ register HDR *h;
+ register char *p;
+ int hopcnt = 0;
+ char *msgid;
+ char buf[MAXLINE];
+
+ /*
+ ** Set up macros for possible expansion in headers.
+ */
+
+ define('f', e->e_sender, e);
+ define('g', e->e_sender, e);
+ if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
+ define('u', e->e_origrcpt, e);
+ else
+ define('u', NULL, e);
+
+ /* full name of from person */
+ p = hvalue("full-name", e);
+ if (p != NULL)
+ define('x', p, e);
+
+ if (tTd(32, 1))
+ printf("----- collected header -----\n");
+ msgid = "<none>";
+ for (h = e->e_header; h != NULL; h = h->h_link)
+ {
+ if (h->h_value == NULL)
+ {
+ if (tTd(32, 1))
+ printf("%s: <NULL>\n", h->h_field);
+ continue;
+ }
+
+ /* do early binding */
+ if (bitset(H_DEFAULT, h->h_flags))
+ {
+ expand(h->h_value, buf, &buf[sizeof buf], e);
+ if (buf[0] != '\0')
+ {
+ h->h_value = newstr(buf);
+ h->h_flags &= ~H_DEFAULT;
+ }
+ }
+
+ if (tTd(32, 1))
+ {
+ printf("%s: ", h->h_field);
+ xputs(h->h_value);
+ printf("\n");
+ }
+
+ /* count the number of times it has been processed */
+ if (bitset(H_TRACE, h->h_flags))
+ hopcnt++;
+
+ /* send to this person if we so desire */
+ if (GrabTo && bitset(H_RCPT, h->h_flags) &&
+ !bitset(H_DEFAULT, h->h_flags) &&
+ (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
+ {
+ int saveflags = e->e_flags;
+
+ (void) sendtolist(h->h_value, NULLADDR,
+ &e->e_sendqueue, e);
+
+ /* delete fatal errors generated by this address */
+ if (!GrabTo && !bitset(EF_FATALERRS, saveflags))
+ e->e_flags &= ~EF_FATALERRS;
+ }
+
+ /* save the message-id for logging */
+ if (full && strcasecmp(h->h_field, "message-id") == 0)
+ {
+ msgid = h->h_value;
+ while (isascii(*msgid) && isspace(*msgid))
+ msgid++;
+ }
+
+ /* see if this is a return-receipt header */
+ if (bitset(H_RECEIPTTO, h->h_flags))
+ e->e_receiptto = h->h_value;
+
+ /* see if this is an errors-to header */
+ if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags))
+ (void) sendtolist(h->h_value, NULLADDR,
+ &e->e_errorqueue, e);
+ }
+ if (tTd(32, 1))
+ printf("----------------------------\n");
+
+ /* if we are just verifying (that is, sendmail -t -bv), drop out now */
+ if (OpMode == MD_VERIFY)
+ return;
+
+ /* store hop count */
+ if (hopcnt > e->e_hopcount)
+ e->e_hopcount = hopcnt;
+
+ /* message priority */
+ p = hvalue("precedence", e);
+ if (p != NULL)
+ e->e_class = priencode(p);
+ if (full)
+ e->e_msgpriority = e->e_msgsize
+ - e->e_class * WkClassFact
+ + e->e_nrcpts * WkRecipFact;
+
+ /* date message originated */
+ p = hvalue("posted-date", e);
+ if (p == NULL)
+ p = hvalue("date", e);
+ if (p != NULL)
+ define('a', p, e);
+
+ /*
+ ** From person in antiquated ARPANET mode
+ ** required by UK Grey Book e-mail gateways (sigh)
+ */
+
+ if (OpMode == MD_ARPAFTP)
+ {
+ register struct hdrinfo *hi;
+
+ for (hi = HdrInfo; hi->hi_field != NULL; hi++)
+ {
+ if (bitset(H_FROM, hi->hi_flags) &&
+ (!bitset(H_RESENT, hi->hi_flags) ||
+ bitset(EF_RESENT, e->e_flags)) &&
+ (p = hvalue(hi->hi_field, e)) != NULL)
+ break;
+ }
+ if (hi->hi_field != NULL)
+ {
+ if (tTd(32, 2))
+ printf("eatheader: setsender(*%s == %s)\n",
+ hi->hi_field, p);
+ setsender(p, e, NULL, TRUE);
+ }
+ }
+
+ /*
+ ** Log collection information.
+ */
+
+# ifdef LOG
+ if (full && LogLevel > 4)
+ logsender(e, msgid);
+# endif /* LOG */
+ e->e_flags &= ~EF_LOGSENDER;
+}
+ /*
+** LOGSENDER -- log sender information
+**
+** Parameters:
+** e -- the envelope to log
+** msgid -- the message id
+**
+** Returns:
+** none
+*/
+
+logsender(e, msgid)
+ register ENVELOPE *e;
+ char *msgid;
+{
+# ifdef LOG
+ char *name;
+ register char *sbp;
+ register char *p;
+ char hbuf[MAXNAME];
+ char sbuf[MAXLINE];
+
+ if (bitset(EF_RESPONSE, e->e_flags))
+ name = "[RESPONSE]";
+ else if ((name = macvalue('_', e)) != NULL)
+ ;
+ else if (RealHostName == NULL)
+ name = "localhost";
+ else if (RealHostName[0] == '[')
+ name = RealHostName;
+ else
+ {
+ name = hbuf;
+ (void) sprintf(hbuf, "%.80s", RealHostName);
+ if (RealHostAddr.sa.sa_family != 0)
+ {
+ p = &hbuf[strlen(hbuf)];
+ (void) sprintf(p, " (%s)",
+ anynet_ntoa(&RealHostAddr));
+ }
+ }
+
+ /* some versions of syslog only take 5 printf args */
+# if (SYSLOG_BUFSIZE) >= 256
+ sbp = sbuf;
+ sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d",
+ e->e_from.q_paddr, e->e_msgsize, e->e_class,
+ e->e_msgpriority, e->e_nrcpts);
+ sbp += strlen(sbp);
+ if (msgid != NULL)
+ {
+ sprintf(sbp, ", msgid=%.100s", msgid);
+ sbp += strlen(sbp);
+ }
+ if (e->e_bodytype != NULL)
+ {
+ (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype);
+ sbp += strlen(sbp);
+ }
+ p = macvalue('r', e);
+ if (p != NULL)
+ (void) sprintf(sbp, ", proto=%.20s", p);
+ syslog(LOG_INFO, "%s: %s, relay=%s",
+ e->e_id, sbuf, name);
+
+# else /* short syslog buffer */
+
+ syslog(LOG_INFO, "%s: from=%s",
+ e->e_id, shortenstring(e->e_from.q_paddr, 83));
+ syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d",
+ e->e_id, e->e_msgsize, e->e_class,
+ e->e_msgpriority, e->e_nrcpts);
+ if (msgid != NULL)
+ syslog(LOG_INFO, "%s: msgid=%s", e->e_id, msgid);
+ sbp = sbuf;
+ sprintf(sbp, "%s:", e->e_id);
+ sbp += strlen(sbp);
+ if (e->e_bodytype != NULL)
+ {
+ sprintf(sbp, " bodytype=%s,", e->e_bodytype);
+ sbp += strlen(sbp);
+ }
+ p = macvalue('r', e);
+ if (p != NULL)
+ {
+ sprintf(sbp, " proto=%s,", p);
+ sbp += strlen(sbp);
+ }
+ syslog(LOG_INFO, "%s relay=%s", sbuf, name);
+# endif
+# endif
+}
+ /*
+** PRIENCODE -- encode external priority names into internal values.
+**
+** Parameters:
+** p -- priority in ascii.
+**
+** Returns:
+** priority as a numeric level.
+**
+** Side Effects:
+** none.
+*/
+
+priencode(p)
+ char *p;
+{
+ register int i;
+
+ for (i = 0; i < NumPriorities; i++)
+ {
+ if (!strcasecmp(p, Priorities[i].pri_name))
+ return (Priorities[i].pri_val);
+ }
+
+ /* unknown priority */
+ return (0);
+}
+ /*
+** CRACKADDR -- parse an address and turn it into a macro
+**
+** This doesn't actually parse the address -- it just extracts
+** it and replaces it with "$g". The parse is totally ad hoc
+** and isn't even guaranteed to leave something syntactically
+** identical to what it started with. However, it does leave
+** something semantically identical.
+**
+** This algorithm has been cleaned up to handle a wider range
+** of cases -- notably quoted and backslash escaped strings.
+** This modification makes it substantially better at preserving
+** the original syntax.
+**
+** Parameters:
+** addr -- the address to be cracked.
+**
+** Returns:
+** a pointer to the new version.
+**
+** Side Effects:
+** none.
+**
+** Warning:
+** The return value is saved in local storage and should
+** be copied if it is to be reused.
+*/
+
+char *
+crackaddr(addr)
+ register char *addr;
+{
+ register char *p;
+ register char c;
+ int cmtlev;
+ int realcmtlev;
+ int anglelev, realanglelev;
+ int copylev;
+ bool qmode;
+ bool realqmode;
+ bool skipping;
+ bool putgmac = FALSE;
+ bool quoteit = FALSE;
+ bool gotangle = FALSE;
+ register char *bp;
+ char *buflim;
+ static char buf[MAXNAME];
+
+ if (tTd(33, 1))
+ printf("crackaddr(%s)\n", addr);
+
+ /* strip leading spaces */
+ while (*addr != '\0' && isascii(*addr) && isspace(*addr))
+ addr++;
+
+ /*
+ ** Start by assuming we have no angle brackets. This will be
+ ** adjusted later if we find them.
+ */
+
+ bp = buf;
+ buflim = &buf[sizeof buf - 5];
+ p = addr;
+ copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
+ qmode = realqmode = FALSE;
+
+ while ((c = *p++) != '\0')
+ {
+ /*
+ ** If the buffer is overful, go into a special "skipping"
+ ** mode that tries to keep legal syntax but doesn't actually
+ ** output things.
+ */
+
+ skipping = bp >= buflim;
+
+ if (copylev > 0 && !skipping)
+ *bp++ = c;
+
+ /* check for backslash escapes */
+ if (c == '\\')
+ {
+ /* arrange to quote the address */
+ if (cmtlev <= 0 && !qmode)
+ quoteit = TRUE;
+
+ if ((c = *p++) == '\0')
+ {
+ /* too far */
+ p--;
+ goto putg;
+ }
+ if (copylev > 0 && !skipping)
+ *bp++ = c;
+ goto putg;
+ }
+
+ /* check for quoted strings */
+ if (c == '"' && cmtlev <= 0)
+ {
+ qmode = !qmode;
+ if (copylev > 0 && !skipping)
+ realqmode = !realqmode;
+ continue;
+ }
+ if (qmode)
+ goto putg;
+
+ /* check for comments */
+ if (c == '(')
+ {
+ cmtlev++;
+
+ /* allow space for closing paren */
+ if (!skipping)
+ {
+ buflim--;
+ realcmtlev++;
+ if (copylev++ <= 0)
+ {
+ *bp++ = ' ';
+ *bp++ = c;
+ }
+ }
+ }
+ if (cmtlev > 0)
+ {
+ if (c == ')')
+ {
+ cmtlev--;
+ copylev--;
+ if (!skipping)
+ {
+ realcmtlev--;
+ buflim++;
+ }
+ }
+ continue;
+ }
+ else if (c == ')')
+ {
+ /* syntax error: unmatched ) */
+ if (copylev > 0 && !skipping)
+ bp--;
+ }
+
+ /* check for characters that may have to be quoted */
+ if (strchr(".'@,;:\\()[]", c) != NULL)
+ {
+ /*
+ ** If these occur as the phrase part of a <>
+ ** construct, but are not inside of () or already
+ ** quoted, they will have to be quoted. Note that
+ ** now (but don't actually do the quoting).
+ */
+
+ if (cmtlev <= 0 && !qmode)
+ quoteit = TRUE;
+ }
+
+ /* check for angle brackets */
+ if (c == '<')
+ {
+ register char *q;
+
+ /* assume first of two angles is bogus */
+ if (gotangle)
+ quoteit = TRUE;
+ gotangle = TRUE;
+
+ /* oops -- have to change our mind */
+ anglelev = 1;
+ if (!skipping)
+ realanglelev = 1;
+
+ bp = buf;
+ if (quoteit)
+ {
+ *bp++ = '"';
+
+ /* back up over the '<' and any spaces */
+ --p;
+ while (isascii(*--p) && isspace(*p))
+ continue;
+ p++;
+ }
+ for (q = addr; q < p; )
+ {
+ c = *q++;
+ if (bp < buflim)
+ {
+ if (quoteit && c == '"')
+ *bp++ = '\\';
+ *bp++ = c;
+ }
+ }
+ if (quoteit)
+ {
+ if (bp == &buf[1])
+ bp--;
+ else
+ *bp++ = '"';
+ while ((c = *p++) != '<')
+ {
+ if (bp < buflim)
+ *bp++ = c;
+ }
+ *bp++ = c;
+ }
+ copylev = 0;
+ putgmac = quoteit = FALSE;
+ continue;
+ }
+
+ if (c == '>')
+ {
+ if (anglelev > 0)
+ {
+ anglelev--;
+ if (!skipping)
+ {
+ realanglelev--;
+ buflim++;
+ }
+ }
+ else if (!skipping)
+ {
+ /* syntax error: unmatched > */
+ if (copylev > 0)
+ bp--;
+ quoteit = TRUE;
+ continue;
+ }
+ if (copylev++ <= 0)
+ *bp++ = c;
+ continue;
+ }
+
+ /* must be a real address character */
+ putg:
+ if (copylev <= 0 && !putgmac)
+ {
+ *bp++ = MACROEXPAND;
+ *bp++ = 'g';
+ putgmac = TRUE;
+ }
+ }
+
+ /* repair any syntactic damage */
+ if (realqmode)
+ *bp++ = '"';
+ while (realcmtlev-- > 0)
+ *bp++ = ')';
+ while (realanglelev-- > 0)
+ *bp++ = '>';
+ *bp++ = '\0';
+
+ if (tTd(33, 1))
+ printf("crackaddr=>`%s'\n", buf);
+
+ return (buf);
+}
+ /*
+** PUTHEADER -- put the header part of a message from the in-core copy
+**
+** Parameters:
+** mci -- the connection information.
+** e -- envelope to use.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+/*
+ * Macro for fast max (not available in e.g. DG/UX, 386/ix).
+ */
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+putheader(mci, e)
+ register MCI *mci;
+ register ENVELOPE *e;
+{
+ char buf[MAX(MAXLINE,BUFSIZ)];
+ register HDR *h;
+ char obuf[MAXLINE];
+
+ if (tTd(34, 1))
+ printf("--- putheader, mailer = %s ---\n",
+ mci->mci_mailer->m_name);
+
+ for (h = e->e_header; h != NULL; h = h->h_link)
+ {
+ register char *p;
+ extern bool bitintersect();
+
+ if (tTd(34, 11))
+ {
+ printf(" %s: ", h->h_field);
+ xputs(h->h_value);
+ }
+
+ if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
+ !bitintersect(h->h_mflags, mci->mci_mailer->m_flags))
+ {
+ if (tTd(34, 11))
+ printf(" (skipped)\n");
+ continue;
+ }
+
+ /* handle Resent-... headers specially */
+ if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
+ {
+ if (tTd(34, 11))
+ printf(" (skipped (resent))\n");
+ continue;
+ }
+
+ /* suppress return receipts if requested */
+ if (bitset(H_RECEIPTTO, h->h_flags) &&
+ bitset(EF_NORECEIPT, e->e_flags))
+ {
+ if (tTd(34, 11))
+ printf(" (skipped (receipt))\n");
+ continue;
+ }
+
+ /* macro expand value if generated internally */
+ p = h->h_value;
+ if (bitset(H_DEFAULT, h->h_flags))
+ {
+ expand(p, buf, &buf[sizeof buf], e);
+ p = buf;
+ if (p == NULL || *p == '\0')
+ {
+ if (tTd(34, 11))
+ printf(" (skipped -- null value)\n");
+ continue;
+ }
+ }
+
+ if (tTd(34, 11))
+ printf("\n");
+
+ if (bitset(H_FROM|H_RCPT, h->h_flags))
+ {
+ /* address field */
+ bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
+
+ if (bitset(H_FROM, h->h_flags))
+ oldstyle = FALSE;
+ commaize(h, p, oldstyle, mci, e);
+ }
+ else
+ {
+ /* vanilla header line */
+ register char *nlp;
+
+ (void) sprintf(obuf, "%s: ", h->h_field);
+ while ((nlp = strchr(p, '\n')) != NULL)
+ {
+ *nlp = '\0';
+ (void) strcat(obuf, p);
+ *nlp = '\n';
+ putline(obuf, mci);
+ p = ++nlp;
+ obuf[0] = '\0';
+ }
+ (void) strcat(obuf, p);
+ putline(obuf, mci);
+ }
+ }
+}
+ /*
+** COMMAIZE -- output a header field, making a comma-translated list.
+**
+** Parameters:
+** h -- the header field to output.
+** p -- the value to put in it.
+** oldstyle -- TRUE if this is an old style header.
+** mci -- the connection information.
+** e -- the envelope containing the message.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** outputs "p" to file "fp".
+*/
+
+void
+commaize(h, p, oldstyle, mci, e)
+ register HDR *h;
+ register char *p;
+ bool oldstyle;
+ register MCI *mci;
+ register ENVELOPE *e;
+{
+ register char *obp;
+ int opos;
+ int omax;
+ bool firstone = TRUE;
+ char obuf[MAXLINE + 3];
+
+ /*
+ ** Output the address list translated by the
+ ** mailer and with commas.
+ */
+
+ if (tTd(14, 2))
+ printf("commaize(%s: %s)\n", h->h_field, p);
+
+ obp = obuf;
+ (void) sprintf(obp, "%s: ", h->h_field);
+ opos = strlen(h->h_field) + 2;
+ obp += opos;
+ omax = mci->mci_mailer->m_linelimit - 2;
+ if (omax < 0 || omax > 78)
+ omax = 78;
+
+ /*
+ ** Run through the list of values.
+ */
+
+ while (*p != '\0')
+ {
+ register char *name;
+ register int c;
+ char savechar;
+ int flags;
+ auto int stat;
+
+ /*
+ ** Find the end of the name. New style names
+ ** end with a comma, old style names end with
+ ** a space character. However, spaces do not
+ ** necessarily delimit an old-style name -- at
+ ** signs mean keep going.
+ */
+
+ /* find end of name */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ name = p;
+ for (;;)
+ {
+ auto char *oldp;
+ char pvpbuf[PSBUFSIZE];
+
+ (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
+ sizeof pvpbuf, &oldp);
+ p = oldp;
+
+ /* look to see if we have an at sign */
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ p++;
+
+ if (*p != '@')
+ {
+ p = oldp;
+ break;
+ }
+ p += *p == '@' ? 1 : 2;
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ p++;
+ }
+ /* at the end of one complete name */
+
+ /* strip off trailing white space */
+ while (p >= name &&
+ ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
+ p--;
+ if (++p == name)
+ continue;
+ savechar = *p;
+ *p = '\0';
+
+ /* translate the name to be relative */
+ flags = RF_HEADERADDR|RF_ADDDOMAIN;
+ if (bitset(H_FROM, h->h_flags))
+ flags |= RF_SENDERADDR;
+ stat = EX_OK;
+ name = remotename(name, mci->mci_mailer, flags, &stat, e);
+ if (*name == '\0')
+ {
+ *p = savechar;
+ continue;
+ }
+
+ /* output the name with nice formatting */
+ opos += strlen(name);
+ if (!firstone)
+ opos += 2;
+ if (opos > omax && !firstone)
+ {
+ (void) strcpy(obp, ",\n");
+ putline(obuf, mci);
+ obp = obuf;
+ (void) strcpy(obp, " ");
+ opos = strlen(obp);
+ obp += opos;
+ opos += strlen(name);
+ }
+ else if (!firstone)
+ {
+ (void) strcpy(obp, ", ");
+ obp += 2;
+ }
+
+ while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
+ *obp++ = c;
+ firstone = FALSE;
+ *p = savechar;
+ }
+ (void) strcpy(obp, "\n");
+ putline(obuf, mci);
+}
+ /*
+** COPYHEADER -- copy header list
+**
+** This routine is the equivalent of newstr for header lists
+**
+** Parameters:
+** header -- list of header structures to copy.
+**
+** Returns:
+** a copy of 'header'.
+**
+** Side Effects:
+** none.
+*/
+
+HDR *
+copyheader(header)
+ register HDR *header;
+{
+ register HDR *newhdr;
+ HDR *ret;
+ register HDR **tail = &ret;
+
+ while (header != NULL)
+ {
+ newhdr = (HDR *) xalloc(sizeof(HDR));
+ STRUCTCOPY(*header, *newhdr);
+ *tail = newhdr;
+ tail = &newhdr->h_link;
+ header = header->h_link;
+ }
+ *tail = NULL;
+
+ return ret;
+}
diff --git a/usr.sbin/sendmail/src/macro.c b/usr.sbin/sendmail/src/macro.c
new file mode 100644
index 00000000000..8a8a90b4f0f
--- /dev/null
+++ b/usr.sbin/sendmail/src/macro.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)macro.c 8.3 (Berkeley) 2/7/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** EXPAND -- macro expand a string using $x escapes.
+**
+** Parameters:
+** s -- the string to expand.
+** buf -- the place to put the expansion.
+** buflim -- the buffer limit, i.e., the address
+** of the last usable position in buf.
+** e -- envelope in which to work.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+void
+expand(s, buf, buflim, e)
+ register char *s;
+ register char *buf;
+ char *buflim;
+ register ENVELOPE *e;
+{
+ register char *xp;
+ register char *q;
+ bool skipping; /* set if conditionally skipping output */
+ bool recurse = FALSE; /* set if recursion required */
+ int i;
+ int iflev; /* if nesting level */
+ char xbuf[BUFSIZ];
+
+ if (tTd(35, 24))
+ {
+ printf("expand(");
+ xputs(s);
+ printf(")\n");
+ }
+
+ skipping = FALSE;
+ iflev = 0;
+ if (s == NULL)
+ s = "";
+ for (xp = xbuf; *s != '\0'; s++)
+ {
+ int c;
+
+ /*
+ ** Check for non-ordinary (special?) character.
+ ** 'q' will be the interpolated quantity.
+ */
+
+ q = NULL;
+ c = *s;
+ switch (c & 0377)
+ {
+ case CONDIF: /* see if var set */
+ c = *++s;
+ if (skipping)
+ iflev++;
+ else
+ skipping = macvalue(c, e) == NULL;
+ continue;
+
+ case CONDELSE: /* change state of skipping */
+ if (iflev == 0)
+ skipping = !skipping;
+ continue;
+
+ case CONDFI: /* stop skipping */
+ if (iflev == 0)
+ skipping = FALSE;
+ if (skipping)
+ iflev--;
+ continue;
+
+ case MACROEXPAND: /* macro interpolation */
+ c = *++s & 0177;
+ if (c != '\0')
+ q = macvalue(c, e);
+ else
+ {
+ s--;
+ q = NULL;
+ }
+ if (q == NULL)
+ continue;
+ break;
+ }
+
+ /*
+ ** Interpolate q or output one character
+ */
+
+ if (skipping || xp >= &xbuf[sizeof xbuf])
+ continue;
+ if (q == NULL)
+ *xp++ = c;
+ else
+ {
+ /* copy to end of q or max space remaining in buf */
+ while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
+ {
+ /* check for any sendmail metacharacters */
+ if ((c & 0340) == 0200)
+ recurse = TRUE;
+ *xp++ = c;
+ }
+ }
+ }
+ *xp = '\0';
+
+ if (tTd(35, 24))
+ {
+ printf("expand ==> ");
+ xputs(xbuf);
+ printf("\n");
+ }
+
+ /* recurse as appropriate */
+ if (recurse)
+ {
+ expand(xbuf, buf, buflim, e);
+ return;
+ }
+
+ /* copy results out */
+ i = buflim - buf - 1;
+ if (i > xp - xbuf)
+ i = xp - xbuf;
+ bcopy(xbuf, buf, i);
+ buf[i] = '\0';
+}
+ /*
+** DEFINE -- define a macro.
+**
+** this would be better done using a #define macro.
+**
+** Parameters:
+** n -- the macro name.
+** v -- the macro value.
+** e -- the envelope to store the definition in.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** e->e_macro[n] is defined.
+**
+** Notes:
+** There is one macro for each ASCII character,
+** although they are not all used. The currently
+** defined macros are:
+**
+** $a date in ARPANET format (preferring the Date: line
+** of the message)
+** $b the current date (as opposed to the date as found
+** the message) in ARPANET format
+** $c hop count
+** $d (current) date in UNIX (ctime) format
+** $e the SMTP entry message+
+** $f raw from address
+** $g translated from address
+** $h to host
+** $i queue id
+** $j official SMTP hostname, used in messages+
+** $k UUCP node name
+** $l UNIX-style from line+
+** $m The domain part of our full name.
+** $n name of sendmail ("MAILER-DAEMON" on local
+** net typically)+
+** $o delimiters ("operators") for address tokens+
+** $p my process id in decimal
+** $q the string that becomes an address -- this is
+** normally used to combine $g & $x.
+** $r protocol used to talk to sender
+** $s sender's host name
+** $t the current time in seconds since 1/1/1970
+** $u to user
+** $v version number of sendmail
+** $w our host name (if it can be determined)
+** $x signature (full name) of from person
+** $y the tty id of our terminal
+** $z home directory of to person
+** $_ RFC1413 authenticated sender address
+**
+** Macros marked with + must be defined in the
+** configuration file and are used internally, but
+** are not set.
+**
+** There are also some macros that can be used
+** arbitrarily to make the configuration file
+** cleaner. In general all upper-case letters
+** are available.
+*/
+
+void
+define(n, v, e)
+ int n;
+ char *v;
+ register ENVELOPE *e;
+{
+ if (tTd(35, 9))
+ {
+ printf("define(%c as ", n);
+ xputs(v);
+ printf(")\n");
+ }
+ e->e_macro[n & 0177] = v;
+}
+ /*
+** MACVALUE -- return uninterpreted value of a macro.
+**
+** Parameters:
+** n -- the name of the macro.
+**
+** Returns:
+** The value of n.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+macvalue(n, e)
+ int n;
+ register ENVELOPE *e;
+{
+ n &= 0177;
+ while (e != NULL)
+ {
+ register char *p = e->e_macro[n];
+
+ if (p != NULL)
+ return (p);
+ e = e->e_parent;
+ }
+ return (NULL);
+}
diff --git a/usr.sbin/sendmail/src/mailq.1 b/usr.sbin/sendmail/src/mailq.1
new file mode 100644
index 00000000000..f7b9da43ed0
--- /dev/null
+++ b/usr.sbin/sendmail/src/mailq.1
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1985, 1990, 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.
+.\"
+.\" @(#)mailq.1 8.4 (Berkeley) 2/22/94
+.\"
+.Dd February 22, 1994
+.Dt MAILQ 1
+.Os BSD 4
+.Sh NAME
+.Nm mailq
+.Nd print the mail queue
+.Sh SYNOPSIS
+.Nm mailq
+.Op Fl v
+.Sh DESCRIPTION
+.Nm Mailq
+prints a summary of the mail messages queued for future delivery.
+.Pp
+The first line printed for each message
+shows the internal identifier used on this host
+for the message,
+the size of the message in bytes,
+the date and time the message was accepted into the queue,
+and the envelope sender of the message.
+The second line shows the error message that caused this message
+to be retained in the queue;
+it will not be present if the message is being processed
+for the first time.
+The following lines show message recipients,
+one per line.
+.Pp
+.Nm Mailq
+is identical to
+.Dq Li "sendmail -bp" .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl v
+Print verbose information.
+This adds the priority of the message and
+a single character indicator (``+'' or blank)
+indicating whether a warning message has been sent
+on the first line of the message.
+Additionally, extra lines may be intermixed with the recipients
+indicating the ``controlling user'' information;
+this shows who will own any programs that are executed
+on behalf of this message
+and the name of the alias this command expanded from, if any.
+.El
+.Pp
+The
+.Nm mailq
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr sendmail 8
+.Sh HISTORY
+The
+.Nm mailq
+command appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/sendmail/src/mailstats.h b/usr.sbin/sendmail/src/mailstats.h
new file mode 100644
index 00000000000..0164d91e144
--- /dev/null
+++ b/usr.sbin/sendmail/src/mailstats.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ *
+ * @(#)mailstats.h 8.1 (Berkeley) 6/7/93
+ */
+
+/*
+** Statistics structure.
+*/
+
+struct statistics
+{
+ time_t stat_itime; /* file initialization time */
+ short stat_size; /* size of this structure */
+ long stat_nf[MAXMAILERS]; /* # msgs from each mailer */
+ long stat_bf[MAXMAILERS]; /* kbytes from each mailer */
+ long stat_nt[MAXMAILERS]; /* # msgs to each mailer */
+ long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
+};
diff --git a/usr.sbin/sendmail/src/main.c b/usr.sbin/sendmail/src/main.c
new file mode 100644
index 00000000000..a0253a252de
--- /dev/null
+++ b/usr.sbin/sendmail/src/main.c
@@ -0,0 +1,1510 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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[] = "@(#)main.c 8.55.1.7 (Berkeley) 3/5/95";
+#endif /* not lint */
+
+#define _DEFINE
+
+#include "sendmail.h"
+#if NAMED_BIND
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
+#include <pwd.h>
+
+# ifdef lint
+char edata, end;
+# endif /* lint */
+
+/*
+** SENDMAIL -- Post mail to a set of destinations.
+**
+** This is the basic mail router. All user mail programs should
+** call this routine to actually deliver mail. Sendmail in
+** turn calls a bunch of mail servers that do the real work of
+** delivering the mail.
+**
+** Sendmail is driven by tables read in from /usr/lib/sendmail.cf
+** (read by readcf.c). Some more static configuration info,
+** including some code that you may want to tailor for your
+** installation, is in conf.c. You may also want to touch
+** daemon.c (if you have some other IPC mechanism), acct.c
+** (to change your accounting), names.c (to adjust the name
+** server mechanism).
+**
+** Usage:
+** /usr/lib/sendmail [flags] addr ...
+**
+** See the associated documentation for details.
+**
+** Author:
+** Eric Allman, UCB/INGRES (until 10/81)
+** Britton-Lee, Inc., purveyors of fine
+** database computers (from 11/81)
+** Now back at UCB at the Mammoth project.
+** The support of the INGRES Project and Britton-Lee is
+** gratefully acknowledged. Britton-Lee in
+** particular had absolutely nothing to gain from
+** my involvement in this project.
+*/
+
+
+int NextMailer; /* "free" index into Mailer struct */
+char *FullName; /* sender's full name */
+ENVELOPE BlankEnvelope; /* a "blank" envelope */
+ENVELOPE MainEnvelope; /* the envelope around the basic letter */
+ADDRESS NullAddress = /* a null address */
+ { "", "", NULL, "" };
+char *UserEnviron[MAXUSERENVIRON + 2];
+ /* saved user environment */
+char RealUserName[256]; /* the actual user id on this host */
+char *CommandLineArgs; /* command line args for pid file */
+bool Warn_Q_option = FALSE; /* warn about Q option use */
+
+/*
+** Pointers for setproctitle.
+** This allows "ps" listings to give more useful information.
+*/
+
+# ifdef SETPROCTITLE
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArgv = NULL; /* end of argv */
+# endif /* SETPROCTITLE */
+
+static void obsolete();
+
+#ifdef DAEMON
+#ifndef SMTP
+ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR
+#endif /* SMTP */
+#endif /* DAEMON */
+
+#define MAXCONFIGLEVEL 5 /* highest config version level known */
+
+main(argc, argv, envp)
+ int argc;
+ char **argv;
+ char **envp;
+{
+ register char *p;
+ char **av;
+ extern int finis();
+ extern char Version[];
+ char *ep, *from;
+ typedef int (*fnptr)();
+ STAB *st;
+ register int i;
+ int j;
+ bool queuemode = FALSE; /* process queue requests */
+ bool safecf = TRUE;
+ bool warn_C_flag = FALSE;
+ char warn_f_flag = '\0';
+ static bool reenter = FALSE;
+ char *argv0 = argv[0];
+ struct passwd *pw;
+ struct stat stb;
+ char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
+ extern int DtableSize;
+ extern int optind;
+ extern time_t convtime();
+ extern putheader(), putbody();
+ extern void intsig();
+ extern char **myhostname();
+ extern char *arpadate();
+ extern char *getauthinfo();
+ extern char *getcfname();
+ extern char *optarg;
+ extern char **environ;
+ extern void sigusr1();
+
+ /*
+ ** Check to see if we reentered.
+ ** This would normally happen if e_putheader or e_putbody
+ ** were NULL when invoked.
+ */
+
+ if (reenter)
+ {
+ syserr("main: reentered!");
+ abort();
+ }
+ reenter = TRUE;
+
+ /* do machine-dependent initializations */
+ init_md(argc, argv);
+
+ /* arrange to dump state on signal */
+#ifdef SIGUSR1
+ setsignal(SIGUSR1, sigusr1);
+#endif
+
+ /* in 4.4BSD, the table can be huge; impose a reasonable limit */
+ DtableSize = getdtsize();
+ if (DtableSize > 256)
+ DtableSize = 256;
+
+ /*
+ ** Be sure we have enough file descriptors.
+ ** But also be sure that 0, 1, & 2 are open.
+ */
+
+ i = open("/dev/null", O_RDWR, 0);
+ if (fstat(STDIN_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
+ (void) dup2(i, STDIN_FILENO);
+ if (fstat(STDOUT_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
+ (void) dup2(i, STDOUT_FILENO);
+ if (fstat(STDERR_FILENO, &stb) < 0 && errno != EOPNOTSUPP)
+ (void) dup2(i, STDERR_FILENO);
+ if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
+ (void) close(i);
+
+ i = DtableSize;
+ while (--i > 0)
+ {
+ if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
+ (void) close(i);
+ }
+ errno = 0;
+
+#ifdef LOG
+# ifdef LOG_MAIL
+ openlog("sendmail", LOG_PID, LOG_MAIL);
+# else
+ openlog("sendmail", LOG_PID);
+# endif
+#endif
+
+ /* set up the blank envelope */
+ BlankEnvelope.e_puthdr = putheader;
+ BlankEnvelope.e_putbody = putbody;
+ BlankEnvelope.e_xfp = NULL;
+ STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
+ CurEnv = &BlankEnvelope;
+ STRUCTCOPY(NullAddress, MainEnvelope.e_from);
+
+ /*
+ ** Set default values for variables.
+ ** These cannot be in initialized data space.
+ */
+
+ setdefaults(&BlankEnvelope);
+
+ RealUid = getuid();
+ RealGid = getgid();
+
+ pw = getpwuid(RealUid);
+ if (pw != NULL)
+ (void) strcpy(RealUserName, pw->pw_name);
+ else
+ (void) sprintf(RealUserName, "Unknown UID %d", RealUid);
+
+ /* save command line arguments */
+ i = 0;
+ for (av = argv; *av != NULL; )
+ i += strlen(*av++) + 1;
+ CommandLineArgs = xalloc(i);
+ p = CommandLineArgs;
+ for (av = argv; *av != NULL; )
+ {
+ if (av != argv)
+ *p++ = ' ';
+ strcpy(p, *av++);
+ p += strlen(p);
+ }
+
+ /* Handle any non-getoptable constructions. */
+ obsolete(argv);
+
+ /*
+ ** Do a quick prescan of the argument list.
+ */
+
+#if defined(__osf__) || defined(_AIX3)
+# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:x"
+#endif
+#if defined(ultrix)
+# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mno:p:q:r:sTtvX:"
+#endif
+#if defined(NeXT)
+# define OPTIONS "B:b:C:cd:e:F:f:h:IimnOo:p:q:r:sTtvX:"
+#endif
+#ifndef OPTIONS
+# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:"
+#endif
+ while ((j = getopt(argc, argv, OPTIONS)) != EOF)
+ {
+ switch (j)
+ {
+ case 'd':
+ tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+ tTflag(optarg);
+ setbuf(stdout, (char *) NULL);
+ printf("Version %s\n", Version);
+ break;
+ }
+ }
+
+ InChannel = stdin;
+ OutChannel = stdout;
+
+ /*
+ ** Move the environment so setproctitle can use the space at
+ ** the top of memory.
+ */
+
+ for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
+ {
+ if (strncmp(p, "IFS=", 4) == 0 || strncmp(p, "LD_", 3) == 0)
+ continue;
+ UserEnviron[j++] = newstr(p);
+ }
+ UserEnviron[j] = NULL;
+ environ = UserEnviron;
+
+# ifdef SETPROCTITLE
+ /*
+ ** Save start and extent of argv for setproctitle.
+ */
+
+ Argv = argv;
+ if (i > 0)
+ LastArgv = envp[i - 1] + strlen(envp[i - 1]);
+ else
+ LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
+# endif /* SETPROCTITLE */
+
+ if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void) setsignal(SIGINT, intsig);
+ if (setsignal(SIGHUP, SIG_IGN) != SIG_IGN)
+ (void) setsignal(SIGHUP, intsig);
+ (void) setsignal(SIGTERM, intsig);
+ (void) setsignal(SIGPIPE, SIG_IGN);
+ OldUmask = umask(022);
+ OpMode = MD_DELIVER;
+ FullName = getenv("NAME");
+
+#if NAMED_BIND
+ if (tTd(8, 8))
+ {
+ res_init();
+ _res.options |= RES_DEBUG;
+ }
+#endif
+
+ errno = 0;
+ from = NULL;
+
+ /* initialize some macros, etc. */
+ initmacros(CurEnv);
+
+ /* version */
+ define('v', Version, CurEnv);
+
+ /* hostname */
+ av = myhostname(jbuf, sizeof jbuf);
+ if (jbuf[0] != '\0')
+ {
+ struct utsname utsname;
+
+ if (tTd(0, 4))
+ printf("canonical name: %s\n", jbuf);
+ define('w', newstr(jbuf), CurEnv); /* must be new string */
+ define('j', newstr(jbuf), CurEnv);
+ setclass('w', jbuf);
+
+ p = strchr(jbuf, '.');
+ if (p != NULL)
+ {
+ if (p[1] != '\0')
+ {
+ define('m', newstr(&p[1]), CurEnv);
+ setclass('m', &p[1]);
+ }
+ while (p != NULL && strchr(&p[1], '.') != NULL)
+ {
+ *p = '\0';
+ setclass('w', jbuf);
+ *p++ = '.';
+ p = strchr(p, '.');
+ }
+ }
+
+ if (uname(&utsname) >= 0)
+ p = utsname.nodename;
+ else
+ {
+ if (tTd(0, 22))
+ printf("uname failed (%s)\n", errstring(errno));
+ makelower(jbuf);
+ p = jbuf;
+ }
+ if (tTd(0, 4))
+ printf("UUCP nodename: %s\n", p);
+ p = newstr(p);
+ define('k', p, CurEnv);
+ setclass('k', p);
+ setclass('w', p);
+ }
+ while (av != NULL && *av != NULL)
+ {
+ if (tTd(0, 4))
+ printf("\ta.k.a.: %s\n", *av);
+ setclass('w', *av++);
+ }
+
+ /* current time */
+ define('b', arpadate((char *) NULL), CurEnv);
+
+ /*
+ ** Find our real host name for future logging.
+ */
+
+ p = getauthinfo(STDIN_FILENO);
+ define('_', p, CurEnv);
+
+ /*
+ ** Crack argv.
+ */
+
+ av = argv;
+ p = strrchr(*av, '/');
+ if (p++ == NULL)
+ p = *av;
+ if (strcmp(p, "newaliases") == 0)
+ OpMode = MD_INITALIAS;
+ else if (strcmp(p, "mailq") == 0)
+ OpMode = MD_PRINT;
+ else if (strcmp(p, "smtpd") == 0)
+ OpMode = MD_DAEMON;
+
+ optind = 1;
+ while ((j = getopt(argc, argv, OPTIONS)) != EOF)
+ {
+ switch (j)
+ {
+ case 'b': /* operations mode */
+ switch (j = *optarg)
+ {
+ case MD_DAEMON:
+# ifdef DAEMON
+ if (RealUid != 0) {
+ usrerr("Permission denied");
+ exit (EX_USAGE);
+ }
+ (void) unsetenv("HOSTALIASES");
+# else
+ usrerr("Daemon mode not implemented");
+ ExitStat = EX_USAGE;
+ break;
+# endif /* DAEMON */
+ case MD_SMTP:
+# ifndef SMTP
+ usrerr("I don't speak SMTP");
+ ExitStat = EX_USAGE;
+ break;
+# endif /* SMTP */
+ case MD_DELIVER:
+ case MD_VERIFY:
+ case MD_TEST:
+ case MD_INITALIAS:
+ case MD_PRINT:
+#ifdef MAYBE_NEXT_RELEASE
+ case MD_ARPAFTP:
+#endif
+ OpMode = j;
+ break;
+
+ case MD_FREEZE:
+ usrerr("Frozen configurations unsupported");
+ ExitStat = EX_USAGE;
+ break;
+
+ default:
+ usrerr("Invalid operation mode %c", j);
+ ExitStat = EX_USAGE;
+ break;
+ }
+ break;
+
+ case 'B': /* body type */
+ if (strcasecmp(optarg, "7bit") == 0 ||
+ strcasecmp(optarg, "8bitmime") == 0)
+ CurEnv->e_bodytype = newstr(optarg);
+ else
+ usrerr("Illegal body type %s", optarg);
+ break;
+
+ case 'C': /* select configuration file (already done) */
+ if (RealUid != 0)
+ warn_C_flag = TRUE;
+ ConfFile = optarg;
+ (void) setgid(RealGid);
+ (void) setuid(RealUid);
+ safecf = FALSE;
+ break;
+
+ case 'd': /* debugging -- already done */
+ break;
+
+ case 'f': /* from address */
+ case 'r': /* obsolete -f flag */
+ if (from != NULL)
+ {
+ usrerr("More than one \"from\" person");
+ ExitStat = EX_USAGE;
+ break;
+ }
+ from = newstr(denlstring(optarg, TRUE, TRUE));
+ if (strcmp(RealUserName, from) != 0)
+ warn_f_flag = j;
+ break;
+
+ case 'F': /* set full name */
+ FullName = newstr(optarg);
+ break;
+
+ case 'h': /* hop count */
+ CurEnv->e_hopcount = strtol(optarg, &ep, 10);
+ if (*ep)
+ {
+ usrerr("Bad hop count (%s)", optarg);
+ ExitStat = EX_USAGE;
+ break;
+ }
+ break;
+
+ case 'n': /* don't alias */
+ NoAlias = TRUE;
+ break;
+
+ case 'o': /* set option */
+ setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
+ break;
+
+ case 'p': /* set protocol */
+ p = strchr(optarg, ':');
+ if (p != NULL)
+ {
+ *p++ = '\0';
+ if (*p != '\0')
+ {
+ ep = xalloc(strlen(p) + 1);
+ cleanstrcpy(ep, p, MAXNAME);
+ define('s', ep, CurEnv);
+ }
+ }
+ if (*optarg != '\0')
+ {
+ ep = xalloc(strlen(optarg) + 1);
+ cleanstrcpy(ep, optarg, MAXNAME);
+ define('r', ep, CurEnv);
+ }
+ break;
+
+ case 'q': /* run queue files at intervals */
+# ifdef QUEUE
+ (void) unsetenv("HOSTALIASES");
+ FullName = NULL;
+ queuemode = TRUE;
+ switch (optarg[0])
+ {
+ case 'I':
+ QueueLimitId = newstr(&optarg[1]);
+ break;
+
+ case 'R':
+ QueueLimitRecipient = newstr(&optarg[1]);
+ break;
+
+ case 'S':
+ QueueLimitSender = newstr(&optarg[1]);
+ break;
+
+ default:
+ QueueIntvl = convtime(optarg, 'm');
+ break;
+ }
+# else /* QUEUE */
+ usrerr("I don't know about queues");
+ ExitStat = EX_USAGE;
+# endif /* QUEUE */
+ break;
+
+ case 't': /* read recipients from message */
+ GrabTo = TRUE;
+ break;
+
+ case 'X': /* traffic log file */
+ setgid(RealGid);
+ setuid(RealUid);
+ TrafficLogFile = fopen(optarg, "a");
+ if (TrafficLogFile == NULL)
+ {
+ syserr("cannot open %s", optarg);
+ break;
+ }
+#ifdef HASSETVBUF
+ setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
+#else
+ setlinebuf(TrafficLogFile);
+#endif
+ break;
+
+ /* compatibility flags */
+ case 'c': /* connect to non-local mailers */
+ case 'i': /* don't let dot stop me */
+ case 'm': /* send to me too */
+ case 'T': /* set timeout interval */
+ case 'v': /* give blow-by-blow description */
+ setoption(j, "T", FALSE, TRUE, CurEnv);
+ break;
+
+ case 'e': /* error message disposition */
+# if defined(ultrix)
+ case 'M': /* define macro */
+# endif
+ setoption(j, optarg, FALSE, TRUE, CurEnv);
+ break;
+
+ case 's': /* save From lines in headers */
+ setoption('f', "T", FALSE, TRUE, CurEnv);
+ break;
+
+# ifdef DBM
+ case 'I': /* initialize alias DBM file */
+ OpMode = MD_INITALIAS;
+ break;
+# endif /* DBM */
+
+# if defined(__osf__) || defined(_AIX3)
+ case 'x': /* random flag that OSF/1 & AIX mailx passes */
+ break;
+# endif
+# if defined(NeXT)
+ case 'O': /* random flag that NeXT Mail.app passes */
+ break;
+# endif
+
+ default:
+ ExitStat = EX_USAGE;
+ finis();
+ break;
+ }
+ }
+ av += optind;
+
+ /*
+ ** Do basic initialization.
+ ** Read system control file.
+ ** Extract special fields for local use.
+ */
+
+#ifdef XDEBUG
+ checkfd012("before readcf");
+#endif
+ readcf(getcfname(), safecf, CurEnv);
+
+ if (tTd(0, 1))
+ {
+ printf("SYSTEM IDENTITY (after readcf):");
+ printf("\n\t (short domain name) $w = ");
+ xputs(macvalue('w', CurEnv));
+ printf("\n\t(canonical domain name) $j = ");
+ xputs(macvalue('j', CurEnv));
+ printf("\n\t (subdomain name) $m = ");
+ xputs(macvalue('m', CurEnv));
+ printf("\n\t (node name) $k = ");
+ xputs(macvalue('k', CurEnv));
+ printf("\n");
+ }
+
+ /*
+ ** Initialize name server if it is going to be used.
+ */
+
+#if NAMED_BIND
+ if (!bitset(RES_INIT, _res.options))
+ res_init();
+#endif
+
+ /*
+ ** Process authorization warnings from command line.
+ */
+
+ if (warn_C_flag)
+ auth_warning(CurEnv, "Processed by %s with -C %s",
+ RealUserName, ConfFile);
+/*
+ if (warn_f_flag != '\0')
+ auth_warning(CurEnv, "%s set sender to %s using -%c",
+ RealUserName, from, warn_f_flag);
+*/
+ if (Warn_Q_option)
+ auth_warning(CurEnv, "Processed from queue %s", QueueDir);
+
+ /* Enforce use of local time (null string overrides this) */
+ if (TimeZoneSpec == NULL)
+ unsetenv("TZ");
+ else if (TimeZoneSpec[0] != '\0')
+ {
+ char **evp = UserEnviron;
+ char tzbuf[100];
+
+ strcpy(tzbuf, "TZ=");
+ strcpy(&tzbuf[3], TimeZoneSpec);
+
+ while (*evp != NULL && strncmp(*evp, "TZ=", 3) != 0)
+ evp++;
+ if (*evp == NULL)
+ {
+ *evp++ = newstr(tzbuf);
+ *evp = NULL;
+ }
+ else
+ *evp++ = newstr(tzbuf);
+ }
+
+ if (ConfigLevel > MAXCONFIGLEVEL)
+ {
+ syserr("Warning: .cf version level (%d) exceeds program functionality (%d)",
+ ConfigLevel, MAXCONFIGLEVEL);
+ }
+
+ if (MeToo)
+ BlankEnvelope.e_flags |= EF_METOO;
+
+# ifdef QUEUE
+ if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
+ {
+ struct stat stbuf;
+
+ /* check to see if we own the queue directory */
+ if (stat(QueueDir, &stbuf) < 0)
+ syserr("main: cannot stat %s", QueueDir);
+ if (stbuf.st_uid != RealUid)
+ {
+ /* nope, really a botch */
+ usrerr("You do not have permission to process the queue");
+ exit (EX_NOPERM);
+ }
+ }
+# endif /* QUEUE */
+
+ switch (OpMode)
+ {
+ case MD_INITALIAS:
+ Verbose = TRUE;
+ break;
+
+ case MD_DAEMON:
+ /* remove things that don't make sense in daemon mode */
+ FullName = NULL;
+ break;
+ }
+
+ /* full names can't have newlines */
+ if (FullName != NULL && strchr(FullName, '\n') != NULL)
+ FullName = newstr(denlstring(FullName, TRUE, TRUE));
+
+ /* do heuristic mode adjustment */
+ if (Verbose)
+ {
+ /* turn off noconnect option */
+ setoption('c', "F", TRUE, FALSE, CurEnv);
+
+ /* turn on interactive delivery */
+ setoption('d', "", TRUE, FALSE, CurEnv);
+ }
+
+ if (ConfigLevel < 3)
+ {
+ UseErrorsTo = TRUE;
+ }
+
+ /* our name for SMTP codes */
+ expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+ MyHostName = jbuf;
+
+ /* make certain that this name is part of the $=w class */
+ setclass('w', MyHostName);
+
+ /* the indices of built-in mailers */
+ st = stab("local", ST_MAILER, ST_FIND);
+ if (st == NULL)
+ syserr("No local mailer defined");
+ else
+ LocalMailer = st->s_mailer;
+
+ st = stab("prog", ST_MAILER, ST_FIND);
+ if (st == NULL)
+ syserr("No prog mailer defined");
+ else
+ ProgMailer = st->s_mailer;
+
+ st = stab("*file*", ST_MAILER, ST_FIND);
+ if (st == NULL)
+ syserr("No *file* mailer defined");
+ else
+ FileMailer = st->s_mailer;
+
+ st = stab("*include*", ST_MAILER, ST_FIND);
+ if (st == NULL)
+ syserr("No *include* mailer defined");
+ else
+ InclMailer = st->s_mailer;
+
+
+ /* operate in queue directory */
+ if (OpMode != MD_TEST && chdir(QueueDir) < 0)
+ {
+ syserr("cannot chdir(%s)", QueueDir);
+ ExitStat = EX_SOFTWARE;
+ }
+
+ /* if we've had errors so far, exit now */
+ if (ExitStat != EX_OK && OpMode != MD_TEST)
+ {
+ setuid(RealUid);
+ exit(ExitStat);
+ }
+
+#ifdef XDEBUG
+ checkfd012("before main() initmaps");
+#endif
+
+ /*
+ ** Do operation-mode-dependent initialization.
+ */
+
+ switch (OpMode)
+ {
+ case MD_PRINT:
+ /* print the queue */
+#ifdef QUEUE
+ dropenvelope(CurEnv);
+ printqueue();
+ setuid(RealUid);
+ exit(EX_OK);
+#else /* QUEUE */
+ usrerr("No queue to print");
+ finis();
+#endif /* QUEUE */
+
+ case MD_INITALIAS:
+ /* initialize alias database */
+ initmaps(TRUE, CurEnv);
+ setuid(RealUid);
+ exit(EX_OK);
+
+ case MD_DAEMON:
+ /* don't open alias database -- done in srvrsmtp */
+ break;
+
+ default:
+ /* open the alias database */
+ initmaps(FALSE, CurEnv);
+ break;
+ }
+
+ if (tTd(0, 15))
+ {
+ /* print configuration table (or at least part of it) */
+ printrules();
+ for (i = 0; i < MAXMAILERS; i++)
+ {
+ register struct mailer *m = Mailer[i];
+ int j;
+
+ if (m == NULL)
+ continue;
+ printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name,
+ m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
+ m->m_re_rwset, m->m_rh_rwset, m->m_maxsize);
+ for (j = '\0'; j <= '\177'; j++)
+ if (bitnset(j, m->m_flags))
+ (void) putchar(j);
+ printf(" E=");
+ xputs(m->m_eol);
+ if (m->m_argv != NULL)
+ {
+ char **a = m->m_argv;
+
+ printf(" A=");
+ while (*a != NULL)
+ {
+ if (a != m->m_argv)
+ printf(" ");
+ xputs(*a++);
+ }
+ }
+ printf("\n");
+ }
+ }
+
+ /*
+ ** Switch to the main envelope.
+ */
+
+ CurEnv = newenvelope(&MainEnvelope, CurEnv);
+ MainEnvelope.e_flags = BlankEnvelope.e_flags;
+
+ /*
+ ** If test mode, read addresses from stdin and process.
+ */
+
+ if (OpMode == MD_TEST)
+ {
+ char buf[MAXLINE];
+
+ if (isatty(fileno(stdin)))
+ Verbose = TRUE;
+
+ if (Verbose)
+ {
+ printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
+ printf("Enter <ruleset> <address>\n");
+ }
+ for (;;)
+ {
+ register char **pvp;
+ char *q;
+ auto char *delimptr;
+ extern bool invalidaddr();
+ extern char *crackaddr();
+
+ if (Verbose)
+ printf("> ");
+ (void) fflush(stdout);
+ if (fgets(buf, sizeof buf, stdin) == NULL)
+ finis();
+ if (!Verbose)
+ printf("> %s", buf);
+ switch (buf[0])
+ {
+ case '#':
+ continue;
+
+#ifdef MAYBENEXTRELEASE
+ case 'C': /* try crackaddr */
+ q = crackaddr(&buf[1]);
+ xputs(q);
+ printf("\n");
+ continue;
+#endif
+ }
+
+ for (p = buf; isascii(*p) && isspace(*p); p++)
+ continue;
+ q = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p == '\0')
+ {
+ printf("No address!\n");
+ continue;
+ }
+ *p = '\0';
+ if (invalidaddr(p + 1, NULL))
+ continue;
+ do
+ {
+ char pvpbuf[PSBUFSIZE];
+
+ pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
+ &delimptr);
+ if (pvp == NULL)
+ continue;
+ p = q;
+ while (*p != '\0')
+ {
+ int stat;
+
+ stat = rewrite(pvp, atoi(p), 0, CurEnv);
+ if (stat != EX_OK)
+ printf("== Ruleset %s status %d\n",
+ p, stat);
+ while (*p != '\0' && *p++ != ',')
+ continue;
+ }
+ } while (*(p = delimptr) != '\0');
+ }
+ }
+
+# ifdef QUEUE
+ /*
+ ** If collecting stuff from the queue, go start doing that.
+ */
+
+ if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
+ {
+ runqueue(FALSE);
+ finis();
+ }
+# endif /* QUEUE */
+
+ /*
+ ** If a daemon, wait for a request.
+ ** getrequests will always return in a child.
+ ** If we should also be processing the queue, start
+ ** doing it in background.
+ ** We check for any errors that might have happened
+ ** during startup.
+ */
+
+ if (OpMode == MD_DAEMON || QueueIntvl != 0)
+ {
+ char dtype[200];
+
+ if (!tTd(0, 1))
+ {
+ /* put us in background */
+ i = fork();
+ if (i < 0)
+ syserr("daemon: cannot fork");
+ if (i != 0)
+ exit(0);
+
+ /* disconnect from our controlling tty */
+ disconnect(2, CurEnv);
+ }
+
+ dtype[0] = '\0';
+ if (OpMode == MD_DAEMON)
+ strcat(dtype, "+SMTP");
+ if (QueueIntvl != 0)
+ {
+ strcat(dtype, "+queueing@");
+ strcat(dtype, pintvl(QueueIntvl, TRUE));
+ }
+ if (tTd(0, 1))
+ strcat(dtype, "+debugging");
+
+#ifdef LOG
+ syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1);
+#endif
+#ifdef XLA
+ xla_create_file();
+#endif
+
+# ifdef QUEUE
+ if (queuemode)
+ {
+ runqueue(TRUE);
+ if (OpMode != MD_DAEMON)
+ for (;;)
+ pause();
+ }
+# endif /* QUEUE */
+ dropenvelope(CurEnv);
+
+#ifdef DAEMON
+ getrequests();
+
+ /* at this point we are in a child: reset state */
+ (void) newenvelope(CurEnv, CurEnv);
+
+ /*
+ ** Get authentication data
+ */
+
+ p = getauthinfo(fileno(InChannel));
+ define('_', p, CurEnv);
+
+#endif /* DAEMON */
+ }
+
+# ifdef SMTP
+ /*
+ ** If running SMTP protocol, start collecting and executing
+ ** commands. This will never return.
+ */
+
+ if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
+ smtp(CurEnv);
+# endif /* SMTP */
+
+ if (OpMode == MD_VERIFY)
+ {
+ CurEnv->e_sendmode = SM_VERIFY;
+ CurEnv->e_errormode = EM_QUIET;
+ }
+ else
+ {
+ /* interactive -- all errors are global */
+ CurEnv->e_flags |= EF_GLOBALERRS;
+ }
+
+ /*
+ ** Do basic system initialization and set the sender
+ */
+
+ initsys(CurEnv);
+ setsender(from, CurEnv, NULL, FALSE);
+ if (macvalue('s', CurEnv) == NULL)
+ define('s', RealHostName, CurEnv);
+
+ if (*av == NULL && !GrabTo)
+ {
+ CurEnv->e_flags |= EF_GLOBALERRS;
+ usrerr("Recipient names must be specified");
+
+ /* collect body for UUCP return */
+ if (OpMode != MD_VERIFY)
+ collect(FALSE, FALSE, CurEnv);
+ finis();
+ }
+
+ /*
+ ** Scan argv and deliver the message to everyone.
+ */
+
+ sendtoargv(av, CurEnv);
+
+ /* if we have had errors sofar, arrange a meaningful exit stat */
+ if (Errors > 0 && ExitStat == EX_OK)
+ ExitStat = EX_USAGE;
+
+ /*
+ ** Read the input mail.
+ */
+
+ CurEnv->e_to = NULL;
+ if (OpMode != MD_VERIFY || GrabTo)
+ {
+ CurEnv->e_flags |= EF_GLOBALERRS;
+ collect(FALSE, FALSE, CurEnv);
+ }
+ errno = 0;
+
+ if (tTd(1, 1))
+ printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
+
+ /*
+ ** Actually send everything.
+ ** If verifying, just ack.
+ */
+
+ CurEnv->e_from.q_flags |= QDONTSEND;
+ if (tTd(1, 5))
+ {
+ printf("main: QDONTSEND ");
+ printaddr(&CurEnv->e_from, FALSE);
+ }
+ CurEnv->e_to = NULL;
+ sendall(CurEnv, SM_DEFAULT);
+
+ /*
+ ** All done.
+ ** Don't send return error message if in VERIFY mode.
+ */
+
+ finis();
+}
+ /*
+** FINIS -- Clean up and exit.
+**
+** Parameters:
+** none
+**
+** Returns:
+** never
+**
+** Side Effects:
+** exits sendmail
+*/
+
+finis()
+{
+ if (tTd(2, 1))
+ printf("\n====finis: stat %d e_flags %o, e_id=%s\n",
+ ExitStat, CurEnv->e_flags,
+ CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
+ if (tTd(2, 9))
+ printopenfds(FALSE);
+
+ /* clean up temp files */
+ CurEnv->e_to = NULL;
+ dropenvelope(CurEnv);
+
+ /* flush any cached connections */
+ mci_flush(TRUE, NULL);
+
+# ifdef XLA
+ /* clean up extended load average stuff */
+ xla_all_end();
+# endif
+
+ /* and exit */
+# ifdef LOG
+ if (LogLevel > 78)
+ syslog(LOG_DEBUG, "finis, pid=%d", getpid());
+# endif /* LOG */
+ if (ExitStat == EX_TEMPFAIL)
+ ExitStat = EX_OK;
+
+ /* reset uid for process accounting */
+ setuid(RealUid);
+
+ exit(ExitStat);
+}
+ /*
+** INTSIG -- clean up on interrupt
+**
+** This just arranges to exit. It pessimises in that it
+** may resend a message.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Unlocks the current job.
+*/
+
+void
+intsig()
+{
+ FileName = NULL;
+ unlockqueue(CurEnv);
+#ifdef XLA
+ xla_all_end();
+#endif
+
+ /* reset uid for process accounting */
+ setuid(RealUid);
+
+ exit(EX_OK);
+}
+ /*
+** INITMACROS -- initialize the macro system
+**
+** This just involves defining some macros that are actually
+** used internally as metasymbols to be themselves.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** initializes several macros to be themselves.
+*/
+
+struct metamac MetaMacros[] =
+{
+ /* LHS pattern matching characters */
+ '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE,
+ '=', MATCHCLASS, '~', MATCHNCLASS,
+
+ /* these are RHS metasymbols */
+ '#', CANONNET, '@', CANONHOST, ':', CANONUSER,
+ '>', CALLSUBR,
+
+ /* the conditional operations */
+ '?', CONDIF, '|', CONDELSE, '.', CONDFI,
+
+ /* the hostname lookup characters */
+ '[', HOSTBEGIN, ']', HOSTEND,
+ '(', LOOKUPBEGIN, ')', LOOKUPEND,
+
+ /* miscellaneous control characters */
+ '&', MACRODEXPAND,
+
+ '\0'
+};
+
+initmacros(e)
+ register ENVELOPE *e;
+{
+ register struct metamac *m;
+ char buf[5];
+ register int c;
+
+ for (m = MetaMacros; m->metaname != '\0'; m++)
+ {
+ buf[0] = m->metaval;
+ buf[1] = '\0';
+ define(m->metaname, newstr(buf), e);
+ }
+ buf[0] = MATCHREPL;
+ buf[2] = '\0';
+ for (c = '0'; c <= '9'; c++)
+ {
+ buf[1] = c;
+ define(c, newstr(buf), e);
+ }
+
+ /* set defaults for some macros sendmail will use later */
+ define('e', "\201j Sendmail \201v ready at \201b", e);
+ define('l', "From \201g \201d", e);
+ define('n', "MAILER-DAEMON", e);
+ define('o', ".:@[]", e);
+ define('q', "<\201g>", e);
+}
+ /*
+** DISCONNECT -- remove our connection with any foreground process
+**
+** Parameters:
+** droplev -- how "deeply" we should drop the line.
+** 0 -- ignore signals, mail back errors, make sure
+** output goes to stdout.
+** 1 -- also, make stdout go to transcript.
+** 2 -- also, disconnect from controlling terminal
+** (only for daemon mode).
+** e -- the current envelope.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Trys to insure that we are immune to vagaries of
+** the controlling tty.
+*/
+
+disconnect(droplev, e)
+ int droplev;
+ register ENVELOPE *e;
+{
+ int fd;
+
+ if (tTd(52, 1))
+ printf("disconnect: In %d Out %d, e=%x\n",
+ fileno(InChannel), fileno(OutChannel), e);
+ if (tTd(52, 5))
+ {
+ printf("don't\n");
+ return;
+ }
+
+ /* be sure we don't get nasty signals */
+ (void) setsignal(SIGHUP, SIG_IGN);
+ (void) setsignal(SIGINT, SIG_IGN);
+ (void) setsignal(SIGQUIT, SIG_IGN);
+
+ /* we can't communicate with our caller, so.... */
+ HoldErrs = TRUE;
+ CurEnv->e_errormode = EM_MAIL;
+ Verbose = FALSE;
+ DisConnected = TRUE;
+
+ /* all input from /dev/null */
+ if (InChannel != stdin)
+ {
+ (void) fclose(InChannel);
+ InChannel = stdin;
+ }
+ (void) freopen("/dev/null", "r", stdin);
+
+ /* output to the transcript */
+ if (OutChannel != stdout)
+ {
+ (void) fclose(OutChannel);
+ OutChannel = stdout;
+ }
+ if (droplev > 0)
+ {
+ if (e->e_xfp == NULL)
+ fd = open("/dev/null", O_WRONLY, 0666);
+ else
+ fd = fileno(e->e_xfp);
+ (void) fflush(stdout);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (e->e_xfp == NULL)
+ close(fd);
+ }
+
+ /* drop our controlling TTY completely if possible */
+ if (droplev > 1)
+ {
+ (void) setsid();
+ errno = 0;
+ }
+
+#ifdef XDEBUG
+ checkfd012("disconnect");
+#endif
+
+# ifdef LOG
+ if (LogLevel > 71)
+ syslog(LOG_DEBUG, "in background, pid=%d", getpid());
+# endif /* LOG */
+
+ errno = 0;
+}
+
+static void
+obsolete(argv)
+ char *argv[];
+{
+ register char *ap;
+ register char *op;
+
+ while ((ap = *++argv) != NULL)
+ {
+ /* Return if "--" or not an option of any form. */
+ if (ap[0] != '-' || ap[1] == '-')
+ return;
+
+ /* skip over options that do have a value */
+ op = strchr(OPTIONS, ap[1]);
+ if (op != NULL && *++op == ':' && ap[2] == '\0' &&
+ ap[1] != 'd' && argv[1] != NULL && argv[1][0] != '-')
+ {
+ argv++;
+ continue;
+ }
+
+ /* If -C doesn't have an argument, use sendmail.cf. */
+#define __DEFPATH "sendmail.cf"
+ if (ap[1] == 'C' && ap[2] == '\0')
+ {
+ *argv = xalloc(sizeof(__DEFPATH) + 2);
+ argv[0][0] = '-';
+ argv[0][1] = 'C';
+ (void)strcpy(&argv[0][2], __DEFPATH);
+ }
+
+ /* If -q doesn't have an argument, run it once. */
+ if (ap[1] == 'q' && ap[2] == '\0')
+ *argv = "-q0";
+
+ /* if -d doesn't have an argument, use 0-99.1 */
+ if (ap[1] == 'd' && ap[2] == '\0')
+ *argv = "-d0-99.1";
+ }
+}
+ /*
+** AUTH_WARNING -- specify authorization warning
+**
+** Parameters:
+** e -- the current envelope.
+** msg -- the text of the message.
+** args -- arguments to the message.
+**
+** Returns:
+** none.
+*/
+
+void
+#ifdef __STDC__
+auth_warning(register ENVELOPE *e, const char *msg, ...)
+#else
+auth_warning(e, msg, va_alist)
+ register ENVELOPE *e;
+ const char *msg;
+ va_dcl
+#endif
+{
+ char buf[MAXLINE];
+ VA_LOCAL_DECL
+
+ if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
+ {
+ register char *p;
+ static char hostbuf[48];
+ extern char **myhostname();
+
+ if (hostbuf[0] == '\0')
+ (void) myhostname(hostbuf, sizeof hostbuf);
+
+ (void) sprintf(buf, "%s: ", hostbuf);
+ p = &buf[strlen(buf)];
+ VA_START(msg);
+ vsprintf(p, msg, ap);
+ VA_END;
+ addheader("X-Authentication-Warning", buf, e);
+ }
+}
+ /*
+** DUMPSTATE -- dump state
+**
+** For debugging.
+*/
+
+void
+dumpstate(when)
+ char *when;
+{
+#ifdef LOG
+ register char *j = macvalue('j', CurEnv);
+ register STAB *s;
+
+ syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---",
+ when,
+ j == NULL ? "<NULL>" : j);
+ if (j != NULL)
+ {
+ s = stab(j, ST_CLASS, ST_FIND);
+ if (s == NULL || !bitnset('w', s->s_class))
+ syslog(LOG_DEBUG, "*** $j not in $=w ***");
+ }
+ syslog(LOG_DEBUG, "--- open file descriptors: ---");
+ printopenfds(TRUE);
+ syslog(LOG_DEBUG, "--- connection cache: ---");
+ mci_dump_all(TRUE);
+ if (RewriteRules[89] != NULL)
+ {
+ int stat;
+ register char **pvp;
+ char *pv[MAXATOM + 1];
+
+ pv[0] = NULL;
+ stat = rewrite(pv, 89, 0, CurEnv);
+ syslog(LOG_DEBUG, "--- ruleset 89 returns stat %d, pv: ---",
+ stat);
+ for (pvp = pv; *pvp != NULL; pvp++)
+ syslog(LOG_DEBUG, "%s", *pvp);
+ }
+ syslog(LOG_DEBUG, "--- end of state dump ---");
+#endif
+}
+
+
+void
+sigusr1()
+{
+ dumpstate("user signal");
+}
diff --git a/usr.sbin/sendmail/src/makesendmail b/usr.sbin/sendmail/src/makesendmail
new file mode 100644
index 00000000000..7c13db9fd9f
--- /dev/null
+++ b/usr.sbin/sendmail/src/makesendmail
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+# Copyright (c) 1993 Eric P. Allman
+# 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.
+#
+# @(#)makesendmail 8.5 (Berkeley) 2/27/94
+#
+
+#
+# A quick-and-dirty script to compile sendmail in the presence of
+# multiple architectures and Makefiles.
+#
+
+# determine machine architecture
+arch=`uname -m`
+case $arch
+in
+ sun4*) arch=sun4;;
+
+ 9000/*) arch=`echo $arch | sed -e 's/9000.//' -e 's/..$/xx/'`;;
+esac
+
+# determine operating system type
+os=`uname -s`
+
+# determine operating system release
+rel=`uname -r`
+rbase=`echo $rel | sed 's/\..*//''`
+
+# now try to find a reasonable object directory
+if [ -r obj.$os.$arch.$rel ]; then
+ obj=obj.$os.$arch.$rel
+elif [ -r obj.$os.$arch.$rbase.x ]; then
+ obj=obj.$os.$arch.$rbase.x
+elif [ -r obj.$os.$rel ]; then
+ obj=obj.$os.$rel
+elif [ -r obj.$os.$rbase.x ]; then
+ obj=obj.$os.$rbase.x
+elif [ -r obj.$os.$arch ]; then
+ obj=obj.$os.$arch
+elif [ -r obj.$arch.$rel ]; then
+ obj=obj.$arch.$rel
+elif [ -r obj.$arch.$rbase.x ]; then
+ obj=obj.$arch.$rbase.x
+elif [ -r obj.$os ]; then
+ obj=obj.$os
+elif [ -r obj.$arch ]; then
+ obj=obj.$arch
+elif [ -r obj.$rel ]; then
+ obj=obj.$rel
+else
+ # no existing obj directory -- try to create one if Makefile found
+ obj=obj.$os.$arch.$rel
+ if [ -r Makefile.$os.$arch.$rel ]; then
+ makefile=Makefile.$os.$arch.$rel
+ elif [ -r Makefile.$os.$arch.$rbase.x ]; then
+ makefile=Makefile.$os.$arch.$rbase.x
+ elif [ -r Makefile.$os.$rel ]; then
+ makefile=Makefile.$os.$rel
+ elif [ -r Makefile.$os.$rbase.x ]; then
+ makefile=Makefile.$os.$rbase.x
+ elif [ -r Makefile.$os.$arch ]; then
+ makefile=Makefile.$os.$arch
+ elif [ -r Makefile.$arch.$rel ]; then
+ makefile=Makefile.$arch.$rel
+ elif [ -r Makefile.$arch.$rbase.x ]; then
+ makefile=Makefile.$arch.$rbase.x
+ elif [ -r Makefile.$os ]; then
+ makefile=Makefile.$os
+ elif [ -r Makefile.$arch ]; then
+ makefile=Makefile.$arch
+ elif [ -r Makefile.$rel ]; then
+ makefile=Makefile.$rel
+ else
+ echo "Cannot determine how to support $arch.$os.$rel"
+ exit 1
+ fi
+ echo "Creating $obj using $makefile"
+ mkdir $obj
+ (cd $obj; ln -s ../*.[ch158] ../sendmail.hf .; ln -s ../$makefile Makefile)
+fi
+echo "Making in $obj"
+cd $obj
+exec make -f Makefile $*
diff --git a/usr.sbin/sendmail/src/map.c b/usr.sbin/sendmail/src/map.c
new file mode 100644
index 00000000000..a2b3337bb0f
--- /dev/null
+++ b/usr.sbin/sendmail/src/map.c
@@ -0,0 +1,1329 @@
+/*
+ * Copyright (c) 1992 Eric P. Allman.
+ * Copyright (c) 1992, 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 sccsid[] = "@(#)map.c 8.25.1.1 (Berkeley) 2/10/95";
+#endif /* not lint */
+
+#include "sendmail.h"
+
+#ifdef NDBM
+#include <ndbm.h>
+#endif
+#ifdef NEWDB
+#include <db.h>
+#endif
+#ifdef NIS
+#include <rpcsvc/ypclnt.h>
+#endif
+
+/*
+** MAP.C -- implementations for various map classes.
+**
+** Each map class implements a series of functions:
+**
+** bool map_parse(MAP *map, char *args)
+** Parse the arguments from the config file. Return TRUE
+** if they were ok, FALSE otherwise. Fill in map with the
+** values.
+**
+** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
+** Look up the key in the given map. If found, do any
+** rewriting the map wants (including "args" if desired)
+** and return the value. Set *pstat to the appropriate status
+** on error and return NULL. Args will be NULL if called
+** from the alias routines, although this should probably
+** not be relied upon. It is suggested you call map_rewrite
+** to return the results -- it takes care of null termination
+** and uses a dynamically expanded buffer as needed.
+**
+** void map_store(MAP *map, char *key, char *value)
+** Store the key:value pair in the map.
+**
+** bool map_open(MAP *map, int mode)
+** Open the map for the indicated mode. Mode should
+** be either O_RDONLY or O_RDWR. Return TRUE if it
+** was opened successfully, FALSE otherwise. If the open
+** failed an the MF_OPTIONAL flag is not set, it should
+** also print an error. If the MF_ALIAS bit is set
+** and this map class understands the @:@ convention, it
+** should call aliaswait() before returning.
+**
+** void map_close(MAP *map)
+** Close the map.
+*/
+
+#define DBMMODE 0644
+
+extern bool aliaswait __P((MAP *, char *, int));
+ /*
+** MAP_PARSEARGS -- parse config line arguments for database lookup
+**
+** This is a generic version of the map_parse method.
+**
+** Parameters:
+** map -- the map being initialized.
+** ap -- a pointer to the args on the config line.
+**
+** Returns:
+** TRUE -- if everything parsed OK.
+** FALSE -- otherwise.
+**
+** Side Effects:
+** null terminates the filename; stores it in map
+*/
+
+bool
+map_parseargs(map, ap)
+ MAP *map;
+ char *ap;
+{
+ register char *p = ap;
+
+ map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'N':
+ map->map_mflags |= MF_INCLNULL;
+ map->map_mflags &= ~MF_TRY0NULL;
+ break;
+
+ case 'O':
+ map->map_mflags &= ~MF_TRY1NULL;
+ break;
+
+ case 'o':
+ map->map_mflags |= MF_OPTIONAL;
+ break;
+
+ case 'f':
+ map->map_mflags |= MF_NOFOLDCASE;
+ break;
+
+ case 'm':
+ map->map_mflags |= MF_MATCHONLY;
+ break;
+
+ case 'a':
+ map->map_app = ++p;
+ break;
+ }
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ if (map->map_app != NULL)
+ map->map_app = newstr(map->map_app);
+
+ if (*p != '\0')
+ {
+ map->map_file = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ map->map_file = newstr(map->map_file);
+ }
+
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '\0')
+ map->map_rebuild = newstr(p);
+
+ if (map->map_file == NULL)
+ {
+ syserr("No file name for %s map %s",
+ map->map_class->map_cname, map->map_mname);
+ return FALSE;
+ }
+ return TRUE;
+}
+ /*
+** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
+**
+** It also adds the map_app string. It can be used as a utility
+** in the map_lookup method.
+**
+** Parameters:
+** map -- the map that causes this.
+** s -- the string to rewrite, NOT necessarily null terminated.
+** slen -- the length of s.
+** av -- arguments to interpolate into buf.
+**
+** Returns:
+** Pointer to rewritten result. This is static data that
+** should be copied if it is to be saved!
+**
+** Side Effects:
+** none.
+*/
+
+char *
+map_rewrite(map, s, slen, av)
+ register MAP *map;
+ register char *s;
+ int slen;
+ char **av;
+{
+ register char *bp;
+ register char c;
+ char **avp;
+ register char *ap;
+ int i;
+ int len;
+ static int buflen = -1;
+ static char *buf = NULL;
+
+ if (tTd(39, 1))
+ {
+ printf("map_rewrite(%.*s), av =", slen, s);
+ if (av == NULL)
+ printf(" (nullv)");
+ else
+ {
+ for (avp = av; *avp != NULL; avp++)
+ printf("\n\t%s", *avp);
+ }
+ printf("\n");
+ }
+
+ /* count expected size of output (can safely overestimate) */
+ i = len = slen;
+ if (av != NULL)
+ {
+ bp = s;
+ for (i = slen; --i >= 0 && (c = *bp++) != 0; )
+ {
+ if (c != '%')
+ continue;
+ if (--i < 0)
+ break;
+ c = *bp++;
+ if (!(isascii(c) && isdigit(c)))
+ continue;
+ for (avp = av; --c >= '0' && *avp != NULL; avp++)
+ continue;
+ if (*avp == NULL)
+ continue;
+ len += strlen(*avp);
+ }
+ }
+ if (map->map_app != NULL)
+ len += strlen(map->map_app);
+ if (buflen < ++len)
+ {
+ /* need to malloc additional space */
+ buflen = len;
+ if (buf != NULL)
+ free(buf);
+ buf = xalloc(buflen);
+ }
+
+ bp = buf;
+ if (av == NULL)
+ {
+ bcopy(s, bp, slen);
+ bp += slen;
+ }
+ else
+ {
+ while (--slen >= 0 && (c = *s++) != '\0')
+ {
+ if (c != '%')
+ {
+ pushc:
+ *bp++ = c;
+ continue;
+ }
+ if (--slen < 0 || (c = *s++) == '\0')
+ c = '%';
+ if (c == '%')
+ goto pushc;
+ if (!(isascii(c) && isdigit(c)))
+ {
+ *bp++ = '%';
+ goto pushc;
+ }
+ for (avp = av; --c >= '0' && *avp != NULL; avp++)
+ continue;
+ if (*avp == NULL)
+ continue;
+
+ /* transliterate argument into output string */
+ for (ap = *avp; (c = *ap++) != '\0'; )
+ *bp++ = c;
+ }
+ }
+ if (map->map_app != NULL)
+ strcpy(bp, map->map_app);
+ else
+ *bp = '\0';
+ if (tTd(39, 1))
+ printf("map_rewrite => %s\n", buf);
+ return buf;
+}
+ /*
+** INITMAPS -- initialize for aliasing
+**
+** Parameters:
+** rebuild -- if TRUE, this rebuilds the cached versions.
+** e -- current envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** initializes aliases:
+** if NDBM: opens the database.
+** if ~NDBM: reads the aliases into the symbol table.
+*/
+
+initmaps(rebuild, e)
+ bool rebuild;
+ register ENVELOPE *e;
+{
+ extern void map_init();
+
+#ifdef XDEBUG
+ checkfd012("entering initmaps");
+#endif
+ CurEnv = e;
+ if (rebuild)
+ {
+ stabapply(map_init, 1);
+ stabapply(map_init, 2);
+ }
+ else
+ {
+ stabapply(map_init, 0);
+ }
+#ifdef XDEBUG
+ checkfd012("exiting initmaps");
+#endif
+}
+
+void
+map_init(s, rebuild)
+ register STAB *s;
+ int rebuild;
+{
+ register MAP *map;
+
+ /* has to be a map */
+ if (s->s_type != ST_MAP)
+ return;
+
+ map = &s->s_map;
+ if (!bitset(MF_VALID, map->map_mflags))
+ return;
+
+ if (tTd(38, 2))
+ printf("map_init(%s:%s, %d)\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" : map->map_file,
+ rebuild);
+
+ if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
+ bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
+ {
+ if (tTd(38, 3))
+ printf("\twrong pass\n");
+ return;
+ }
+
+ /* if already open, close it (for nested open) */
+ if (bitset(MF_OPEN, map->map_mflags))
+ {
+ map->map_class->map_close(map);
+ map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
+ }
+
+ if (rebuild == 2)
+ {
+ rebuildaliases(map, FALSE);
+ }
+ else
+ {
+ if (map->map_class->map_open(map, O_RDONLY))
+ {
+ if (tTd(38, 4))
+ printf("\t%s:%s: valid\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" :
+ map->map_file);
+ map->map_mflags |= MF_OPEN;
+ }
+ else if (tTd(38, 4))
+ printf("\t%s:%s: invalid: %s\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" :
+ map->map_file,
+ errstring(errno));
+ }
+}
+ /*
+** NDBM modules
+*/
+
+#ifdef NDBM
+
+/*
+** DBM_MAP_OPEN -- DBM-style map open
+*/
+
+bool
+ndbm_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ register DBM *dbm;
+ struct stat st;
+
+ if (tTd(38, 2))
+ printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
+
+ if (mode == O_RDWR)
+ mode |= O_CREAT|O_TRUNC;
+
+ /* open the database */
+ dbm = dbm_open(map->map_file, mode, DBMMODE);
+ if (dbm == NULL)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".pag", FALSE))
+ return TRUE;
+#endif
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot open DBM database %s", map->map_file);
+ return FALSE;
+ }
+ map->map_db1 = (void *) dbm;
+ if (mode == O_RDONLY)
+ {
+ if (bitset(MF_ALIAS, map->map_mflags) &&
+ !aliaswait(map, ".pag", TRUE))
+ return FALSE;
+ }
+ else
+ {
+ int fd;
+
+ /* exclusive lock for duration of rebuild */
+ fd = dbm_dirfno((DBM *) map->map_db1);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
+ lockfile(fd, map->map_file, ".dir", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+ if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
+ map->map_mtime = st.st_mtime;
+ return TRUE;
+}
+
+
+/*
+** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
+*/
+
+char *
+ndbm_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ datum key, val;
+ int fd;
+ char keybuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("ndbm_map_lookup(%s)\n", name);
+
+ key.dptr = name;
+ key.dsize = strlen(name);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ {
+ if (key.dsize > sizeof keybuf - 1)
+ key.dsize = sizeof keybuf - 1;
+ bcopy(key.dptr, keybuf, key.dsize + 1);
+ makelower(keybuf);
+ key.dptr = keybuf;
+ }
+ fd = dbm_dirfno((DBM *) map->map_db1);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
+ val.dptr = NULL;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ val = dbm_fetch((DBM *) map->map_db1, key);
+ if (val.dptr != NULL)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ key.dsize++;
+ val = dbm_fetch((DBM *) map->map_db1, key);
+ if (val.dptr != NULL)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
+ if (val.dptr == NULL)
+ return NULL;
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, val.dptr, val.dsize, av);
+}
+
+
+/*
+** DBM_MAP_STORE -- store a datum in the database
+*/
+
+void
+ndbm_map_store(map, lhs, rhs)
+ register MAP *map;
+ char *lhs;
+ char *rhs;
+{
+ datum key;
+ datum data;
+ int stat;
+
+ if (tTd(38, 12))
+ printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
+
+ key.dsize = strlen(lhs);
+ key.dptr = lhs;
+
+ data.dsize = strlen(rhs);
+ data.dptr = rhs;
+
+ if (bitset(MF_INCLNULL, map->map_mflags))
+ {
+ key.dsize++;
+ data.dsize++;
+ }
+
+ stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
+ if (stat > 0)
+ {
+ usrerr("050 Warning: duplicate alias name %s", lhs);
+ stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
+ }
+ if (stat != 0)
+ syserr("readaliases: dbm put (%s)", lhs);
+}
+
+
+/*
+** NDBM_MAP_CLOSE -- close the database
+*/
+
+void
+ndbm_map_close(map)
+ register MAP *map;
+{
+ if (tTd(38, 9))
+ printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+
+ if (bitset(MF_WRITABLE, map->map_mflags))
+ {
+#ifdef NIS
+ bool inclnull;
+ char buf[200];
+
+ inclnull = bitset(MF_INCLNULL, map->map_mflags);
+ map->map_mflags &= ~MF_INCLNULL;
+
+ (void) sprintf(buf, "%010ld", curtime());
+ ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
+
+ (void) gethostname(buf, sizeof buf);
+ ndbm_map_store(map, "YP_MASTER_NAME", buf);
+
+ if (inclnull)
+ map->map_mflags |= MF_INCLNULL;
+#endif
+
+ /* write out the distinguished alias */
+ ndbm_map_store(map, "@", "@");
+ }
+ dbm_close((DBM *) map->map_db1);
+}
+
+#endif
+ /*
+** NEWDB (Hash and BTree) Modules
+*/
+
+#ifdef NEWDB
+
+/*
+** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
+**
+** These do rather bizarre locking. If you can lock on open,
+** do that to avoid the condition of opening a database that
+** is being rebuilt. If you don't, we'll try to fake it, but
+** there will be a race condition. If opening for read-only,
+** we immediately release the lock to avoid freezing things up.
+** We really ought to hold the lock, but guarantee that we won't
+** be pokey about it. That's hard to do.
+*/
+
+bool
+bt_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ DB *db;
+ int i;
+ int omode;
+ int fd;
+ struct stat st;
+ char buf[MAXNAME];
+
+ if (tTd(38, 2))
+ printf("bt_map_open(%s, %d)\n", map->map_file, mode);
+
+ omode = mode;
+ if (omode == O_RDWR)
+ {
+ omode |= O_CREAT|O_TRUNC;
+#if defined(O_EXLOCK) && HASFLOCK
+ omode |= O_EXLOCK;
+# if !OLD_NEWDB
+ }
+ else
+ {
+ omode |= O_SHLOCK;
+# endif
+#endif
+ }
+
+ (void) strcpy(buf, map->map_file);
+ i = strlen(buf);
+ if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
+ (void) strcat(buf, ".db");
+ db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
+ if (db == NULL)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".db", FALSE))
+ return TRUE;
+#endif
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot open BTREE database %s", map->map_file);
+ return FALSE;
+ }
+#if !OLD_NEWDB && HASFLOCK
+ fd = db->fd(db);
+# if !defined(O_EXLOCK)
+ if (mode == O_RDWR && fd >= 0)
+ {
+ if (lockfile(fd, map->map_file, ".db", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+# else
+ if (mode == O_RDONLY && fd >= 0)
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+ else
+ map->map_mflags |= MF_LOCKED;
+# endif
+#endif
+
+ /* try to make sure that at least the database header is on disk */
+ if (mode == O_RDWR)
+#if OLD_NEWDB
+ (void) db->sync(db);
+#else
+ (void) db->sync(db, 0);
+
+ if (fd >= 0 && fstat(fd, &st) >= 0)
+ map->map_mtime = st.st_mtime;
+#endif
+
+ map->map_db2 = (void *) db;
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+ if (!aliaswait(map, ".db", TRUE))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+** HASH_MAP_INIT -- HASH-style map initialization
+*/
+
+bool
+hash_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ DB *db;
+ int i;
+ int omode;
+ int fd;
+ struct stat st;
+ char buf[MAXNAME];
+
+ if (tTd(38, 2))
+ printf("hash_map_open(%s, %d)\n", map->map_file, mode);
+
+ omode = mode;
+ if (omode == O_RDWR)
+ {
+ omode |= O_CREAT|O_TRUNC;
+#if defined(O_EXLOCK) && HASFLOCK
+ omode |= O_EXLOCK;
+# if !OLD_NEWDB
+ }
+ else
+ {
+ omode |= O_SHLOCK;
+# endif
+#endif
+ }
+
+ (void) strcpy(buf, map->map_file);
+ i = strlen(buf);
+ if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
+ (void) strcat(buf, ".db");
+ db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
+ if (db == NULL)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".db", FALSE))
+ return TRUE;
+#endif
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot open HASH database %s", map->map_file);
+ return FALSE;
+ }
+#if !OLD_NEWDB && HASFLOCK
+ fd = db->fd(db);
+# if !defined(O_EXLOCK)
+ if (mode == O_RDWR && fd >= 0)
+ {
+ if (lockfile(fd, map->map_file, ".db", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+# else
+ if (mode == O_RDONLY && fd >= 0)
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+ else
+ map->map_mflags |= MF_LOCKED;
+# endif
+#endif
+
+ /* try to make sure that at least the database header is on disk */
+ if (mode == O_RDWR)
+#if OLD_NEWDB
+ (void) db->sync(db);
+#else
+ (void) db->sync(db, 0);
+
+ if (fd >= 0 && fstat(fd, &st) >= 0)
+ map->map_mtime = st.st_mtime;
+#endif
+
+ map->map_db2 = (void *) db;
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+ if (!aliaswait(map, ".db", TRUE))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
+*/
+
+char *
+db_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ DBT key, val;
+ register DB *db = (DB *) map->map_db2;
+ int st;
+ int saveerrno;
+ int fd;
+ char keybuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("db_map_lookup(%s)\n", name);
+
+ key.size = strlen(name);
+ if (key.size > sizeof keybuf - 1)
+ key.size = sizeof keybuf - 1;
+ key.data = keybuf;
+ bcopy(name, keybuf, key.size + 1);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ makelower(keybuf);
+#if !OLD_NEWDB
+ fd = db->fd(db);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
+#endif
+ st = 1;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ st = db->get(db, &key, &val, 0);
+ if (st == 0)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ key.size++;
+ st = db->get(db, &key, &val, 0);
+ if (st == 0)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ saveerrno = errno;
+#if !OLD_NEWDB
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+#endif
+ if (st != 0)
+ {
+ errno = saveerrno;
+ if (st < 0)
+ syserr("db_map_lookup: get (%s)", name);
+ return NULL;
+ }
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, val.data, val.size, av);
+}
+
+
+/*
+** DB_MAP_STORE -- store a datum in the NEWDB database
+*/
+
+void
+db_map_store(map, lhs, rhs)
+ register MAP *map;
+ char *lhs;
+ char *rhs;
+{
+ int stat;
+ DBT key;
+ DBT data;
+ register DB *db = map->map_db2;
+
+ if (tTd(38, 20))
+ printf("db_map_store(%s, %s)\n", lhs, rhs);
+
+ key.size = strlen(lhs);
+ key.data = lhs;
+
+ data.size = strlen(rhs);
+ data.data = rhs;
+
+ if (bitset(MF_INCLNULL, map->map_mflags))
+ {
+ key.size++;
+ data.size++;
+ }
+
+ stat = db->put(db, &key, &data, R_NOOVERWRITE);
+ if (stat > 0)
+ {
+ usrerr("050 Warning: duplicate alias name %s", lhs);
+ stat = db->put(db, &key, &data, 0);
+ }
+ if (stat != 0)
+ syserr("readaliases: db put (%s)", lhs);
+}
+
+
+/*
+** DB_MAP_CLOSE -- add distinguished entries and close the database
+*/
+
+void
+db_map_close(map)
+ MAP *map;
+{
+ register DB *db = map->map_db2;
+
+ if (tTd(38, 9))
+ printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+
+ if (bitset(MF_WRITABLE, map->map_mflags))
+ {
+ /* write out the distinguished alias */
+ db_map_store(map, "@", "@");
+ }
+
+ if (db->close(db) != 0)
+ syserr("readaliases: db close failure");
+}
+
+#endif
+ /*
+** NIS Modules
+*/
+
+# ifdef NIS
+
+# ifndef YPERR_BUSY
+# define YPERR_BUSY 16
+# endif
+
+/*
+** NIS_MAP_OPEN -- open DBM map
+*/
+
+bool
+nis_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ int yperr;
+ register char *p;
+ auto char *vp;
+ auto int vsize;
+ char *master;
+
+ if (tTd(38, 2))
+ printf("nis_map_open(%s)\n", map->map_file);
+
+ if (mode != O_RDONLY)
+ {
+ /* issue a pseudo-error message */
+#ifdef ENOSYS
+ errno = ENOSYS;
+#else
+# ifdef EFTYPE
+ errno = EFTYPE;
+# else
+ errno = ENXIO;
+# endif
+#endif
+ return FALSE;
+ }
+
+ p = strchr(map->map_file, '@');
+ if (p != NULL)
+ {
+ *p++ = '\0';
+ if (*p != '\0')
+ map->map_domain = p;
+ }
+
+ if (*map->map_file == '\0')
+ map->map_file = "mail.aliases";
+
+ if (map->map_domain == NULL)
+ {
+ yperr = yp_get_default_domain(&map->map_domain);
+ if (yperr != 0)
+ {
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("NIS map %s specified, but NIS not running\n",
+ map->map_file);
+ return FALSE;
+ }
+ }
+
+ /* check to see if this map actually exists */
+ yperr = yp_match(map->map_domain, map->map_file, "@", 1,
+ &vp, &vsize);
+ if (tTd(38, 10))
+ printf("nis_map_open: yp_match(%s, %s) => %s\n",
+ map->map_domain, map->map_file, yperr_string(yperr));
+ if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
+ return TRUE;
+
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot bind to domain %s: %s", map->map_domain,
+ yperr_string(yperr));
+
+ return FALSE;
+}
+
+
+/*
+** NIS_MAP_LOOKUP -- look up a datum in a NIS map
+*/
+
+char *
+nis_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ char *vp;
+ auto int vsize;
+ int buflen;
+ int yperr;
+ char keybuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("nis_map_lookup(%s)\n", name);
+
+ buflen = strlen(name);
+ if (buflen > sizeof keybuf - 1)
+ buflen = sizeof keybuf - 1;
+ bcopy(name, keybuf, buflen + 1);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ makelower(keybuf);
+ yperr = YPERR_KEY;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
+ &vp, &vsize);
+ if (yperr == 0)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ buflen++;
+ yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
+ &vp, &vsize);
+ if (yperr == 0)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ if (yperr != 0)
+ {
+ if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
+ map->map_mflags &= ~(MF_VALID|MF_OPEN);
+ return NULL;
+ }
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, vp, vsize, av);
+}
+
+
+/*
+** NIS_MAP_STORE
+*/
+
+void
+nis_map_store(map, lhs, rhs)
+ MAP *map;
+ char *lhs;
+ char *rhs;
+{
+ /* nothing */
+}
+
+
+/*
+** NIS_MAP_CLOSE
+*/
+
+void
+nis_map_close(map)
+ MAP *map;
+{
+ /* nothing */
+}
+
+#endif /* NIS */
+ /*
+** STAB (Symbol Table) Modules
+*/
+
+
+/*
+** STAB_MAP_LOOKUP -- look up alias in symbol table
+*/
+
+char *
+stab_map_lookup(map, name, av, pstat)
+ register MAP *map;
+ char *name;
+ char **av;
+ int *pstat;
+{
+ register STAB *s;
+
+ if (tTd(38, 20))
+ printf("stab_lookup(%s)\n", name);
+
+ s = stab(name, ST_ALIAS, ST_FIND);
+ if (s != NULL)
+ return (s->s_alias);
+ return (NULL);
+}
+
+
+/*
+** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
+*/
+
+void
+stab_map_store(map, lhs, rhs)
+ register MAP *map;
+ char *lhs;
+ char *rhs;
+{
+ register STAB *s;
+
+ s = stab(lhs, ST_ALIAS, ST_ENTER);
+ s->s_alias = newstr(rhs);
+}
+
+
+/*
+** STAB_MAP_OPEN -- initialize (reads data file)
+**
+** This is a wierd case -- it is only intended as a fallback for
+** aliases. For this reason, opens for write (only during a
+** "newaliases") always fails, and opens for read open the
+** actual underlying text file instead of the database.
+*/
+
+bool
+stab_map_open(map, mode)
+ register MAP *map;
+ int mode;
+{
+ FILE *af;
+ struct stat st;
+
+ if (tTd(38, 2))
+ printf("stab_map_open(%s)\n", map->map_file);
+
+ if (mode != O_RDONLY)
+ {
+ errno = ENODEV;
+ return FALSE;
+ }
+
+ af = fopen(map->map_file, "r");
+ if (af == NULL)
+ return FALSE;
+ readaliases(map, af, TRUE);
+
+ if (fstat(fileno(af), &st) >= 0)
+ map->map_mtime = st.st_mtime;
+ fclose(af);
+
+ return TRUE;
+}
+
+
+/*
+** STAB_MAP_CLOSE -- close symbol table.
+**
+** Since this is in memory, there is nothing to do.
+*/
+
+void
+stab_map_close(map)
+ MAP *map;
+{
+ /* ignore it */
+}
+ /*
+** Implicit Modules
+**
+** Tries several types. For back compatibility of aliases.
+*/
+
+
+/*
+** IMPL_MAP_LOOKUP -- lookup in best open database
+*/
+
+char *
+impl_map_lookup(map, name, av, pstat)
+ MAP *map;
+ char *name;
+ char **av;
+ int *pstat;
+{
+ if (tTd(38, 20))
+ printf("impl_map_lookup(%s)\n", name);
+
+#ifdef NEWDB
+ if (bitset(MF_IMPL_HASH, map->map_mflags))
+ return db_map_lookup(map, name, av, pstat);
+#endif
+#ifdef NDBM
+ if (bitset(MF_IMPL_NDBM, map->map_mflags))
+ return ndbm_map_lookup(map, name, av, pstat);
+#endif
+ return stab_map_lookup(map, name, av, pstat);
+}
+
+/*
+** IMPL_MAP_STORE -- store in open databases
+*/
+
+void
+impl_map_store(map, lhs, rhs)
+ MAP *map;
+ char *lhs;
+ char *rhs;
+{
+#ifdef NEWDB
+ if (bitset(MF_IMPL_HASH, map->map_mflags))
+ db_map_store(map, lhs, rhs);
+#endif
+#ifdef NDBM
+ if (bitset(MF_IMPL_NDBM, map->map_mflags))
+ ndbm_map_store(map, lhs, rhs);
+#endif
+ stab_map_store(map, lhs, rhs);
+}
+
+/*
+** IMPL_MAP_OPEN -- implicit database open
+*/
+
+bool
+impl_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ struct stat stb;
+
+ if (tTd(38, 2))
+ printf("impl_map_open(%s, %d)\n", map->map_file, mode);
+
+ if (stat(map->map_file, &stb) < 0)
+ {
+ /* no alias file at all */
+ if (tTd(38, 3))
+ printf("no map file\n");
+ return FALSE;
+ }
+
+#ifdef NEWDB
+ map->map_mflags |= MF_IMPL_HASH;
+ if (hash_map_open(map, mode))
+ {
+#if defined(NDBM) && defined(NIS)
+ if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
+#endif
+ return TRUE;
+ }
+ else
+ map->map_mflags &= ~MF_IMPL_HASH;
+#endif
+#ifdef NDBM
+ map->map_mflags |= MF_IMPL_NDBM;
+ if (ndbm_map_open(map, mode))
+ {
+ return TRUE;
+ }
+ else
+ map->map_mflags &= ~MF_IMPL_NDBM;
+#endif
+
+#if defined(NEWDB) || defined(NDBM)
+ if (Verbose)
+ message("WARNING: cannot open alias database %s", map->map_file);
+#else
+ if (mode != O_RDONLY)
+ usrerr("Cannot rebuild aliases: no database format defined");
+#endif
+
+ return stab_map_open(map, mode);
+}
+
+
+/*
+** IMPL_MAP_CLOSE -- close any open database(s)
+*/
+
+void
+impl_map_close(map)
+ MAP *map;
+{
+#ifdef NEWDB
+ if (bitset(MF_IMPL_HASH, map->map_mflags))
+ {
+ db_map_close(map);
+ map->map_mflags &= ~MF_IMPL_HASH;
+ }
+#endif
+
+#ifdef NDBM
+ if (bitset(MF_IMPL_NDBM, map->map_mflags))
+ {
+ ndbm_map_close(map);
+ map->map_mflags &= ~MF_IMPL_NDBM;
+ }
+#endif
+}
+ /*
+** NULL stubs
+*/
+
+bool
+null_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ return TRUE;
+}
+
+void
+null_map_close(map)
+ MAP *map;
+{
+ return;
+}
+
+void
+null_map_store(map, key, val)
+ MAP *map;
+ char *key;
+ char *val;
+{
+ return;
+}
diff --git a/usr.sbin/sendmail/src/mci.c b/usr.sbin/sendmail/src/mci.c
new file mode 100644
index 00000000000..8211a6280d0
--- /dev/null
+++ b/usr.sbin/sendmail/src/mci.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)mci.c 8.14 (Berkeley) 5/15/94";
+#endif /* not lint */
+
+#include "sendmail.h"
+
+/*
+** Mail Connection Information (MCI) Caching Module.
+**
+** There are actually two separate things cached. The first is
+** the set of all open connections -- these are stored in a
+** (small) list. The second is stored in the symbol table; it
+** has the overall status for all hosts, whether or not there
+** is a connection open currently.
+**
+** There should never be too many connections open (since this
+** could flood the socket table), nor should a connection be
+** allowed to sit idly for too long.
+**
+** MaxMciCache is the maximum number of open connections that
+** will be supported.
+**
+** MciCacheTimeout is the time (in seconds) that a connection
+** is permitted to survive without activity.
+**
+** We actually try any cached connections by sending a NOOP
+** before we use them; if the NOOP fails we close down the
+** connection and reopen it. Note that this means that a
+** server SMTP that doesn't support NOOP will hose the
+** algorithm -- but that doesn't seem too likely.
+*/
+
+MCI **MciCache; /* the open connection cache */
+ /*
+** MCI_CACHE -- enter a connection structure into the open connection cache
+**
+** This may cause something else to be flushed.
+**
+** Parameters:
+** mci -- the connection to cache.
+**
+** Returns:
+** none.
+*/
+
+mci_cache(mci)
+ register MCI *mci;
+{
+ register MCI **mcislot;
+ extern MCI **mci_scan();
+
+ /*
+ ** Find the best slot. This may cause expired connections
+ ** to be closed.
+ */
+
+ mcislot = mci_scan(mci);
+ if (mcislot == NULL)
+ {
+ /* we don't support caching */
+ return;
+ }
+
+ /* if this is already cached, we are done */
+ if (bitset(MCIF_CACHED, mci->mci_flags))
+ return;
+
+ /* otherwise we may have to clear the slot */
+ if (*mcislot != NULL)
+ mci_uncache(mcislot, TRUE);
+
+ if (tTd(42, 5))
+ printf("mci_cache: caching %x (%s) in slot %d\n",
+ mci, mci->mci_host, mcislot - MciCache);
+#ifdef LOG
+ if (tTd(91, 100))
+ syslog(LOG_DEBUG, "%s: mci_cache: caching %x (%s) in slot %d",
+ CurEnv->e_id ? CurEnv->e_id : "NOQUEUE",
+ mci, mci->mci_host, mcislot - MciCache);
+#endif
+
+ *mcislot = mci;
+ mci->mci_flags |= MCIF_CACHED;
+}
+ /*
+** MCI_SCAN -- scan the cache, flush junk, and return best slot
+**
+** Parameters:
+** savemci -- never flush this one. Can be null.
+**
+** Returns:
+** The LRU (or empty) slot.
+*/
+
+MCI **
+mci_scan(savemci)
+ MCI *savemci;
+{
+ time_t now;
+ register MCI **bestmci;
+ register MCI *mci;
+ register int i;
+
+ if (MaxMciCache <= 0)
+ {
+ /* we don't support caching */
+ return NULL;
+ }
+
+ if (MciCache == NULL)
+ {
+ /* first call */
+ MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
+ bzero((char *) MciCache, MaxMciCache * sizeof *MciCache);
+ return (&MciCache[0]);
+ }
+
+ now = curtime();
+ bestmci = &MciCache[0];
+ for (i = 0; i < MaxMciCache; i++)
+ {
+ mci = MciCache[i];
+ if (mci == NULL || mci->mci_state == MCIS_CLOSED)
+ {
+ bestmci = &MciCache[i];
+ continue;
+ }
+ if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci)
+ {
+ /* connection idle too long -- close it */
+ bestmci = &MciCache[i];
+ mci_uncache(bestmci, TRUE);
+ continue;
+ }
+ if (*bestmci == NULL)
+ continue;
+ if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
+ bestmci = &MciCache[i];
+ }
+ return bestmci;
+}
+ /*
+** MCI_UNCACHE -- remove a connection from a slot.
+**
+** May close a connection.
+**
+** Parameters:
+** mcislot -- the slot to empty.
+** doquit -- if TRUE, send QUIT protocol on this connection.
+** if FALSE, we are assumed to be in a forked child;
+** all we want to do is close the file(s).
+**
+** Returns:
+** none.
+*/
+
+mci_uncache(mcislot, doquit)
+ register MCI **mcislot;
+ bool doquit;
+{
+ register MCI *mci;
+ extern ENVELOPE BlankEnvelope;
+
+ mci = *mcislot;
+ if (mci == NULL)
+ return;
+ *mcislot = NULL;
+
+ if (tTd(42, 5))
+ printf("mci_uncache: uncaching %x (%s) from slot %d (%d)\n",
+ mci, mci->mci_host, mcislot - MciCache, doquit);
+#ifdef LOG
+ if (tTd(91, 100))
+ syslog(LOG_DEBUG, "%s: mci_uncache: uncaching %x (%s) from slot %d (%d)",
+ CurEnv->e_id ? CurEnv->e_id : "NOQUEUE",
+ mci, mci->mci_host, mcislot - MciCache, doquit);
+#endif
+
+ if (doquit)
+ {
+ message("Closing connection to %s", mci->mci_host);
+
+ mci->mci_flags &= ~MCIF_CACHED;
+
+ /* only uses the envelope to flush the transcript file */
+ if (mci->mci_state != MCIS_CLOSED)
+ smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
+#ifdef XLA
+ xla_host_end(mci->mci_host);
+#endif
+ }
+ else
+ {
+ if (mci->mci_in != NULL)
+ xfclose(mci->mci_in, "mci_uncache", "mci_in");
+ if (mci->mci_out != NULL)
+ xfclose(mci->mci_out, "mci_uncache", "mci_out");
+ mci->mci_in = mci->mci_out = NULL;
+ mci->mci_state = MCIS_CLOSED;
+ mci->mci_exitstat = EX_OK;
+ mci->mci_errno = 0;
+ mci->mci_flags = 0;
+ }
+}
+ /*
+** MCI_FLUSH -- flush the entire cache
+**
+** Parameters:
+** doquit -- if TRUE, send QUIT protocol.
+** if FALSE, just close the connection.
+** allbut -- but leave this one open.
+**
+** Returns:
+** none.
+*/
+
+mci_flush(doquit, allbut)
+ bool doquit;
+ MCI *allbut;
+{
+ register int i;
+
+ if (MciCache == NULL)
+ return;
+
+ for (i = 0; i < MaxMciCache; i++)
+ if (allbut != MciCache[i])
+ mci_uncache(&MciCache[i], doquit);
+}
+ /*
+** MCI_GET -- get information about a particular host
+*/
+
+MCI *
+mci_get(host, m)
+ char *host;
+ MAILER *m;
+{
+ register MCI *mci;
+ register STAB *s;
+ extern MCI **mci_scan();
+
+#ifdef DAEMON
+ extern SOCKADDR CurHostAddr;
+
+ /* clear CurHostAddr so we don't get a bogus address with this name */
+ bzero(&CurHostAddr, sizeof CurHostAddr);
+#endif
+
+ /* clear out any expired connections */
+ (void) mci_scan(NULL);
+
+ if (m->m_mno < 0)
+ syserr("negative mno %d (%s)", m->m_mno, m->m_name);
+ s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
+ mci = &s->s_mci;
+ mci->mci_host = s->s_name;
+
+ if (tTd(42, 2))
+ {
+ printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
+ host, m->m_name, mci->mci_state, mci->mci_flags,
+ mci->mci_exitstat, mci->mci_errno);
+ }
+
+ if (mci->mci_state == MCIS_OPEN)
+ {
+ /* poke the connection to see if it's still alive */
+ smtpprobe(mci);
+
+ /* reset the stored state in the event of a timeout */
+ if (mci->mci_state != MCIS_OPEN)
+ {
+ mci->mci_errno = 0;
+ mci->mci_exitstat = EX_OK;
+ mci->mci_state = MCIS_CLOSED;
+ }
+ else
+ {
+ /* get peer host address for logging reasons only */
+ /* (this should really be in the mci struct) */
+ int socksize = sizeof CurHostAddr;
+
+ (void) getpeername(fileno(mci->mci_in),
+ (struct sockaddr *) &CurHostAddr, &socksize);
+ }
+ }
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ /* copy out any mailer flags needed in connection state */
+ if (bitnset(M_7BITS, m->m_flags))
+ mci->mci_flags |= MCIF_7BIT;
+ }
+
+ return mci;
+}
+ /*
+** MCI_DUMP -- dump the contents of an MCI structure.
+**
+** Parameters:
+** mci -- the MCI structure to dump.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+mci_dump(mci, logit)
+ register MCI *mci;
+ bool logit;
+{
+ register char *p;
+ char *sep;
+ char buf[1000];
+ extern char *ctime();
+
+ sep = logit ? " " : "\n\t";
+ p = buf;
+ sprintf(p, "MCI@%x: ", mci);
+ p += strlen(p);
+ if (mci == NULL)
+ {
+ sprintf(p, "NULL");
+ goto printit;
+ }
+ sprintf(p, "flags=%o, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
+ mci->mci_flags, mci->mci_errno, mci->mci_herrno,
+ mci->mci_exitstat, mci->mci_state, mci->mci_pid, sep);
+ p += strlen(p);
+ sprintf(p, "maxsize=%ld, phase=%s, mailer=%s,%s",
+ mci->mci_maxsize,
+ mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
+ mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
+ sep);
+ p += strlen(p);
+ sprintf(p, "host=%s, lastuse=%s",
+ mci->mci_host == NULL ? "NULL" : mci->mci_host,
+ ctime(&mci->mci_lastuse));
+printit:
+#ifdef LOG
+ if (logit)
+ syslog(LOG_DEBUG, "%s", buf);
+ else
+#endif
+ printf("%s\n", buf);
+}
+ /*
+** MCI_DUMP_ALL -- print the entire MCI cache
+**
+** Parameters:
+** logit -- if set, log the result instead of printing
+** to stdout.
+**
+** Returns:
+** none.
+*/
+
+mci_dump_all(logit)
+ bool logit;
+{
+ register int i;
+
+ if (MciCache == NULL)
+ return;
+
+ for (i = 0; i < MaxMciCache; i++)
+ mci_dump(MciCache[i], logit);
+}
diff --git a/usr.sbin/sendmail/src/newaliases.1 b/usr.sbin/sendmail/src/newaliases.1
new file mode 100644
index 00000000000..c611b78b62b
--- /dev/null
+++ b/usr.sbin/sendmail/src/newaliases.1
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1985, 1990, 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.
+.\"
+.\" @(#)newaliases.1 8.4 (Berkeley) 2/22/94
+.\"
+.Dd February 22, 1994
+.Dt NEWALIASES 1
+.Os BSD 4
+.Sh NAME
+.Nm newaliases
+.Nd rebuild the data base for the mail aliases file
+.Sh SYNOPSIS
+.Nm newaliases
+.Sh DESCRIPTION
+.Nm Newaliases
+rebuilds the random access data base for the mail aliases file
+.Pa /etc/aliases .
+It must be run each time this file is changed in order
+for the change to take effect.
+.Pp
+.Nm Newaliases
+is identical to
+.Dq Li "sendmail -bi" .
+.Pp
+The
+.Nm newaliases
+utility exits 0 on success, and >0 if an error occurs.
+.Sh FILES
+.Bl -tag -width /etc/aliases -compact
+.It Pa /etc/aliases
+The mail aliases file
+.El
+.Sh SEE ALSO
+.Xr aliases 5 ,
+.Xr sendmail 8
+.Sh HISTORY
+The
+.Nm newaliases
+command appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/sendmail/src/parseaddr.c b/usr.sbin/sendmail/src/parseaddr.c
new file mode 100644
index 00000000000..00621c25345
--- /dev/null
+++ b/usr.sbin/sendmail/src/parseaddr.c
@@ -0,0 +1,1964 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)parseaddr.c 8.31 (Berkeley) 4/15/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** PARSEADDR -- Parse an address
+**
+** Parses an address and breaks it up into three parts: a
+** net to transmit the message on, the host to transmit it
+** to, and a user on that host. These are loaded into an
+** ADDRESS header with the values squirreled away if necessary.
+** The "user" part may not be a real user; the process may
+** just reoccur on that machine. For example, on a machine
+** with an arpanet connection, the address
+** csvax.bill@berkeley
+** will break up to a "user" of 'csvax.bill' and a host
+** of 'berkeley' -- to be transmitted over the arpanet.
+**
+** Parameters:
+** addr -- the address to parse.
+** a -- a pointer to the address descriptor buffer.
+** If NULL, a header will be created.
+** flags -- describe detail for parsing. See RF_ definitions
+** in sendmail.h.
+** delim -- the character to terminate the address, passed
+** to prescan.
+** delimptr -- if non-NULL, set to the location of the
+** delim character that was found.
+** e -- the envelope that will contain this address.
+**
+** Returns:
+** A pointer to the address descriptor header (`a' if
+** `a' is non-NULL).
+** NULL on error.
+**
+** Side Effects:
+** none
+*/
+
+/* following delimiters are inherent to the internal algorithms */
+# define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
+
+ADDRESS *
+parseaddr(addr, a, flags, delim, delimptr, e)
+ char *addr;
+ register ADDRESS *a;
+ int flags;
+ int delim;
+ char **delimptr;
+ register ENVELOPE *e;
+{
+ register char **pvp;
+ auto char *delimptrbuf;
+ bool queueup;
+ char pvpbuf[PSBUFSIZE];
+ extern ADDRESS *buildaddr();
+ extern bool invalidaddr();
+
+ /*
+ ** Initialize and prescan address.
+ */
+
+ e->e_to = addr;
+ if (tTd(20, 1))
+ printf("\n--parseaddr(%s)\n", addr);
+
+ if (delimptr == NULL)
+ delimptr = &delimptrbuf;
+
+ pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr);
+ if (pvp == NULL)
+ {
+ if (tTd(20, 1))
+ printf("parseaddr-->NULL\n");
+ return (NULL);
+ }
+
+ if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
+ {
+ if (tTd(20, 1))
+ printf("parseaddr-->bad address\n");
+ return NULL;
+ }
+
+ /*
+ ** Save addr if we are going to have to.
+ **
+ ** We have to do this early because there is a chance that
+ ** the map lookups in the rewriting rules could clobber
+ ** static memory somewhere.
+ */
+
+ if (bitset(RF_COPYPADDR, flags) && addr != NULL)
+ {
+ char savec = **delimptr;
+
+ if (savec != '\0')
+ **delimptr = '\0';
+ e->e_to = addr = newstr(addr);
+ if (savec != '\0')
+ **delimptr = savec;
+ }
+
+ /*
+ ** Apply rewriting rules.
+ ** Ruleset 0 does basic parsing. It must resolve.
+ */
+
+ queueup = FALSE;
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
+ queueup = TRUE;
+ if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
+ queueup = TRUE;
+
+
+ /*
+ ** Build canonical address from pvp.
+ */
+
+ a = buildaddr(pvp, a, flags, e);
+
+ /*
+ ** Make local copies of the host & user and then
+ ** transport them out.
+ */
+
+ allocaddr(a, flags, addr);
+ if (bitset(QBADADDR, a->q_flags))
+ return a;
+
+ /*
+ ** If there was a parsing failure, mark it for queueing.
+ */
+
+ if (queueup)
+ {
+ char *msg = "Transient parse error -- message queued for future delivery";
+
+ if (tTd(20, 1))
+ printf("parseaddr: queuing message\n");
+ message(msg);
+ if (e->e_message == NULL)
+ e->e_message = newstr(msg);
+ a->q_flags |= QQUEUEUP;
+ }
+
+ /*
+ ** Compute return value.
+ */
+
+ if (tTd(20, 1))
+ {
+ printf("parseaddr-->");
+ printaddr(a, FALSE);
+ }
+
+ return (a);
+}
+ /*
+** INVALIDADDR -- check for address containing meta-characters
+**
+** Parameters:
+** addr -- the address to check.
+**
+** Returns:
+** TRUE -- if the address has any "wierd" characters
+** FALSE -- otherwise.
+*/
+
+bool
+invalidaddr(addr, delimptr)
+ register char *addr;
+ char *delimptr;
+{
+ char savedelim;
+
+ if (delimptr != NULL)
+ {
+ savedelim = *delimptr;
+ if (savedelim != '\0')
+ *delimptr = '\0';
+ }
+#if 0
+ /* for testing.... */
+ if (strcmp(addr, "INvalidADDR") == 0)
+ {
+ usrerr("553 INvalid ADDRess");
+ goto addrfailure;
+ }
+#endif
+ for (; *addr != '\0'; addr++)
+ {
+ if ((*addr & 0340) == 0200)
+ break;
+ }
+ if (*addr == '\0')
+ {
+ if (savedelim != '\0' && delimptr != NULL)
+ *delimptr = savedelim;
+ return FALSE;
+ }
+ setstat(EX_USAGE);
+ usrerr("553 Address contained invalid control characters");
+ addrfailure:
+ if (savedelim != '\0' && delimptr != NULL)
+ *delimptr = savedelim;
+ return TRUE;
+}
+ /*
+** ALLOCADDR -- do local allocations of address on demand.
+**
+** Also lowercases the host name if requested.
+**
+** Parameters:
+** a -- the address to reallocate.
+** flags -- the copy flag (see RF_ definitions in sendmail.h
+** for a description).
+** paddr -- the printname of the address.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Copies portions of a into local buffers as requested.
+*/
+
+allocaddr(a, flags, paddr)
+ register ADDRESS *a;
+ int flags;
+ char *paddr;
+{
+ if (tTd(24, 4))
+ printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr);
+
+ a->q_paddr = paddr;
+
+ if (a->q_user == NULL)
+ a->q_user = "";
+ if (a->q_host == NULL)
+ a->q_host = "";
+
+ if (bitset(RF_COPYPARSE, flags))
+ {
+ a->q_host = newstr(a->q_host);
+ if (a->q_user != a->q_paddr)
+ a->q_user = newstr(a->q_user);
+ }
+
+ if (a->q_paddr == NULL)
+ a->q_paddr = a->q_user;
+}
+ /*
+** PRESCAN -- Prescan name and make it canonical
+**
+** Scans a name and turns it into a set of tokens. This process
+** deletes blanks and comments (in parentheses).
+**
+** This routine knows about quoted strings and angle brackets.
+**
+** There are certain subtleties to this routine. The one that
+** comes to mind now is that backslashes on the ends of names
+** are silently stripped off; this is intentional. The problem
+** is that some versions of sndmsg (like at LBL) set the kill
+** character to something other than @ when reading addresses;
+** so people type "csvax.eric\@berkeley" -- which screws up the
+** berknet mailer.
+**
+** Parameters:
+** addr -- the name to chomp.
+** delim -- the delimiter for the address, normally
+** '\0' or ','; \0 is accepted in any case.
+** If '\t' then we are reading the .cf file.
+** pvpbuf -- place to put the saved text -- note that
+** the pointers are static.
+** pvpbsize -- size of pvpbuf.
+** delimptr -- if non-NULL, set to the location of the
+** terminating delimiter.
+**
+** Returns:
+** A pointer to a vector of tokens.
+** NULL on error.
+*/
+
+/* states and character types */
+# define OPR 0 /* operator */
+# define ATM 1 /* atom */
+# define QST 2 /* in quoted string */
+# define SPC 3 /* chewing up spaces */
+# define ONE 4 /* pick up one character */
+
+# define NSTATES 5 /* number of states */
+# define TYPE 017 /* mask to select state type */
+
+/* meta bits for table */
+# define M 020 /* meta character; don't pass through */
+# define B 040 /* cause a break */
+# define MB M|B /* meta-break */
+
+static short StateTab[NSTATES][NSTATES] =
+{
+ /* oldst chtype> OPR ATM QST SPC ONE */
+ /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B,
+ /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B,
+ /*QST*/ QST, QST, OPR, QST, QST,
+ /*SPC*/ OPR, ATM, QST, SPC|M, ONE,
+ /*ONE*/ OPR, OPR, OPR, OPR, OPR,
+};
+
+/* token type table -- it gets modified with $o characters */
+static TokTypeTab[256] =
+{
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
+ OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+};
+
+#define toktype(c) ((int) TokTypeTab[(c) & 0xff])
+
+
+# define NOCHAR -1 /* signal nothing in lookahead token */
+
+char **
+prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
+ char *addr;
+ char delim;
+ char pvpbuf[];
+ char **delimptr;
+{
+ register char *p;
+ register char *q;
+ register int c;
+ char **avp;
+ bool bslashmode;
+ int cmntcnt;
+ int anglecnt;
+ char *tok;
+ int state;
+ int newstate;
+ char *saveto = CurEnv->e_to;
+ static char *av[MAXATOM+1];
+ static char firsttime = TRUE;
+ extern int errno;
+
+ if (firsttime)
+ {
+ /* initialize the token type table */
+ char obuf[50];
+
+ firsttime = FALSE;
+ expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv);
+ strcat(obuf, DELIMCHARS);
+ for (p = obuf; *p != '\0'; p++)
+ {
+ if (TokTypeTab[*p & 0xff] == ATM)
+ TokTypeTab[*p & 0xff] = OPR;
+ }
+ }
+
+ /* make sure error messages don't have garbage on them */
+ errno = 0;
+
+ q = pvpbuf;
+ bslashmode = FALSE;
+ cmntcnt = 0;
+ anglecnt = 0;
+ avp = av;
+ state = ATM;
+ c = NOCHAR;
+ p = addr;
+ CurEnv->e_to = p;
+ if (tTd(22, 11))
+ {
+ printf("prescan: ");
+ xputs(p);
+ (void) putchar('\n');
+ }
+
+ do
+ {
+ /* read a token */
+ tok = q;
+ for (;;)
+ {
+ /* store away any old lookahead character */
+ if (c != NOCHAR && !bslashmode)
+ {
+ /* see if there is room */
+ if (q >= &pvpbuf[pvpbsize - 5])
+ {
+ usrerr("553 Address too long");
+ returnnull:
+ if (delimptr != NULL)
+ *delimptr = p;
+ CurEnv->e_to = saveto;
+ return (NULL);
+ }
+
+ /* squirrel it away */
+ *q++ = c;
+ }
+
+ /* read a new input character */
+ c = *p++;
+ if (c == '\0')
+ {
+ /* diagnose and patch up bad syntax */
+ if (state == QST)
+ {
+ usrerr("653 Unbalanced '\"'");
+ c = '"';
+ }
+ else if (cmntcnt > 0)
+ {
+ usrerr("653 Unbalanced '('");
+ c = ')';
+ }
+ else if (anglecnt > 0)
+ {
+ c = '>';
+ usrerr("653 Unbalanced '<'");
+ }
+ else
+ break;
+
+ p--;
+ }
+ else if (c == delim && anglecnt <= 0 &&
+ cmntcnt <= 0 && state != QST)
+ break;
+
+ if (tTd(22, 101))
+ printf("c=%c, s=%d; ", c, state);
+
+ /* chew up special characters */
+ *q = '\0';
+ if (bslashmode)
+ {
+ bslashmode = FALSE;
+
+ /* kludge \! for naive users */
+ if (cmntcnt > 0)
+ {
+ c = NOCHAR;
+ continue;
+ }
+ else if (c != '!' || state == QST)
+ {
+ *q++ = '\\';
+ continue;
+ }
+ }
+
+ if (c == '\\')
+ {
+ bslashmode = TRUE;
+ }
+ else if (state == QST)
+ {
+ /* do nothing, just avoid next clauses */
+ }
+ else if (c == '(')
+ {
+ cmntcnt++;
+ c = NOCHAR;
+ }
+ else if (c == ')')
+ {
+ if (cmntcnt <= 0)
+ {
+ usrerr("653 Unbalanced ')'");
+ c = NOCHAR;
+ }
+ else
+ cmntcnt--;
+ }
+ else if (cmntcnt > 0)
+ c = NOCHAR;
+ else if (c == '<')
+ anglecnt++;
+ else if (c == '>')
+ {
+ if (anglecnt <= 0)
+ {
+ usrerr("653 Unbalanced '>'");
+ c = NOCHAR;
+ }
+ else
+ anglecnt--;
+ }
+ else if (delim == ' ' && isascii(c) && isspace(c))
+ c = ' ';
+
+ if (c == NOCHAR)
+ continue;
+
+ /* see if this is end of input */
+ if (c == delim && anglecnt <= 0 && state != QST)
+ break;
+
+ newstate = StateTab[state][toktype(c)];
+ if (tTd(22, 101))
+ printf("ns=%02o\n", newstate);
+ state = newstate & TYPE;
+ if (bitset(M, newstate))
+ c = NOCHAR;
+ if (bitset(B, newstate))
+ break;
+ }
+
+ /* new token */
+ if (tok != q)
+ {
+ *q++ = '\0';
+ if (tTd(22, 36))
+ {
+ printf("tok=");
+ xputs(tok);
+ (void) putchar('\n');
+ }
+ if (avp >= &av[MAXATOM])
+ {
+ syserr("553 prescan: too many tokens");
+ goto returnnull;
+ }
+ if (q - tok > MAXNAME)
+ {
+ syserr("553 prescan: token too long");
+ goto returnnull;
+ }
+ *avp++ = tok;
+ }
+ } while (c != '\0' && (c != delim || anglecnt > 0));
+ *avp = NULL;
+ p--;
+ if (delimptr != NULL)
+ *delimptr = p;
+ if (tTd(22, 12))
+ {
+ printf("prescan==>");
+ printav(av);
+ }
+ CurEnv->e_to = saveto;
+ if (av[0] == NULL)
+ {
+ if (tTd(22, 1))
+ printf("prescan: null leading token\n");
+ return (NULL);
+ }
+ return (av);
+}
+ /*
+** REWRITE -- apply rewrite rules to token vector.
+**
+** This routine is an ordered production system. Each rewrite
+** rule has a LHS (called the pattern) and a RHS (called the
+** rewrite); 'rwr' points the the current rewrite rule.
+**
+** For each rewrite rule, 'avp' points the address vector we
+** are trying to match against, and 'pvp' points to the pattern.
+** If pvp points to a special match value (MATCHZANY, MATCHANY,
+** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
+** matched is saved away in the match vector (pointed to by 'mvp').
+**
+** When a match between avp & pvp does not match, we try to
+** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
+** we must also back out the match in mvp. If we reach a
+** MATCHANY or MATCHZANY we just extend the match and start
+** over again.
+**
+** When we finally match, we rewrite the address vector
+** and try over again.
+**
+** Parameters:
+** pvp -- pointer to token vector.
+** ruleset -- the ruleset to use for rewriting.
+** reclevel -- recursion level (to catch loops).
+** e -- the current envelope.
+**
+** Returns:
+** A status code. If EX_TEMPFAIL, higher level code should
+** attempt recovery.
+**
+** Side Effects:
+** pvp is modified.
+*/
+
+struct match
+{
+ char **first; /* first token matched */
+ char **last; /* last token matched */
+ char **pattern; /* pointer to pattern */
+};
+
+# define MAXMATCH 9 /* max params per rewrite */
+
+# ifndef MAXRULERECURSION
+# define MAXRULERECURSION 50 /* max recursion depth */
+# endif
+
+
+int
+rewrite(pvp, ruleset, reclevel, e)
+ char **pvp;
+ int ruleset;
+ int reclevel;
+ register ENVELOPE *e;
+{
+ register char *ap; /* address pointer */
+ register char *rp; /* rewrite pointer */
+ register char **avp; /* address vector pointer */
+ register char **rvp; /* rewrite vector pointer */
+ register struct match *mlp; /* cur ptr into mlist */
+ register struct rewrite *rwr; /* pointer to current rewrite rule */
+ int ruleno; /* current rule number */
+ int rstat = EX_OK; /* return status */
+ int loopcount;
+ struct match mlist[MAXMATCH]; /* stores match on LHS */
+ char *npvp[MAXATOM+1]; /* temporary space for rebuild */
+
+ if (OpMode == MD_TEST || tTd(21, 2))
+ {
+ printf("rewrite: ruleset %2d input:", ruleset);
+ printav(pvp);
+ }
+ if (ruleset < 0 || ruleset >= MAXRWSETS)
+ {
+ syserr("554 rewrite: illegal ruleset number %d", ruleset);
+ return EX_CONFIG;
+ }
+ if (reclevel++ > MAXRULERECURSION)
+ {
+ syserr("rewrite: infinite recursion, ruleset %d", ruleset);
+ return EX_CONFIG;
+ }
+ if (pvp == NULL)
+ return EX_USAGE;
+
+ /*
+ ** Run through the list of rewrite rules, applying
+ ** any that match.
+ */
+
+ ruleno = 1;
+ loopcount = 0;
+ for (rwr = RewriteRules[ruleset]; rwr != NULL; )
+ {
+ if (tTd(21, 12))
+ {
+ printf("-----trying rule:");
+ printav(rwr->r_lhs);
+ }
+
+ /* try to match on this rule */
+ mlp = mlist;
+ rvp = rwr->r_lhs;
+ avp = pvp;
+ if (++loopcount > 100)
+ {
+ syserr("554 Infinite loop in ruleset %d, rule %d",
+ ruleset, ruleno);
+ if (tTd(21, 1))
+ {
+ printf("workspace: ");
+ printav(pvp);
+ }
+ break;
+ }
+
+ while ((ap = *avp) != NULL || *rvp != NULL)
+ {
+ rp = *rvp;
+ if (tTd(21, 35))
+ {
+ printf("ADVANCE rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
+ }
+ if (rp == NULL)
+ {
+ /* end-of-pattern before end-of-address */
+ goto backup;
+ }
+ if (ap == NULL && (*rp & 0377) != MATCHZANY &&
+ (*rp & 0377) != MATCHZERO)
+ {
+ /* end-of-input with patterns left */
+ goto backup;
+ }
+
+ switch (*rp & 0377)
+ {
+ register STAB *s;
+ char buf[MAXLINE];
+
+ case MATCHCLASS:
+ /* match any phrase in a class */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ extendclass:
+ ap = *avp;
+ if (ap == NULL)
+ goto backup;
+ mlp->last = avp++;
+ cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
+ s = stab(buf, ST_CLASS, ST_FIND);
+ if (s == NULL || !bitnset(rp[1], s->s_class))
+ {
+ if (tTd(21, 36))
+ {
+ printf("EXTEND rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
+ }
+ goto extendclass;
+ }
+ if (tTd(21, 36))
+ printf("CLMATCH\n");
+ mlp++;
+ break;
+
+ case MATCHNCLASS:
+ /* match any token not in a class */
+ s = stab(ap, ST_CLASS, ST_FIND);
+ if (s != NULL && bitnset(rp[1], s->s_class))
+ goto backup;
+
+ /* fall through */
+
+ case MATCHONE:
+ case MATCHANY:
+ /* match exactly one token */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp++;
+ mlp++;
+ break;
+
+ case MATCHZANY:
+ /* match zero or more tokens */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp - 1;
+ mlp++;
+ break;
+
+ case MATCHZERO:
+ /* match zero tokens */
+ break;
+
+ case MACRODEXPAND:
+ /*
+ ** Match against run-time macro.
+ ** This algorithm is broken for the
+ ** general case (no recursive macros,
+ ** improper tokenization) but should
+ ** work for the usual cases.
+ */
+
+ ap = macvalue(rp[1], e);
+ mlp->first = avp;
+ if (tTd(21, 2))
+ printf("rewrite: LHS $&%c => \"%s\"\n",
+ rp[1],
+ ap == NULL ? "(NULL)" : ap);
+
+ if (ap == NULL)
+ break;
+ while (*ap != '\0')
+ {
+ if (*avp == NULL ||
+ strncasecmp(ap, *avp, strlen(*avp)) != 0)
+ {
+ /* no match */
+ avp = mlp->first;
+ goto backup;
+ }
+ ap += strlen(*avp++);
+ }
+
+ /* match */
+ break;
+
+ default:
+ /* must have exact match */
+ if (strcasecmp(rp, ap))
+ goto backup;
+ avp++;
+ break;
+ }
+
+ /* successful match on this token */
+ rvp++;
+ continue;
+
+ backup:
+ /* match failed -- back up */
+ while (--mlp >= mlist)
+ {
+ rvp = mlp->pattern;
+ rp = *rvp;
+ avp = mlp->last + 1;
+ ap = *avp;
+
+ if (tTd(21, 36))
+ {
+ printf("BACKUP rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
+ }
+
+ if (ap == NULL)
+ {
+ /* run off the end -- back up again */
+ continue;
+ }
+ if ((*rp & 0377) == MATCHANY ||
+ (*rp & 0377) == MATCHZANY)
+ {
+ /* extend binding and continue */
+ mlp->last = avp++;
+ rvp++;
+ mlp++;
+ break;
+ }
+ if ((*rp & 0377) == MATCHCLASS)
+ {
+ /* extend binding and try again */
+ mlp->last = avp;
+ goto extendclass;
+ }
+ }
+
+ if (mlp < mlist)
+ {
+ /* total failure to match */
+ break;
+ }
+ }
+
+ /*
+ ** See if we successfully matched
+ */
+
+ if (mlp < mlist || *rvp != NULL)
+ {
+ if (tTd(21, 10))
+ printf("----- rule fails\n");
+ rwr = rwr->r_next;
+ ruleno++;
+ loopcount = 0;
+ continue;
+ }
+
+ rvp = rwr->r_rhs;
+ if (tTd(21, 12))
+ {
+ printf("-----rule matches:");
+ printav(rvp);
+ }
+
+ rp = *rvp;
+ if ((*rp & 0377) == CANONUSER)
+ {
+ rvp++;
+ rwr = rwr->r_next;
+ ruleno++;
+ loopcount = 0;
+ }
+ else if ((*rp & 0377) == CANONHOST)
+ {
+ rvp++;
+ rwr = NULL;
+ }
+ else if ((*rp & 0377) == CANONNET)
+ rwr = NULL;
+
+ /* substitute */
+ for (avp = npvp; *rvp != NULL; rvp++)
+ {
+ register struct match *m;
+ register char **pp;
+
+ rp = *rvp;
+ if ((*rp & 0377) == MATCHREPL)
+ {
+ /* substitute from LHS */
+ m = &mlist[rp[1] - '1'];
+ if (m < mlist || m >= mlp)
+ {
+ syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
+ ruleset, rp[1]);
+ return EX_CONFIG;
+ }
+ if (tTd(21, 15))
+ {
+ printf("$%c:", rp[1]);
+ pp = m->first;
+ while (pp <= m->last)
+ {
+ printf(" %x=\"", *pp);
+ (void) fflush(stdout);
+ printf("%s\"", *pp++);
+ }
+ printf("\n");
+ }
+ pp = m->first;
+ while (pp <= m->last)
+ {
+ if (avp >= &npvp[MAXATOM])
+ {
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
+ }
+ *avp++ = *pp++;
+ }
+ }
+ else
+ {
+ /* vanilla replacement */
+ if (avp >= &npvp[MAXATOM])
+ {
+ toolong:
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
+ }
+ if ((*rp & 0377) != MACRODEXPAND)
+ *avp++ = rp;
+ else
+ {
+ *avp = macvalue(rp[1], e);
+ if (tTd(21, 2))
+ printf("rewrite: RHS $&%c => \"%s\"\n",
+ rp[1],
+ *avp == NULL ? "(NULL)" : *avp);
+ if (*avp != NULL)
+ avp++;
+ }
+ }
+ }
+ *avp++ = NULL;
+
+ /*
+ ** Check for any hostname/keyword lookups.
+ */
+
+ for (rvp = npvp; *rvp != NULL; rvp++)
+ {
+ char **hbrvp;
+ char **xpvp;
+ int trsize;
+ char *replac;
+ int endtoken;
+ STAB *map;
+ char *mapname;
+ char **key_rvp;
+ char **arg_rvp;
+ char **default_rvp;
+ char buf[MAXNAME + 1];
+ char *pvpb1[MAXATOM + 1];
+ char *argvect[10];
+ char pvpbuf[PSBUFSIZE];
+ char *nullpvp[1];
+
+ if ((**rvp & 0377) != HOSTBEGIN &&
+ (**rvp & 0377) != LOOKUPBEGIN)
+ continue;
+
+ /*
+ ** Got a hostname/keyword lookup.
+ **
+ ** This could be optimized fairly easily.
+ */
+
+ hbrvp = rvp;
+ if ((**rvp & 0377) == HOSTBEGIN)
+ {
+ endtoken = HOSTEND;
+ mapname = "host";
+ }
+ else
+ {
+ endtoken = LOOKUPEND;
+ mapname = *++rvp;
+ }
+ map = stab(mapname, ST_MAP, ST_FIND);
+ if (map == NULL)
+ syserr("554 rewrite: map %s not found", mapname);
+
+ /* extract the match part */
+ key_rvp = ++rvp;
+ default_rvp = NULL;
+ arg_rvp = argvect;
+ xpvp = NULL;
+ replac = pvpbuf;
+ while (*rvp != NULL && (**rvp & 0377) != endtoken)
+ {
+ int nodetype = **rvp & 0377;
+
+ if (nodetype != CANONHOST && nodetype != CANONUSER)
+ {
+ rvp++;
+ continue;
+ }
+
+ *rvp++ = NULL;
+
+ if (xpvp != NULL)
+ {
+ cataddr(xpvp, NULL, replac,
+ &pvpbuf[sizeof pvpbuf] - replac,
+ '\0');
+ *++arg_rvp = replac;
+ replac += strlen(replac) + 1;
+ xpvp = NULL;
+ }
+ switch (nodetype)
+ {
+ case CANONHOST:
+ xpvp = rvp;
+ break;
+
+ case CANONUSER:
+ default_rvp = rvp;
+ break;
+ }
+ }
+ if (*rvp != NULL)
+ *rvp++ = NULL;
+ if (xpvp != NULL)
+ {
+ cataddr(xpvp, NULL, replac,
+ &pvpbuf[sizeof pvpbuf] - replac,
+ '\0');
+ *++arg_rvp = replac;
+ }
+ *++arg_rvp = NULL;
+
+ /* save the remainder of the input string */
+ trsize = (int) (avp - rvp + 1) * sizeof *rvp;
+ bcopy((char *) rvp, (char *) pvpb1, trsize);
+
+ /* look it up */
+ cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
+ argvect[0] = buf;
+ if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
+ {
+ auto int stat = EX_OK;
+
+ /* XXX should try to auto-open the map here */
+
+ if (tTd(60, 1))
+ printf("map_lookup(%s, %s) => ",
+ mapname, buf);
+ replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
+ buf, argvect, &stat);
+ if (tTd(60, 1))
+ printf("%s (%d)\n",
+ replac ? replac : "NOT FOUND",
+ stat);
+
+ /* should recover if stat == EX_TEMPFAIL */
+ if (stat == EX_TEMPFAIL)
+ rstat = stat;
+ }
+ else
+ replac = NULL;
+
+ /* if no replacement, use default */
+ if (replac == NULL && default_rvp != NULL)
+ {
+ /* create the default */
+ cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
+ replac = buf;
+ }
+
+ if (replac == NULL)
+ {
+ xpvp = key_rvp;
+ }
+ else if (*replac == '\0')
+ {
+ /* null replacement */
+ nullpvp[0] = NULL;
+ xpvp = nullpvp;
+ }
+ else
+ {
+ /* scan the new replacement */
+ xpvp = prescan(replac, '\0', pvpbuf,
+ sizeof pvpbuf, NULL);
+ if (xpvp == NULL)
+ {
+ /* prescan already printed error */
+ return EX_DATAERR;
+ }
+ }
+
+ /* append it to the token list */
+ for (avp = hbrvp; *xpvp != NULL; xpvp++)
+ {
+ *avp++ = newstr(*xpvp);
+ if (avp >= &npvp[MAXATOM])
+ goto toolong;
+ }
+
+ /* restore the old trailing information */
+ for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
+ if (avp >= &npvp[MAXATOM])
+ goto toolong;
+
+ break;
+ }
+
+ /*
+ ** Check for subroutine calls.
+ */
+
+ if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
+ {
+ int stat;
+
+ if (npvp[1] == NULL)
+ {
+ syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
+ ruleset, ruleno);
+ *pvp = NULL;
+ }
+ else
+ {
+ bcopy((char *) &npvp[2], (char *) pvp,
+ (int) (avp - npvp - 2) * sizeof *avp);
+ if (tTd(21, 3))
+ printf("-----callsubr %s\n", npvp[1]);
+ stat = rewrite(pvp, atoi(npvp[1]), reclevel, e);
+ if (rstat == EX_OK || stat == EX_TEMPFAIL)
+ rstat = stat;
+ if (*pvp != NULL && (**pvp & 0377) == CANONNET)
+ rwr = NULL;
+ }
+ }
+ else
+ {
+ bcopy((char *) npvp, (char *) pvp,
+ (int) (avp - npvp) * sizeof *avp);
+ }
+ if (tTd(21, 4))
+ {
+ printf("rewritten as:");
+ printav(pvp);
+ }
+ }
+
+ if (OpMode == MD_TEST || tTd(21, 2))
+ {
+ printf("rewrite: ruleset %2d returns:", ruleset);
+ printav(pvp);
+ }
+
+ return rstat;
+}
+ /*
+** BUILDADDR -- build address from token vector.
+**
+** Parameters:
+** tv -- token vector.
+** a -- pointer to address descriptor to fill.
+** If NULL, one will be allocated.
+** flags -- info regarding whether this is a sender or
+** a recipient.
+** e -- the current envelope.
+**
+** Returns:
+** NULL if there was an error.
+** 'a' otherwise.
+**
+** Side Effects:
+** fills in 'a'
+*/
+
+struct errcodes
+{
+ char *ec_name; /* name of error code */
+ int ec_code; /* numeric code */
+} ErrorCodes[] =
+{
+ "usage", EX_USAGE,
+ "nouser", EX_NOUSER,
+ "nohost", EX_NOHOST,
+ "unavailable", EX_UNAVAILABLE,
+ "software", EX_SOFTWARE,
+ "tempfail", EX_TEMPFAIL,
+ "protocol", EX_PROTOCOL,
+#ifdef EX_CONFIG
+ "config", EX_CONFIG,
+#endif
+ NULL, EX_UNAVAILABLE,
+};
+
+ADDRESS *
+buildaddr(tv, a, flags, e)
+ register char **tv;
+ register ADDRESS *a;
+ int flags;
+ register ENVELOPE *e;
+{
+ struct mailer **mp;
+ register struct mailer *m;
+ char *bp;
+ int spaceleft;
+ static MAILER errormailer;
+ static char *errorargv[] = { "ERROR", NULL };
+ static char buf[MAXNAME];
+
+ if (tTd(24, 5))
+ {
+ printf("buildaddr, flags=%o, tv=", flags);
+ printav(tv);
+ }
+
+ if (a == NULL)
+ a = (ADDRESS *) xalloc(sizeof *a);
+ bzero((char *) a, sizeof *a);
+
+ /* figure out what net/mailer to use */
+ if (*tv == NULL || (**tv & 0377) != CANONNET)
+ {
+ syserr("554 buildaddr: no net");
+badaddr:
+ a->q_flags |= QBADADDR;
+ a->q_mailer = &errormailer;
+ if (errormailer.m_name == NULL)
+ {
+ /* initialize the bogus mailer */
+ errormailer.m_name = "*error*";
+ errormailer.m_mailer = "ERROR";
+ errormailer.m_argv = errorargv;
+ }
+ return a;
+ }
+ tv++;
+ if (strcasecmp(*tv, "error") == 0)
+ {
+ if ((**++tv & 0377) == CANONHOST)
+ {
+ register struct errcodes *ep;
+
+ if (isascii(**++tv) && isdigit(**tv))
+ {
+ setstat(atoi(*tv));
+ }
+ else
+ {
+ for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
+ if (strcasecmp(ep->ec_name, *tv) == 0)
+ break;
+ setstat(ep->ec_code);
+ }
+ tv++;
+ }
+ else
+ setstat(EX_UNAVAILABLE);
+ if ((**tv & 0377) != CANONUSER)
+ syserr("554 buildaddr: error: no user");
+ cataddr(++tv, NULL, buf, sizeof buf, ' ');
+ stripquotes(buf);
+ if (isascii(buf[0]) && isdigit(buf[0]) &&
+ isascii(buf[1]) && isdigit(buf[1]) &&
+ isascii(buf[2]) && isdigit(buf[2]) &&
+ buf[3] == ' ')
+ {
+ char fmt[10];
+
+ strncpy(fmt, buf, 3);
+ strcpy(&fmt[3], " %s");
+ usrerr(fmt, buf + 4);
+ }
+ else
+ {
+ usrerr("553 %s", buf);
+ }
+ goto badaddr;
+ }
+
+ for (mp = Mailer; (m = *mp++) != NULL; )
+ {
+ if (strcasecmp(m->m_name, *tv) == 0)
+ break;
+ }
+ if (m == NULL)
+ {
+ syserr("554 buildaddr: unknown mailer %s", *tv);
+ goto badaddr;
+ }
+ a->q_mailer = m;
+
+ /* figure out what host (if any) */
+ tv++;
+ if ((**tv & 0377) == CANONHOST)
+ {
+ bp = buf;
+ spaceleft = sizeof buf - 1;
+ while (*++tv != NULL && (**tv & 0377) != CANONUSER)
+ {
+ int i = strlen(*tv);
+
+ if (i > spaceleft)
+ {
+ /* out of space for this address */
+ if (spaceleft >= 0)
+ syserr("554 buildaddr: host too long (%.40s...)",
+ buf);
+ i = spaceleft;
+ spaceleft = 0;
+ }
+ if (i <= 0)
+ continue;
+ bcopy(*tv, bp, i);
+ bp += i;
+ spaceleft -= i;
+ }
+ *bp = '\0';
+ a->q_host = newstr(buf);
+ }
+ else
+ {
+ if (!bitnset(M_LOCALMAILER, m->m_flags))
+ {
+ syserr("554 buildaddr: no host");
+ goto badaddr;
+ }
+ a->q_host = NULL;
+ }
+
+ /* figure out the user */
+ if (*tv == NULL || (**tv & 0377) != CANONUSER)
+ {
+ syserr("554 buildaddr: no user");
+ goto badaddr;
+ }
+ tv++;
+
+ /* do special mapping for local mailer */
+ if (m == LocalMailer && *tv != NULL)
+ {
+ register char *p = *tv;
+
+ if (*p == '"')
+ p++;
+ if (*p == '|')
+ a->q_mailer = m = ProgMailer;
+ else if (*p == '/')
+ a->q_mailer = m = FileMailer;
+ else if (*p == ':')
+ {
+ /* may be :include: */
+ cataddr(tv, NULL, buf, sizeof buf, '\0');
+ stripquotes(buf);
+ if (strncasecmp(buf, ":include:", 9) == 0)
+ {
+ /* if :include:, don't need further rewriting */
+ a->q_mailer = m = InclMailer;
+ a->q_user = &buf[9];
+ return (a);
+ }
+ }
+ }
+
+ if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0)
+ {
+ tv++;
+ a->q_flags |= QNOTREMOTE;
+ }
+
+ /* rewrite according recipient mailer rewriting rules */
+ define('h', a->q_host, e);
+ if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
+ {
+ /* sender addresses done later */
+ (void) rewrite(tv, 2, 0, e);
+ if (m->m_re_rwset > 0)
+ (void) rewrite(tv, m->m_re_rwset, 0, e);
+ }
+ (void) rewrite(tv, 4, 0, e);
+
+ /* save the result for the command line/RCPT argument */
+ cataddr(tv, NULL, buf, sizeof buf, '\0');
+ a->q_user = buf;
+
+ /*
+ ** Do mapping to lower case as requested by mailer
+ */
+
+ if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
+ makelower(a->q_host);
+ if (!bitnset(M_USR_UPPER, m->m_flags))
+ makelower(a->q_user);
+
+ return (a);
+}
+ /*
+** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
+**
+** Parameters:
+** pvp -- parameter vector to rebuild.
+** evp -- last parameter to include. Can be NULL to
+** use entire pvp.
+** buf -- buffer to build the string into.
+** sz -- size of buf.
+** spacesub -- the space separator character; if null,
+** use SpaceSub.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Destroys buf.
+*/
+
+cataddr(pvp, evp, buf, sz, spacesub)
+ char **pvp;
+ char **evp;
+ char *buf;
+ register int sz;
+ char spacesub;
+{
+ bool oatomtok = FALSE;
+ bool natomtok = FALSE;
+ register int i;
+ register char *p;
+
+ if (spacesub == '\0')
+ spacesub = SpaceSub;
+
+ if (pvp == NULL)
+ {
+ (void) strcpy(buf, "");
+ return;
+ }
+ p = buf;
+ sz -= 2;
+ while (*pvp != NULL && (i = strlen(*pvp)) < sz)
+ {
+ natomtok = (toktype(**pvp) == ATM);
+ if (oatomtok && natomtok)
+ *p++ = spacesub;
+ (void) strcpy(p, *pvp);
+ oatomtok = natomtok;
+ p += i;
+ sz -= i + 1;
+ if (pvp++ == evp)
+ break;
+ }
+ *p = '\0';
+}
+ /*
+** SAMEADDR -- Determine if two addresses are the same
+**
+** This is not just a straight comparison -- if the mailer doesn't
+** care about the host we just ignore it, etc.
+**
+** Parameters:
+** a, b -- pointers to the internal forms to compare.
+**
+** Returns:
+** TRUE -- they represent the same mailbox.
+** FALSE -- they don't.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+sameaddr(a, b)
+ register ADDRESS *a;
+ register ADDRESS *b;
+{
+ register ADDRESS *ca, *cb;
+
+ /* if they don't have the same mailer, forget it */
+ if (a->q_mailer != b->q_mailer)
+ return (FALSE);
+
+ /* if the user isn't the same, we can drop out */
+ if (strcmp(a->q_user, b->q_user) != 0)
+ return (FALSE);
+
+ /* if we have good uids for both but they differ, these are different */
+ if (a->q_mailer == ProgMailer)
+ {
+ ca = getctladdr(a);
+ cb = getctladdr(b);
+ if (ca != NULL && cb != NULL &&
+ bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
+ ca->q_uid != cb->q_uid)
+ return (FALSE);
+ }
+
+ /* otherwise compare hosts (but be careful for NULL ptrs) */
+ if (a->q_host == b->q_host)
+ {
+ /* probably both null pointers */
+ return (TRUE);
+ }
+ if (a->q_host == NULL || b->q_host == NULL)
+ {
+ /* only one is a null pointer */
+ return (FALSE);
+ }
+ if (strcmp(a->q_host, b->q_host) != 0)
+ return (FALSE);
+
+ return (TRUE);
+}
+ /*
+** PRINTADDR -- print address (for debugging)
+**
+** Parameters:
+** a -- the address to print
+** follow -- follow the q_next chain.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+printaddr(a, follow)
+ register ADDRESS *a;
+ bool follow;
+{
+ bool first = TRUE;
+ register MAILER *m;
+ MAILER pseudomailer;
+
+ while (a != NULL)
+ {
+ first = FALSE;
+ printf("%x=", a);
+ (void) fflush(stdout);
+
+ /* find the mailer -- carefully */
+ m = a->q_mailer;
+ if (m == NULL)
+ {
+ m = &pseudomailer;
+ m->m_mno = -1;
+ m->m_name = "NULL";
+ }
+
+ printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
+ a->q_paddr, m->m_mno, m->m_name,
+ a->q_host, a->q_user,
+ a->q_ruser ? a->q_ruser : "<null>");
+ printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n",
+ a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid);
+ printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
+ a->q_owner == NULL ? "(none)" : a->q_owner,
+ a->q_home == NULL ? "(none)" : a->q_home,
+ a->q_fullname == NULL ? "(none)" : a->q_fullname);
+
+ if (!follow)
+ return;
+ a = a->q_next;
+ }
+ if (first)
+ printf("[NULL]\n");
+}
+
+ /*
+** REMOTENAME -- return the name relative to the current mailer
+**
+** Parameters:
+** name -- the name to translate.
+** m -- the mailer that we want to do rewriting relative
+** to.
+** flags -- fine tune operations.
+** pstat -- pointer to status word.
+** e -- the current envelope.
+**
+** Returns:
+** the text string representing this address relative to
+** the receiving mailer.
+**
+** Side Effects:
+** none.
+**
+** Warnings:
+** The text string returned is tucked away locally;
+** copy it if you intend to save it.
+*/
+
+char *
+remotename(name, m, flags, pstat, e)
+ char *name;
+ struct mailer *m;
+ int flags;
+ int *pstat;
+ register ENVELOPE *e;
+{
+ register char **pvp;
+ char *fancy;
+ char *oldg = macvalue('g', e);
+ int rwset;
+ static char buf[MAXNAME];
+ char lbuf[MAXNAME];
+ char pvpbuf[PSBUFSIZE];
+ extern char *crackaddr();
+
+ if (tTd(12, 1))
+ printf("remotename(%s)\n", name);
+
+ /* don't do anything if we are tagging it as special */
+ if (bitset(RF_SENDERADDR, flags))
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
+ : m->m_se_rwset;
+ else
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
+ : m->m_re_rwset;
+ if (rwset < 0)
+ return (name);
+
+ /*
+ ** Do a heuristic crack of this name to extract any comment info.
+ ** This will leave the name as a comment and a $g macro.
+ */
+
+ if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
+ fancy = "\201g";
+ else
+ fancy = crackaddr(name);
+
+ /*
+ ** Turn the name into canonical form.
+ ** Normally this will be RFC 822 style, i.e., "user@domain".
+ ** If this only resolves to "user", and the "C" flag is
+ ** specified in the sending mailer, then the sender's
+ ** domain will be appended.
+ */
+
+ pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL);
+ if (pvp == NULL)
+ return (name);
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
+ {
+ /* append from domain to this address */
+ register char **pxp = pvp;
+
+ /* see if there is an "@domain" in the current name */
+ while (*pxp != NULL && strcmp(*pxp, "@") != 0)
+ pxp++;
+ if (*pxp == NULL)
+ {
+ /* no.... append the "@domain" from the sender */
+ register char **qxq = e->e_fromdomain;
+
+ while ((*pxp++ = *qxq++) != NULL)
+ continue;
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
+ }
+
+ /*
+ ** Do more specific rewriting.
+ ** Rewrite using ruleset 1 or 2 depending on whether this is
+ ** a sender address or not.
+ ** Then run it through any receiving-mailer-specific rulesets.
+ */
+
+ if (bitset(RF_SENDERADDR, flags))
+ {
+ if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
+ else
+ {
+ if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
+ if (rwset > 0)
+ {
+ if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
+
+ /*
+ ** Do any final sanitation the address may require.
+ ** This will normally be used to turn internal forms
+ ** (e.g., user@host.LOCAL) into external form. This
+ ** may be used as a default to the above rules.
+ */
+
+ if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+
+ /*
+ ** Now restore the comment information we had at the beginning.
+ */
+
+ cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
+ define('g', lbuf, e);
+
+ /* need to make sure route-addrs have <angle brackets> */
+ if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
+ expand("<\201g>", buf, &buf[sizeof buf - 1], e);
+ else
+ expand(fancy, buf, &buf[sizeof buf - 1], e);
+
+ define('g', oldg, e);
+
+ if (tTd(12, 1))
+ printf("remotename => `%s'\n", buf);
+ return (buf);
+}
+ /*
+** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
+**
+** Parameters:
+** a -- the address to map (but just the user name part).
+** sendq -- the sendq in which to install any replacement
+** addresses.
+**
+** Returns:
+** none.
+*/
+
+maplocaluser(a, sendq, e)
+ register ADDRESS *a;
+ ADDRESS **sendq;
+ ENVELOPE *e;
+{
+ register char **pvp;
+ register ADDRESS *a1 = NULL;
+ auto char *delimptr;
+ char pvpbuf[PSBUFSIZE];
+
+ if (tTd(29, 1))
+ {
+ printf("maplocaluser: ");
+ printaddr(a, FALSE);
+ }
+ pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr);
+ if (pvp == NULL)
+ return;
+
+ (void) rewrite(pvp, 5, 0, e);
+ if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
+ return;
+
+ /* if non-null, mailer destination specified -- has it changed? */
+ a1 = buildaddr(pvp, NULL, 0, e);
+ if (a1 == NULL || sameaddr(a, a1))
+ return;
+
+ /* mark old address as dead; insert new address */
+ a->q_flags |= QDONTSEND;
+ if (tTd(29, 5))
+ {
+ printf("maplocaluser: QDONTSEND ");
+ printaddr(a, FALSE);
+ }
+ a1->q_alias = a;
+ allocaddr(a1, RF_COPYALL, NULL);
+ (void) recipient(a1, sendq, e);
+}
+ /*
+** DEQUOTE_INIT -- initialize dequote map
+**
+** This is a no-op.
+**
+** Parameters:
+** map -- the internal map structure.
+** args -- arguments.
+**
+** Returns:
+** TRUE.
+*/
+
+bool
+dequote_init(map, args)
+ MAP *map;
+ char *args;
+{
+ register char *p = args;
+
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'a':
+ map->map_app = ++p;
+ break;
+ }
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p = '\0';
+ }
+ if (map->map_app != NULL)
+ map->map_app = newstr(map->map_app);
+
+ return TRUE;
+}
+ /*
+** DEQUOTE_MAP -- unquote an address
+**
+** Parameters:
+** map -- the internal map structure (ignored).
+** name -- the name to dequote.
+** av -- arguments (ignored).
+** statp -- pointer to status out-parameter.
+**
+** Returns:
+** NULL -- if there were no quotes, or if the resulting
+** unquoted buffer would not be acceptable to prescan.
+** else -- The dequoted buffer.
+*/
+
+char *
+dequote_map(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ register char *p;
+ register char *q;
+ register char c;
+ int anglecnt;
+ int cmntcnt;
+ int quotecnt;
+ int spacecnt;
+ bool quotemode;
+ bool bslashmode;
+
+ anglecnt = 0;
+ cmntcnt = 0;
+ quotecnt = 0;
+ spacecnt = 0;
+ quotemode = FALSE;
+ bslashmode = FALSE;
+
+ for (p = q = name; (c = *p++) != '\0'; )
+ {
+ if (bslashmode)
+ {
+ bslashmode = FALSE;
+ *q++ = c;
+ continue;
+ }
+
+ switch (c)
+ {
+ case '\\':
+ bslashmode = TRUE;
+ break;
+
+ case '(':
+ cmntcnt++;
+ break;
+
+ case ')':
+ if (cmntcnt-- <= 0)
+ return NULL;
+ break;
+
+ case ' ':
+ spacecnt++;
+ break;
+ }
+
+ if (cmntcnt > 0)
+ {
+ *q++ = c;
+ continue;
+ }
+
+ switch (c)
+ {
+ case '"':
+ quotemode = !quotemode;
+ quotecnt++;
+ continue;
+
+ case '<':
+ anglecnt++;
+ break;
+
+ case '>':
+ if (anglecnt-- <= 0)
+ return NULL;
+ break;
+ }
+ *q++ = c;
+ }
+
+ if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
+ quotemode || quotecnt <= 0 || spacecnt != 0)
+ return NULL;
+ *q++ = '\0';
+ return name;
+}
diff --git a/usr.sbin/sendmail/src/pathnames.h b/usr.sbin/sendmail/src/pathnames.h
new file mode 100644
index 00000000000..a611c0b0b2b
--- /dev/null
+++ b/usr.sbin/sendmail/src/pathnames.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1990, 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.
+ *
+ * @(#)pathnames.h 8.2 (Berkeley) 8/20/93
+ */
+
+#ifndef _PATH_SENDMAILCF
+# define _PATH_SENDMAILCF "/etc/sendmail.cf"
+#endif
+
+#ifndef _PATH_SENDMAILPID
+# ifdef BSD4_4
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# else
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif
+#endif
diff --git a/usr.sbin/sendmail/src/queue.c b/usr.sbin/sendmail/src/queue.c
new file mode 100644
index 00000000000..a5324164110
--- /dev/null
+++ b/usr.sbin/sendmail/src/queue.c
@@ -0,0 +1,1571 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+# include "sendmail.h"
+
+#ifndef lint
+#ifdef QUEUE
+static char sccsid[] = "@(#)queue.c 8.41.1.3 (Berkeley) 3/5/95 (with queueing)";
+#else
+static char sccsid[] = "@(#)queue.c 8.41.1.3 (Berkeley) 3/5/95 (without queueing)";
+#endif
+#endif /* not lint */
+
+# include <errno.h>
+# include <pwd.h>
+# include <dirent.h>
+
+# ifdef QUEUE
+
+/*
+** Work queue.
+*/
+
+struct work
+{
+ char *w_name; /* name of control file */
+ long w_pri; /* priority of message, see below */
+ time_t w_ctime; /* creation time of message */
+ struct work *w_next; /* next in queue */
+};
+
+typedef struct work WORK;
+
+WORK *WorkQ; /* queue of things to be done */
+ /*
+** QUEUEUP -- queue a message up for future transmission.
+**
+** Parameters:
+** e -- the envelope to queue up.
+** queueall -- if TRUE, queue all addresses, rather than
+** just those with the QQUEUEUP flag set.
+** announce -- if TRUE, tell when you are queueing up.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** The current request are saved in a control file.
+** The queue file is left locked.
+*/
+
+queueup(e, queueall, announce)
+ register ENVELOPE *e;
+ bool queueall;
+ bool announce;
+{
+ char *qf;
+ register FILE *tfp;
+ register HDR *h;
+ register ADDRESS *q;
+ int fd;
+ int i;
+ bool newid;
+ register char *p;
+ MAILER nullmailer;
+ MCI mcibuf;
+ char buf[MAXLINE], tf[MAXLINE];
+
+ /*
+ ** Create control file.
+ */
+
+ newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
+
+ /* if newid, queuename will create a locked qf file in e->lockfp */
+ strcpy(tf, queuename(e, 't'));
+ tfp = e->e_lockfp;
+ if (tfp == NULL)
+ newid = FALSE;
+
+ /* if newid, just write the qf file directly (instead of tf file) */
+ if (!newid)
+ {
+ /* get a locked tf file */
+ for (i = 0; i < 128; i++)
+ {
+ fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
+ if (fd < 0)
+ {
+ if (errno != EEXIST)
+ break;
+#ifdef LOG
+ if (LogLevel > 0 && (i % 32) == 0)
+ syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s",
+ tf, geteuid(), errstring(errno));
+#endif
+ }
+ else
+ {
+ if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
+ break;
+#ifdef LOG
+ else if (LogLevel > 0 && (i % 32) == 0)
+ syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
+ tf, errstring(errno));
+#endif
+ close(fd);
+ }
+
+ if ((i % 32) == 31)
+ {
+ /* save the old temp file away */
+ (void) rename(tf, queuename(e, 'T'));
+ }
+ else
+ sleep(i % 32);
+ }
+ if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
+ {
+ printopenfds(TRUE);
+ syserr("!queueup: cannot create queue temp file %s, uid=%d",
+ tf, geteuid());
+ }
+ }
+
+ if (tTd(40, 1))
+ printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id,
+ newid ? " (new id)" : "");
+ if (tTd(40, 9))
+ {
+ printf(" tfp=");
+ dumpfd(fileno(tfp), TRUE, FALSE);
+ printf(" lockfp=");
+ if (e->e_lockfp == NULL)
+ printf("NULL\n");
+ else
+ dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
+ }
+
+ /*
+ ** If there is no data file yet, create one.
+ */
+
+ if (e->e_df == NULL)
+ {
+ register FILE *dfp;
+ extern putbody();
+
+ e->e_df = queuename(e, 'd');
+ e->e_df = newstr(e->e_df);
+ fd = open(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
+ if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
+ syserr("!queueup: cannot create data temp file %s, uid=%d",
+ e->e_df, geteuid());
+ bzero(&mcibuf, sizeof mcibuf);
+ mcibuf.mci_out = dfp;
+ mcibuf.mci_mailer = FileMailer;
+ (*e->e_putbody)(&mcibuf, e, NULL);
+ (void) xfclose(dfp, "queueup dfp", e->e_id);
+ e->e_putbody = putbody;
+ }
+
+ /*
+ ** Output future work requests.
+ ** Priority and creation time should be first, since
+ ** they are required by orderq.
+ */
+
+ /* output message priority */
+ fprintf(tfp, "P%ld\n", e->e_msgpriority);
+
+ /* output creation time */
+ fprintf(tfp, "T%ld\n", e->e_ctime);
+
+ /* output type and name of data file */
+ if (e->e_bodytype != NULL)
+ fprintf(tfp, "B%s\n", e->e_bodytype);
+ fprintf(tfp, "D%s\n", e->e_df);
+
+ /* message from envelope, if it exists */
+ if (e->e_message != NULL)
+ fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
+
+ /* send various flag bits through */
+ p = buf;
+ if (bitset(EF_WARNING, e->e_flags))
+ *p++ = 'w';
+ if (bitset(EF_RESPONSE, e->e_flags))
+ *p++ = 'r';
+ *p++ = '\0';
+ if (buf[0] != '\0')
+ fprintf(tfp, "F%s\n", buf);
+
+ /* $r and $s and $_ macro values */
+ if ((p = macvalue('r', e)) != NULL)
+ fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
+ if ((p = macvalue('s', e)) != NULL)
+ fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
+ if ((p = macvalue('_', e)) != NULL)
+ fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
+
+ /* output name of sender */
+ fprintf(tfp, "S%s\n", denlstring(e->e_from.q_paddr, TRUE, FALSE));
+
+ /* output list of error recipients */
+ printctladdr(NULL, NULL);
+ for (q = e->e_errorqueue; q != NULL; q = q->q_next)
+ {
+ if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
+ {
+ printctladdr(q, tfp);
+ fprintf(tfp, "E%s\n", denlstring(q->q_paddr, TRUE, FALSE));
+ }
+ }
+
+ /* output list of recipient addresses */
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QQUEUEUP, q->q_flags) ||
+ (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
+ {
+ printctladdr(q, tfp);
+ fprintf(tfp, "R%s\n", denlstring(q->q_paddr, TRUE, FALSE));
+ if (announce)
+ {
+ e->e_to = q->q_paddr;
+ message("queued");
+ if (LogLevel > 8)
+ logdelivery(NULL, NULL, "queued", NULL, e);
+ e->e_to = NULL;
+ }
+ if (tTd(40, 1))
+ {
+ printf("queueing ");
+ printaddr(q, FALSE);
+ }
+ }
+ }
+
+ /*
+ ** Output headers for this message.
+ ** Expand macros completely here. Queue run will deal with
+ ** everything as absolute headers.
+ ** All headers that must be relative to the recipient
+ ** can be cracked later.
+ ** We set up a "null mailer" -- i.e., a mailer that will have
+ ** no effect on the addresses as they are output.
+ */
+
+ bzero((char *) &nullmailer, sizeof nullmailer);
+ nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
+ nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
+ nullmailer.m_eol = "\n";
+ bzero(&mcibuf, sizeof mcibuf);
+ mcibuf.mci_mailer = &nullmailer;
+ mcibuf.mci_out = tfp;
+
+ define('g', "\201f", e);
+ for (h = e->e_header; h != NULL; h = h->h_link)
+ {
+ extern bool bitzerop();
+
+ /* don't output null headers */
+ if (h->h_value == NULL || h->h_value[0] == '\0')
+ continue;
+
+ /* don't output resent headers on non-resent messages */
+ if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
+ continue;
+
+ /* expand macros; if null, don't output header at all */
+ if (bitset(H_DEFAULT, h->h_flags))
+ {
+ (void) expand(h->h_value, buf, &buf[sizeof buf], e);
+ if (buf[0] == '\0')
+ continue;
+ }
+
+ /* output this header */
+ fprintf(tfp, "H");
+
+ /* if conditional, output the set of conditions */
+ if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
+ {
+ int j;
+
+ (void) putc('?', tfp);
+ for (j = '\0'; j <= '\177'; j++)
+ if (bitnset(j, h->h_mflags))
+ (void) putc(j, tfp);
+ (void) putc('?', tfp);
+ }
+
+ /* output the header: expand macros, convert addresses */
+ if (bitset(H_DEFAULT, h->h_flags))
+ {
+ fprintf(tfp, "%s: %s\n", h->h_field, buf);
+ }
+ else if (bitset(H_FROM|H_RCPT, h->h_flags))
+ {
+ bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
+ FILE *savetrace = TrafficLogFile;
+
+ TrafficLogFile = NULL;
+
+ if (bitset(H_FROM, h->h_flags))
+ oldstyle = FALSE;
+
+ commaize(h, h->h_value, oldstyle, &mcibuf, e);
+
+ TrafficLogFile = savetrace;
+ }
+ else
+ fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
+ }
+
+ /*
+ ** Clean up.
+ */
+
+ if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
+ {
+ if (newid)
+ syserr("!552 Error writing control file %s", tf);
+ else
+ syserr("!452 Error writing control file %s", tf);
+ }
+
+ if (!newid)
+ {
+ /* rename (locked) tf to be (locked) qf */
+ qf = queuename(e, 'q');
+ if (rename(tf, qf) < 0)
+ syserr("cannot rename(%s, %s), df=%s, uid=%d",
+ tf, qf, e->e_df, geteuid());
+
+ /* close and unlock old (locked) qf */
+ if (e->e_lockfp != NULL)
+ (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
+ e->e_lockfp = tfp;
+ }
+ else
+ qf = tf;
+ errno = 0;
+ e->e_flags |= EF_INQUEUE;
+
+# ifdef LOG
+ /* save log info */
+ if (LogLevel > 79)
+ syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
+# endif /* LOG */
+
+ if (tTd(40, 1))
+ printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
+ return;
+}
+
+printctladdr(a, tfp)
+ register ADDRESS *a;
+ FILE *tfp;
+{
+ char *uname;
+ register struct passwd *pw;
+ register ADDRESS *q;
+ uid_t uid;
+ static ADDRESS *lastctladdr;
+ static uid_t lastuid;
+
+ /* initialization */
+ if (a == NULL || a->q_alias == NULL || tfp == NULL)
+ {
+ if (lastctladdr != NULL && tfp != NULL)
+ fprintf(tfp, "C\n");
+ lastctladdr = NULL;
+ lastuid = 0;
+ return;
+ }
+
+ /* find the active uid */
+ q = getctladdr(a);
+ if (q == NULL)
+ uid = 0;
+ else
+ uid = q->q_uid;
+ a = a->q_alias;
+
+ /* check to see if this is the same as last time */
+ if (lastctladdr != NULL && uid == lastuid &&
+ strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
+ return;
+ lastuid = uid;
+ lastctladdr = a;
+
+ if (uid == 0 || (pw = getpwuid(uid)) == NULL)
+ uname = "";
+ else
+ uname = pw->pw_name;
+
+ fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE));
+}
+
+ /*
+** RUNQUEUE -- run the jobs in the queue.
+**
+** Gets the stuff out of the queue in some presumably logical
+** order and processes them.
+**
+** Parameters:
+** forkflag -- TRUE if the queue scanning should be done in
+** a child process. We double-fork so it is not our
+** child and we don't have to clean up after it.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** runs things in the mail queue.
+*/
+
+ENVELOPE QueueEnvelope; /* the queue run envelope */
+
+runqueue(forkflag)
+ bool forkflag;
+{
+ register ENVELOPE *e;
+ extern ENVELOPE BlankEnvelope;
+
+ /*
+ ** If no work will ever be selected, don't even bother reading
+ ** the queue.
+ */
+
+ CurrentLA = getla(); /* get load average */
+
+ if (shouldqueue(0L, curtime()))
+ {
+ if (Verbose)
+ printf("Skipping queue run -- load average too high\n");
+ if (forkflag && QueueIntvl != 0)
+ (void) setevent(QueueIntvl, runqueue, TRUE);
+ return;
+ }
+
+ /*
+ ** See if we want to go off and do other useful work.
+ */
+
+ if (forkflag)
+ {
+ int pid;
+#ifdef SIGCHLD
+ extern void reapchild();
+
+ (void) setsignal(SIGCHLD, reapchild);
+#endif
+
+ pid = dofork();
+ if (pid != 0)
+ {
+ /* parent -- pick up intermediate zombie */
+#ifndef SIGCHLD
+ (void) waitfor(pid);
+#endif /* SIGCHLD */
+ if (QueueIntvl != 0)
+ (void) setevent(QueueIntvl, runqueue, TRUE);
+ return;
+ }
+ /* child -- double fork */
+#ifndef SIGCHLD
+ if (fork() != 0)
+ exit(EX_OK);
+#else /* SIGCHLD */
+ (void) setsignal(SIGCHLD, SIG_DFL);
+#endif /* SIGCHLD */
+ }
+
+ setproctitle("running queue: %s", QueueDir);
+
+# ifdef LOG
+ if (LogLevel > 69)
+ syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
+ QueueDir, getpid(), forkflag);
+# endif /* LOG */
+
+ /*
+ ** Release any resources used by the daemon code.
+ */
+
+# ifdef DAEMON
+ clrdaemon();
+# endif /* DAEMON */
+
+ /* force it to run expensive jobs */
+ NoConnect = FALSE;
+
+ /*
+ ** Create ourselves an envelope
+ */
+
+ CurEnv = &QueueEnvelope;
+ e = newenvelope(&QueueEnvelope, CurEnv);
+ e->e_flags = BlankEnvelope.e_flags;
+
+ /*
+ ** Make sure the alias database is open.
+ */
+
+ initmaps(FALSE, e);
+
+ /*
+ ** Start making passes through the queue.
+ ** First, read and sort the entire queue.
+ ** Then, process the work in that order.
+ ** But if you take too long, start over.
+ */
+
+ /* order the existing work requests */
+ (void) orderq(FALSE);
+
+ /* process them once at a time */
+ while (WorkQ != NULL)
+ {
+ WORK *w = WorkQ;
+
+ WorkQ = WorkQ->w_next;
+
+ /*
+ ** Ignore jobs that are too expensive for the moment.
+ */
+
+ if (shouldqueue(w->w_pri, w->w_ctime))
+ {
+ if (Verbose)
+ printf("\nSkipping %s\n", w->w_name + 2);
+ }
+ else
+ {
+ pid_t pid;
+ extern pid_t dowork();
+
+ pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
+ errno = 0;
+ if (pid != 0)
+ (void) waitfor(pid);
+ }
+ free(w->w_name);
+ free((char *) w);
+ }
+
+ /* exit without the usual cleanup */
+ e->e_id = NULL;
+ finis();
+}
+ /*
+** ORDERQ -- order the work queue.
+**
+** Parameters:
+** doall -- if set, include everything in the queue (even
+** the jobs that cannot be run because the load
+** average is too high). Otherwise, exclude those
+** jobs.
+**
+** Returns:
+** The number of request in the queue (not necessarily
+** the number of requests in WorkQ however).
+**
+** Side Effects:
+** Sets WorkQ to the queue of available work, in order.
+*/
+
+# define NEED_P 001
+# define NEED_T 002
+# define NEED_R 004
+# define NEED_S 010
+
+orderq(doall)
+ bool doall;
+{
+ register struct dirent *d;
+ register WORK *w;
+ DIR *f;
+ register int i;
+ WORK wlist[QUEUESIZE+1];
+ int wn = -1;
+ extern workcmpf();
+
+ if (tTd(41, 1))
+ {
+ printf("orderq:\n");
+ if (QueueLimitId != NULL)
+ printf("\tQueueLimitId = %s\n", QueueLimitId);
+ if (QueueLimitSender != NULL)
+ printf("\tQueueLimitSender = %s\n", QueueLimitSender);
+ if (QueueLimitRecipient != NULL)
+ printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
+ }
+
+ /* clear out old WorkQ */
+ for (w = WorkQ; w != NULL; )
+ {
+ register WORK *nw = w->w_next;
+
+ WorkQ = nw;
+ free(w->w_name);
+ free((char *) w);
+ w = nw;
+ }
+
+ /* open the queue directory */
+ f = opendir(".");
+ if (f == NULL)
+ {
+ syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
+ return (0);
+ }
+
+ /*
+ ** Read the work directory.
+ */
+
+ while ((d = readdir(f)) != NULL)
+ {
+ FILE *cf;
+ register char *p;
+ char lbuf[MAXNAME];
+ extern bool strcontainedin();
+
+ /* is this an interesting entry? */
+ if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
+ continue;
+
+ if (QueueLimitId != NULL &&
+ !strcontainedin(QueueLimitId, d->d_name))
+ continue;
+
+ /*
+ ** Check queue name for plausibility. This handles
+ ** both old and new type ids.
+ */
+
+ p = d->d_name + 2;
+ if (isupper(p[0]) && isupper(p[2]))
+ p += 3;
+ else if (isupper(p[1]))
+ p += 2;
+ else
+ p = d->d_name;
+ for (i = 0; isdigit(*p); p++)
+ i++;
+ if (i < 5 || *p != '\0')
+ {
+ if (Verbose)
+ printf("orderq: bogus qf name %s\n", d->d_name);
+#ifdef LOG
+ if (LogLevel > 3)
+ syslog(LOG_CRIT, "orderq: bogus qf name %s",
+ d->d_name);
+#endif
+ if (strlen(d->d_name) >= MAXNAME)
+ d->d_name[MAXNAME - 1] = '\0';
+ strcpy(lbuf, d->d_name);
+ lbuf[0] = 'Q';
+ (void) rename(d->d_name, lbuf);
+ continue;
+ }
+
+ /* yes -- open control file (if not too many files) */
+ if (++wn >= QUEUESIZE)
+ continue;
+
+ cf = fopen(d->d_name, "r");
+ if (cf == NULL)
+ {
+ /* this may be some random person sending hir msgs */
+ /* syserr("orderq: cannot open %s", cbuf); */
+ if (tTd(41, 2))
+ printf("orderq: cannot open %s (%d)\n",
+ d->d_name, errno);
+ errno = 0;
+ wn--;
+ continue;
+ }
+ w = &wlist[wn];
+ w->w_name = newstr(d->d_name);
+
+ /* make sure jobs in creation don't clog queue */
+ w->w_pri = 0x7fffffff;
+ w->w_ctime = 0;
+
+ /* extract useful information */
+ i = NEED_P | NEED_T;
+ if (QueueLimitSender != NULL)
+ i |= NEED_S;
+ if (QueueLimitRecipient != NULL)
+ i |= NEED_R;
+ while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
+ {
+ extern long atol();
+ extern bool strcontainedin();
+
+ switch (lbuf[0])
+ {
+ case 'P':
+ w->w_pri = atol(&lbuf[1]);
+ i &= ~NEED_P;
+ break;
+
+ case 'T':
+ w->w_ctime = atol(&lbuf[1]);
+ i &= ~NEED_T;
+ break;
+
+ case 'R':
+ if (QueueLimitRecipient != NULL &&
+ strcontainedin(QueueLimitRecipient, &lbuf[1]))
+ i &= ~NEED_R;
+ break;
+
+ case 'S':
+ if (QueueLimitSender != NULL &&
+ strcontainedin(QueueLimitSender, &lbuf[1]))
+ i &= ~NEED_S;
+ break;
+ }
+ }
+ (void) fclose(cf);
+
+ if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
+ bitset(NEED_R|NEED_S, i))
+ {
+ /* don't even bother sorting this job in */
+ wn--;
+ }
+ }
+ (void) closedir(f);
+ wn++;
+
+ /*
+ ** Sort the work directory.
+ */
+
+ qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
+
+ /*
+ ** Convert the work list into canonical form.
+ ** Should be turning it into a list of envelopes here perhaps.
+ */
+
+ WorkQ = NULL;
+ for (i = min(wn, QUEUESIZE); --i >= 0; )
+ {
+ w = (WORK *) xalloc(sizeof *w);
+ w->w_name = wlist[i].w_name;
+ w->w_pri = wlist[i].w_pri;
+ w->w_ctime = wlist[i].w_ctime;
+ w->w_next = WorkQ;
+ WorkQ = w;
+ }
+
+ if (tTd(40, 1))
+ {
+ for (w = WorkQ; w != NULL; w = w->w_next)
+ printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
+ }
+
+ return (wn);
+}
+ /*
+** WORKCMPF -- compare function for ordering work.
+**
+** Parameters:
+** a -- the first argument.
+** b -- the second argument.
+**
+** Returns:
+** -1 if a < b
+** 0 if a == b
+** +1 if a > b
+**
+** Side Effects:
+** none.
+*/
+
+workcmpf(a, b)
+ register WORK *a;
+ register WORK *b;
+{
+ long pa = a->w_pri;
+ long pb = b->w_pri;
+
+ if (pa == pb)
+ return (0);
+ else if (pa > pb)
+ return (1);
+ else
+ return (-1);
+}
+ /*
+** DOWORK -- do a work request.
+**
+** Parameters:
+** id -- the ID of the job to run.
+** forkflag -- if set, run this in background.
+** requeueflag -- if set, reinstantiate the queue quickly.
+** This is used when expanding aliases in the queue.
+** If forkflag is also set, it doesn't wait for the
+** child.
+** e - the envelope in which to run it.
+**
+** Returns:
+** process id of process that is running the queue job.
+**
+** Side Effects:
+** The work request is satisfied if possible.
+*/
+
+pid_t
+dowork(id, forkflag, requeueflag, e)
+ char *id;
+ bool forkflag;
+ bool requeueflag;
+ register ENVELOPE *e;
+{
+ register pid_t pid;
+ extern bool readqf();
+
+ if (tTd(40, 1))
+ printf("dowork(%s)\n", id);
+
+ /*
+ ** Fork for work.
+ */
+
+ if (forkflag)
+ {
+ pid = fork();
+ if (pid < 0)
+ {
+ syserr("dowork: cannot fork");
+ return 0;
+ }
+ else if (pid > 0)
+ {
+ /* parent -- clean out connection cache */
+ mci_flush(FALSE, NULL);
+ }
+ }
+ else
+ {
+ pid = 0;
+ }
+
+ if (pid == 0)
+ {
+ /*
+ ** CHILD
+ ** Lock the control file to avoid duplicate deliveries.
+ ** Then run the file as though we had just read it.
+ ** We save an idea of the temporary name so we
+ ** can recover on interrupt.
+ */
+
+ /* set basic modes, etc. */
+ (void) alarm(0);
+ clearenvelope(e, FALSE);
+ e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
+ e->e_errormode = EM_MAIL;
+ e->e_id = id;
+ GrabTo = UseErrorsTo = FALSE;
+ ExitStat = EX_OK;
+ if (forkflag)
+ {
+ disconnect(1, e);
+ OpMode = MD_DELIVER;
+ }
+# ifdef LOG
+ if (LogLevel > 76)
+ syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
+ getpid());
+# endif /* LOG */
+
+ /* don't use the headers from sendmail.cf... */
+ e->e_header = NULL;
+
+ /* read the queue control file -- return if locked */
+ if (!readqf(e))
+ {
+ if (tTd(40, 4))
+ printf("readqf(%s) failed\n", e->e_id);
+ if (forkflag)
+ exit(EX_OK);
+ else
+ return 0;
+ }
+
+ e->e_flags |= EF_INQUEUE;
+ eatheader(e, requeueflag);
+
+ if (requeueflag)
+ queueup(e, TRUE, FALSE);
+
+ /* do the delivery */
+ sendall(e, SM_DELIVER);
+
+ /* finish up and exit */
+ if (forkflag)
+ finis();
+ else
+ dropenvelope(e);
+ }
+ e->e_id = NULL;
+ return pid;
+}
+ /*
+** READQF -- read queue file and set up environment.
+**
+** Parameters:
+** e -- the envelope of the job to run.
+**
+** Returns:
+** TRUE if it successfully read the queue file.
+** FALSE otherwise.
+**
+** Side Effects:
+** The queue file is returned locked.
+*/
+
+bool
+readqf(e)
+ register ENVELOPE *e;
+{
+ register FILE *qfp;
+ ADDRESS *ctladdr;
+ struct stat st;
+ char *bp;
+ char qf[20];
+ char buf[MAXLINE];
+ extern long atol();
+ extern ADDRESS *setctluser();
+
+ /*
+ ** Read and process the file.
+ */
+
+ strcpy(qf, queuename(e, 'q'));
+ qfp = fopen(qf, "r+");
+ if (qfp == NULL)
+ {
+ if (tTd(40, 8))
+ printf("readqf(%s): fopen failure (%s)\n",
+ qf, errstring(errno));
+ if (errno != ENOENT)
+ syserr("readqf: no control file %s", qf);
+ return FALSE;
+ }
+
+ if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
+ {
+ /* being processed by another queuer */
+ if (tTd(40, 8))
+ printf("readqf(%s): locked\n", qf);
+ if (Verbose)
+ printf("%s: locked\n", e->e_id);
+# ifdef LOG
+ if (LogLevel > 19)
+ syslog(LOG_DEBUG, "%s: locked", e->e_id);
+# endif /* LOG */
+ (void) fclose(qfp);
+ return FALSE;
+ }
+
+ /*
+ ** Check the queue file for plausibility to avoid attacks.
+ */
+
+ if (fstat(fileno(qfp), &st) < 0)
+ {
+ /* must have been being processed by someone else */
+ if (tTd(40, 8))
+ printf("readqf(%s): fstat failure (%s)\n",
+ qf, errstring(errno));
+ fclose(qfp);
+ return FALSE;
+ }
+
+ if (st.st_uid != geteuid())
+ {
+# ifdef LOG
+ if (LogLevel > 0)
+ {
+ syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
+ e->e_id, st.st_uid, st.st_mode);
+ }
+# endif /* LOG */
+ if (tTd(40, 8))
+ printf("readqf(%s): bogus file\n", qf);
+ rename(qf, queuename(e, 'Q'));
+ fclose(qfp);
+ return FALSE;
+ }
+
+ if (st.st_size == 0)
+ {
+ /* must be a bogus file -- just remove it */
+ (void) unlink(qf);
+ fclose(qfp);
+ return FALSE;
+ }
+
+ if (st.st_nlink == 0)
+ {
+ /*
+ ** Race condition -- we got a file just as it was being
+ ** unlinked. Just assume it is zero length.
+ */
+
+ fclose(qfp);
+ return FALSE;
+ }
+
+ /* good file -- save this lock */
+ e->e_lockfp = qfp;
+
+ /* do basic system initialization */
+ initsys(e);
+ define('i', e->e_id, e);
+
+ LineNumber = 0;
+ e->e_flags |= EF_GLOBALERRS;
+ OpMode = MD_DELIVER;
+ if (Verbose)
+ printf("\nRunning %s\n", e->e_id);
+ ctladdr = NULL;
+ while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
+ {
+ register char *p;
+ struct stat st;
+
+ if (tTd(40, 4))
+ printf("+++++ %s\n", bp);
+ switch (bp[0])
+ {
+ case 'C': /* specify controlling user */
+ ctladdr = setctluser(&bp[1]);
+ break;
+
+ case 'R': /* specify recipient */
+ (void) sendtolist(&bp[1], ctladdr, &e->e_sendqueue, e);
+ break;
+
+ case 'E': /* specify error recipient */
+ (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e);
+ break;
+
+ case 'H': /* header */
+ (void) chompheader(&bp[1], FALSE, e);
+ break;
+
+ case 'M': /* message */
+ /* ignore this; we want a new message next time */
+ break;
+
+ case 'S': /* sender */
+ setsender(newstr(&bp[1]), e, NULL, TRUE);
+ break;
+
+ case 'B': /* body type */
+ e->e_bodytype = newstr(&bp[1]);
+ break;
+
+ case 'D': /* data file name */
+ e->e_df = newstr(&bp[1]);
+ e->e_dfp = fopen(e->e_df, "r");
+ if (e->e_dfp == NULL)
+ {
+ syserr("readqf: cannot open %s", e->e_df);
+ e->e_msgsize = -1;
+ }
+ else if (fstat(fileno(e->e_dfp), &st) >= 0)
+ e->e_msgsize = st.st_size;
+ break;
+
+ case 'T': /* init time */
+ e->e_ctime = atol(&bp[1]);
+ break;
+
+ case 'P': /* message priority */
+ e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
+ break;
+
+ case 'F': /* flag bits */
+ for (p = &bp[1]; *p != '\0'; p++)
+ {
+ switch (*p)
+ {
+ case 'w': /* warning sent */
+ e->e_flags |= EF_WARNING;
+ break;
+
+ case 'r': /* response */
+ e->e_flags |= EF_RESPONSE;
+ break;
+ }
+ }
+ break;
+
+ case '$': /* define macro */
+ define(bp[1], newstr(&bp[2]), e);
+ break;
+
+ case '\0': /* blank line; ignore */
+ break;
+
+ default:
+ syserr("readqf: %s: line %d: bad line \"%s\"",
+ qf, LineNumber, bp);
+ fclose(qfp);
+ rename(qf, queuename(e, 'Q'));
+ return FALSE;
+ }
+
+ if (bp != buf)
+ free(bp);
+ }
+
+ /*
+ ** If we haven't read any lines, this queue file is empty.
+ ** Arrange to remove it without referencing any null pointers.
+ */
+
+ if (LineNumber == 0)
+ {
+ errno = 0;
+ e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
+ }
+ return TRUE;
+}
+ /*
+** PRINTQUEUE -- print out a representation of the mail queue
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Prints a listing of the mail queue on the standard output.
+*/
+
+printqueue()
+{
+ register WORK *w;
+ FILE *f;
+ int nrequests;
+ char buf[MAXLINE];
+
+ /*
+ ** Check for permission to print the queue
+ */
+
+ if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
+ {
+ struct stat st;
+# ifdef NGROUPS
+ int n;
+ GIDSET_T gidset[NGROUPS];
+# endif
+
+ if (stat(QueueDir, &st) < 0)
+ {
+ syserr("Cannot stat %s", QueueDir);
+ return;
+ }
+# ifdef NGROUPS
+ n = getgroups(NGROUPS, gidset);
+ while (--n >= 0)
+ {
+ if (gidset[n] == st.st_gid)
+ break;
+ }
+ if (n < 0 && RealGid != st.st_gid)
+# else
+ if (RealGid != st.st_gid)
+# endif
+ {
+ usrerr("510 You are not permitted to see the queue");
+ setstat(EX_NOPERM);
+ return;
+ }
+ }
+
+ /*
+ ** Read and order the queue.
+ */
+
+ nrequests = orderq(TRUE);
+
+ /*
+ ** Print the work list that we have read.
+ */
+
+ /* first see if there is anything */
+ if (nrequests <= 0)
+ {
+ printf("Mail queue is empty\n");
+ return;
+ }
+
+ CurrentLA = getla(); /* get load average */
+
+ printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
+ if (nrequests > QUEUESIZE)
+ printf(", only %d printed", QUEUESIZE);
+ if (Verbose)
+ printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
+ else
+ printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
+ for (w = WorkQ; w != NULL; w = w->w_next)
+ {
+ struct stat st;
+ auto time_t submittime = 0;
+ long dfsize = -1;
+ int flags = 0;
+ char message[MAXLINE];
+ char bodytype[MAXNAME];
+
+ printf("%8s", w->w_name + 2);
+ f = fopen(w->w_name, "r");
+ if (f == NULL)
+ {
+ printf(" (job completed)\n");
+ errno = 0;
+ continue;
+ }
+ if (!lockfile(fileno(f), w->w_name, NULL, LOCK_SH|LOCK_NB))
+ printf("*");
+ else if (shouldqueue(w->w_pri, w->w_ctime))
+ printf("X");
+ else
+ printf(" ");
+ errno = 0;
+
+ message[0] = bodytype[0] = '\0';
+ while (fgets(buf, sizeof buf, f) != NULL)
+ {
+ register int i;
+ register char *p;
+
+ fixcrlf(buf, TRUE);
+ switch (buf[0])
+ {
+ case 'M': /* error message */
+ if ((i = strlen(&buf[1])) >= sizeof message)
+ i = sizeof message - 1;
+ bcopy(&buf[1], message, i);
+ message[i] = '\0';
+ break;
+
+ case 'B': /* body type */
+ if ((i = strlen(&buf[1])) >= sizeof bodytype)
+ i = sizeof bodytype - 1;
+ bcopy(&buf[1], bodytype, i);
+ bodytype[i] = '\0';
+ break;
+
+ case 'S': /* sender name */
+ if (Verbose)
+ printf("%8ld %10ld%c%.12s %.38s",
+ dfsize,
+ w->w_pri,
+ bitset(EF_WARNING, flags) ? '+' : ' ',
+ ctime(&submittime) + 4,
+ &buf[1]);
+ else
+ printf("%8ld %.16s %.45s", dfsize,
+ ctime(&submittime), &buf[1]);
+ if (message[0] != '\0' || bodytype[0] != '\0')
+ {
+ printf("\n %10.10s", bodytype);
+ if (message[0] != '\0')
+ printf(" (%.60s)", message);
+ }
+ break;
+
+ case 'C': /* controlling user */
+ if (Verbose)
+ printf("\n\t\t\t\t (---%.34s---)",
+ &buf[1]);
+ break;
+
+ case 'R': /* recipient name */
+ if (Verbose)
+ printf("\n\t\t\t\t\t %.38s", &buf[1]);
+ else
+ printf("\n\t\t\t\t %.45s", &buf[1]);
+ break;
+
+ case 'T': /* creation time */
+ submittime = atol(&buf[1]);
+ break;
+
+ case 'D': /* data file name */
+ if (stat(&buf[1], &st) >= 0)
+ dfsize = st.st_size;
+ break;
+
+ case 'F': /* flag bits */
+ for (p = &buf[1]; *p != '\0'; p++)
+ {
+ switch (*p)
+ {
+ case 'w':
+ flags |= EF_WARNING;
+ break;
+ }
+ }
+ }
+ }
+ if (submittime == (time_t) 0)
+ printf(" (no control file)");
+ printf("\n");
+ (void) fclose(f);
+ }
+}
+
+# endif /* QUEUE */
+ /*
+** QUEUENAME -- build a file name in the queue directory for this envelope.
+**
+** Assigns an id code if one does not already exist.
+** This code is very careful to avoid trashing existing files
+** under any circumstances.
+**
+** Parameters:
+** e -- envelope to build it in/from.
+** type -- the file type, used as the first character
+** of the file name.
+**
+** Returns:
+** a pointer to the new file name (in a static buffer).
+**
+** Side Effects:
+** If no id code is already assigned, queuename will
+** assign an id code, create a qf file, and leave a
+** locked, open-for-write file pointer in the envelope.
+*/
+
+char *
+queuename(e, type)
+ register ENVELOPE *e;
+ int type;
+{
+ static int pid = -1;
+ static char c0;
+ static char c1;
+ static char c2;
+ time_t now;
+ struct tm *tm;
+ static char buf[MAXNAME];
+
+ if (e->e_id == NULL)
+ {
+ char qf[20];
+
+ /* find a unique id */
+ if (pid != getpid())
+ {
+ /* new process -- start back at "AA" */
+ pid = getpid();
+ now = curtime();
+ tm = localtime(&now);
+ c0 = 'A' + tm->tm_hour;
+ c1 = 'A';
+ c2 = 'A' - 1;
+ }
+ (void) sprintf(qf, "qf%cAA%05d", c0, pid);
+
+ while (c1 < '~' || c2 < 'Z')
+ {
+ int i;
+
+ if (c2 >= 'Z')
+ {
+ c1++;
+ c2 = 'A' - 1;
+ }
+ qf[3] = c1;
+ qf[4] = ++c2;
+ if (tTd(7, 20))
+ printf("queuename: trying \"%s\"\n", qf);
+
+ i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
+ if (i < 0)
+ {
+ if (errno == EEXIST)
+ continue;
+ syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
+ qf, QueueDir, geteuid());
+ exit(EX_UNAVAILABLE);
+ }
+ if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
+ {
+ e->e_lockfp = fdopen(i, "w");
+ break;
+ }
+
+ /* a reader got the file; abandon it and try again */
+ (void) close(i);
+ }
+ if (c1 >= '~' && c2 >= 'Z')
+ {
+ syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
+ qf, QueueDir, geteuid());
+ exit(EX_OSERR);
+ }
+ e->e_id = newstr(&qf[2]);
+ define('i', e->e_id, e);
+ if (tTd(7, 1))
+ printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
+ if (tTd(7, 9))
+ {
+ printf(" lockfd=");
+ dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
+ }
+# ifdef LOG
+ if (LogLevel > 93)
+ syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
+# endif /* LOG */
+ }
+
+ if (type == '\0')
+ return (NULL);
+ (void) sprintf(buf, "%cf%s", type, e->e_id);
+ if (tTd(7, 2))
+ printf("queuename: %s\n", buf);
+ return (buf);
+}
+ /*
+** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
+**
+** Parameters:
+** e -- the envelope to unlock.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** unlocks the queue for `e'.
+*/
+
+unlockqueue(e)
+ ENVELOPE *e;
+{
+ if (tTd(51, 4))
+ printf("unlockqueue(%s)\n", e->e_id);
+
+ /* if there is a lock file in the envelope, close it */
+ if (e->e_lockfp != NULL)
+ xfclose(e->e_lockfp, "unlockqueue", e->e_id);
+ e->e_lockfp = NULL;
+
+ /* don't create a queue id if we don't already have one */
+ if (e->e_id == NULL)
+ return;
+
+ /* remove the transcript */
+# ifdef LOG
+ if (LogLevel > 87)
+ syslog(LOG_DEBUG, "%s: unlock", e->e_id);
+# endif /* LOG */
+ if (!tTd(51, 104))
+ xunlink(queuename(e, 'x'));
+
+}
+ /*
+** SETCTLUSER -- create a controlling address
+**
+** Create a fake "address" given only a local login name; this is
+** used as a "controlling user" for future recipient addresses.
+**
+** Parameters:
+** user -- the user name of the controlling user.
+**
+** Returns:
+** An address descriptor for the controlling user.
+**
+** Side Effects:
+** none.
+*/
+
+ADDRESS *
+setctluser(user)
+ char *user;
+{
+ register ADDRESS *a;
+ struct passwd *pw;
+ char *p;
+
+ /*
+ ** See if this clears our concept of controlling user.
+ */
+
+ if (user == NULL || *user == '\0')
+ return NULL;
+
+ /*
+ ** Set up addr fields for controlling user.
+ */
+
+ a = (ADDRESS *) xalloc(sizeof *a);
+ bzero((char *) a, sizeof *a);
+
+ p = strchr(user, ':');
+ if (p != NULL)
+ *p++ = '\0';
+ if (*user != '\0' && (pw = getpwnam(user)) != NULL)
+ {
+ if (strcmp(pw->pw_dir, "/") == 0)
+ a->q_home = "";
+ else
+ a->q_home = newstr(pw->pw_dir);
+ a->q_uid = pw->pw_uid;
+ a->q_gid = pw->pw_gid;
+ a->q_user = newstr(user);
+ a->q_flags |= QGOODUID;
+ }
+ else
+ {
+ a->q_user = newstr(DefUser);
+ }
+
+ a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
+ a->q_mailer = LocalMailer;
+ if (p == NULL)
+ a->q_paddr = a->q_user;
+ else
+ a->q_paddr = newstr(p);
+ return a;
+}
diff --git a/usr.sbin/sendmail/src/readcf.c b/usr.sbin/sendmail/src/readcf.c
new file mode 100644
index 00000000000..ad7da2a2f95
--- /dev/null
+++ b/usr.sbin/sendmail/src/readcf.c
@@ -0,0 +1,1685 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)readcf.c 8.23.1.3 (Berkeley) 3/5/95";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include <pwd.h>
+# include <grp.h>
+#if NAMED_BIND
+# include <arpa/nameser.h>
+# include <resolv.h>
+#endif
+
+/*
+** READCF -- read control file.
+**
+** This routine reads the control file and builds the internal
+** form.
+**
+** The file is formatted as a sequence of lines, each taken
+** atomically. The first character of each line describes how
+** the line is to be interpreted. The lines are:
+** Dxval Define macro x to have value val.
+** Cxword Put word into class x.
+** Fxfile [fmt] Read file for lines to put into
+** class x. Use scanf string 'fmt'
+** or "%s" if not present. Fmt should
+** only produce one string-valued result.
+** Hname: value Define header with field-name 'name'
+** and value as specified; this will be
+** macro expanded immediately before
+** use.
+** Sn Use rewriting set n.
+** Rlhs rhs Rewrite addresses that match lhs to
+** be rhs.
+** Mn arg=val... Define mailer. n is the internal name.
+** Args specify mailer parameters.
+** Oxvalue Set option x to value.
+** Pname=value Set precedence name to value.
+** Vversioncode[/vendorcode]
+** Version level/vendor name of
+** configuration syntax.
+** Kmapname mapclass arguments....
+** Define keyed lookup of a given class.
+** Arguments are class dependent.
+**
+** Parameters:
+** cfname -- control file name.
+** safe -- TRUE if this is the system config file;
+** FALSE otherwise.
+** e -- the main envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Builds several internal tables.
+*/
+
+readcf(cfname, safe, e)
+ char *cfname;
+ bool safe;
+ register ENVELOPE *e;
+{
+ FILE *cf;
+ int ruleset = 0;
+ char *q;
+ struct rewrite *rwp = NULL;
+ char *bp;
+ auto char *ep;
+ int nfuzzy;
+ char *file;
+ bool optional;
+ char buf[MAXLINE];
+ register char *p;
+ extern char **copyplist();
+ struct stat statb;
+ char exbuf[MAXLINE];
+ char pvpbuf[MAXLINE + MAXATOM];
+ extern char *munchstring();
+ extern void makemapentry();
+
+ FileName = cfname;
+ LineNumber = 0;
+
+ cf = fopen(cfname, "r");
+ if (cf == NULL)
+ {
+ syserr("cannot open");
+ exit(EX_OSFILE);
+ }
+
+ if (fstat(fileno(cf), &statb) < 0)
+ {
+ syserr("cannot fstat");
+ exit(EX_OSFILE);
+ }
+
+ if (!S_ISREG(statb.st_mode))
+ {
+ syserr("not a plain file");
+ exit(EX_OSFILE);
+ }
+
+ if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
+ {
+ if (OpMode == MD_DAEMON || OpMode == MD_FREEZE)
+ fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
+ FileName);
+#ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
+ FileName);
+#endif
+ }
+
+#ifdef XLA
+ xla_zero();
+#endif
+
+ while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
+ {
+ if (bp[0] == '#')
+ {
+ if (bp != buf)
+ free(bp);
+ continue;
+ }
+
+ /* map $ into \201 for macro expansion */
+ for (p = bp; *p != '\0'; p++)
+ {
+ if (*p == '#' && p > bp && ConfigLevel >= 3)
+ {
+ /* this is an on-line comment */
+ register char *e;
+
+ switch (*--p & 0377)
+ {
+ case MACROEXPAND:
+ /* it's from $# -- let it go through */
+ p++;
+ break;
+
+ case '\\':
+ /* it's backslash escaped */
+ (void) strcpy(p, p + 1);
+ break;
+
+ default:
+ /* delete preceeding white space */
+ while (isascii(*p) && isspace(*p) && p > bp)
+ p--;
+ if ((e = strchr(++p, '\n')) != NULL)
+ (void) strcpy(p, e);
+ else
+ p[0] = p[1] = '\0';
+ break;
+ }
+ continue;
+ }
+
+ if (*p != '$')
+ continue;
+
+ if (p[1] == '$')
+ {
+ /* actual dollar sign.... */
+ (void) strcpy(p, p + 1);
+ continue;
+ }
+
+ /* convert to macro expansion character */
+ *p = MACROEXPAND;
+ }
+
+ /* interpret this line */
+ errno = 0;
+ switch (bp[0])
+ {
+ case '\0':
+ case '#': /* comment */
+ break;
+
+ case 'R': /* rewriting rule */
+ for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
+ continue;
+
+ if (*p == '\0')
+ {
+ syserr("invalid rewrite line \"%s\" (tab expected)", bp);
+ break;
+ }
+
+ /* allocate space for the rule header */
+ if (rwp == NULL)
+ {
+ RewriteRules[ruleset] = rwp =
+ (struct rewrite *) xalloc(sizeof *rwp);
+ }
+ else
+ {
+ rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
+ rwp = rwp->r_next;
+ }
+ rwp->r_next = NULL;
+
+ /* expand and save the LHS */
+ *p = '\0';
+ expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
+ rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
+ sizeof pvpbuf, NULL);
+ nfuzzy = 0;
+ if (rwp->r_lhs != NULL)
+ {
+ register char **ap;
+
+ rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
+
+ /* count the number of fuzzy matches in LHS */
+ for (ap = rwp->r_lhs; *ap != NULL; ap++)
+ {
+ char *botch;
+
+ botch = NULL;
+ switch (**ap & 0377)
+ {
+ case MATCHZANY:
+ case MATCHANY:
+ case MATCHONE:
+ case MATCHCLASS:
+ case MATCHNCLASS:
+ nfuzzy++;
+ break;
+
+ case MATCHREPL:
+ botch = "$0-$9";
+ break;
+
+ case CANONNET:
+ botch = "$#";
+ break;
+
+ case CANONUSER:
+ botch = "$:";
+ break;
+
+ case CALLSUBR:
+ botch = "$>";
+ break;
+
+ case CONDIF:
+ botch = "$?";
+ break;
+
+ case CONDELSE:
+ botch = "$|";
+ break;
+
+ case CONDFI:
+ botch = "$.";
+ break;
+
+ case HOSTBEGIN:
+ botch = "$[";
+ break;
+
+ case HOSTEND:
+ botch = "$]";
+ break;
+
+ case LOOKUPBEGIN:
+ botch = "$(";
+ break;
+
+ case LOOKUPEND:
+ botch = "$)";
+ break;
+ }
+ if (botch != NULL)
+ syserr("Inappropriate use of %s on LHS",
+ botch);
+ }
+ }
+ else
+ syserr("R line: null LHS");
+
+ /* expand and save the RHS */
+ while (*++p == '\t')
+ continue;
+ q = p;
+ while (*p != '\0' && *p != '\t')
+ p++;
+ *p = '\0';
+ expand(q, exbuf, &exbuf[sizeof exbuf], e);
+ rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
+ sizeof pvpbuf, NULL);
+ if (rwp->r_rhs != NULL)
+ {
+ register char **ap;
+
+ rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
+
+ /* check no out-of-bounds replacements */
+ nfuzzy += '0';
+ for (ap = rwp->r_rhs; *ap != NULL; ap++)
+ {
+ char *botch;
+
+ botch = NULL;
+ switch (**ap & 0377)
+ {
+ case MATCHREPL:
+ if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
+ {
+ syserr("replacement $%c out of bounds",
+ (*ap)[1]);
+ }
+ break;
+
+ case MATCHZANY:
+ botch = "$*";
+ break;
+
+ case MATCHANY:
+ botch = "$+";
+ break;
+
+ case MATCHONE:
+ botch = "$-";
+ break;
+
+ case MATCHCLASS:
+ botch = "$=";
+ break;
+
+ case MATCHNCLASS:
+ botch = "$~";
+ break;
+ }
+ if (botch != NULL)
+ syserr("Inappropriate use of %s on RHS",
+ botch);
+ }
+ }
+ else
+ syserr("R line: null RHS");
+ break;
+
+ case 'S': /* select rewriting set */
+ for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+ continue;
+ if (!isascii(*p) || !isdigit(*p))
+ {
+ syserr("invalid argument to S line: \"%.20s\"",
+ &bp[1]);
+ break;
+ }
+ ruleset = atoi(p);
+ if (ruleset >= MAXRWSETS || ruleset < 0)
+ {
+ syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
+ ruleset = 0;
+ }
+ rwp = NULL;
+ break;
+
+ case 'D': /* macro definition */
+ p = munchstring(&bp[2], NULL);
+ define(bp[1], newstr(p), e);
+ break;
+
+ case 'H': /* required header line */
+ (void) chompheader(&bp[1], TRUE, e);
+ break;
+
+ case 'C': /* word class */
+ /* scan the list of words and set class for all */
+ expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e);
+ for (p = exbuf; *p != '\0'; )
+ {
+ register char *wd;
+ char delim;
+
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ p++;
+ wd = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ delim = *p;
+ *p = '\0';
+ if (wd[0] != '\0')
+ setclass(bp[1], wd);
+ *p = delim;
+ }
+ break;
+
+ case 'F': /* word class from file */
+ for (p = &bp[2]; isascii(*p) && isspace(*p); )
+ p++;
+ if (p[0] == '-' && p[1] == 'o')
+ {
+ optional = TRUE;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ while (isascii(*p) && isspace(*p))
+ *p++;
+ }
+ else
+ optional = FALSE;
+ file = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p == '\0')
+ p = "%s";
+ else
+ {
+ *p = '\0';
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ }
+ fileclass(bp[1], file, p, safe, optional);
+ break;
+
+#ifdef XLA
+ case 'L': /* extended load average description */
+ xla_init(&bp[1]);
+ break;
+#endif
+
+ case 'M': /* define mailer */
+ makemailer(&bp[1]);
+ break;
+
+ case 'O': /* set option */
+ setoption(bp[1], &bp[2], safe, FALSE, e);
+ break;
+
+ case 'P': /* set precedence */
+ if (NumPriorities >= MAXPRIORITIES)
+ {
+ toomany('P', MAXPRIORITIES);
+ break;
+ }
+ for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
+ continue;
+ if (*p == '\0')
+ goto badline;
+ *p = '\0';
+ Priorities[NumPriorities].pri_name = newstr(&bp[1]);
+ Priorities[NumPriorities].pri_val = atoi(++p);
+ NumPriorities++;
+ break;
+
+ case 'T': /* trusted user(s) */
+ /* this option is obsolete, but will be ignored */
+ break;
+
+ case 'V': /* configuration syntax version */
+ for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+ continue;
+ if (!isascii(*p) || !isdigit(*p))
+ {
+ syserr("invalid argument to V line: \"%.20s\"",
+ &bp[1]);
+ break;
+ }
+ ConfigLevel = strtol(p, &ep, 10);
+ if (ConfigLevel >= 5)
+ {
+ /* level 5 configs have short name in $w */
+ p = macvalue('w', e);
+ if (p != NULL && (p = strchr(p, '.')) != NULL)
+ *p = '\0';
+ }
+ if (*ep++ == '/')
+ {
+ /* extract vendor code */
+ for (p = ep; isascii(*p) && isalpha(*p); )
+ p++;
+ *p = '\0';
+
+ if (!setvendor(ep))
+ syserr("invalid V line vendor code: \"%s\"",
+ ep);
+ }
+ break;
+
+ case 'K':
+ makemapentry(&bp[1]);
+ break;
+
+ default:
+ badline:
+ syserr("unknown control line \"%s\"", bp);
+ }
+ if (bp != buf)
+ free(bp);
+ }
+ if (ferror(cf))
+ {
+ syserr("I/O read error", cfname);
+ exit(EX_OSFILE);
+ }
+ fclose(cf);
+ FileName = NULL;
+
+ if (stab("host", ST_MAP, ST_FIND) == NULL)
+ {
+ /* user didn't initialize: set up host map */
+ strcpy(buf, "host host");
+#if NAMED_BIND
+ if (ConfigLevel >= 2)
+ strcat(buf, " -a.");
+#endif
+ makemapentry(buf);
+ }
+}
+ /*
+** TOOMANY -- signal too many of some option
+**
+** Parameters:
+** id -- the id of the error line
+** maxcnt -- the maximum possible values
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** gives a syserr.
+*/
+
+toomany(id, maxcnt)
+ char id;
+ int maxcnt;
+{
+ syserr("too many %c lines, %d max", id, maxcnt);
+}
+ /*
+** FILECLASS -- read members of a class from a file
+**
+** Parameters:
+** class -- class to define.
+** filename -- name of file to read.
+** fmt -- scanf string to use for match.
+** safe -- if set, this is a safe read.
+** optional -- if set, it is not an error for the file to
+** not exist.
+**
+** Returns:
+** none
+**
+** Side Effects:
+**
+** puts all lines in filename that match a scanf into
+** the named class.
+*/
+
+fileclass(class, filename, fmt, safe, optional)
+ int class;
+ char *filename;
+ char *fmt;
+ bool safe;
+ bool optional;
+{
+ FILE *f;
+ struct stat stbuf;
+ char buf[MAXLINE];
+
+ if (tTd(37, 2))
+ printf("fileclass(%s, fmt=%s)\n", filename, fmt);
+
+ if (filename[0] == '|')
+ {
+ syserr("fileclass: pipes (F%c%s) not supported due to security problems",
+ class, filename);
+ return;
+ }
+ if (stat(filename, &stbuf) < 0)
+ {
+ if (tTd(37, 2))
+ printf(" cannot stat (%s)\n", errstring(errno));
+ if (!optional)
+ syserr("fileclass: cannot stat %s", filename);
+ return;
+ }
+ if (!S_ISREG(stbuf.st_mode))
+ {
+ syserr("fileclass: %s not a regular file", filename);
+ return;
+ }
+ if (!safe && access(filename, R_OK) < 0)
+ {
+ syserr("fileclass: access denied on %s", filename);
+ return;
+ }
+ f = fopen(filename, "r");
+ if (f == NULL)
+ {
+ syserr("fileclass: cannot open %s", filename);
+ return;
+ }
+
+ while (fgets(buf, sizeof buf, f) != NULL)
+ {
+ register STAB *s;
+ register char *p;
+# ifdef SCANF
+ char wordbuf[MAXNAME+1];
+
+ if (sscanf(buf, fmt, wordbuf) != 1)
+ continue;
+ p = wordbuf;
+# else /* SCANF */
+ p = buf;
+# endif /* SCANF */
+
+ /*
+ ** Break up the match into words.
+ */
+
+ while (*p != '\0')
+ {
+ register char *q;
+
+ /* strip leading spaces */
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p == '\0')
+ break;
+
+ /* find the end of the word */
+ q = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+
+ /* enter the word in the symbol table */
+ setclass(class, q);
+ }
+ }
+
+ (void) fclose(f);
+}
+ /*
+** MAKEMAILER -- define a new mailer.
+**
+** Parameters:
+** line -- description of mailer. This is in labeled
+** fields. The fields are:
+** P -- the path to the mailer
+** F -- the flags associated with the mailer
+** A -- the argv for this mailer
+** S -- the sender rewriting set
+** R -- the recipient rewriting set
+** E -- the eol string
+** The first word is the canonical name of the mailer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** enters the mailer into the mailer table.
+*/
+
+makemailer(line)
+ char *line;
+{
+ register char *p;
+ register struct mailer *m;
+ register STAB *s;
+ int i;
+ char fcode;
+ auto char *endp;
+ extern int NextMailer;
+ extern char **makeargv();
+ extern char *munchstring();
+ extern long atol();
+
+ /* allocate a mailer and set up defaults */
+ m = (struct mailer *) xalloc(sizeof *m);
+ bzero((char *) m, sizeof *m);
+ m->m_eol = "\n";
+
+ /* collect the mailer name */
+ for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+ m->m_name = newstr(line);
+
+ /* now scan through and assign info from the fields */
+ while (*p != '\0')
+ {
+ auto char *delimptr;
+
+ while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
+ p++;
+
+ /* p now points to field code */
+ fcode = *p;
+ while (*p != '\0' && *p != '=' && *p != ',')
+ p++;
+ if (*p++ != '=')
+ {
+ syserr("mailer %s: `=' expected", m->m_name);
+ return;
+ }
+ while (isascii(*p) && isspace(*p))
+ p++;
+
+ /* p now points to the field body */
+ p = munchstring(p, &delimptr);
+
+ /* install the field into the mailer struct */
+ switch (fcode)
+ {
+ case 'P': /* pathname */
+ m->m_mailer = newstr(p);
+ break;
+
+ case 'F': /* flags */
+ for (; *p != '\0'; p++)
+ if (!(isascii(*p) && isspace(*p)))
+ setbitn(*p, m->m_flags);
+ break;
+
+ case 'S': /* sender rewriting ruleset */
+ case 'R': /* recipient rewriting ruleset */
+ i = strtol(p, &endp, 10);
+ if (i < 0 || i >= MAXRWSETS)
+ {
+ syserr("invalid rewrite set, %d max", MAXRWSETS);
+ return;
+ }
+ if (fcode == 'S')
+ m->m_sh_rwset = m->m_se_rwset = i;
+ else
+ m->m_rh_rwset = m->m_re_rwset = i;
+
+ p = endp;
+ if (*p++ == '/')
+ {
+ i = strtol(p, NULL, 10);
+ if (i < 0 || i >= MAXRWSETS)
+ {
+ syserr("invalid rewrite set, %d max",
+ MAXRWSETS);
+ return;
+ }
+ if (fcode == 'S')
+ m->m_sh_rwset = i;
+ else
+ m->m_rh_rwset = i;
+ }
+ break;
+
+ case 'E': /* end of line string */
+ m->m_eol = newstr(p);
+ break;
+
+ case 'A': /* argument vector */
+ m->m_argv = makeargv(p);
+ break;
+
+ case 'M': /* maximum message size */
+ m->m_maxsize = atol(p);
+ break;
+
+ case 'L': /* maximum line length */
+ m->m_linelimit = atoi(p);
+ break;
+
+ case 'D': /* working directory */
+ m->m_execdir = newstr(p);
+ break;
+ }
+
+ p = delimptr;
+ }
+
+ /* do some heuristic cleanup for back compatibility */
+ if (bitnset(M_LIMITS, m->m_flags))
+ {
+ if (m->m_linelimit == 0)
+ m->m_linelimit = SMTPLINELIM;
+ if (ConfigLevel < 2)
+ setbitn(M_7BITS, m->m_flags);
+ }
+
+ /* do some rationality checking */
+ if (m->m_argv == NULL)
+ {
+ syserr("M%s: A= argument required", m->m_name);
+ return;
+ }
+ if (m->m_mailer == NULL)
+ {
+ syserr("M%s: P= argument required", m->m_name);
+ return;
+ }
+
+ if (NextMailer >= MAXMAILERS)
+ {
+ syserr("too many mailers defined (%d max)", MAXMAILERS);
+ return;
+ }
+
+ s = stab(m->m_name, ST_MAILER, ST_ENTER);
+ if (s->s_mailer != NULL)
+ {
+ i = s->s_mailer->m_mno;
+ free(s->s_mailer);
+ }
+ else
+ {
+ i = NextMailer++;
+ }
+ Mailer[i] = s->s_mailer = m;
+ m->m_mno = i;
+}
+ /*
+** MUNCHSTRING -- translate a string into internal form.
+**
+** Parameters:
+** p -- the string to munch.
+** delimptr -- if non-NULL, set to the pointer of the
+** field delimiter character.
+**
+** Returns:
+** the munched string.
+*/
+
+char *
+munchstring(p, delimptr)
+ register char *p;
+ char **delimptr;
+{
+ register char *q;
+ bool backslash = FALSE;
+ bool quotemode = FALSE;
+ static char buf[MAXLINE];
+
+ for (q = buf; *p != '\0'; p++)
+ {
+ if (backslash)
+ {
+ /* everything is roughly literal */
+ backslash = FALSE;
+ switch (*p)
+ {
+ case 'r': /* carriage return */
+ *q++ = '\r';
+ continue;
+
+ case 'n': /* newline */
+ *q++ = '\n';
+ continue;
+
+ case 'f': /* form feed */
+ *q++ = '\f';
+ continue;
+
+ case 'b': /* backspace */
+ *q++ = '\b';
+ continue;
+ }
+ *q++ = *p;
+ }
+ else
+ {
+ if (*p == '\\')
+ backslash = TRUE;
+ else if (*p == '"')
+ quotemode = !quotemode;
+ else if (quotemode || *p != ',')
+ *q++ = *p;
+ else
+ break;
+ }
+ }
+
+ if (delimptr != NULL)
+ *delimptr = p;
+ *q++ = '\0';
+ return (buf);
+}
+ /*
+** MAKEARGV -- break up a string into words
+**
+** Parameters:
+** p -- the string to break up.
+**
+** Returns:
+** a char **argv (dynamically allocated)
+**
+** Side Effects:
+** munges p.
+*/
+
+char **
+makeargv(p)
+ register char *p;
+{
+ char *q;
+ int i;
+ char **avp;
+ char *argv[MAXPV + 1];
+
+ /* take apart the words */
+ i = 0;
+ while (*p != '\0' && i < MAXPV)
+ {
+ q = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ while (isascii(*p) && isspace(*p))
+ *p++ = '\0';
+ argv[i++] = newstr(q);
+ }
+ argv[i++] = NULL;
+
+ /* now make a copy of the argv */
+ avp = (char **) xalloc(sizeof *avp * i);
+ bcopy((char *) argv, (char *) avp, sizeof *avp * i);
+
+ return (avp);
+}
+ /*
+** PRINTRULES -- print rewrite rules (for debugging)
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** prints rewrite rules.
+*/
+
+printrules()
+{
+ register struct rewrite *rwp;
+ register int ruleset;
+
+ for (ruleset = 0; ruleset < 10; ruleset++)
+ {
+ if (RewriteRules[ruleset] == NULL)
+ continue;
+ printf("\n----Rule Set %d:", ruleset);
+
+ for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
+ {
+ printf("\nLHS:");
+ printav(rwp->r_lhs);
+ printf("RHS:");
+ printav(rwp->r_rhs);
+ }
+ }
+}
+
+ /*
+** SETOPTION -- set global processing option
+**
+** Parameters:
+** opt -- option name.
+** val -- option value (as a text string).
+** safe -- set if this came from a configuration file.
+** Some options (if set from the command line) will
+** reset the user id to avoid security problems.
+** sticky -- if set, don't let other setoptions override
+** this value.
+** e -- the main envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets options as implied by the arguments.
+*/
+
+static BITMAP StickyOpt; /* set if option is stuck */
+
+
+#if NAMED_BIND
+
+struct resolverflags
+{
+ char *rf_name; /* name of the flag */
+ long rf_bits; /* bits to set/clear */
+} ResolverFlags[] =
+{
+ "debug", RES_DEBUG,
+ "aaonly", RES_AAONLY,
+ "usevc", RES_USEVC,
+ "primary", RES_PRIMARY,
+ "igntc", RES_IGNTC,
+ "recurse", RES_RECURSE,
+ "defnames", RES_DEFNAMES,
+ "stayopen", RES_STAYOPEN,
+ "dnsrch", RES_DNSRCH,
+ "true", 0, /* to avoid error on old syntax */
+ NULL, 0
+};
+
+#endif
+
+setoption(opt, val, safe, sticky, e)
+ char opt;
+ char *val;
+ bool safe;
+ bool sticky;
+ register ENVELOPE *e;
+{
+ register char *p;
+ extern bool atobool();
+ extern time_t convtime();
+ extern int QueueLA;
+ extern int RefuseLA;
+ extern bool Warn_Q_option;
+ extern bool trusteduser();
+
+ if (tTd(37, 1))
+ printf("setoption %c=%s", opt, val);
+
+ /*
+ ** See if this option is preset for us.
+ */
+
+ if (!sticky && bitnset(opt, StickyOpt))
+ {
+ if (tTd(37, 1))
+ printf(" (ignored)\n");
+ return;
+ }
+
+ /*
+ ** Check to see if this option can be specified by this user.
+ */
+
+ if (!safe && RealUid == 0)
+ safe = TRUE;
+ if (!safe && strchr("bCdeijLmoprsvw7", opt) == NULL)
+ {
+ if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
+ {
+ if (tTd(37, 1))
+ printf(" (unsafe)");
+ if (RealUid != geteuid())
+ {
+ if (tTd(37, 1))
+ printf("(Resetting uid)");
+ (void) setgid(RealGid);
+ (void) setuid(RealUid);
+ }
+ }
+ }
+ if (tTd(37, 1))
+ printf("\n");
+
+ switch (opt)
+ {
+ case '7': /* force seven-bit input */
+ SevenBit = atobool(val);
+ break;
+
+ case 'A': /* set default alias file */
+ if (val[0] == '\0')
+ setalias("aliases");
+ else
+ setalias(val);
+ break;
+
+ case 'a': /* look N minutes for "@:@" in alias file */
+ if (val[0] == '\0')
+ SafeAlias = 5 * 60; /* five minutes */
+ else
+ SafeAlias = convtime(val, 'm');
+ break;
+
+ case 'B': /* substitution for blank character */
+ SpaceSub = val[0];
+ if (SpaceSub == '\0')
+ SpaceSub = ' ';
+ break;
+
+ case 'b': /* min blocks free on queue fs/max msg size */
+ p = strchr(val, '/');
+ if (p != NULL)
+ {
+ *p++ = '\0';
+ MaxMessageSize = atol(p);
+ }
+ MinBlocksFree = atol(val);
+ break;
+
+ case 'c': /* don't connect to "expensive" mailers */
+ NoConnect = atobool(val);
+ break;
+
+ case 'C': /* checkpoint every N addresses */
+ CheckpointInterval = atoi(val);
+ break;
+
+ case 'd': /* delivery mode */
+ switch (*val)
+ {
+ case '\0':
+ e->e_sendmode = SM_DELIVER;
+ break;
+
+ case SM_QUEUE: /* queue only */
+#ifndef QUEUE
+ syserr("need QUEUE to set -odqueue");
+#endif /* QUEUE */
+ /* fall through..... */
+
+ case SM_DELIVER: /* do everything */
+ case SM_FORK: /* fork after verification */
+ e->e_sendmode = *val;
+ break;
+
+ default:
+ syserr("Unknown delivery mode %c", *val);
+ exit(EX_USAGE);
+ }
+ break;
+
+ case 'D': /* rebuild alias database as needed */
+ AutoRebuild = atobool(val);
+ break;
+
+ case 'E': /* error message header/header file */
+ if (*val != '\0')
+ ErrMsgFile = newstr(val);
+ break;
+
+ case 'e': /* set error processing mode */
+ switch (*val)
+ {
+ case EM_QUIET: /* be silent about it */
+ case EM_MAIL: /* mail back */
+ case EM_BERKNET: /* do berknet error processing */
+ case EM_WRITE: /* write back (or mail) */
+ HoldErrs = TRUE;
+ /* fall through... */
+
+ case EM_PRINT: /* print errors normally (default) */
+ e->e_errormode = *val;
+ break;
+ }
+ break;
+
+ case 'F': /* file mode */
+ FileMode = atooct(val) & 0777;
+ break;
+
+ case 'f': /* save Unix-style From lines on front */
+ SaveFrom = atobool(val);
+ break;
+
+ case 'G': /* match recipients against GECOS field */
+ MatchGecos = atobool(val);
+ break;
+
+ case 'g': /* default gid */
+ if (isascii(*val) && isdigit(*val))
+ DefGid = atoi(val);
+ else
+ {
+ register struct group *gr;
+
+ DefGid = -1;
+ gr = getgrnam(val);
+ if (gr == NULL)
+ syserr("readcf: option g: unknown group %s", val);
+ else
+ DefGid = gr->gr_gid;
+ }
+ break;
+
+ case 'H': /* help file */
+ if (val[0] == '\0')
+ HelpFile = "sendmail.hf";
+ else
+ HelpFile = newstr(val);
+ break;
+
+ case 'h': /* maximum hop count */
+ MaxHopCount = atoi(val);
+ break;
+
+ case 'I': /* use internet domain name server */
+#if NAMED_BIND
+ UseNameServer = TRUE;
+ for (p = val; *p != 0; )
+ {
+ bool clearmode;
+ char *q;
+ struct resolverflags *rfp;
+
+ while (*p == ' ')
+ p++;
+ if (*p == '\0')
+ break;
+ clearmode = FALSE;
+ if (*p == '-')
+ clearmode = TRUE;
+ else if (*p != '+')
+ p--;
+ p++;
+ q = p;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
+ {
+ if (strcasecmp(q, rfp->rf_name) == 0)
+ break;
+ }
+ if (rfp->rf_name == NULL)
+ syserr("readcf: I option value %s unrecognized", q);
+ else if (clearmode)
+ _res.options &= ~rfp->rf_bits;
+ else
+ _res.options |= rfp->rf_bits;
+ }
+ if (tTd(8, 2))
+ printf("_res.options = %x\n", _res.options);
+#else
+ usrerr("name server (I option) specified but BIND not compiled in");
+#endif
+ break;
+
+ case 'i': /* ignore dot lines in message */
+ IgnrDot = atobool(val);
+ break;
+
+ case 'j': /* send errors in MIME (RFC 1341) format */
+ SendMIMEErrors = atobool(val);
+ break;
+
+ case 'J': /* .forward search path */
+ ForwardPath = newstr(val);
+ break;
+
+ case 'k': /* connection cache size */
+ MaxMciCache = atoi(val);
+ if (MaxMciCache < 0)
+ MaxMciCache = 0;
+ break;
+
+ case 'K': /* connection cache timeout */
+ MciCacheTimeout = convtime(val, 'm');
+ break;
+
+ case 'l': /* use Errors-To: header */
+ UseErrorsTo = atobool(val);
+ break;
+
+ case 'L': /* log level */
+ if (safe || LogLevel < atoi(val))
+ LogLevel = atoi(val);
+ break;
+
+ case 'M': /* define macro */
+ p = newstr(&val[1]);
+ if (!safe)
+ cleanstrcpy(p, p, MAXNAME);
+ define(val[0], p, CurEnv);
+ sticky = FALSE;
+ break;
+
+ case 'm': /* send to me too */
+ MeToo = atobool(val);
+ break;
+
+ case 'n': /* validate RHS in newaliases */
+ CheckAliases = atobool(val);
+ break;
+
+ /* 'N' available -- was "net name" */
+
+ case 'O': /* daemon options */
+ setdaemonoptions(val);
+ break;
+
+ case 'o': /* assume old style headers */
+ if (atobool(val))
+ CurEnv->e_flags |= EF_OLDSTYLE;
+ else
+ CurEnv->e_flags &= ~EF_OLDSTYLE;
+ break;
+
+ case 'p': /* select privacy level */
+ p = val;
+ for (;;)
+ {
+ register struct prival *pv;
+ extern struct prival PrivacyValues[];
+
+ while (isascii(*p) && (isspace(*p) || ispunct(*p)))
+ p++;
+ if (*p == '\0')
+ break;
+ val = p;
+ while (isascii(*p) && isalnum(*p))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+
+ for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
+ {
+ if (strcasecmp(val, pv->pv_name) == 0)
+ break;
+ }
+ if (pv->pv_name == NULL)
+ syserr("readcf: Op line: %s unrecognized", val);
+ PrivacyFlags |= pv->pv_flag;
+ }
+ sticky = FALSE;
+ break;
+
+ case 'P': /* postmaster copy address for returned mail */
+ PostMasterCopy = newstr(val);
+ break;
+
+ case 'q': /* slope of queue only function */
+ QueueFactor = atoi(val);
+ break;
+
+ case 'Q': /* queue directory */
+ if (val[0] == '\0')
+ QueueDir = "mqueue";
+ else
+ QueueDir = newstr(val);
+ if (RealUid != 0 && !safe)
+ Warn_Q_option = TRUE;
+ break;
+
+ case 'R': /* don't prune routes */
+ DontPruneRoutes = atobool(val);
+ break;
+
+ case 'r': /* read timeout */
+ settimeouts(val);
+ break;
+
+ case 'S': /* status file */
+ if (val[0] == '\0')
+ StatFile = "sendmail.st";
+ else
+ StatFile = newstr(val);
+ break;
+
+ case 's': /* be super safe, even if expensive */
+ SuperSafe = atobool(val);
+ break;
+
+ case 'T': /* queue timeout */
+ p = strchr(val, '/');
+ if (p != NULL)
+ {
+ *p++ = '\0';
+ TimeOuts.to_q_warning = convtime(p, 'd');
+ }
+ TimeOuts.to_q_return = convtime(val, 'h');
+ break;
+
+ case 't': /* time zone name */
+ TimeZoneSpec = newstr(val);
+ break;
+
+ case 'U': /* location of user database */
+ UdbSpec = newstr(val);
+ break;
+
+ case 'u': /* set default uid */
+ if (isascii(*val) && isdigit(*val))
+ DefUid = atoi(val);
+ else
+ {
+ register struct passwd *pw;
+
+ DefUid = -1;
+ pw = getpwnam(val);
+ if (pw == NULL)
+ syserr("readcf: option u: unknown user %s", val);
+ else
+ DefUid = pw->pw_uid;
+ }
+ setdefuser();
+ break;
+
+ case 'V': /* fallback MX host */
+ FallBackMX = newstr(val);
+ break;
+
+ case 'v': /* run in verbose mode */
+ Verbose = atobool(val);
+ break;
+
+ case 'w': /* if we are best MX, try host directly */
+ TryNullMXList = atobool(val);
+ break;
+
+ /* 'W' available -- was wizard password */
+
+ case 'x': /* load avg at which to auto-queue msgs */
+ QueueLA = atoi(val);
+ break;
+
+ case 'X': /* load avg at which to auto-reject connections */
+ RefuseLA = atoi(val);
+ break;
+
+ case 'y': /* work recipient factor */
+ WkRecipFact = atoi(val);
+ break;
+
+ case 'Y': /* fork jobs during queue runs */
+ ForkQueueRuns = atobool(val);
+ break;
+
+ case 'z': /* work message class factor */
+ WkClassFact = atoi(val);
+ break;
+
+ case 'Z': /* work time factor */
+ WkTimeFact = atoi(val);
+ break;
+
+ default:
+ break;
+ }
+ if (sticky)
+ setbitn(opt, StickyOpt);
+ return;
+}
+ /*
+** SETCLASS -- set a word into a class
+**
+** Parameters:
+** class -- the class to put the word in.
+** word -- the word to enter
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** puts the word into the symbol table.
+*/
+
+setclass(class, word)
+ int class;
+ char *word;
+{
+ register STAB *s;
+
+ if (tTd(37, 8))
+ printf("setclass(%c, %s)\n", class, word);
+ s = stab(word, ST_CLASS, ST_ENTER);
+ setbitn(class, s->s_class);
+}
+ /*
+** MAKEMAPENTRY -- create a map entry
+**
+** Parameters:
+** line -- the config file line
+**
+** Returns:
+** TRUE if it successfully entered the map entry.
+** FALSE otherwise (usually syntax error).
+**
+** Side Effects:
+** Enters the map into the dictionary.
+*/
+
+void
+makemapentry(line)
+ char *line;
+{
+ register char *p;
+ char *mapname;
+ char *classname;
+ register STAB *s;
+ STAB *class;
+
+ for (p = line; isascii(*p) && isspace(*p); p++)
+ continue;
+ if (!(isascii(*p) && isalnum(*p)))
+ {
+ syserr("readcf: config K line: no map name");
+ return;
+ }
+
+ mapname = p;
+ while (isascii(*++p) && isalnum(*p))
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (!(isascii(*p) && isalnum(*p)))
+ {
+ syserr("readcf: config K line, map %s: no map class", mapname);
+ return;
+ }
+ classname = p;
+ while (isascii(*++p) && isalnum(*p))
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+ while (isascii(*p) && isspace(*p))
+ p++;
+
+ /* look up the class */
+ class = stab(classname, ST_MAPCLASS, ST_FIND);
+ if (class == NULL)
+ {
+ syserr("readcf: map %s: class %s not available", mapname, classname);
+ return;
+ }
+
+ /* enter the map */
+ s = stab(mapname, ST_MAP, ST_ENTER);
+ s->s_map.map_class = &class->s_mapclass;
+ s->s_map.map_mname = newstr(mapname);
+
+ if (class->s_mapclass.map_parse(&s->s_map, p))
+ s->s_map.map_mflags |= MF_VALID;
+
+ if (tTd(37, 5))
+ {
+ printf("map %s, class %s, flags %x, file %s,\n",
+ s->s_map.map_mname, s->s_map.map_class->map_cname,
+ s->s_map.map_mflags,
+ s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
+ printf("\tapp %s, domain %s, rebuild %s\n",
+ s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
+ s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
+ s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
+ }
+}
+ /*
+** SETTIMEOUTS -- parse and set timeout values
+**
+** Parameters:
+** val -- a pointer to the values. If NULL, do initial
+** settings.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Initializes the TimeOuts structure
+*/
+
+#define SECONDS
+#define MINUTES * 60
+#define HOUR * 3600
+
+settimeouts(val)
+ register char *val;
+{
+ register char *p;
+ extern time_t convtime();
+
+ if (val == NULL)
+ {
+ TimeOuts.to_initial = (time_t) 5 MINUTES;
+ TimeOuts.to_helo = (time_t) 5 MINUTES;
+ TimeOuts.to_mail = (time_t) 10 MINUTES;
+ TimeOuts.to_rcpt = (time_t) 1 HOUR;
+ TimeOuts.to_datainit = (time_t) 5 MINUTES;
+ TimeOuts.to_datablock = (time_t) 1 HOUR;
+ TimeOuts.to_datafinal = (time_t) 1 HOUR;
+ TimeOuts.to_rset = (time_t) 5 MINUTES;
+ TimeOuts.to_quit = (time_t) 2 MINUTES;
+ TimeOuts.to_nextcommand = (time_t) 1 HOUR;
+ TimeOuts.to_miscshort = (time_t) 2 MINUTES;
+ TimeOuts.to_ident = (time_t) 30 SECONDS;
+ return;
+ }
+
+ for (;; val = p)
+ {
+ while (isascii(*val) && isspace(*val))
+ val++;
+ if (*val == '\0')
+ break;
+ for (p = val; *p != '\0' && *p != ','; p++)
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+
+ if (isascii(*val) && isdigit(*val))
+ {
+ /* old syntax -- set everything */
+ TimeOuts.to_mail = convtime(val, 'm');
+ TimeOuts.to_rcpt = TimeOuts.to_mail;
+ TimeOuts.to_datainit = TimeOuts.to_mail;
+ TimeOuts.to_datablock = TimeOuts.to_mail;
+ TimeOuts.to_datafinal = TimeOuts.to_mail;
+ TimeOuts.to_nextcommand = TimeOuts.to_mail;
+ continue;
+ }
+ else
+ {
+ register char *q = strchr(val, '=');
+ time_t to;
+
+ if (q == NULL)
+ {
+ /* syntax error */
+ continue;
+ }
+ *q++ = '\0';
+ to = convtime(q, 'm');
+
+ if (strcasecmp(val, "initial") == 0)
+ TimeOuts.to_initial = to;
+ else if (strcasecmp(val, "mail") == 0)
+ TimeOuts.to_mail = to;
+ else if (strcasecmp(val, "rcpt") == 0)
+ TimeOuts.to_rcpt = to;
+ else if (strcasecmp(val, "datainit") == 0)
+ TimeOuts.to_datainit = to;
+ else if (strcasecmp(val, "datablock") == 0)
+ TimeOuts.to_datablock = to;
+ else if (strcasecmp(val, "datafinal") == 0)
+ TimeOuts.to_datafinal = to;
+ else if (strcasecmp(val, "command") == 0)
+ TimeOuts.to_nextcommand = to;
+ else if (strcasecmp(val, "rset") == 0)
+ TimeOuts.to_rset = to;
+ else if (strcasecmp(val, "helo") == 0)
+ TimeOuts.to_helo = to;
+ else if (strcasecmp(val, "quit") == 0)
+ TimeOuts.to_quit = to;
+ else if (strcasecmp(val, "misc") == 0)
+ TimeOuts.to_miscshort = to;
+ else if (strcasecmp(val, "ident") == 0)
+ TimeOuts.to_ident = to;
+ else
+ syserr("settimeouts: invalid timeout %s", val);
+ }
+ }
+}
diff --git a/usr.sbin/sendmail/src/recipient.c b/usr.sbin/sendmail/src/recipient.c
new file mode 100644
index 00000000000..a43cf5c93df
--- /dev/null
+++ b/usr.sbin/sendmail/src/recipient.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)recipient.c 8.44.1.6 (Berkeley) 3/5/95";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include <pwd.h>
+
+/*
+** SENDTOLIST -- Designate a send list.
+**
+** The parameter is a comma-separated list of people to send to.
+** This routine arranges to send to all of them.
+**
+** Parameters:
+** list -- the send list.
+** ctladdr -- the address template for the person to
+** send to -- effective uid/gid are important.
+** This is typically the alias that caused this
+** expansion.
+** sendq -- a pointer to the head of a queue to put
+** these people into.
+** e -- the envelope in which to add these recipients.
+**
+** Returns:
+** The number of addresses actually on the list.
+**
+** Side Effects:
+** none.
+*/
+
+# define MAXRCRSN 10
+
+sendtolist(list, ctladdr, sendq, e)
+ char *list;
+ ADDRESS *ctladdr;
+ ADDRESS **sendq;
+ register ENVELOPE *e;
+{
+ register char *p;
+ register ADDRESS *al; /* list of addresses to send to */
+ bool firstone; /* set on first address sent */
+ char delimiter; /* the address delimiter */
+ int naddrs;
+ int i;
+ char *oldto = e->e_to;
+ char *bufp;
+ char buf[MAXNAME + 1];
+
+ if (list == NULL)
+ {
+ syserr("sendtolist: null list");
+ return 0;
+ }
+
+ if (tTd(25, 1))
+ {
+ printf("sendto: %s\n ctladdr=", list);
+ printaddr(ctladdr, FALSE);
+ }
+
+ /* heuristic to determine old versus new style addresses */
+ if (ctladdr == NULL &&
+ (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
+ strchr(list, '<') != NULL || strchr(list, '(') != NULL))
+ e->e_flags &= ~EF_OLDSTYLE;
+ delimiter = ' ';
+ if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
+ delimiter = ',';
+
+ firstone = TRUE;
+ al = NULL;
+ naddrs = 0;
+
+ /* make sure we have enough space to copy the string */
+ i = strlen(list) + 1;
+ if (i <= sizeof buf)
+ bufp = buf;
+ else
+ bufp = xalloc(i);
+ strcpy(bufp, denlstring(list, FALSE, TRUE));
+
+ for (p = bufp; *p != '\0'; )
+ {
+ auto char *delimptr;
+ register ADDRESS *a;
+
+ /* parse the address */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
+ p = delimptr;
+ if (a == NULL)
+ continue;
+ a->q_next = al;
+ a->q_alias = ctladdr;
+
+ /* see if this should be marked as a primary address */
+ if (ctladdr == NULL ||
+ (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
+ a->q_flags |= QPRIMARY;
+
+ if (ctladdr != NULL && sameaddr(ctladdr, a))
+ ctladdr->q_flags |= QSELFREF;
+ al = a;
+ firstone = FALSE;
+ }
+
+ /* arrange to send to everyone on the local send list */
+ while (al != NULL)
+ {
+ register ADDRESS *a = al;
+
+ al = a->q_next;
+ a = recipient(a, sendq, e);
+
+ /* arrange to inherit full name */
+ if (a->q_fullname == NULL && ctladdr != NULL)
+ a->q_fullname = ctladdr->q_fullname;
+ naddrs++;
+ }
+
+ e->e_to = oldto;
+ if (bufp != buf)
+ free(bufp);
+ return (naddrs);
+}
+ /*
+** RECIPIENT -- Designate a message recipient
+**
+** Saves the named person for future mailing.
+**
+** Parameters:
+** a -- the (preparsed) address header for the recipient.
+** sendq -- a pointer to the head of a queue to put the
+** recipient in. Duplicate supression is done
+** in this queue.
+** e -- the current envelope.
+**
+** Returns:
+** The actual address in the queue. This will be "a" if
+** the address is not a duplicate, else the original address.
+**
+** Side Effects:
+** none.
+*/
+
+ADDRESS *
+recipient(a, sendq, e)
+ register ADDRESS *a;
+ register ADDRESS **sendq;
+ register ENVELOPE *e;
+{
+ register ADDRESS *q;
+ ADDRESS **pq;
+ register struct mailer *m;
+ register char *p;
+ bool quoted = FALSE; /* set if the addr has a quote bit */
+ int findusercount = 0;
+ char buf[MAXNAME]; /* unquoted image of the user name */
+ extern int safefile();
+
+ e->e_to = a->q_paddr;
+ m = a->q_mailer;
+ errno = 0;
+ if (tTd(26, 1))
+ {
+ printf("\nrecipient: ");
+ printaddr(a, FALSE);
+ }
+
+ /* if this is primary, add it to the original recipient list */
+ if (a->q_alias == NULL)
+ {
+ if (e->e_origrcpt == NULL)
+ e->e_origrcpt = a->q_paddr;
+ else if (e->e_origrcpt != a->q_paddr)
+ e->e_origrcpt = "";
+ }
+
+ /* break aliasing loops */
+ if (AliasLevel > MAXRCRSN)
+ {
+ usrerr("554 aliasing/forwarding loop broken");
+ return (a);
+ }
+
+ /*
+ ** Finish setting up address structure.
+ */
+
+ /* set the queue timeout */
+ a->q_timeout = TimeOuts.to_q_return;
+
+ /* get unquoted user for file, program or user.name check */
+ (void) strcpy(buf, a->q_user);
+ for (p = buf; *p != '\0' && !quoted; p++)
+ {
+ if (*p == '\\')
+ quoted = TRUE;
+ }
+ stripquotes(buf);
+
+ /* check for direct mailing to restricted mailers */
+ if (m == ProgMailer)
+ {
+ if (a->q_alias == NULL)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Cannot mail directly to programs");
+ }
+ else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs",
+ a->q_alias->q_ruser, MyHostName);
+ }
+ else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Address %s is unsafe for mailing to programs",
+ a->q_alias->q_paddr);
+ }
+ }
+
+ /*
+ ** Look up this person in the recipient list.
+ ** If they are there already, return, otherwise continue.
+ ** If the list is empty, just add it. Notice the cute
+ ** hack to make from addresses suppress things correctly:
+ ** the QDONTSEND bit will be set in the send list.
+ ** [Please note: the emphasis is on "hack."]
+ */
+
+ for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
+ {
+ if (sameaddr(q, a))
+ {
+ if (tTd(26, 1))
+ {
+ printf("%s in sendq: ", a->q_paddr);
+ printaddr(q, FALSE);
+ }
+ if (!bitset(QPRIMARY, q->q_flags))
+ {
+ if (!bitset(QDONTSEND, a->q_flags))
+ message("duplicate suppressed");
+ q->q_flags |= a->q_flags;
+ }
+ else if (bitset(QSELFREF, q->q_flags))
+ q->q_flags |= a->q_flags & ~QDONTSEND;
+ a = q;
+ goto testselfdestruct;
+ }
+ }
+
+ /* add address on list */
+ *pq = a;
+ a->q_next = NULL;
+
+ /*
+ ** Alias the name and handle special mailer types.
+ */
+
+ trylocaluser:
+ if (tTd(29, 7))
+ printf("at trylocaluser %s\n", a->q_user);
+
+ if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
+ goto testselfdestruct;
+
+ if (m == InclMailer)
+ {
+ a->q_flags |= QDONTSEND;
+ if (a->q_alias == NULL)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Cannot mail directly to :include:s");
+ }
+ else
+ {
+ int ret;
+
+ message("including file %s", a->q_user);
+ ret = include(a->q_user, FALSE, a, sendq, e);
+ if (transienterror(ret))
+ {
+#ifdef LOG
+ if (LogLevel > 2)
+ syslog(LOG_ERR, "%s: include %s: transient error: %s",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id,
+ a->q_user, errstring(ret));
+#endif
+ a->q_flags |= QQUEUEUP;
+ a->q_flags &= ~QDONTSEND;
+ usrerr("451 Cannot open %s: %s",
+ a->q_user, errstring(ret));
+ }
+ else if (ret != 0)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Cannot open %s: %s",
+ a->q_user, errstring(ret));
+ }
+ }
+ }
+ else if (m == FileMailer)
+ {
+ extern bool writable();
+
+ /* check if writable or creatable */
+ if (a->q_alias == NULL)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Cannot mail directly to files");
+ }
+ else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 User %s@%s doesn't have a valid shell for mailing to files",
+ a->q_alias->q_ruser, MyHostName);
+ }
+ else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("550 Address %s is unsafe for mailing to files",
+ a->q_alias->q_paddr);
+ }
+ else if (!writable(buf, getctladdr(a), SFF_ANYFILE))
+ {
+ a->q_flags |= QBADADDR;
+ giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, e);
+ }
+ }
+
+ if (m != LocalMailer)
+ {
+ if (!bitset(QDONTSEND, a->q_flags))
+ e->e_nrcpts++;
+ goto testselfdestruct;
+ }
+
+ /* try aliasing */
+ alias(a, sendq, e);
+
+# ifdef USERDB
+ /* if not aliased, look it up in the user database */
+ if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags))
+ {
+ extern int udbexpand();
+
+ if (udbexpand(a, sendq, e) == EX_TEMPFAIL)
+ {
+ a->q_flags |= QQUEUEUP;
+ if (e->e_message == NULL)
+ e->e_message = newstr("Deferred: user database error");
+# ifdef LOG
+ if (LogLevel > 8)
+ syslog(LOG_INFO, "%s: deferred: udbexpand: %s",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id,
+ errstring(errno));
+# endif
+ message("queued (user database error): %s",
+ errstring(errno));
+ e->e_nrcpts++;
+ goto testselfdestruct;
+ }
+ }
+# endif
+
+ /* if it was an alias or a UDB expansion, just return now */
+ if (bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags))
+ goto testselfdestruct;
+
+ /*
+ ** If we have a level two config file, then pass the name through
+ ** Ruleset 5 before sending it off. Ruleset 5 has the right
+ ** to send rewrite it to another mailer. This gives us a hook
+ ** after local aliasing has been done.
+ */
+
+ if (tTd(29, 5))
+ {
+ printf("recipient: testing local? cl=%d, rr5=%x\n\t",
+ ConfigLevel, RewriteRules[5]);
+ printaddr(a, FALSE);
+ }
+ if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 &&
+ RewriteRules[5] != NULL)
+ {
+ maplocaluser(a, sendq, e);
+ }
+
+ /*
+ ** If it didn't get rewritten to another mailer, go ahead
+ ** and deliver it.
+ */
+
+ if (!bitset(QDONTSEND|QQUEUEUP, a->q_flags))
+ {
+ auto bool fuzzy;
+ register struct passwd *pw;
+ extern struct passwd *finduser();
+
+ /* warning -- finduser may trash buf */
+ pw = finduser(buf, &fuzzy);
+ if (pw == NULL)
+ {
+ a->q_flags |= QBADADDR;
+ giveresponse(EX_NOUSER, m, NULL, a->q_alias, e);
+ }
+ else
+ {
+ char nbuf[MAXNAME];
+
+ if (fuzzy)
+ {
+ /* name was a fuzzy match */
+ a->q_user = newstr(pw->pw_name);
+ if (findusercount++ > 3)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("554 aliasing/forwarding loop for %s broken",
+ pw->pw_name);
+ return (a);
+ }
+
+ /* see if it aliases */
+ (void) strcpy(buf, pw->pw_name);
+ goto trylocaluser;
+ }
+ if (strcmp(pw->pw_dir, "/") == 0)
+ a->q_home = "";
+ else
+ a->q_home = newstr(pw->pw_dir);
+ a->q_uid = pw->pw_uid;
+ a->q_gid = pw->pw_gid;
+ a->q_ruser = newstr(pw->pw_name);
+ a->q_flags |= QGOODUID;
+ buildfname(pw->pw_gecos, pw->pw_name, nbuf);
+ if (nbuf[0] != '\0')
+ a->q_fullname = newstr(nbuf);
+ if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' &&
+ !usershellok(pw->pw_shell))
+ {
+ a->q_flags |= QBOGUSSHELL;
+ }
+ if (!quoted)
+ forward(a, sendq, e);
+ }
+ }
+ if (!bitset(QDONTSEND, a->q_flags))
+ e->e_nrcpts++;
+
+ testselfdestruct:
+ if (tTd(26, 8))
+ {
+ printf("testselfdestruct: ");
+ printaddr(a, TRUE);
+ }
+ if (a->q_alias == NULL && a != &e->e_from &&
+ bitset(QDONTSEND, a->q_flags))
+ {
+ q = *sendq;
+ while (q != NULL && bitset(QDONTSEND, q->q_flags))
+ q = q->q_next;
+ if (q == NULL)
+ {
+ a->q_flags |= QBADADDR;
+ usrerr("554 aliasing/forwarding loop broken");
+ }
+ }
+ return (a);
+}
+ /*
+** FINDUSER -- find the password entry for a user.
+**
+** This looks a lot like getpwnam, except that it may want to
+** do some fancier pattern matching in /etc/passwd.
+**
+** This routine contains most of the time of many sendmail runs.
+** It deserves to be optimized.
+**
+** Parameters:
+** name -- the name to match against.
+** fuzzyp -- an outarg that is set to TRUE if this entry
+** was found using the fuzzy matching algorithm;
+** set to FALSE otherwise.
+**
+** Returns:
+** A pointer to a pw struct.
+** NULL if name is unknown or ambiguous.
+**
+** Side Effects:
+** may modify name.
+*/
+
+struct passwd *
+finduser(name, fuzzyp)
+ char *name;
+ bool *fuzzyp;
+{
+ register struct passwd *pw;
+ register char *p;
+ extern struct passwd *getpwent();
+ extern struct passwd *getpwnam();
+
+ if (tTd(29, 4))
+ printf("finduser(%s): ", name);
+
+ *fuzzyp = FALSE;
+
+ /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
+ for (p = name; *p != '\0'; p++)
+ if (!isascii(*p) || !isdigit(*p))
+ break;
+ if (*p == '\0')
+ {
+ if (tTd(29, 4))
+ printf("failed (numeric input)\n");
+ return NULL;
+ }
+
+ /* look up this login name using fast path */
+ if ((pw = getpwnam(name)) != NULL)
+ {
+ if (tTd(29, 4))
+ printf("found (non-fuzzy)\n");
+ return (pw);
+ }
+
+#ifdef MATCHGECOS
+ /* see if fuzzy matching allowed */
+ if (!MatchGecos)
+ {
+ if (tTd(29, 4))
+ printf("not found (fuzzy disabled)\n");
+ return NULL;
+ }
+
+ /* search for a matching full name instead */
+ for (p = name; *p != '\0'; p++)
+ {
+ if (*p == (SpaceSub & 0177) || *p == '_')
+ *p = ' ';
+ }
+ (void) setpwent();
+ while ((pw = getpwent()) != NULL)
+ {
+ char buf[MAXNAME];
+
+ buildfname(pw->pw_gecos, pw->pw_name, buf);
+ if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
+ {
+ if (tTd(29, 4))
+ printf("fuzzy matches %s\n", pw->pw_name);
+ message("sending to login name %s", pw->pw_name);
+ *fuzzyp = TRUE;
+ return (pw);
+ }
+ }
+ if (tTd(29, 4))
+ printf("no fuzzy match found\n");
+#else
+ if (tTd(29, 4))
+ printf("not found (fuzzy disabled)\n");
+#endif
+ return (NULL);
+}
+ /*
+** WRITABLE -- predicate returning if the file is writable.
+**
+** This routine must duplicate the algorithm in sys/fio.c.
+** Unfortunately, we cannot use the access call since we
+** won't necessarily be the real uid when we try to
+** actually open the file.
+**
+** Notice that ANY file with ANY execute bit is automatically
+** not writable. This is also enforced by mailfile.
+**
+** Parameters:
+** filename -- the file name to check.
+** ctladdr -- the controlling address for this file.
+** flags -- SFF_* flags to control the function.
+**
+** Returns:
+** TRUE -- if we will be able to write this file.
+** FALSE -- if we cannot write this file.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+writable(filename, ctladdr, flags)
+ char *filename;
+ ADDRESS *ctladdr;
+ int flags;
+{
+ uid_t euid;
+ gid_t egid;
+ int bits;
+ register char *p;
+ char *uname;
+ struct stat stb;
+ extern char RealUserName[];
+
+ if (tTd(29, 5))
+ printf("writable(%s, %x)\n", filename, flags);
+
+#ifdef HASLSTAT
+ if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb)
+ : stat(filename, &stb)) < 0)
+#else
+ if (stat(filename, &stb) < 0)
+#endif
+ {
+ /* file does not exist -- see if directory is safe */
+ p = strrchr(filename, '/');
+ if (p == NULL)
+ {
+ errno = ENOTDIR;
+ return FALSE;
+ }
+ *p = '\0';
+ errno = safefile(filename, RealUid, RealGid, RealUserName,
+ SFF_MUSTOWN, S_IWRITE|S_IEXEC);
+ *p = '/';
+ return errno == 0;
+ }
+
+#ifdef SUID_ROOT_FILES_OK
+ /* really ought to be passed down -- and not a good idea */
+ flags |= SFF_ROOTOK;
+#endif
+
+ /*
+ ** File does exist -- check that it is writable.
+ */
+
+ if (bitset(0111, stb.st_mode))
+ {
+ if (tTd(29, 5))
+ printf("failed (mode %o: x bits)\n", stb.st_mode);
+ errno = EPERM;
+ return (FALSE);
+ }
+
+ if (ctladdr != NULL && geteuid() == 0)
+ {
+ euid = ctladdr->q_uid;
+ egid = ctladdr->q_gid;
+ uname = ctladdr->q_user;
+ }
+ else
+ {
+ euid = RealUid;
+ egid = RealGid;
+ uname = RealUserName;
+ }
+ if (euid == 0)
+ {
+ euid = DefUid;
+ uname = DefUser;
+ }
+ if (egid == 0)
+ egid = DefGid;
+ if (geteuid() == 0)
+ {
+ if (bitset(S_ISUID, stb.st_mode) &&
+ (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags)))
+ {
+ euid = stb.st_uid;
+ uname = NULL;
+ }
+ if (bitset(S_ISGID, stb.st_mode) &&
+ (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags)))
+ egid = stb.st_gid;
+ }
+
+ if (tTd(29, 5))
+ printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n",
+ euid, egid, stb.st_uid, stb.st_gid);
+
+ errno = safefile(filename, euid, egid, uname, flags, S_IWRITE);
+ return errno == 0;
+}
+ /*
+** INCLUDE -- handle :include: specification.
+**
+** Parameters:
+** fname -- filename to include.
+** forwarding -- if TRUE, we are reading a .forward file.
+** if FALSE, it's a :include: file.
+** ctladdr -- address template to use to fill in these
+** addresses -- effective user/group id are
+** the important things.
+** sendq -- a pointer to the head of the send queue
+** to put these addresses in.
+**
+** Returns:
+** open error status
+**
+** Side Effects:
+** reads the :include: file and sends to everyone
+** listed in that file.
+**
+** Security Note:
+** If you have restricted chown (that is, you can't
+** give a file away), it is reasonable to allow programs
+** and files called from this :include: file to be to be
+** run as the owner of the :include: file. This is bogus
+** if there is any chance of someone giving away a file.
+** We assume that pre-POSIX systems can give away files.
+**
+** There is an additional restriction that if you
+** forward to a :include: file, it will not take on
+** the ownership of the :include: file. This may not
+** be necessary, but shouldn't hurt.
+*/
+
+static jmp_buf CtxIncludeTimeout;
+static int includetimeout();
+
+#ifndef S_IWOTH
+# define S_IWOTH (S_IWRITE >> 6)
+#endif
+
+int
+include(fname, forwarding, ctladdr, sendq, e)
+ char *fname;
+ bool forwarding;
+ ADDRESS *ctladdr;
+ ADDRESS **sendq;
+ ENVELOPE *e;
+{
+ register FILE *fp = NULL;
+ char *oldto = e->e_to;
+ char *oldfilename = FileName;
+ int oldlinenumber = LineNumber;
+ register EVENT *ev = NULL;
+ int nincludes;
+ register ADDRESS *ca;
+ uid_t saveduid, uid;
+ gid_t savedgid, gid;
+ char *uname;
+ int rval = 0;
+ int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE;
+ struct stat st;
+ char buf[MAXLINE];
+#ifdef _POSIX_CHOWN_RESTRICTED
+# if _POSIX_CHOWN_RESTRICTED == -1
+# define safechown FALSE
+# else
+# define safechown TRUE
+# endif
+#else
+# ifdef _PC_CHOWN_RESTRICTED
+ bool safechown;
+# else
+# ifdef BSD
+# define safechown TRUE
+# else
+# define safechown FALSE
+# endif
+# endif
+#endif
+ extern bool chownsafe();
+
+ if (tTd(27, 2))
+ printf("include(%s)\n", fname);
+ if (tTd(27, 4))
+ printf(" ruid=%d euid=%d\n", getuid(), geteuid());
+ if (tTd(27, 14))
+ {
+ printf("ctladdr ");
+ printaddr(ctladdr, FALSE);
+ }
+
+ if (tTd(27, 9))
+ printf("include: old uid = %d/%d\n", getuid(), geteuid());
+
+ ca = getctladdr(ctladdr);
+ if (ca == NULL)
+ {
+ uid = DefUid;
+ gid = DefGid;
+ uname = DefUser;
+ saveduid = -1;
+ }
+ else
+ {
+ uid = ca->q_uid;
+ gid = ca->q_gid;
+ uname = ca->q_user;
+#ifdef HASSETREUID
+ saveduid = geteuid();
+ savedgid = getegid();
+ if (saveduid == 0)
+ {
+ initgroups(uname, gid);
+ if (uid != 0)
+ (void) setreuid(0, uid);
+ }
+#endif
+ }
+
+ if (tTd(27, 9))
+ printf("include: new uid = %d/%d\n", getuid(), geteuid());
+
+ /*
+ ** If home directory is remote mounted but server is down,
+ ** this can hang or give errors; use a timeout to avoid this
+ */
+
+ if (setjmp(CtxIncludeTimeout) != 0)
+ {
+ ctladdr->q_flags |= QQUEUEUP;
+ errno = 0;
+
+ /* return pseudo-error code */
+ rval = EOPENTIMEOUT;
+ goto resetuid;
+ }
+ ev = setevent((time_t) 60, includetimeout, 0);
+
+ /* the input file must be marked safe */
+ rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD);
+ if (rval != 0)
+ {
+ /* don't use this :include: file */
+ if (tTd(27, 4))
+ printf("include: not safe (uid=%d): %s\n",
+ uid, errstring(rval));
+ }
+ else
+ {
+ fp = fopen(fname, "r");
+ if (fp == NULL)
+ {
+ rval = errno;
+ if (tTd(27, 4))
+ printf("include: open: %s\n", errstring(rval));
+ }
+ }
+ clrevent(ev);
+
+resetuid:
+
+#ifdef HASSETREUID
+ if (saveduid == 0)
+ {
+ if (uid != 0)
+ if (setreuid(-1, 0) < 0 || setreuid(RealUid, 0) < 0)
+ syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
+ RealUid, getuid(), geteuid());
+ setgid(savedgid);
+ }
+#endif
+
+ if (tTd(27, 9))
+ printf("include: reset uid = %d/%d\n", getuid(), geteuid());
+
+ if (rval == EOPENTIMEOUT)
+ usrerr("451 open timeout on %s", fname);
+
+ if (fp == NULL)
+ return rval;
+
+ if (fstat(fileno(fp), &st) < 0)
+ {
+ rval = errno;
+ syserr("Cannot fstat %s!", fname);
+ return rval;
+ }
+
+#ifndef safechown
+ safechown = chownsafe(fileno(fp));
+#endif
+ if (ca == NULL && safechown)
+ {
+ ctladdr->q_uid = st.st_uid;
+ ctladdr->q_gid = st.st_gid;
+ ctladdr->q_flags |= QGOODUID;
+ }
+ if (ca != NULL && ca->q_uid == st.st_uid)
+ {
+ /* optimization -- avoid getpwuid if we already have info */
+ ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
+ ctladdr->q_ruser = ca->q_ruser;
+ }
+ else
+ {
+ char *sh;
+ register struct passwd *pw;
+
+ sh = "/SENDMAIL/ANY/SHELL/";
+ pw = getpwuid(st.st_uid);
+ if (pw != NULL)
+ {
+ ctladdr->q_ruser = newstr(pw->pw_name);
+ if (safechown)
+ sh = pw->pw_shell;
+ }
+ if (pw == NULL)
+ ctladdr->q_flags |= QBOGUSSHELL;
+ else if(!usershellok(sh))
+ {
+ if (safechown)
+ ctladdr->q_flags |= QBOGUSSHELL;
+ else
+ ctladdr->q_flags |= QUNSAFEADDR;
+ }
+ }
+
+ if (bitset(EF_VRFYONLY, e->e_flags))
+ {
+ /* don't do any more now */
+ ctladdr->q_flags |= QVERIFIED;
+ e->e_nrcpts++;
+ xfclose(fp, "include", fname);
+ return rval;
+ }
+
+ /*
+ ** Check to see if some bad guy can write this file
+ **
+ ** This should really do something clever with group
+ ** permissions; currently we just view world writable
+ ** as unsafe. Also, we don't check for writable
+ ** directories in the path. We've got to leave
+ ** something for the local sysad to do.
+ */
+
+ if (bitset(S_IWOTH, st.st_mode))
+ ctladdr->q_flags |= QUNSAFEADDR;
+
+ /* read the file -- each line is a comma-separated list. */
+ FileName = fname;
+ LineNumber = 0;
+ ctladdr->q_flags &= ~QSELFREF;
+ nincludes = 0;
+ while (fgets(buf, sizeof buf, fp) != NULL)
+ {
+ register char *p = strchr(buf, '\n');
+
+ LineNumber++;
+ if (p != NULL)
+ *p = '\0';
+ if (buf[0] == '#' || buf[0] == '\0')
+ continue;
+ e->e_to = NULL;
+ message("%s to %s",
+ forwarding ? "forwarding" : "sending", buf);
+#ifdef LOG
+ if (forwarding && LogLevel > 9)
+ syslog(LOG_INFO, "%s: forward %s => %s",
+ e->e_id == NULL ? "NOQUEUE" : e->e_id,
+ oldto, buf);
+#endif
+
+ AliasLevel++;
+ nincludes += sendtolist(buf, ctladdr, sendq, e);
+ AliasLevel--;
+ }
+
+ if (ferror(fp) && tTd(27, 3))
+ printf("include: read error: %s\n", errstring(errno));
+ if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
+ {
+ if (tTd(27, 5))
+ {
+ printf("include: QDONTSEND ");
+ printaddr(ctladdr, FALSE);
+ }
+ ctladdr->q_flags |= QDONTSEND;
+ }
+
+ (void) xfclose(fp, "include", fname);
+ FileName = oldfilename;
+ LineNumber = oldlinenumber;
+ e->e_to = oldto;
+ return rval;
+}
+
+static
+includetimeout()
+{
+ longjmp(CtxIncludeTimeout, 1);
+}
+ /*
+** SENDTOARGV -- send to an argument vector.
+**
+** Parameters:
+** argv -- argument vector to send to.
+** e -- the current envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** puts all addresses on the argument vector onto the
+** send queue.
+*/
+
+sendtoargv(argv, e)
+ register char **argv;
+ register ENVELOPE *e;
+{
+ register char *p;
+
+ while ((p = *argv++) != NULL)
+ {
+ (void) sendtolist(p, NULLADDR, &e->e_sendqueue, e);
+ }
+}
+ /*
+** GETCTLADDR -- get controlling address from an address header.
+**
+** If none, get one corresponding to the effective userid.
+**
+** Parameters:
+** a -- the address to find the controller of.
+**
+** Returns:
+** the controlling address.
+**
+** Side Effects:
+** none.
+*/
+
+ADDRESS *
+getctladdr(a)
+ register ADDRESS *a;
+{
+ while (a != NULL && !bitset(QGOODUID, a->q_flags))
+ a = a->q_alias;
+ return (a);
+}
diff --git a/usr.sbin/sendmail/src/savemail.c b/usr.sbin/sendmail/src/savemail.c
new file mode 100644
index 00000000000..214dca5c96f
--- /dev/null
+++ b/usr.sbin/sendmail/src/savemail.c
@@ -0,0 +1,833 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)savemail.c 8.29 (Berkeley) 5/10/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include <pwd.h>
+
+/*
+** SAVEMAIL -- Save mail on error
+**
+** If mailing back errors, mail it back to the originator
+** together with an error message; otherwise, just put it in
+** dead.letter in the user's home directory (if he exists on
+** this machine).
+**
+** Parameters:
+** e -- the envelope containing the message in error.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Saves the letter, by writing or mailing it back to the
+** sender, or by putting it in dead.letter in her home
+** directory.
+*/
+
+/* defines for state machine */
+# define ESM_REPORT 0 /* report to sender's terminal */
+# define ESM_MAIL 1 /* mail back to sender */
+# define ESM_QUIET 2 /* messages have already been returned */
+# define ESM_DEADLETTER 3 /* save in ~/dead.letter */
+# define ESM_POSTMASTER 4 /* return to postmaster */
+# define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */
+# define ESM_PANIC 6 /* leave the locked queue/transcript files */
+# define ESM_DONE 7 /* the message is successfully delivered */
+
+# ifndef _PATH_VARTMP
+# define _PATH_VARTMP "/usr/tmp/"
+# endif
+
+
+savemail(e)
+ register ENVELOPE *e;
+{
+ register struct passwd *pw;
+ register FILE *fp;
+ int state;
+ auto ADDRESS *q = NULL;
+ register char *p;
+ MCI mcibuf;
+ char buf[MAXLINE+1];
+ extern struct passwd *getpwnam();
+ extern char *ttypath();
+ typedef int (*fnptr)();
+ extern bool writable();
+
+ if (tTd(6, 1))
+ {
+ printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
+ e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
+ ExitStat);
+ printaddr(&e->e_from, FALSE);
+ }
+
+ if (e->e_id == NULL)
+ {
+ /* can't return a message with no id */
+ return;
+ }
+
+ /*
+ ** In the unhappy event we don't know who to return the mail
+ ** to, make someone up.
+ */
+
+ if (e->e_from.q_paddr == NULL)
+ {
+ e->e_sender = "Postmaster";
+ if (parseaddr(e->e_sender, &e->e_from,
+ RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
+ {
+ syserr("553 Cannot parse Postmaster!");
+ ExitStat = EX_SOFTWARE;
+ finis();
+ }
+ }
+ e->e_to = NULL;
+
+ /*
+ ** Basic state machine.
+ **
+ ** This machine runs through the following states:
+ **
+ ** ESM_QUIET Errors have already been printed iff the
+ ** sender is local.
+ ** ESM_REPORT Report directly to the sender's terminal.
+ ** ESM_MAIL Mail response to the sender.
+ ** ESM_DEADLETTER Save response in ~/dead.letter.
+ ** ESM_POSTMASTER Mail response to the postmaster.
+ ** ESM_PANIC Save response anywhere possible.
+ */
+
+ /* determine starting state */
+ switch (e->e_errormode)
+ {
+ case EM_WRITE:
+ state = ESM_REPORT;
+ break;
+
+ case EM_BERKNET:
+ /* mail back, but return o.k. exit status */
+ ExitStat = EX_OK;
+
+ /* fall through.... */
+
+ case EM_MAIL:
+ state = ESM_MAIL;
+ break;
+
+ case EM_PRINT:
+ case '\0':
+ state = ESM_QUIET;
+ break;
+
+ case EM_QUIET:
+ /* no need to return anything at all */
+ return;
+
+ default:
+ syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
+ state = ESM_MAIL;
+ break;
+ }
+
+ /* if this is already an error response, send to postmaster */
+ if (bitset(EF_RESPONSE, e->e_flags))
+ {
+ if (e->e_parent != NULL &&
+ bitset(EF_RESPONSE, e->e_parent->e_flags))
+ {
+ /* got an error sending a response -- can it */
+ return;
+ }
+ state = ESM_POSTMASTER;
+ }
+
+ while (state != ESM_DONE)
+ {
+ if (tTd(6, 5))
+ printf(" state %d\n", state);
+
+ switch (state)
+ {
+ case ESM_QUIET:
+ if (e->e_from.q_mailer == LocalMailer)
+ state = ESM_DEADLETTER;
+ else
+ state = ESM_MAIL;
+ break;
+
+ case ESM_REPORT:
+
+ /*
+ ** If the user is still logged in on the same terminal,
+ ** then write the error messages back to hir (sic).
+ */
+
+ p = ttypath();
+ if (p == NULL || freopen(p, "w", stdout) == NULL)
+ {
+ state = ESM_MAIL;
+ break;
+ }
+
+ expand("\201n", buf, &buf[sizeof buf - 1], e);
+ printf("\r\nMessage from %s...\r\n", buf);
+ printf("Errors occurred while sending mail.\r\n");
+ if (e->e_xfp != NULL)
+ {
+ (void) fflush(e->e_xfp);
+ fp = fopen(queuename(e, 'x'), "r");
+ }
+ else
+ fp = NULL;
+ if (fp == NULL)
+ {
+ syserr("Cannot open %s", queuename(e, 'x'));
+ printf("Transcript of session is unavailable.\r\n");
+ }
+ else
+ {
+ printf("Transcript follows:\r\n");
+ while (fgets(buf, sizeof buf, fp) != NULL &&
+ !ferror(stdout))
+ fputs(buf, stdout);
+ (void) xfclose(fp, "savemail transcript", e->e_id);
+ }
+ printf("Original message will be saved in dead.letter.\r\n");
+ state = ESM_DEADLETTER;
+ break;
+
+ case ESM_MAIL:
+ /*
+ ** If mailing back, do it.
+ ** Throw away all further output. Don't alias,
+ ** since this could cause loops, e.g., if joe
+ ** mails to joe@x, and for some reason the network
+ ** for @x is down, then the response gets sent to
+ ** joe@x, which gives a response, etc. Also force
+ ** the mail to be delivered even if a version of
+ ** it has already been sent to the sender.
+ **
+ ** If this is a configuration or local software
+ ** error, send to the local postmaster as well,
+ ** since the originator can't do anything
+ ** about it anyway. Note that this is a full
+ ** copy of the message (intentionally) so that
+ ** the Postmaster can forward things along.
+ */
+
+ if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
+ {
+ (void) sendtolist("postmaster",
+ NULLADDR, &e->e_errorqueue, e);
+ }
+ if (strcmp(e->e_from.q_paddr, "<>") != 0)
+ {
+ (void) sendtolist(e->e_from.q_paddr,
+ NULLADDR, &e->e_errorqueue, e);
+ }
+
+ /*
+ ** Deliver a non-delivery report to the
+ ** Postmaster-designate (not necessarily
+ ** Postmaster). This does not include the
+ ** body of the message, for privacy reasons.
+ ** You really shouldn't need this.
+ */
+
+ e->e_flags |= EF_PM_NOTIFY;
+
+ /* check to see if there are any good addresses */
+ for (q = e->e_errorqueue; q != NULL; q = q->q_next)
+ if (!bitset(QBADADDR|QDONTSEND, q->q_flags))
+ break;
+ if (q == NULL)
+ {
+ /* this is an error-error */
+ state = ESM_POSTMASTER;
+ break;
+ }
+ if (returntosender(e->e_message, e->e_errorqueue,
+ (e->e_class >= 0), e) == 0)
+ {
+ state = ESM_DONE;
+ break;
+ }
+
+ /* didn't work -- return to postmaster */
+ state = ESM_POSTMASTER;
+ break;
+
+ case ESM_POSTMASTER:
+ /*
+ ** Similar to previous case, but to system postmaster.
+ */
+
+ q = NULL;
+ if (sendtolist("postmaster", NULL, &q, e) <= 0)
+ {
+ syserr("553 cannot parse postmaster!");
+ ExitStat = EX_SOFTWARE;
+ state = ESM_USRTMP;
+ break;
+ }
+ if (returntosender(e->e_message,
+ q, (e->e_class >= 0), e) == 0)
+ {
+ state = ESM_DONE;
+ break;
+ }
+
+ /* didn't work -- last resort */
+ state = ESM_USRTMP;
+ break;
+
+ case ESM_DEADLETTER:
+ /*
+ ** Save the message in dead.letter.
+ ** If we weren't mailing back, and the user is
+ ** local, we should save the message in
+ ** ~/dead.letter so that the poor person doesn't
+ ** have to type it over again -- and we all know
+ ** what poor typists UNIX users are.
+ */
+
+ p = NULL;
+ if (e->e_from.q_mailer == LocalMailer)
+ {
+ if (e->e_from.q_home != NULL)
+ p = e->e_from.q_home;
+ else if ((pw = getpwnam(e->e_from.q_user)) != NULL)
+ p = pw->pw_dir;
+ }
+ if (p == NULL)
+ {
+ /* no local directory */
+ state = ESM_MAIL;
+ break;
+ }
+ if (e->e_dfp != NULL)
+ {
+ bool oldverb = Verbose;
+
+ /* we have a home directory; open dead.letter */
+ define('z', p, e);
+ expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e);
+ Verbose = TRUE;
+ message("Saving message in %s", buf);
+ Verbose = oldverb;
+ e->e_to = buf;
+ q = NULL;
+ (void) sendtolist(buf, &e->e_from, &q, e);
+ if (q != NULL &&
+ !bitset(QBADADDR, q->q_flags) &&
+ deliver(e, q) == 0)
+ state = ESM_DONE;
+ else
+ state = ESM_MAIL;
+ }
+ else
+ {
+ /* no data file -- try mailing back */
+ state = ESM_MAIL;
+ }
+ break;
+
+ case ESM_USRTMP:
+ /*
+ ** Log the mail in /usr/tmp/dead.letter.
+ */
+
+ if (e->e_class < 0)
+ {
+ state = ESM_DONE;
+ break;
+ }
+
+ strcpy(buf, _PATH_VARTMP);
+ strcat(buf, "dead.letter");
+ if (!writable(buf, NULLADDR, SFF_NOSLINK))
+ {
+ state = ESM_PANIC;
+ break;
+ }
+ fp = dfopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode);
+ if (fp == NULL)
+ {
+ state = ESM_PANIC;
+ break;
+ }
+
+ bzero(&mcibuf, sizeof mcibuf);
+ mcibuf.mci_out = fp;
+ mcibuf.mci_mailer = FileMailer;
+ if (bitnset(M_7BITS, FileMailer->m_flags))
+ mcibuf.mci_flags |= MCIF_7BIT;
+
+ putfromline(&mcibuf, e);
+ (*e->e_puthdr)(&mcibuf, e);
+ putline("\n", &mcibuf);
+ (*e->e_putbody)(&mcibuf, e, NULL);
+ putline("\n", &mcibuf);
+ (void) fflush(fp);
+ state = ferror(fp) ? ESM_PANIC : ESM_DONE;
+ (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter");
+ break;
+
+ default:
+ syserr("554 savemail: unknown state %d", state);
+
+ /* fall through ... */
+
+ case ESM_PANIC:
+ /* leave the locked queue & transcript files around */
+ syserr("!554 savemail: cannot save rejected email anywhere");
+ }
+ }
+}
+ /*
+** RETURNTOSENDER -- return a message to the sender with an error.
+**
+** Parameters:
+** msg -- the explanatory message.
+** returnq -- the queue of people to send the message to.
+** sendbody -- if TRUE, also send back the body of the
+** message; otherwise just send the header.
+** e -- the current envelope.
+**
+** Returns:
+** zero -- if everything went ok.
+** else -- some error.
+**
+** Side Effects:
+** Returns the current message to the sender via
+** mail.
+*/
+
+static bool SendBody;
+
+#define MAXRETURNS 6 /* max depth of returning messages */
+#define ERRORFUDGE 100 /* nominal size of error message text */
+
+returntosender(msg, returnq, sendbody, e)
+ char *msg;
+ ADDRESS *returnq;
+ bool sendbody;
+ register ENVELOPE *e;
+{
+ char buf[MAXNAME];
+ extern putheader(), errbody();
+ register ENVELOPE *ee;
+ ENVELOPE *oldcur = CurEnv;
+ ENVELOPE errenvelope;
+ static int returndepth;
+ register ADDRESS *q;
+
+ if (returnq == NULL)
+ return (-1);
+
+ if (msg == NULL)
+ msg = "Unable to deliver mail";
+
+ if (tTd(6, 1))
+ {
+ printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
+ msg, returndepth, e);
+ printaddr(returnq, TRUE);
+ }
+
+ if (++returndepth >= MAXRETURNS)
+ {
+ if (returndepth != MAXRETURNS)
+ syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
+ /* don't "unrecurse" and fake a clean exit */
+ /* returndepth--; */
+ return (0);
+ }
+
+ SendBody = sendbody;
+ define('g', e->e_from.q_paddr, e);
+ define('u', NULL, e);
+ ee = newenvelope(&errenvelope, e);
+ define('a', "\201b", ee);
+ define('r', "internal", ee);
+ define('s', "localhost", ee);
+ define('_', "localhost", ee);
+ ee->e_puthdr = putheader;
+ ee->e_putbody = errbody;
+ ee->e_flags |= EF_RESPONSE|EF_METOO;
+ if (!bitset(EF_OLDSTYLE, e->e_flags))
+ ee->e_flags &= ~EF_OLDSTYLE;
+ ee->e_sendqueue = returnq;
+ ee->e_msgsize = ERRORFUDGE;
+ if (!NoReturn)
+ ee->e_msgsize += e->e_msgsize;
+ initsys(ee);
+ for (q = returnq; q != NULL; q = q->q_next)
+ {
+ if (bitset(QBADADDR, q->q_flags))
+ continue;
+
+ if (!bitset(QDONTSEND, q->q_flags))
+ ee->e_nrcpts++;
+
+ if (!DontPruneRoutes && pruneroute(q->q_paddr))
+ parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e);
+
+ if (q->q_alias == NULL)
+ addheader("To", q->q_paddr, ee);
+ }
+
+# ifdef LOG
+ if (LogLevel > 5)
+ syslog(LOG_INFO, "%s: %s: return to sender: %s",
+ e->e_id, ee->e_id, msg);
+# endif
+
+ (void) sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg);
+ addheader("Subject", buf, ee);
+ if (SendMIMEErrors)
+ {
+ addheader("MIME-Version", "1.0", ee);
+ (void) sprintf(buf, "%s.%ld/%s",
+ ee->e_id, curtime(), MyHostName);
+ ee->e_msgboundary = newstr(buf);
+ (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"",
+ ee->e_msgboundary);
+ addheader("Content-Type", buf, ee);
+ }
+
+ /* fake up an address header for the from person */
+ expand("\201n", buf, &buf[sizeof buf - 1], e);
+ if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
+ {
+ syserr("553 Can't parse myself!");
+ ExitStat = EX_SOFTWARE;
+ returndepth--;
+ return (-1);
+ }
+ ee->e_sender = ee->e_from.q_paddr;
+
+ /* push state into submessage */
+ CurEnv = ee;
+ define('f', "\201n", ee);
+ define('x', "Mail Delivery Subsystem", ee);
+ eatheader(ee, TRUE);
+
+ /* mark statistics */
+ markstats(ee, NULLADDR);
+
+ /* actually deliver the error message */
+ sendall(ee, SM_DEFAULT);
+
+ /* restore state */
+ dropenvelope(ee);
+ CurEnv = oldcur;
+ returndepth--;
+
+ /* should check for delivery errors here */
+ return (0);
+}
+ /*
+** ERRBODY -- output the body of an error message.
+**
+** Typically this is a copy of the transcript plus a copy of the
+** original offending message.
+**
+** Parameters:
+** mci -- the mailer connection information.
+** e -- the envelope we are working in.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Outputs the body of an error message.
+*/
+
+errbody(mci, e)
+ register MCI *mci;
+ register ENVELOPE *e;
+{
+ register FILE *xfile;
+ char *p;
+ register ADDRESS *q;
+ bool printheader;
+ char buf[MAXLINE];
+
+ if (e->e_parent == NULL)
+ {
+ syserr("errbody: null parent");
+ putline(" ----- Original message lost -----\n", mci);
+ return;
+ }
+
+ /*
+ ** Output MIME header.
+ */
+
+ if (e->e_msgboundary != NULL)
+ {
+ putline("This is a MIME-encapsulated message", mci);
+ putline("", mci);
+ (void) sprintf(buf, "--%s", e->e_msgboundary);
+ putline(buf, mci);
+ putline("", mci);
+ }
+
+ /*
+ ** Output introductory information.
+ */
+
+ for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
+ if (bitset(QBADADDR, q->q_flags))
+ break;
+ if (q == NULL &&
+ !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
+ {
+ putline(" **********************************************",
+ mci);
+ putline(" ** THIS IS A WARNING MESSAGE ONLY **",
+ mci);
+ putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
+ mci);
+ putline(" **********************************************",
+ mci);
+ putline("", mci);
+ }
+ sprintf(buf, "The original message was received at %s",
+ arpadate(ctime(&e->e_parent->e_ctime)));
+ putline(buf, mci);
+ expand("from \201_", buf, &buf[sizeof buf - 1], e->e_parent);
+ putline(buf, mci);
+ putline("", mci);
+
+ /*
+ ** Output error message header (if specified and available).
+ */
+
+ if (ErrMsgFile != NULL)
+ {
+ if (*ErrMsgFile == '/')
+ {
+ xfile = fopen(ErrMsgFile, "r");
+ if (xfile != NULL)
+ {
+ while (fgets(buf, sizeof buf, xfile) != NULL)
+ {
+ expand(buf, buf, &buf[sizeof buf - 1], e);
+ putline(buf, mci);
+ }
+ (void) fclose(xfile);
+ putline("\n", mci);
+ }
+ }
+ else
+ {
+ expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e);
+ putline(buf, mci);
+ putline("", mci);
+ }
+ }
+
+ /*
+ ** Output message introduction
+ */
+
+ printheader = TRUE;
+ for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QBADADDR|QREPORT, q->q_flags))
+ {
+ if (printheader)
+ {
+ putline(" ----- The following addresses had delivery problems -----",
+ mci);
+ printheader = FALSE;
+ }
+ strcpy(buf, q->q_paddr);
+ if (bitset(QBADADDR, q->q_flags))
+ strcat(buf, " (unrecoverable error)");
+ else
+ strcat(buf, " (transient failure)");
+ putline(buf, mci);
+ if (q->q_alias != NULL)
+ {
+ strcpy(buf, " (expanded from: ");
+ strcat(buf, q->q_alias->q_paddr);
+ strcat(buf, ")");
+ putline(buf, mci);
+ }
+ }
+ }
+ if (!printheader)
+ putline("\n", mci);
+
+ /*
+ ** Output transcript of errors
+ */
+
+ (void) fflush(stdout);
+ p = queuename(e->e_parent, 'x');
+ if ((xfile = fopen(p, "r")) == NULL)
+ {
+ syserr("Cannot open %s", p);
+ putline(" ----- Transcript of session is unavailable -----\n", mci);
+ }
+ else
+ {
+ putline(" ----- Transcript of session follows -----\n", mci);
+ if (e->e_xfp != NULL)
+ (void) fflush(e->e_xfp);
+ while (fgets(buf, sizeof buf, xfile) != NULL)
+ putline(buf, mci);
+ (void) xfclose(xfile, "errbody xscript", p);
+ }
+ errno = 0;
+
+ /*
+ ** Output text of original message
+ */
+
+ if (NoReturn)
+ SendBody = FALSE;
+ putline("", mci);
+ if (e->e_parent->e_df != NULL)
+ {
+ if (SendBody)
+ putline(" ----- Original message follows -----\n", mci);
+ else
+ putline(" ----- Message header follows -----\n", mci);
+ (void) fflush(mci->mci_out);
+
+ if (e->e_msgboundary != NULL)
+ {
+ putline("", mci);
+ (void) sprintf(buf, "--%s", e->e_msgboundary);
+ putline(buf, mci);
+ putline("Content-Type: message/rfc822", mci);
+ putline("", mci);
+ }
+ putheader(mci, e->e_parent);
+ putline("", mci);
+ if (SendBody)
+ putbody(mci, e->e_parent, e->e_msgboundary);
+ else
+ putline(" ----- Message body suppressed -----", mci);
+ }
+ else
+ {
+ putline(" ----- No message was collected -----\n", mci);
+ }
+
+ if (e->e_msgboundary != NULL)
+ {
+ putline("", mci);
+ (void) sprintf(buf, "--%s--", e->e_msgboundary);
+ putline(buf, mci);
+ }
+ putline("", mci);
+
+ /*
+ ** Cleanup and exit
+ */
+
+ if (errno != 0)
+ syserr("errbody: I/O error");
+}
+ /*
+** PRUNEROUTE -- prune an RFC-822 source route
+**
+** Trims down a source route to the last internet-registered hop.
+** This is encouraged by RFC 1123 section 5.3.3.
+**
+** Parameters:
+** addr -- the address
+**
+** Returns:
+** TRUE -- address was modified
+** FALSE -- address could not be pruned
+**
+** Side Effects:
+** modifies addr in-place
+*/
+
+pruneroute(addr)
+ char *addr;
+{
+#if NAMED_BIND
+ char *start, *at, *comma;
+ char c;
+ int rcode;
+ char hostbuf[BUFSIZ];
+ char *mxhosts[MAXMXHOSTS + 1];
+
+ /* check to see if this is really a route-addr */
+ if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
+ return FALSE;
+ start = strchr(addr, ':');
+ at = strrchr(addr, '@');
+ if (start == NULL || at == NULL || at < start)
+ return FALSE;
+
+ /* slice off the angle brackets */
+ strcpy(hostbuf, at + 1);
+ hostbuf[strlen(hostbuf) - 1] = '\0';
+
+ while (start)
+ {
+ if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
+ {
+ strcpy(addr + 1, start + 1);
+ return TRUE;
+ }
+ c = *start;
+ *start = '\0';
+ comma = strrchr(addr, ',');
+ if (comma && comma[1] == '@')
+ strcpy(hostbuf, comma + 2);
+ else
+ comma = 0;
+ *start = c;
+ start = comma;
+ }
+#endif
+ return FALSE;
+}
diff --git a/usr.sbin/sendmail/src/sendmail.8 b/usr.sbin/sendmail/src/sendmail.8
new file mode 100644
index 00000000000..f03d3deb9c1
--- /dev/null
+++ b/usr.sbin/sendmail/src/sendmail.8
@@ -0,0 +1,501 @@
+.\" Copyright (c) 1988, 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.
+.\"
+.\" @(#)sendmail.8 8.4 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt SENDMAIL 8
+.Os BSD 4
+.Sh NAME
+.Nm sendmail
+.Nd send mail over the internet
+.Sh SYNOPSIS
+.Nm sendmail
+.Op Ar flags
+.Op Ar address ...
+.Nm newaliases
+.Nm mailq
+.Op Fl v
+.Sh DESCRIPTION
+.Nm Sendmail
+sends a message to one or more
+.Em recipients ,
+routing the message over whatever networks
+are necessary.
+.Nm Sendmail
+does internetwork forwarding as necessary
+to deliver the message to the correct place.
+.Pp
+.Nm Sendmail
+is not intended as a user interface routine;
+other programs provide user-friendly
+front ends;
+.Nm sendmail
+is used only to deliver pre-formatted messages.
+.Pp
+With no flags,
+.Nm sendmail
+reads its standard input
+up to an end-of-file
+or a line consisting only of a single dot
+and sends a copy of the message found there
+to all of the addresses listed.
+It determines the network(s) to use
+based on the syntax and contents of the addresses.
+.Pp
+Local addresses are looked up in a file
+and aliased appropriately.
+Aliasing can be prevented by preceding the address
+with a backslash.
+Normally the sender is not included in any alias
+expansions, e.g.,
+if `john' sends to `group',
+and `group' includes `john' in the expansion,
+then the letter will not be delivered to `john'.
+.Ss Parameters
+.Bl -tag -width Fl
+.It Fl B Ns Ar type
+Set the body type to
+.Ar type .
+Current legal values
+.Li 7BIT
+or
+.Li 8BITMIME .
+.It Fl ba
+Go into
+.Tn ARPANET
+mode.
+All input lines must end with a CR-LF,
+and all messages will be generated with a CR-LF at the end.
+Also,
+the ``From:'' and ``Sender:''
+fields are examined for the name of the sender.
+.It Fl bd
+Run as a daemon. This requires Berkeley
+.Tn IPC .
+.Nm Sendmail
+will fork and run in background
+listening on socket 25 for incoming
+.Tn SMTP
+connections.
+This is normally run from
+.Pa /etc/rc .
+.It Fl bi
+Initialize the alias database.
+.It Fl bm
+Deliver mail in the usual way (default).
+.It Fl bp
+Print a listing of the queue.
+.It Fl bs
+Use the
+.Tn SMTP
+protocol as described in
+.Tn RFC821
+on standard input and output.
+This flag implies all the operations of the
+.Fl ba
+flag that are compatible with
+.Tn SMTP .
+.It Fl bt
+Run in address test mode.
+This mode reads addresses and shows the steps in parsing;
+it is used for debugging configuration tables.
+.It Fl bv
+Verify names only \- do not try to collect or deliver a message.
+Verify mode is normally used for validating
+users or mailing lists.
+.It Fl C Ns Ar file
+Use alternate configuration file.
+.Nm Sendmail
+refuses to run as root if an alternate configuration file is specified.
+.It Fl d Ns Ar X
+Set debugging value to
+.Ar X .
+.ne 1i
+.It Fl F Ns Ar fullname
+Set the full name of the sender.
+.It Fl f Ns Ar name
+Sets the name of the ``from'' person
+(i.e., the sender of the mail).
+.Fl f
+can only be used
+by ``trusted'' users
+(normally
+.Em root ,
+.Em daemon ,
+and
+.Em network )
+or if the person you are trying to become
+is the same as the person you are.
+.It Fl h Ns Ar N
+Set the hop count to
+.Ar N .
+The hop count is incremented every time the mail is
+processed.
+When it reaches a limit,
+the mail is returned with an error message,
+the victim of an aliasing loop.
+If not specified,
+``Received:'' lines in the message are counted.
+.It Fl n
+Don't do aliasing.
+.It Fl o Ns Ar x Em value
+Set option
+.Ar x
+to the specified
+.Em value .
+Options are described below.
+.It Fl p Ns Ar protocol
+Set the name of the protocol used to receive the message.
+This can be a simple protocol name such as ``UUCP''
+or a protocol and hostname, such as ``UUCP:ucbvax''.
+.It Fl q Ns Bq Ar time
+Processed saved messages in the queue at given intervals.
+If
+.Ar time
+is omitted,
+process the queue once.
+.Xr Time
+is given as a tagged number,
+with
+.Ql s
+being seconds,
+.Ql m
+being minutes,
+.Ql h
+being hours,
+.Ql d
+being days,
+and
+.Ql w
+being weeks.
+For example,
+.Ql \-q1h30m
+or
+.Ql \-q90m
+would both set the timeout to one hour thirty minutes.
+If
+.Ar time
+is specified,
+.Nm sendmail
+will run in background.
+This option can be used safely with
+.Fl bd .
+.It Fl r Ns Ar name
+An alternate and obsolete form of the
+.Fl f
+flag.
+.It Fl t
+Read message for recipients.
+To:, Cc:, and Bcc: lines will be scanned for recipient addresses.
+The Bcc: line will be deleted before transmission.
+Any addresses in the argument list will be suppressed,
+that is,
+they will
+.Em not
+receive copies even if listed in the message header.
+.It Fl v
+Go into verbose mode.
+Alias expansions will be announced, etc.
+.It Fl X Ar logfile
+Log all traffic in and out of mailers in the indicated log file.
+This should only be used as a last resort
+for debugging mailer bugs.
+It will log a lot of data very quickly.
+.El
+.Ss Options
+There are also a number of processing options that may be set.
+Normally these will only be used by a system administrator.
+Options may be set either on the command line
+using the
+.Fl o
+flag
+or in the configuration file.
+This is a partial list;
+for a complete list (and details), consult the
+.%T "Sendmail Installation and Operation Guide" .
+The options are:
+.Bl -tag -width Fl
+.It Li A Ns Ar file
+Use alternate alias file.
+.It Li b Ns Ar nblocks
+The minimum number of free blocks needed on the spool filesystem.
+.It Li c
+On mailers that are considered ``expensive'' to connect to,
+don't initiate immediate connection.
+This requires queueing.
+.It Li C Ar N
+Checkpoint the queue file after every
+.Ar N
+successful deliveries (default 10).
+This avoids excessive duplicate deliveries
+when sending to long mailing lists
+interrupted by system crashes.
+.It Li d Ns Ar x
+Set the delivery mode to
+.Ar x .
+Delivery modes are
+.Ql i
+for interactive (synchronous) delivery,
+.Ql b
+for background (asynchronous) delivery,
+and
+.Ql q
+for queue only \- i.e.,
+actual delivery is done the next time the queue is run.
+.It Li D
+Try to automatically rebuild the alias database
+if necessary.
+.It Li e Ns Ar x
+Set error processing to mode
+.Ar x .
+Valid modes are
+.Ql m
+to mail back the error message,
+.Ql w
+to ``write'' back the error message
+(or mail it back if the sender is not logged in),
+.Ql p
+to print the errors on the terminal
+(default),
+.Ql q
+to throw away error messages
+(only exit status is returned),
+and
+.Ql e
+to do special processing for the BerkNet.
+If the text of the message is not mailed back
+by
+modes
+.Ql m
+or
+.Ql w
+and if the sender is local to this machine,
+a copy of the message is appended to the file
+.Pa dead.letter
+in the sender's home directory.
+.It Li f
+Save
+.Tn UNIX Ns \-style
+From lines at the front of messages.
+.It Li G
+Match local mail names against the GECOS portion of the password file.
+.It Li g Ar N
+The default group id to use when calling mailers.
+.It Li H Ns Ar file
+The
+.Tn SMTP
+help file.
+.It Li h Ar N
+The maximum number of times a message is allowed to ``hop''
+before we decide it is in a loop.
+.It Li i
+Do not take dots on a line by themselves
+as a message terminator.
+.It Li j
+Send error messages in MIME format.
+.It Li K Ns Ar timeout
+Set connection cache timeout.
+.It Li k Ns Ar N
+Set connection cache size.
+.It Li L Ns Ar n
+The log level.
+.It Li l
+Pay attention to the Errors-To: header.
+.It Li m
+Send to ``me'' (the sender) also if I am in an alias expansion.
+.It Li n
+Validate the right hand side of aliases during a
+.Xr newaliases 1
+command.
+.It Li o
+If set, this message may have
+old style headers.
+If not set,
+this message is guaranteed to have new style headers
+(i.e., commas instead of spaces between addresses).
+If set, an adaptive algorithm is used that will correctly
+determine the header format in most cases.
+.It Li Q Ns Ar queuedir
+Select the directory in which to queue messages.
+.It Li S Ns Ar file
+Save statistics in the named file.
+.It Li s
+Always instantiate the queue file,
+even under circumstances where it is not strictly necessary.
+This provides safety against system crashes during delivery.
+.It Li T Ns Ar time
+Set the timeout on undelivered messages in the queue to the specified time.
+After delivery has failed
+(e.g., because of a host being down)
+for this amount of time,
+failed messages will be returned to the sender.
+The default is three days.
+.It Li t Ns Ar stz , Ar dtz
+Set the name of the time zone.
+.It Li U Ns Ar userdatabase
+If set, a user database is consulted to get forwarding information.
+You can consider this an adjunct to the aliasing mechanism,
+except that the database is intended to be distributed;
+aliases are local to a particular host.
+This may not be available if your sendmail does not have the
+.Dv USERDB
+option compiled in.
+.It Li u Ns Ar N
+Set the default user id for mailers.
+.It Li Y
+Fork each job during queue runs.
+May be convenient on memory-poor machines.
+.It Li 7
+Strip incoming messages to seven bits.
+.El
+.Pp
+In aliases,
+the first character of a name may be
+a vertical bar to cause interpretation of
+the rest of the name as a command
+to pipe the mail to.
+It may be necessary to quote the name
+to keep
+.Nm sendmail
+from suppressing the blanks from between arguments.
+For example, a common alias is:
+.Pp
+.Bd -literal -offset indent -compact
+msgs: "|/usr/bin/msgs -s"
+.Ed
+.Pp
+Aliases may also have the syntax
+.Dq :include: Ns Ar filename
+to ask
+.Xr sendmail
+to read the named file for a list of recipients.
+For example, an alias such as:
+.Pp
+.Bd -literal -offset indent -compact
+poets: ":include:/usr/local/lib/poets.list"
+.Ed
+.Pp
+would read
+.Pa /usr/local/lib/poets.list
+for the list of addresses making up the group.
+.Pp
+.Nm Sendmail
+returns an exit status
+describing what it did.
+The codes are defined in
+.Aq Pa sysexits.h :
+.Bl -tag -width EX_UNAVAILABLE -compact -offset indent
+.It Dv EX_OK
+Successful completion on all addresses.
+.It Dv EX_NOUSER
+User name not recognized.
+.It Dv EX_UNAVAILABLE
+Catchall meaning necessary resources
+were not available.
+.It Dv EX_SYNTAX
+Syntax error in address.
+.It Dv EX_SOFTWARE
+Internal software error,
+including bad arguments.
+.It Dv EX_OSERR
+Temporary operating system error,
+such as
+.Dq cannot fork .
+.It Dv EX_NOHOST
+Host name not recognized.
+.It Dv EX_TEMPFAIL
+Message could not be sent immediately,
+but was queued.
+.El
+.Pp
+If invoked as
+.Nm newaliases ,
+.Nm sendmail
+will rebuild the alias database.
+If invoked as
+.Nm mailq ,
+.Nm sendmail
+will print the contents of the mail queue.
+.Sh FILES
+Except for the file
+.Pa /etc/sendmail.cf
+itself,
+the following pathnames are all specified in
+.Pa /etc/sendmail.cf.
+Thus,
+these values are only approximations.
+.Pp
+.Bl -tag -width /usr/lib/sendmail.fc -compact
+.It Pa /etc/aliases
+raw data for alias names
+.It Pa /etc/aliases.db
+data base of alias names
+.It Pa /etc/sendmail.cf
+configuration file
+.It Pa /etc/sendmail.hf
+help file
+.It Pa /var/log/sendmail.st
+collected statistics
+.It Pa /var/spool/mqueue/*
+temp files
+.It Pa /var/run/sendmail.pid
+The process id of the daemon
+.El
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr rmail 1 ,
+.Xr syslog 3 ,
+.Xr aliases 5 ,
+.Xr mailaddr 7 ,
+.Xr mail.local 8 ,
+.Xr rc 8 ;
+.Pp
+DARPA
+Internet Request For Comments
+.%T RFC819 ,
+.%T RFC821 ,
+.%T RFC822 .
+.Rs
+.%T "Sendmail \- An Internetwork Mail Router"
+.%V SMM
+.%N \&No. 9
+.Re
+.Rs
+.%T "Sendmail Installation and Operation Guide"
+.%V SMM
+.%N \&No. 8
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/sendmail/src/sendmail.h b/usr.sbin/sendmail/src/sendmail.h
new file mode 100644
index 00000000000..4fc1ef7addc
--- /dev/null
+++ b/usr.sbin/sendmail/src/sendmail.h
@@ -0,0 +1,974 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ *
+ * @(#)sendmail.h 8.43.1.3 (Berkeley) 3/5/95
+ */
+
+/*
+** SENDMAIL.H -- Global definitions for sendmail.
+*/
+
+# ifdef _DEFINE
+# define EXTERN
+# ifndef lint
+static char SmailSccsId[] = "@(#)sendmail.h 8.43.1.3 3/5/95";
+# endif
+# else /* _DEFINE */
+# define EXTERN extern
+# endif /* _DEFINE */
+
+# include <unistd.h>
+# include <stddef.h>
+# include <stdlib.h>
+# include <stdio.h>
+# include <ctype.h>
+# include <setjmp.h>
+# include <sysexits.h>
+# include <string.h>
+# include <time.h>
+# include <errno.h>
+
+# include "conf.h"
+# include "useful.h"
+
+# ifdef LOG
+# include <syslog.h>
+# endif /* LOG */
+
+# ifdef DAEMON
+# include <sys/socket.h>
+# endif
+# ifdef NETUNIX
+# include <sys/un.h>
+# endif
+# ifdef NETINET
+# include <netinet/in.h>
+# endif
+# ifdef NETISO
+# include <netiso/iso.h>
+# endif
+# ifdef NETNS
+# include <netns/ns.h>
+# endif
+# ifdef NETX25
+# include <netccitt/x25.h>
+# endif
+
+
+
+
+/*
+** Data structure for bit maps.
+**
+** Each bit in this map can be referenced by an ascii character.
+** This is 128 possible bits, or 12 8-bit bytes.
+*/
+
+#define BITMAPBYTES 16 /* number of bytes in a bit map */
+#define BYTEBITS 8 /* number of bits in a byte */
+
+/* internal macros */
+#define _BITWORD(bit) (bit / (BYTEBITS * sizeof (int)))
+#define _BITBIT(bit) (1 << (bit % (BYTEBITS * sizeof (int))))
+
+typedef int BITMAP[BITMAPBYTES / sizeof (int)];
+
+/* test bit number N */
+#define bitnset(bit, map) ((map)[_BITWORD(bit)] & _BITBIT(bit))
+
+/* set bit number N */
+#define setbitn(bit, map) (map)[_BITWORD(bit)] |= _BITBIT(bit)
+
+/* clear bit number N */
+#define clrbitn(bit, map) (map)[_BITWORD(bit)] &= ~_BITBIT(bit)
+
+/* clear an entire bit map */
+#define clrbitmap(map) bzero((char *) map, BITMAPBYTES)
+ /*
+** Address structure.
+** Addresses are stored internally in this structure.
+*/
+
+struct address
+{
+ char *q_paddr; /* the printname for the address */
+ char *q_user; /* user name */
+ char *q_ruser; /* real user name, or NULL if q_user */
+ char *q_host; /* host name */
+ struct mailer *q_mailer; /* mailer to use */
+ u_short q_flags; /* status flags, see below */
+ uid_t q_uid; /* user-id of receiver (if known) */
+ gid_t q_gid; /* group-id of receiver (if known) */
+ char *q_home; /* home dir (local mailer only) */
+ char *q_fullname; /* full name if known */
+ struct address *q_next; /* chain */
+ struct address *q_alias; /* address this results from */
+ char *q_owner; /* owner of q_alias */
+ struct address *q_tchain; /* temporary use chain */
+ time_t q_timeout; /* timeout for this address */
+};
+
+typedef struct address ADDRESS;
+
+# define QDONTSEND 000001 /* don't send to this address */
+# define QBADADDR 000002 /* this address is verified bad */
+# define QGOODUID 000004 /* the q_uid q_gid fields are good */
+# define QPRIMARY 000010 /* set from argv */
+# define QQUEUEUP 000020 /* queue for later transmission */
+# define QSENT 000040 /* has been successfully delivered */
+# define QNOTREMOTE 000100 /* not an address for remote forwarding */
+# define QSELFREF 000200 /* this address references itself */
+# define QVERIFIED 000400 /* verified, but not expanded */
+# define QREPORT 001000 /* report this address in return message */
+# define QBOGUSSHELL 002000 /* this entry has an invalid shell listed */
+# define QUNSAFEADDR 004000 /* address aquired through an unsafe path */
+
+# define NULLADDR ((ADDRESS *) NULL)
+ /*
+** Mailer definition structure.
+** Every mailer known to the system is declared in this
+** structure. It defines the pathname of the mailer, some
+** flags associated with it, and the argument vector to
+** pass to it. The flags are defined in conf.c
+**
+** The argument vector is expanded before actual use. All
+** words except the first are passed through the macro
+** processor.
+*/
+
+struct mailer
+{
+ char *m_name; /* symbolic name of this mailer */
+ char *m_mailer; /* pathname of the mailer to use */
+ BITMAP m_flags; /* status flags, see below */
+ short m_mno; /* mailer number internally */
+ char **m_argv; /* template argument vector */
+ short m_sh_rwset; /* rewrite set: sender header addresses */
+ short m_se_rwset; /* rewrite set: sender envelope addresses */
+ short m_rh_rwset; /* rewrite set: recipient header addresses */
+ short m_re_rwset; /* rewrite set: recipient envelope addresses */
+ char *m_eol; /* end of line string */
+ long m_maxsize; /* size limit on message to this mailer */
+ int m_linelimit; /* max # characters per line */
+ char *m_execdir; /* directory to chdir to before execv */
+};
+
+typedef struct mailer MAILER;
+
+/* bits for m_flags */
+# define M_ESMTP 'a' /* run Extended SMTP protocol */
+# define M_BLANKEND 'b' /* ensure blank line at end of message */
+# define M_NOCOMMENT 'c' /* don't include comment part of address */
+# define M_CANONICAL 'C' /* make addresses canonical "u@dom" */
+ /* 'D' /* CF: include Date: */
+# define M_EXPENSIVE 'e' /* it costs to use this mailer.... */
+# define M_ESCFROM 'E' /* escape From lines to >From */
+# define M_FOPT 'f' /* mailer takes picky -f flag */
+ /* 'F' /* CF: include From: or Resent-From: */
+# define M_NO_NULL_FROM 'g' /* sender of errors should be $g */
+# define M_HST_UPPER 'h' /* preserve host case distinction */
+# define M_PREHEAD 'H' /* MAIL11V3: preview headers */
+# define M_INTERNAL 'I' /* SMTP to another sendmail site */
+# define M_LOCALMAILER 'l' /* delivery is to this host */
+# define M_LIMITS 'L' /* must enforce SMTP line limits */
+# define M_MUSER 'm' /* can handle multiple users at once */
+ /* 'M' /* CF: include Message-Id: */
+# define M_NHDR 'n' /* don't insert From line */
+# define M_MANYSTATUS 'N' /* MAIL11V3: DATA returns multi-status */
+# define M_FROMPATH 'p' /* use reverse-path in MAIL FROM: */
+ /* 'P' /* CF: include Return-Path: */
+# define M_ROPT 'r' /* mailer takes picky -r flag */
+# define M_SECURE_PORT 'R' /* try to send on a reserved TCP port */
+# define M_STRIPQ 's' /* strip quote chars from user/host */
+# define M_RESTR 'S' /* must be daemon to execute */
+# define M_USR_UPPER 'u' /* preserve user case distinction */
+# define M_UGLYUUCP 'U' /* this wants an ugly UUCP from line */
+ /* 'V' /* UIUC: !-relativize all addresses */
+ /* 'x' /* CF: include Full-Name: */
+# define M_XDOT 'X' /* use hidden-dot algorithm */
+# define M_7BITS '7' /* use 7-bit path */
+
+EXTERN MAILER *Mailer[MAXMAILERS+1];
+
+EXTERN MAILER *LocalMailer; /* ptr to local mailer */
+EXTERN MAILER *ProgMailer; /* ptr to program mailer */
+EXTERN MAILER *FileMailer; /* ptr to *file* mailer */
+EXTERN MAILER *InclMailer; /* ptr to *include* mailer */
+ /*
+** Header structure.
+** This structure is used internally to store header items.
+*/
+
+struct header
+{
+ char *h_field; /* the name of the field */
+ char *h_value; /* the value of that field */
+ struct header *h_link; /* the next header */
+ u_short h_flags; /* status bits, see below */
+ BITMAP h_mflags; /* m_flags bits needed */
+};
+
+typedef struct header HDR;
+
+/*
+** Header information structure.
+** Defined in conf.c, this struct declares the header fields
+** that have some magic meaning.
+*/
+
+struct hdrinfo
+{
+ char *hi_field; /* the name of the field */
+ u_short hi_flags; /* status bits, see below */
+};
+
+extern struct hdrinfo HdrInfo[];
+
+/* bits for h_flags and hi_flags */
+# define H_EOH 00001 /* this field terminates header */
+# define H_RCPT 00002 /* contains recipient addresses */
+# define H_DEFAULT 00004 /* if another value is found, drop this */
+# define H_RESENT 00010 /* this address is a "Resent-..." address */
+# define H_CHECK 00020 /* check h_mflags against m_flags */
+# define H_ACHECK 00040 /* ditto, but always (not just default) */
+# define H_FORCE 00100 /* force this field, even if default */
+# define H_TRACE 00200 /* this field contains trace information */
+# define H_FROM 00400 /* this is a from-type field */
+# define H_VALID 01000 /* this field has a validated value */
+# define H_RECEIPTTO 02000 /* this field has return receipt info */
+# define H_ERRORSTO 04000 /* this field has error address info */
+ /*
+** Information about currently open connections to mailers, or to
+** hosts that we have looked up recently.
+*/
+
+# define MCI struct mailer_con_info
+
+MCI
+{
+ short mci_flags; /* flag bits, see below */
+ short mci_errno; /* error number on last connection */
+ short mci_herrno; /* h_errno from last DNS lookup */
+ short mci_exitstat; /* exit status from last connection */
+ short mci_state; /* SMTP state */
+ long mci_maxsize; /* max size this server will accept */
+ FILE *mci_in; /* input side of connection */
+ FILE *mci_out; /* output side of connection */
+ int mci_pid; /* process id of subordinate proc */
+ char *mci_phase; /* SMTP phase string */
+ struct mailer *mci_mailer; /* ptr to the mailer for this conn */
+ char *mci_host; /* host name */
+ time_t mci_lastuse; /* last usage time */
+};
+
+
+/* flag bits */
+#define MCIF_VALID 000001 /* this entry is valid */
+#define MCIF_TEMP 000002 /* don't cache this connection */
+#define MCIF_CACHED 000004 /* currently in open cache */
+#define MCIF_ESMTP 000010 /* this host speaks ESMTP */
+#define MCIF_EXPN 000020 /* EXPN command supported */
+#define MCIF_SIZE 000040 /* SIZE option supported */
+#define MCIF_8BITMIME 000100 /* BODY=8BITMIME supported */
+#define MCIF_7BIT 000200 /* strip this message to 7 bits */
+#define MCIF_MULTSTAT 000400 /* MAIL11V3: handles MULT status */
+
+/* states */
+#define MCIS_CLOSED 0 /* no traffic on this connection */
+#define MCIS_OPENING 1 /* sending initial protocol */
+#define MCIS_OPEN 2 /* open, initial protocol sent */
+#define MCIS_ACTIVE 3 /* message being sent */
+#define MCIS_QUITING 4 /* running quit protocol */
+#define MCIS_SSD 5 /* service shutting down */
+#define MCIS_ERROR 6 /* I/O error on connection */
+ /*
+** Envelope structure.
+** This structure defines the message itself. There is usually
+** only one of these -- for the message that we originally read
+** and which is our primary interest -- but other envelopes can
+** be generated during processing. For example, error messages
+** will have their own envelope.
+*/
+
+# define ENVELOPE struct envelope
+
+ENVELOPE
+{
+ HDR *e_header; /* head of header list */
+ long e_msgpriority; /* adjusted priority of this message */
+ time_t e_ctime; /* time message appeared in the queue */
+ char *e_to; /* the target person */
+ char *e_receiptto; /* return receipt address */
+ ADDRESS e_from; /* the person it is from */
+ char *e_sender; /* e_from.q_paddr w comments stripped */
+ char **e_fromdomain; /* the domain part of the sender */
+ ADDRESS *e_sendqueue; /* list of message recipients */
+ ADDRESS *e_errorqueue; /* the queue for error responses */
+ long e_msgsize; /* size of the message in bytes */
+ long e_flags; /* flags, see below */
+ int e_nrcpts; /* number of recipients */
+ short e_class; /* msg class (priority, junk, etc.) */
+ short e_hopcount; /* number of times processed */
+ short e_nsent; /* number of sends since checkpoint */
+ short e_sendmode; /* message send mode */
+ short e_errormode; /* error return mode */
+ int (*e_puthdr)__P((MCI *, ENVELOPE *));
+ /* function to put header of message */
+ int (*e_putbody)__P((MCI *, ENVELOPE *, char *));
+ /* function to put body of message */
+ struct envelope *e_parent; /* the message this one encloses */
+ struct envelope *e_sibling; /* the next envelope of interest */
+ char *e_bodytype; /* type of message body */
+ char *e_df; /* location of temp file */
+ FILE *e_dfp; /* temporary file */
+ char *e_id; /* code for this entry in queue */
+ FILE *e_xfp; /* transcript file */
+ FILE *e_lockfp; /* the lock file for this message */
+ char *e_message; /* error message */
+ char *e_statmsg; /* stat msg (changes per delivery) */
+ char *e_msgboundary; /* MIME-style message part boundary */
+ char *e_origrcpt; /* original recipient (one only) */
+ char *e_macro[128]; /* macro definitions */
+};
+
+/* values for e_flags */
+#define EF_OLDSTYLE 0x0000001 /* use spaces (not commas) in hdrs */
+#define EF_INQUEUE 0x0000002 /* this message is fully queued */
+#define EF_CLRQUEUE 0x0000008 /* disk copy is no longer needed */
+#define EF_SENDRECEIPT 0x0000010 /* send a return receipt */
+#define EF_FATALERRS 0x0000020 /* fatal errors occured */
+#define EF_KEEPQUEUE 0x0000040 /* keep queue files always */
+#define EF_RESPONSE 0x0000080 /* this is an error or return receipt */
+#define EF_RESENT 0x0000100 /* this message is being forwarded */
+#define EF_VRFYONLY 0x0000200 /* verify only (don't expand aliases) */
+#define EF_WARNING 0x0000400 /* warning message has been sent */
+#define EF_QUEUERUN 0x0000800 /* this envelope is from queue */
+#define EF_GLOBALERRS 0x0001000 /* treat errors as global */
+#define EF_PM_NOTIFY 0x0002000 /* send return mail to postmaster */
+#define EF_METOO 0x0004000 /* send to me too */
+#define EF_LOGSENDER 0x0008000 /* need to log the sender */
+#define EF_NORECEIPT 0x0010000 /* suppress all return-receipts */
+
+EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
+ /*
+** Message priority classes.
+**
+** The message class is read directly from the Priority: header
+** field in the message.
+**
+** CurEnv->e_msgpriority is the number of bytes in the message plus
+** the creation time (so that jobs ``tend'' to be ordered correctly),
+** adjusted by the message class, the number of recipients, and the
+** amount of time the message has been sitting around. This number
+** is used to order the queue. Higher values mean LOWER priority.
+**
+** Each priority class point is worth WkClassFact priority points;
+** each recipient is worth WkRecipFact priority points. Each time
+** we reprocess a message the priority is adjusted by WkTimeFact.
+** WkTimeFact should normally decrease the priority so that jobs
+** that have historically failed will be run later; thanks go to
+** Jay Lepreau at Utah for pointing out the error in my thinking.
+**
+** The "class" is this number, unadjusted by the age or size of
+** this message. Classes with negative representations will have
+** error messages thrown away if they are not local.
+*/
+
+struct priority
+{
+ char *pri_name; /* external name of priority */
+ int pri_val; /* internal value for same */
+};
+
+EXTERN struct priority Priorities[MAXPRIORITIES];
+EXTERN int NumPriorities; /* pointer into Priorities */
+ /*
+** Rewrite rules.
+*/
+
+struct rewrite
+{
+ char **r_lhs; /* pattern match */
+ char **r_rhs; /* substitution value */
+ struct rewrite *r_next;/* next in chain */
+};
+
+EXTERN struct rewrite *RewriteRules[MAXRWSETS];
+
+/*
+** Special characters in rewriting rules.
+** These are used internally only.
+** The COND* rules are actually used in macros rather than in
+** rewriting rules, but are given here because they
+** cannot conflict.
+*/
+
+/* left hand side items */
+# define MATCHZANY 0220 /* match zero or more tokens */
+# define MATCHANY 0221 /* match one or more tokens */
+# define MATCHONE 0222 /* match exactly one token */
+# define MATCHCLASS 0223 /* match one token in a class */
+# define MATCHNCLASS 0224 /* match anything not in class */
+# define MATCHREPL 0225 /* replacement on RHS for above */
+
+/* right hand side items */
+# define CANONNET 0226 /* canonical net, next token */
+# define CANONHOST 0227 /* canonical host, next token */
+# define CANONUSER 0230 /* canonical user, next N tokens */
+# define CALLSUBR 0231 /* call another rewriting set */
+
+/* conditionals in macros */
+# define CONDIF 0232 /* conditional if-then */
+# define CONDELSE 0233 /* conditional else */
+# define CONDFI 0234 /* conditional fi */
+
+/* bracket characters for host name lookup */
+# define HOSTBEGIN 0235 /* hostname lookup begin */
+# define HOSTEND 0236 /* hostname lookup end */
+
+/* bracket characters for generalized lookup */
+# define LOOKUPBEGIN 0205 /* generalized lookup begin */
+# define LOOKUPEND 0206 /* generalized lookup end */
+
+/* macro substitution character */
+# define MACROEXPAND 0201 /* macro expansion */
+# define MACRODEXPAND 0202 /* deferred macro expansion */
+
+/* to make the code clearer */
+# define MATCHZERO CANONHOST
+
+/* external <==> internal mapping table */
+struct metamac
+{
+ char metaname; /* external code (after $) */
+ u_char metaval; /* internal code (as above) */
+};
+ /*
+** Name canonification short circuit.
+**
+** If the name server for a host is down, the process of trying to
+** canonify the name can hang. This is similar to (but alas, not
+** identical to) looking up the name for delivery. This stab type
+** caches the result of the name server lookup so we don't hang
+** multiple times.
+*/
+
+#define NAMECANON struct _namecanon
+
+NAMECANON
+{
+ short nc_errno; /* cached errno */
+ short nc_herrno; /* cached h_errno */
+ short nc_stat; /* cached exit status code */
+ short nc_flags; /* flag bits */
+ char *nc_cname; /* the canonical name */
+};
+
+/* values for nc_flags */
+#define NCF_VALID 0x0001 /* entry valid */
+ /*
+** Mapping functions
+**
+** These allow arbitrary mappings in the config file. The idea
+** (albeit not the implementation) comes from IDA sendmail.
+*/
+
+# define MAPCLASS struct _mapclass
+# define MAP struct _map
+
+
+/*
+** An actual map.
+*/
+
+MAP
+{
+ MAPCLASS *map_class; /* the class of this map */
+ char *map_mname; /* name of this map */
+ int map_mflags; /* flags, see below */
+ char *map_file; /* the (nominal) filename */
+ ARBPTR_T map_db1; /* the open database ptr */
+ ARBPTR_T map_db2; /* an "extra" database pointer */
+ char *map_app; /* to append to successful matches */
+ char *map_domain; /* the (nominal) NIS domain */
+ char *map_rebuild; /* program to run to do auto-rebuild */
+ time_t map_mtime; /* last database modification time */
+};
+
+/* bit values for map_flags */
+# define MF_VALID 0x0001 /* this entry is valid */
+# define MF_INCLNULL 0x0002 /* include null byte in key */
+# define MF_OPTIONAL 0x0004 /* don't complain if map not found */
+# define MF_NOFOLDCASE 0x0008 /* don't fold case in keys */
+# define MF_MATCHONLY 0x0010 /* don't use the map value */
+# define MF_OPEN 0x0020 /* this entry is open */
+# define MF_WRITABLE 0x0040 /* open for writing */
+# define MF_ALIAS 0x0080 /* this is an alias file */
+# define MF_TRY0NULL 0x0100 /* try with no null byte */
+# define MF_TRY1NULL 0x0200 /* try with the null byte */
+# define MF_LOCKED 0x0400 /* this map is currently locked */
+# define MF_ALIASWAIT 0x0800 /* alias map in aliaswait state */
+# define MF_IMPL_HASH 0x1000 /* implicit: underlying hash database */
+# define MF_IMPL_NDBM 0x2000 /* implicit: underlying NDBM database */
+
+
+/*
+** The class of a map -- essentially the functions to call
+*/
+
+MAPCLASS
+{
+ char *map_cname; /* name of this map class */
+ char *map_ext; /* extension for database file */
+ short map_cflags; /* flag bits, see below */
+ bool (*map_parse)__P((MAP *, char *));
+ /* argument parsing function */
+ char *(*map_lookup)__P((MAP *, char *, char **, int *));
+ /* lookup function */
+ void (*map_store)__P((MAP *, char *, char *));
+ /* store function */
+ bool (*map_open)__P((MAP *, int));
+ /* open function */
+ void (*map_close)__P((MAP *));
+ /* close function */
+};
+
+/* bit values for map_cflags */
+#define MCF_ALIASOK 0x0001 /* can be used for aliases */
+#define MCF_ALIASONLY 0x0002 /* usable only for aliases */
+#define MCF_REBUILDABLE 0x0004 /* can rebuild alias files */
+ /*
+** Symbol table definitions
+*/
+
+struct symtab
+{
+ char *s_name; /* name to be entered */
+ char s_type; /* general type (see below) */
+ struct symtab *s_next; /* pointer to next in chain */
+ union
+ {
+ BITMAP sv_class; /* bit-map of word classes */
+ ADDRESS *sv_addr; /* pointer to address header */
+ MAILER *sv_mailer; /* pointer to mailer */
+ char *sv_alias; /* alias */
+ MAPCLASS sv_mapclass; /* mapping function class */
+ MAP sv_map; /* mapping function */
+ char *sv_hostsig; /* host signature */
+ MCI sv_mci; /* mailer connection info */
+ NAMECANON sv_namecanon; /* canonical name cache */
+ } s_value;
+};
+
+typedef struct symtab STAB;
+
+/* symbol types */
+# define ST_UNDEF 0 /* undefined type */
+# define ST_CLASS 1 /* class map */
+# define ST_ADDRESS 2 /* an address in parsed format */
+# define ST_MAILER 3 /* a mailer header */
+# define ST_ALIAS 4 /* an alias */
+# define ST_MAPCLASS 5 /* mapping function class */
+# define ST_MAP 6 /* mapping function */
+# define ST_HOSTSIG 7 /* host signature */
+# define ST_NAMECANON 8 /* cached canonical name */
+# define ST_MCI 16 /* mailer connection info (offset) */
+
+# define s_class s_value.sv_class
+# define s_address s_value.sv_addr
+# define s_mailer s_value.sv_mailer
+# define s_alias s_value.sv_alias
+# define s_mci s_value.sv_mci
+# define s_mapclass s_value.sv_mapclass
+# define s_hostsig s_value.sv_hostsig
+# define s_map s_value.sv_map
+# define s_namecanon s_value.sv_namecanon
+
+extern STAB *stab __P((char *, int, int));
+extern void stabapply __P((void (*)(STAB *, int), int));
+
+/* opcodes to stab */
+# define ST_FIND 0 /* find entry */
+# define ST_ENTER 1 /* enter if not there */
+ /*
+** STRUCT EVENT -- event queue.
+**
+** Maintained in sorted order.
+**
+** We store the pid of the process that set this event to insure
+** that when we fork we will not take events intended for the parent.
+*/
+
+struct event
+{
+ time_t ev_time; /* time of the function call */
+ int (*ev_func)__P((int));
+ /* function to call */
+ int ev_arg; /* argument to ev_func */
+ int ev_pid; /* pid that set this event */
+ struct event *ev_link; /* link to next item */
+};
+
+typedef struct event EVENT;
+
+EXTERN EVENT *EventQueue; /* head of event queue */
+ /*
+** Operation, send, and error modes
+**
+** The operation mode describes the basic operation of sendmail.
+** This can be set from the command line, and is "send mail" by
+** default.
+**
+** The send mode tells how to send mail. It can be set in the
+** configuration file. It's setting determines how quickly the
+** mail will be delivered versus the load on your system. If the
+** -v (verbose) flag is given, it will be forced to SM_DELIVER
+** mode.
+**
+** The error mode tells how to return errors.
+*/
+
+EXTERN char OpMode; /* operation mode, see below */
+
+#define MD_DELIVER 'm' /* be a mail sender */
+#define MD_SMTP 's' /* run SMTP on standard input */
+#define MD_ARPAFTP 'a' /* obsolete ARPANET mode (Grey Book) */
+#define MD_DAEMON 'd' /* run as a daemon */
+#define MD_VERIFY 'v' /* verify: don't collect or deliver */
+#define MD_TEST 't' /* test mode: resolve addrs only */
+#define MD_INITALIAS 'i' /* initialize alias database */
+#define MD_PRINT 'p' /* print the queue */
+#define MD_FREEZE 'z' /* freeze the configuration file */
+
+
+/* values for e_sendmode -- send modes */
+#define SM_DELIVER 'i' /* interactive delivery */
+#define SM_QUICKD 'j' /* deliver w/o queueing */
+#define SM_FORK 'b' /* deliver in background */
+#define SM_QUEUE 'q' /* queue, don't deliver */
+#define SM_VERIFY 'v' /* verify only (used internally) */
+
+/* used only as a parameter to sendall */
+#define SM_DEFAULT '\0' /* unspecified, use SendMode */
+
+
+/* values for e_errormode -- error handling modes */
+#define EM_PRINT 'p' /* print errors */
+#define EM_MAIL 'm' /* mail back errors */
+#define EM_WRITE 'w' /* write back errors */
+#define EM_BERKNET 'e' /* special berknet processing */
+#define EM_QUIET 'q' /* don't print messages (stat only) */
+ /*
+** Additional definitions
+*/
+
+
+/*
+** Privacy flags
+** These are bit values for the PrivacyFlags word.
+*/
+
+#define PRIV_PUBLIC 0 /* what have I got to hide? */
+#define PRIV_NEEDMAILHELO 00001 /* insist on HELO for MAIL, at least */
+#define PRIV_NEEDEXPNHELO 00002 /* insist on HELO for EXPN */
+#define PRIV_NEEDVRFYHELO 00004 /* insist on HELO for VRFY */
+#define PRIV_NOEXPN 00010 /* disallow EXPN command entirely */
+#define PRIV_NOVRFY 00020 /* disallow VRFY command entirely */
+#define PRIV_AUTHWARNINGS 00040 /* flag possible authorization probs */
+#define PRIV_NORECEIPTS 00100 /* disallow return receipts */
+#define PRIV_RESTRICTMAILQ 01000 /* restrict mailq command */
+#define PRIV_RESTRICTQRUN 02000 /* restrict queue run */
+#define PRIV_GOAWAY 00777 /* don't give no info, anyway, anyhow */
+
+/* struct defining such things */
+struct prival
+{
+ char *pv_name; /* name of privacy flag */
+ int pv_flag; /* numeric level */
+};
+
+
+/*
+** Flags passed to remotename, parseaddr, allocaddr, and buildaddr.
+*/
+
+#define RF_SENDERADDR 0001 /* this is a sender address */
+#define RF_HEADERADDR 0002 /* this is a header address */
+#define RF_CANONICAL 0004 /* strip comment information */
+#define RF_ADDDOMAIN 0010 /* OK to do domain extension */
+#define RF_COPYPARSE 0020 /* copy parsed user & host */
+#define RF_COPYPADDR 0040 /* copy print address */
+#define RF_COPYALL (RF_COPYPARSE|RF_COPYPADDR)
+#define RF_COPYNONE 0
+
+
+/*
+** Flags passed to safefile.
+*/
+
+#define SFF_ANYFILE 0 /* no special restrictions */
+#define SFF_MUSTOWN 0x0001 /* user must own this file */
+#define SFF_NOSLINK 0x0002 /* file cannot be a symbolic link */
+#define SFF_ROOTOK 0x0004 /* ok for root to own this file */
+
+
+/*
+** Regular UNIX sockaddrs are too small to handle ISO addresses, so
+** we are forced to declare a supertype here.
+*/
+
+union bigsockaddr
+{
+ struct sockaddr sa; /* general version */
+#ifdef NETUNIX
+ struct sockaddr_un sunix; /* UNIX family */
+#endif
+#ifdef NETINET
+ struct sockaddr_in sin; /* INET family */
+#endif
+#ifdef NETISO
+ struct sockaddr_iso siso; /* ISO family */
+#endif
+#ifdef NETNS
+ struct sockaddr_ns sns; /* XNS family */
+#endif
+#ifdef NETX25
+ struct sockaddr_x25 sx25; /* X.25 family */
+#endif
+};
+
+#define SOCKADDR union bigsockaddr
+ /*
+** Global variables.
+*/
+
+EXTERN bool FromFlag; /* if set, "From" person is explicit */
+EXTERN bool MeToo; /* send to the sender also */
+EXTERN bool IgnrDot; /* don't let dot end messages */
+EXTERN bool SaveFrom; /* save leading "From" lines */
+EXTERN bool Verbose; /* set if blow-by-blow desired */
+EXTERN bool GrabTo; /* if set, get recipients from msg */
+EXTERN bool NoReturn; /* don't return letter to sender */
+EXTERN bool SuprErrs; /* set if we are suppressing errors */
+EXTERN bool HoldErrs; /* only output errors to transcript */
+EXTERN bool NoConnect; /* don't connect to non-local mailers */
+EXTERN bool SuperSafe; /* be extra careful, even if expensive */
+EXTERN bool ForkQueueRuns; /* fork for each job when running the queue */
+EXTERN bool AutoRebuild; /* auto-rebuild the alias database as needed */
+EXTERN bool CheckAliases; /* parse addresses during newaliases */
+EXTERN bool NoAlias; /* suppress aliasing */
+EXTERN bool UseNameServer; /* use internet domain name server */
+EXTERN bool SevenBit; /* force 7-bit data */
+EXTERN time_t SafeAlias; /* interval to wait until @:@ in alias file */
+EXTERN FILE *InChannel; /* input connection */
+EXTERN FILE *OutChannel; /* output connection */
+EXTERN uid_t RealUid; /* when Daemon, real uid of caller */
+EXTERN gid_t RealGid; /* when Daemon, real gid of caller */
+EXTERN uid_t DefUid; /* default uid to run as */
+EXTERN gid_t DefGid; /* default gid to run as */
+EXTERN char *DefUser; /* default user to run as (from DefUid) */
+EXTERN int OldUmask; /* umask when sendmail starts up */
+EXTERN int Errors; /* set if errors (local to single pass) */
+EXTERN int ExitStat; /* exit status code */
+EXTERN int AliasLevel; /* depth of aliasing */
+EXTERN int LineNumber; /* line number in current input */
+EXTERN int LogLevel; /* level of logging to perform */
+EXTERN int FileMode; /* mode on files */
+EXTERN int QueueLA; /* load average starting forced queueing */
+EXTERN int RefuseLA; /* load average refusing connections are */
+EXTERN int CurrentLA; /* current load average */
+EXTERN long QueueFactor; /* slope of queue function */
+EXTERN time_t QueueIntvl; /* intervals between running the queue */
+EXTERN char *HelpFile; /* location of SMTP help file */
+EXTERN char *ErrMsgFile; /* file to prepend to all error messages */
+EXTERN char *StatFile; /* location of statistics summary */
+EXTERN char *QueueDir; /* location of queue directory */
+EXTERN char *FileName; /* name to print on error messages */
+EXTERN char *SmtpPhase; /* current phase in SMTP processing */
+EXTERN char *MyHostName; /* name of this host for SMTP messages */
+EXTERN char *RealHostName; /* name of host we are talking to */
+EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */
+EXTERN char *CurHostName; /* current host we are dealing with */
+EXTERN jmp_buf TopFrame; /* branch-to-top-of-loop-on-error frame */
+EXTERN bool QuickAbort; /* .... but only if we want a quick abort */
+EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */
+EXTERN bool SendMIMEErrors; /* send error messages in MIME format */
+EXTERN bool MatchGecos; /* look for user names in gecos field */
+EXTERN bool UseErrorsTo; /* use Errors-To: header (back compat) */
+EXTERN bool TryNullMXList; /* if we are the best MX, try host directly */
+extern bool CheckLoopBack; /* check for loopback on HELO packet */
+EXTERN bool InChild; /* true if running in an SMTP subprocess */
+EXTERN bool DisConnected; /* running with OutChannel redirected to xf */
+EXTERN char SpaceSub; /* substitution for <lwsp> */
+EXTERN int PrivacyFlags; /* privacy flags */
+EXTERN char *ConfFile; /* location of configuration file [conf.c] */
+extern char *PidFile; /* location of proc id file [conf.c] */
+extern ADDRESS NullAddress; /* a null (template) address [main.c] */
+EXTERN long WkClassFact; /* multiplier for message class -> priority */
+EXTERN long WkRecipFact; /* multiplier for # of recipients -> priority */
+EXTERN long WkTimeFact; /* priority offset each time this job is run */
+EXTERN char *UdbSpec; /* user database source spec */
+EXTERN int MaxHopCount; /* max # of hops until bounce */
+EXTERN int ConfigLevel; /* config file level */
+EXTERN char *TimeZoneSpec; /* override time zone specification */
+EXTERN char *ForwardPath; /* path to search for .forward files */
+EXTERN long MinBlocksFree; /* min # of blocks free on queue fs */
+EXTERN char *FallBackMX; /* fall back MX host */
+EXTERN long MaxMessageSize; /* advertised max size we will accept */
+EXTERN char *PostMasterCopy; /* address to get errs cc's */
+EXTERN int CheckpointInterval; /* queue file checkpoint interval */
+EXTERN bool DontPruneRoutes; /* don't prune source routes */
+extern bool BrokenSmtpPeers; /* peers can't handle 2-line greeting */
+EXTERN int MaxMciCache; /* maximum entries in MCI cache */
+EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */
+EXTERN char *QueueLimitRecipient; /* limit queue runs to this recipient */
+EXTERN char *QueueLimitSender; /* limit queue runs to this sender */
+EXTERN char *QueueLimitId; /* limit queue runs to this id */
+EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */
+extern int errno;
+
+
+/*
+** Timeouts
+**
+** Indicated values are the MINIMUM per RFC 1123 section 5.3.2.
+*/
+
+EXTERN struct
+{
+ /* RFC 1123-specified timeouts [minimum value] */
+ time_t to_initial; /* initial greeting timeout [5m] */
+ time_t to_mail; /* MAIL command [5m] */
+ time_t to_rcpt; /* RCPT command [5m] */
+ time_t to_datainit; /* DATA initiation [2m] */
+ time_t to_datablock; /* DATA block [3m] */
+ time_t to_datafinal; /* DATA completion [10m] */
+ time_t to_nextcommand; /* next command [5m] */
+ /* following timeouts are not mentioned in RFC 1123 */
+ time_t to_rset; /* RSET command */
+ time_t to_helo; /* HELO command */
+ time_t to_quit; /* QUIT command */
+ time_t to_miscshort; /* misc short commands (NOOP, VERB, etc) */
+ time_t to_ident; /* IDENT protocol requests */
+ /* following are per message */
+ time_t to_q_return; /* queue return timeout */
+ time_t to_q_warning; /* queue warning timeout */
+} TimeOuts;
+
+
+/*
+** Trace information
+*/
+
+/* trace vector and macros for debugging flags */
+EXTERN u_char tTdvect[100];
+# define tTd(flag, level) (tTdvect[flag] >= level)
+# define tTdlevel(flag) (tTdvect[flag])
+ /*
+** Miscellaneous information.
+*/
+
+
+
+/*
+** Some in-line functions
+*/
+
+/* set exit status */
+#define setstat(s) { \
+ if (ExitStat == EX_OK || ExitStat == EX_TEMPFAIL) \
+ ExitStat = s; \
+ }
+
+/* make a copy of a string */
+#define newstr(s) strcpy(xalloc(strlen(s) + 1), s)
+
+#define STRUCTCOPY(s, d) d = s
+
+
+/*
+** Declarations of useful functions
+*/
+
+extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *));
+extern char *xalloc __P((int));
+extern bool sameaddr __P((ADDRESS *, ADDRESS *));
+extern FILE *dfopen __P((char *, int, int));
+extern EVENT *setevent __P((time_t, int(*)(), int));
+extern char *sfgets __P((char *, int, FILE *, time_t, char *));
+extern char *queuename __P((ENVELOPE *, int));
+extern time_t curtime __P(());
+extern bool transienterror __P((int));
+extern const char *errstring __P((int));
+extern void expand __P((char *, char *, char *, ENVELOPE *));
+extern void define __P((int, char *, ENVELOPE *));
+extern char *macvalue __P((int, ENVELOPE *));
+extern char **prescan __P((char *, int, char[], int, char **));
+extern int rewrite __P((char **, int, int, ENVELOPE *));
+extern char *fgetfolded __P((char *, int, FILE *));
+extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, ENVELOPE *));
+extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *));
+extern void dropenvelope __P((ENVELOPE *));
+extern void clearenvelope __P((ENVELOPE *, int));
+extern char *username __P(());
+extern MCI *mci_get __P((char *, MAILER *));
+extern char *pintvl __P((time_t, int));
+extern char *map_rewrite __P((MAP *, char *, int, char **));
+extern ADDRESS *getctladdr __P((ADDRESS *));
+extern char *anynet_ntoa __P((SOCKADDR *));
+extern char *remotename __P((char *, MAILER *, int, int *, ENVELOPE *));
+extern bool shouldqueue __P((long, time_t));
+extern bool lockfile __P((int, char *, char *, int));
+extern char *hostsignature __P((MAILER *, char *, ENVELOPE *));
+extern void openxscript __P((ENVELOPE *));
+extern void closexscript __P((ENVELOPE *));
+extern sigfunc_t setsignal __P((int, sigfunc_t));
+extern char *shortenstring __P((char *, int));
+extern bool usershellok __P((char *));
+extern void commaize __P((HDR *, char *, int, MCI *, ENVELOPE *));
+extern char *denlstring __P((char *, int, int));
+
+/* ellipsis is a different case though */
+#ifdef __STDC__
+extern void auth_warning(ENVELOPE *, const char *, ...);
+extern void syserr(const char *, ...);
+extern void usrerr(const char *, ...);
+extern void message(const char *, ...);
+extern void nmessage(const char *, ...);
+#else
+extern void auth_warning();
+extern void syserr();
+extern void usrerr();
+extern void message();
+extern void nmessage();
+#endif
diff --git a/usr.sbin/sendmail/src/sendmail.hf b/usr.sbin/sendmail/src/sendmail.hf
new file mode 100644
index 00000000000..142a7f57705
--- /dev/null
+++ b/usr.sbin/sendmail/src/sendmail.hf
@@ -0,0 +1,58 @@
+cpyr
+cpyr Copyright (c) 1983 Eric P. Allman
+cpyr Copyright (c) 1988, 1993
+cpyr The Regents of the University of California. All rights reserved.
+cpyr
+cpyr @(#)sendmail.hf 8.2 (Berkeley) 7/16/93
+cpyr
+smtp Commands:
+smtp HELO EHLO MAIL RCPT DATA
+smtp RSET NOOP QUIT HELP VRFY
+smtp EXPN VERB
+smtp For more info use "HELP <topic>".
+smtp To report bugs in the implementation send email to
+smtp sendmail@CS.Berkeley.EDU.
+smtp For local information send email to Postmaster at your site.
+help HELP [ <topic> ]
+help The HELP command gives help info.
+helo HELO <hostname>
+helo Introduce yourself.
+ehlo EHLO <hostname>
+ehlo Introduce yourself, and request extended SMTP mode.
+mail MAIL FROM: <sender>
+mail Specifies the sender.
+rcpt RCPT TO: <recipient>
+rcpt Specifies the recipient. Can be used any number of times.
+data DATA
+data Following text is collected as the message.
+data End with a single dot.
+rset RSET
+rset Resets the system.
+quit QUIT
+quit Exit sendmail (SMTP).
+verb VERB
+verb Go into verbose mode. This sends 0xy responses that are
+verb are not RFC821 standard (but should be) They are recognized
+verb by humans and other sendmail implementations.
+vrfy VRFY <recipient>
+vrfy Verify an address. If you want to see what it aliases
+vrfy to, use EXPN instead.
+expn EXPN <recipient>
+expn Expand an address. If the address indicates a mailing
+expn list, return the contents of that list.
+noop NOOP
+noop Do nothing.
+send SEND FROM: <sender>
+send replaces the MAIL command, and can be used to send
+send directly to a users terminal. Not supported in this
+send implementation.
+soml SOML FROM: <sender>
+soml Send or mail. If the user is logged in, send directly,
+soml otherwise mail. Not supported in this implementation.
+saml SAML FROM: <sender>
+saml Send and mail. Send directly to the user's terminal,
+saml and also mail a letter. Not supported in this
+saml implementation.
+turn TURN
+turn Reverses the direction of the connection. Not currently
+turn implemented.
diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c
new file mode 100644
index 00000000000..eef525de730
--- /dev/null
+++ b/usr.sbin/sendmail/src/srvrsmtp.c
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+# include "sendmail.h"
+
+#ifndef lint
+#ifdef SMTP
+static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (with SMTP)";
+#else
+static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (without SMTP)";
+#endif
+#endif /* not lint */
+
+# include <errno.h>
+
+# ifdef SMTP
+
+/*
+** SMTP -- run the SMTP protocol.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** never.
+**
+** Side Effects:
+** Reads commands from the input channel and processes
+** them.
+*/
+
+struct cmd
+{
+ char *cmdname; /* command name */
+ int cmdcode; /* internal code, see below */
+};
+
+/* values for cmdcode */
+# define CMDERROR 0 /* bad command */
+# define CMDMAIL 1 /* mail -- designate sender */
+# define CMDRCPT 2 /* rcpt -- designate recipient */
+# define CMDDATA 3 /* data -- send message text */
+# define CMDRSET 4 /* rset -- reset state */
+# define CMDVRFY 5 /* vrfy -- verify address */
+# define CMDEXPN 6 /* expn -- expand address */
+# define CMDNOOP 7 /* noop -- do nothing */
+# define CMDQUIT 8 /* quit -- close connection and die */
+# define CMDHELO 9 /* helo -- be polite */
+# define CMDHELP 10 /* help -- give usage info */
+# define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */
+/* non-standard commands */
+# define CMDONEX 16 /* onex -- sending one transaction only */
+# define CMDVERB 17 /* verb -- go into verbose mode */
+/* use this to catch and log "door handle" attempts on your system */
+# define CMDLOGBOGUS 23 /* bogus command that should be logged */
+/* debugging-only commands, only enabled if SMTPDEBUG is defined */
+# define CMDDBGQSHOW 24 /* showq -- show send queue */
+# define CMDDBGDEBUG 25 /* debug -- set debug mode */
+
+static struct cmd CmdTab[] =
+{
+ "mail", CMDMAIL,
+ "rcpt", CMDRCPT,
+ "data", CMDDATA,
+ "rset", CMDRSET,
+ "vrfy", CMDVRFY,
+ "expn", CMDEXPN,
+ "help", CMDHELP,
+ "noop", CMDNOOP,
+ "quit", CMDQUIT,
+ "helo", CMDHELO,
+ "ehlo", CMDEHLO,
+ "verb", CMDVERB,
+ "onex", CMDONEX,
+ /*
+ * remaining commands are here only
+ * to trap and log attempts to use them
+ */
+ "showq", CMDDBGQSHOW,
+ "debug", CMDDBGDEBUG,
+ "wiz", CMDLOGBOGUS,
+ NULL, CMDERROR,
+};
+
+bool OneXact = FALSE; /* one xaction only this run */
+char *CurSmtpClient; /* who's at the other end of channel */
+
+static char *skipword();
+extern char RealUserName[];
+
+
+#define MAXBADCOMMANDS 25 /* maximum number of bad commands */
+
+smtp(e)
+ register ENVELOPE *e;
+{
+ register char *p;
+ register struct cmd *c;
+ char *cmd;
+ auto ADDRESS *vrfyqueue;
+ ADDRESS *a;
+ bool gotmail; /* mail command received */
+ bool gothello; /* helo command received */
+ bool vrfy; /* set if this is a vrfy command */
+ char *protocol; /* sending protocol */
+ char *sendinghost; /* sending hostname */
+ unsigned long msize; /* approximate maximum message size */
+ char *peerhostname; /* name of SMTP peer or "localhost" */
+ auto char *delimptr;
+ char *id;
+ int nrcpts; /* number of RCPT commands */
+ bool doublequeue;
+ int badcommands = 0; /* count of bad commands */
+ char inp[MAXLINE];
+ char cmdbuf[MAXLINE];
+ extern char Version[];
+ extern ENVELOPE BlankEnvelope;
+
+ if (fileno(OutChannel) != fileno(stdout))
+ {
+ /* arrange for debugging output to go to remote host */
+ (void) dup2(fileno(OutChannel), fileno(stdout));
+ }
+ settime(e);
+ peerhostname = RealHostName;
+ if (peerhostname == NULL)
+ peerhostname = "localhost";
+ CurHostName = peerhostname;
+ CurSmtpClient = macvalue('_', e);
+ if (CurSmtpClient == NULL)
+ CurSmtpClient = CurHostName;
+
+ setproctitle("server %s startup", CurSmtpClient);
+ expand("\201e", inp, &inp[sizeof inp], e);
+ if (BrokenSmtpPeers)
+ {
+ p = strchr(inp, '\n');
+ if (p != NULL)
+ *p = '\0';
+ message("220 %s", inp);
+ }
+ else
+ {
+ char *q = inp;
+
+ while (q != NULL)
+ {
+ p = strchr(q, '\n');
+ if (p != NULL)
+ *p++ = '\0';
+ message("220-%s", q);
+ q = p;
+ }
+ message("220 ESMTP spoken here");
+ }
+ protocol = NULL;
+ sendinghost = macvalue('s', e);
+ gothello = FALSE;
+ gotmail = FALSE;
+ for (;;)
+ {
+ /* arrange for backout */
+ if (setjmp(TopFrame) > 0)
+ {
+ /* if() nesting is necessary for Cray UNICOS */
+ if (InChild)
+ {
+ QuickAbort = FALSE;
+ SuprErrs = TRUE;
+ finis();
+ }
+ }
+ QuickAbort = FALSE;
+ HoldErrs = FALSE;
+ LogUsrErrs = FALSE;
+ e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
+
+ /* setup for the read */
+ e->e_to = NULL;
+ Errors = 0;
+ (void) fflush(stdout);
+
+ /* read the input line */
+ SmtpPhase = "server cmd read";
+ setproctitle("server %s cmd read", CurHostName);
+ p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
+ SmtpPhase);
+
+ /* handle errors */
+ if (p == NULL)
+ {
+ /* end of file, just die */
+ disconnect(1, e);
+ message("421 %s Lost input channel from %s",
+ MyHostName, CurSmtpClient);
+#ifdef LOG
+ if (LogLevel > (gotmail ? 1 : 19))
+ syslog(LOG_NOTICE, "lost input channel from %s",
+ CurSmtpClient);
+#endif
+ if (InChild)
+ ExitStat = EX_QUIT;
+ finis();
+ }
+
+ /* clean up end of line */
+ fixcrlf(inp, TRUE);
+
+ /* echo command to transcript */
+ if (e->e_xfp != NULL)
+ fprintf(e->e_xfp, "<<< %s\n", inp);
+
+ if (e->e_id == NULL)
+ setproctitle("%s: %.80s", CurSmtpClient, inp);
+ else
+ setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
+
+ /* break off command */
+ for (p = inp; isascii(*p) && isspace(*p); p++)
+ continue;
+ cmd = cmdbuf;
+ while (*p != '\0' &&
+ !(isascii(*p) && isspace(*p)) &&
+ cmd < &cmdbuf[sizeof cmdbuf - 2])
+ *cmd++ = *p++;
+ *cmd = '\0';
+
+ /* throw away leading whitespace */
+ while (isascii(*p) && isspace(*p))
+ p++;
+
+ /* decode command */
+ for (c = CmdTab; c->cmdname != NULL; c++)
+ {
+ if (!strcasecmp(c->cmdname, cmdbuf))
+ break;
+ }
+
+ /* reset errors */
+ errno = 0;
+
+ /* process command */
+ switch (c->cmdcode)
+ {
+ case CMDHELO: /* hello -- introduce yourself */
+ case CMDEHLO: /* extended hello */
+ if (c->cmdcode == CMDEHLO)
+ {
+ protocol = "ESMTP";
+ SmtpPhase = "server EHLO";
+ }
+ else
+ {
+ protocol = "SMTP";
+ SmtpPhase = "server HELO";
+ }
+ sendinghost = newstr(p);
+ gothello = TRUE;
+ if (c->cmdcode != CMDEHLO)
+ {
+ /* print old message and be done with it */
+ message("250 %s Hello %s, pleased to meet you",
+ MyHostName, CurSmtpClient);
+ break;
+ }
+
+ /* print extended message and brag */
+ message("250-%s Hello %s, pleased to meet you",
+ MyHostName, CurSmtpClient);
+ if (!bitset(PRIV_NOEXPN, PrivacyFlags))
+ message("250-EXPN");
+ if (MaxMessageSize > 0)
+ message("250-SIZE %ld", MaxMessageSize);
+ else
+ message("250-SIZE");
+ message("250 HELP");
+ break;
+
+ case CMDMAIL: /* mail -- designate sender */
+ SmtpPhase = "server MAIL";
+
+ /* check for validity of this command */
+ if (!gothello)
+ {
+ /* set sending host to our known value */
+ if (sendinghost == NULL)
+ sendinghost = peerhostname;
+
+ if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
+ {
+ message("503 Polite people say HELO first");
+ break;
+ }
+ }
+ if (gotmail)
+ {
+ message("503 Sender already specified");
+ if (InChild)
+ finis();
+ break;
+ }
+ if (InChild)
+ {
+ errno = 0;
+ syserr("503 Nested MAIL command: MAIL %s", p);
+ finis();
+ }
+
+ /* fork a subprocess to process this command */
+ if (runinchild("SMTP-MAIL", e) > 0)
+ break;
+ if (!gothello)
+ {
+ auth_warning(e,
+ "Host %s didn't use HELO protocol",
+ peerhostname);
+ }
+#ifdef PICKY_HELO_CHECK
+ if (strcasecmp(sendinghost, peerhostname) != 0 &&
+ (strcasecmp(peerhostname, "localhost") != 0 ||
+ strcasecmp(sendinghost, MyHostName) != 0))
+ {
+ auth_warning(e, "Host %s claimed to be %s",
+ peerhostname, sendinghost);
+ }
+#endif
+
+ if (protocol == NULL)
+ protocol = "SMTP";
+ define('r', protocol, e);
+ define('s', sendinghost, e);
+ initsys(e);
+ nrcpts = 0;
+ e->e_flags |= EF_LOGSENDER;
+ setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
+
+ /* child -- go do the processing */
+ p = skipword(p, "from");
+ if (p == NULL)
+ break;
+ if (setjmp(TopFrame) > 0)
+ {
+ /* this failed -- undo work */
+ if (InChild)
+ {
+ QuickAbort = FALSE;
+ SuprErrs = TRUE;
+ e->e_flags &= ~EF_FATALERRS;
+ finis();
+ }
+ break;
+ }
+ QuickAbort = TRUE;
+
+ /* must parse sender first */
+ delimptr = NULL;
+ setsender(p, e, &delimptr, FALSE);
+ p = delimptr;
+ if (p != NULL && *p != '\0')
+ *p++ = '\0';
+
+ /* check for possible spoofing */
+ if (RealUid != 0 && OpMode == MD_SMTP &&
+ (e->e_from.q_mailer != LocalMailer &&
+ strcmp(e->e_from.q_user, RealUserName) != 0))
+ {
+ auth_warning(e, "%s owned process doing -bs",
+ RealUserName);
+ }
+
+ /* now parse ESMTP arguments */
+ msize = 0;
+ while (p != NULL && *p != '\0')
+ {
+ char *kp;
+ char *vp = NULL;
+
+ /* locate the beginning of the keyword */
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p == '\0')
+ break;
+ kp = p;
+
+ /* skip to the value portion */
+ while (isascii(*p) && isalnum(*p) || *p == '-')
+ p++;
+ if (*p == '=')
+ {
+ *p++ = '\0';
+ vp = p;
+
+ /* skip to the end of the value */
+ while (*p != '\0' && *p != ' ' &&
+ !(isascii(*p) && iscntrl(*p)) &&
+ *p != '=')
+ p++;
+ }
+
+ if (*p != '\0')
+ *p++ = '\0';
+
+ if (tTd(19, 1))
+ printf("MAIL: got arg %s=\"%s\"\n", kp,
+ vp == NULL ? "<null>" : vp);
+
+ if (strcasecmp(kp, "size") == 0)
+ {
+ if (vp == NULL)
+ {
+ usrerr("501 SIZE requires a value");
+ /* NOTREACHED */
+ }
+# ifdef __STDC__
+ msize = strtoul(vp, (char **) NULL, 10);
+# else
+ msize = strtol(vp, (char **) NULL, 10);
+# endif
+ }
+ else if (strcasecmp(kp, "body") == 0)
+ {
+ if (vp == NULL)
+ {
+ usrerr("501 BODY requires a value");
+ /* NOTREACHED */
+ }
+# ifdef MIME
+ if (strcasecmp(vp, "8bitmime") == 0)
+ {
+ e->e_bodytype = "8BITMIME";
+ SevenBit = FALSE;
+ }
+ else if (strcasecmp(vp, "7bit") == 0)
+ {
+ e->e_bodytype = "7BIT";
+ SevenBit = TRUE;
+ }
+ else
+ {
+ usrerr("501 Unknown BODY type %s",
+ vp);
+ }
+# endif
+ }
+ else
+ {
+ usrerr("501 %s parameter unrecognized", kp);
+ /* NOTREACHED */
+ }
+ }
+
+ if (MaxMessageSize > 0 && msize > MaxMessageSize)
+ {
+ usrerr("552 Message size exceeds fixed maximum message size (%ld)",
+ MaxMessageSize);
+ /* NOTREACHED */
+ }
+
+ if (!enoughspace(msize))
+ {
+ message("452 Insufficient disk space; try again later");
+ break;
+ }
+ message("250 Sender ok");
+ gotmail = TRUE;
+ break;
+
+ case CMDRCPT: /* rcpt -- designate recipient */
+ if (!gotmail)
+ {
+ usrerr("503 Need MAIL before RCPT");
+ break;
+ }
+ SmtpPhase = "server RCPT";
+ if (setjmp(TopFrame) > 0)
+ {
+ e->e_flags &= ~EF_FATALERRS;
+ break;
+ }
+ QuickAbort = TRUE;
+ LogUsrErrs = TRUE;
+
+ if (e->e_sendmode != SM_DELIVER)
+ e->e_flags |= EF_VRFYONLY;
+
+ p = skipword(p, "to");
+ if (p == NULL)
+ break;
+ a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', NULL, e);
+ if (a == NULL)
+ break;
+ a->q_flags |= QPRIMARY;
+ a = recipient(a, &e->e_sendqueue, e);
+ if (Errors != 0)
+ break;
+
+ /* no errors during parsing, but might be a duplicate */
+ e->e_to = p;
+ if (!bitset(QBADADDR, a->q_flags))
+ {
+ message("250 Recipient ok%s",
+ bitset(QQUEUEUP, a->q_flags) ?
+ " (will queue)" : "");
+ nrcpts++;
+ }
+ else
+ {
+ /* punt -- should keep message in ADDRESS.... */
+ message("550 Addressee unknown");
+ }
+ e->e_to = NULL;
+ break;
+
+ case CMDDATA: /* data -- text of mail */
+ SmtpPhase = "server DATA";
+ if (!gotmail)
+ {
+ message("503 Need MAIL command");
+ break;
+ }
+ else if (nrcpts <= 0)
+ {
+ message("503 Need RCPT (recipient)");
+ break;
+ }
+
+ /* check to see if we need to re-expand aliases */
+ /* also reset QBADADDR on already-diagnosted addrs */
+ doublequeue = FALSE;
+ for (a = e->e_sendqueue; a != NULL; a = a->q_next)
+ {
+ if (bitset(QVERIFIED, a->q_flags))
+ {
+ /* need to re-expand aliases */
+ doublequeue = TRUE;
+ }
+ if (bitset(QBADADDR, a->q_flags))
+ {
+ /* make this "go away" */
+ a->q_flags |= QDONTSEND;
+ a->q_flags &= ~QBADADDR;
+ }
+ }
+
+ /* collect the text of the message */
+ SmtpPhase = "collect";
+ collect(TRUE, doublequeue, e);
+ if (Errors != 0)
+ goto abortmessage;
+ HoldErrs = TRUE;
+
+ /*
+ ** Arrange to send to everyone.
+ ** If sending to multiple people, mail back
+ ** errors rather than reporting directly.
+ ** In any case, don't mail back errors for
+ ** anything that has happened up to
+ ** now (the other end will do this).
+ ** Truncate our transcript -- the mail has gotten
+ ** to us successfully, and if we have
+ ** to mail this back, it will be easier
+ ** on the reader.
+ ** Then send to everyone.
+ ** Finally give a reply code. If an error has
+ ** already been given, don't mail a
+ ** message back.
+ ** We goose error returns by clearing error bit.
+ */
+
+ SmtpPhase = "delivery";
+ if (nrcpts != 1 && !doublequeue)
+ {
+ HoldErrs = TRUE;
+ e->e_errormode = EM_MAIL;
+ }
+ e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
+ id = e->e_id;
+
+ /* send to all recipients */
+ sendall(e, doublequeue ? SM_QUEUE : SM_DEFAULT);
+ e->e_to = NULL;
+
+ /* issue success if appropriate and reset */
+ if (Errors == 0 || HoldErrs)
+ message("250 %s Message accepted for delivery", id);
+
+ if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs)
+ {
+ /* avoid sending back an extra message */
+ e->e_flags &= ~EF_FATALERRS;
+ e->e_flags |= EF_CLRQUEUE;
+ }
+ else
+ {
+ /* from now on, we have to operate silently */
+ HoldErrs = TRUE;
+ e->e_errormode = EM_MAIL;
+
+ /* if we just queued, poke it */
+ if (doublequeue && e->e_sendmode != SM_QUEUE)
+ {
+ extern pid_t dowork();
+
+ unlockqueue(e);
+ (void) dowork(id, TRUE, TRUE, e);
+ }
+ }
+
+ abortmessage:
+ /* if in a child, pop back to our parent */
+ if (InChild)
+ finis();
+
+ /* clean up a bit */
+ gotmail = FALSE;
+ dropenvelope(e);
+ CurEnv = e = newenvelope(e, CurEnv);
+ e->e_flags = BlankEnvelope.e_flags;
+ break;
+
+ case CMDRSET: /* rset -- reset state */
+ message("250 Reset state");
+ e->e_flags |= EF_CLRQUEUE;
+ if (InChild)
+ finis();
+
+ /* clean up a bit */
+ gotmail = FALSE;
+ dropenvelope(e);
+ CurEnv = e = newenvelope(e, CurEnv);
+ break;
+
+ case CMDVRFY: /* vrfy -- verify address */
+ case CMDEXPN: /* expn -- expand address */
+ vrfy = c->cmdcode == CMDVRFY;
+ if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
+ PrivacyFlags))
+ {
+ if (vrfy)
+ message("252 Who's to say?");
+ else
+ message("502 Sorry, we do not allow this operation");
+#ifdef LOG
+ if (LogLevel > 5)
+ syslog(LOG_INFO, "%s: %s [rejected]",
+ CurSmtpClient, inp);
+#endif
+ break;
+ }
+ else if (!gothello &&
+ bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
+ PrivacyFlags))
+ {
+ message("503 I demand that you introduce yourself first");
+ break;
+ }
+ if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
+ break;
+#ifdef LOG
+ if (LogLevel > 5)
+ syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
+#endif
+ vrfyqueue = NULL;
+ QuickAbort = TRUE;
+ if (vrfy)
+ e->e_flags |= EF_VRFYONLY;
+ while (*p != '\0' && isascii(*p) && isspace(*p))
+ *p++;
+ if (*p == '\0')
+ {
+ message("501 Argument required");
+ Errors++;
+ }
+ else
+ {
+ (void) sendtolist(p, NULLADDR, &vrfyqueue, e);
+ }
+ if (Errors != 0)
+ {
+ if (InChild)
+ finis();
+ break;
+ }
+ if (vrfyqueue == NULL)
+ {
+ message("554 Nothing to %s", vrfy ? "VRFY" : "EXPN");
+ }
+ while (vrfyqueue != NULL)
+ {
+ a = vrfyqueue;
+ while ((a = a->q_next) != NULL &&
+ bitset(QDONTSEND|QBADADDR, a->q_flags))
+ continue;
+ if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
+ printvrfyaddr(vrfyqueue, a == NULL);
+ vrfyqueue = vrfyqueue->q_next;
+ }
+ if (InChild)
+ finis();
+ break;
+
+ case CMDHELP: /* help -- give user info */
+ help(p);
+ break;
+
+ case CMDNOOP: /* noop -- do nothing */
+ message("250 OK");
+ break;
+
+ case CMDQUIT: /* quit -- leave mail */
+ message("221 %s closing connection", MyHostName);
+
+doquit:
+ /* avoid future 050 messages */
+ disconnect(1, e);
+
+ if (InChild)
+ ExitStat = EX_QUIT;
+ finis();
+
+ case CMDVERB: /* set verbose mode */
+ if (bitset(PRIV_NOEXPN, PrivacyFlags))
+ {
+ /* this would give out the same info */
+ message("502 Verbose unavailable");
+ break;
+ }
+ Verbose = TRUE;
+ e->e_sendmode = SM_DELIVER;
+ message("250 Verbose mode");
+ break;
+
+ case CMDONEX: /* doing one transaction only */
+ OneXact = TRUE;
+ message("250 Only one transaction");
+ break;
+
+# ifdef SMTPDEBUG
+ case CMDDBGQSHOW: /* show queues */
+ printf("Send Queue=");
+ printaddr(e->e_sendqueue, TRUE);
+ break;
+
+ case CMDDBGDEBUG: /* set debug mode */
+ tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+ tTflag(p);
+ message("200 Debug set");
+ break;
+
+# else /* not SMTPDEBUG */
+ case CMDDBGQSHOW: /* show queues */
+ case CMDDBGDEBUG: /* set debug mode */
+# endif /* SMTPDEBUG */
+ case CMDLOGBOGUS: /* bogus command */
+# ifdef LOG
+ if (LogLevel > 0)
+ syslog(LOG_CRIT,
+ "\"%s\" command from %s (%s)",
+ c->cmdname, peerhostname,
+ anynet_ntoa(&RealHostAddr));
+# endif
+ /* FALL THROUGH */
+
+ case CMDERROR: /* unknown command */
+ if (++badcommands > MAXBADCOMMANDS)
+ {
+ message("421 %s Too many bad commands; closing connection",
+ MyHostName);
+ goto doquit;
+ }
+
+ message("500 Command unrecognized");
+ break;
+
+ default:
+ errno = 0;
+ syserr("500 smtp: unknown code %d", c->cmdcode);
+ break;
+ }
+ }
+}
+ /*
+** SKIPWORD -- skip a fixed word.
+**
+** Parameters:
+** p -- place to start looking.
+** w -- word to skip.
+**
+** Returns:
+** p following w.
+** NULL on error.
+**
+** Side Effects:
+** clobbers the p data area.
+*/
+
+static char *
+skipword(p, w)
+ register char *p;
+ char *w;
+{
+ register char *q;
+ char *firstp = p;
+
+ /* find beginning of word */
+ while (isascii(*p) && isspace(*p))
+ p++;
+ q = p;
+
+ /* find end of word */
+ while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
+ p++;
+ while (isascii(*p) && isspace(*p))
+ *p++ = '\0';
+ if (*p != ':')
+ {
+ syntax:
+ message("501 Syntax error in parameters scanning \"%s\"",
+ firstp);
+ Errors++;
+ return (NULL);
+ }
+ *p++ = '\0';
+ while (isascii(*p) && isspace(*p))
+ p++;
+
+ if (*p == '\0')
+ goto syntax;
+
+ /* see if the input word matches desired word */
+ if (strcasecmp(q, w))
+ goto syntax;
+
+ return (p);
+}
+ /*
+** PRINTVRFYADDR -- print an entry in the verify queue
+**
+** Parameters:
+** a -- the address to print
+** last -- set if this is the last one.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Prints the appropriate 250 codes.
+*/
+
+printvrfyaddr(a, last)
+ register ADDRESS *a;
+ bool last;
+{
+ char fmtbuf[20];
+
+ strcpy(fmtbuf, "250");
+ fmtbuf[3] = last ? ' ' : '-';
+
+ if (a->q_fullname == NULL)
+ {
+ if (strchr(a->q_user, '@') == NULL)
+ strcpy(&fmtbuf[4], "<%s@%s>");
+ else
+ strcpy(&fmtbuf[4], "<%s>");
+ message(fmtbuf, a->q_user, MyHostName);
+ }
+ else
+ {
+ if (strchr(a->q_user, '@') == NULL)
+ strcpy(&fmtbuf[4], "%s <%s@%s>");
+ else
+ strcpy(&fmtbuf[4], "%s <%s>");
+ message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
+ }
+}
+ /*
+** HELP -- implement the HELP command.
+**
+** Parameters:
+** topic -- the topic we want help for.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** outputs the help file to message output.
+*/
+
+help(topic)
+ char *topic;
+{
+ register FILE *hf;
+ int len;
+ char buf[MAXLINE];
+ bool noinfo;
+
+ if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
+ {
+ /* no help */
+ errno = 0;
+ message("502 HELP not implemented");
+ return;
+ }
+
+ if (topic == NULL || *topic == '\0')
+ topic = "smtp";
+ else
+ makelower(topic);
+
+ len = strlen(topic);
+ noinfo = TRUE;
+
+ while (fgets(buf, sizeof buf, hf) != NULL)
+ {
+ if (strncmp(buf, topic, len) == 0)
+ {
+ register char *p;
+
+ p = strchr(buf, '\t');
+ if (p == NULL)
+ p = buf;
+ else
+ p++;
+ fixcrlf(p, TRUE);
+ message("214-%s", p);
+ noinfo = FALSE;
+ }
+ }
+
+ if (noinfo)
+ message("504 HELP topic unknown");
+ else
+ message("214 End of HELP info");
+ (void) fclose(hf);
+}
+ /*
+** RUNINCHILD -- return twice -- once in the child, then in the parent again
+**
+** Parameters:
+** label -- a string used in error messages
+**
+** Returns:
+** zero in the child
+** one in the parent
+**
+** Side Effects:
+** none.
+*/
+
+runinchild(label, e)
+ char *label;
+ register ENVELOPE *e;
+{
+ int childpid;
+
+ if (!OneXact)
+ {
+ childpid = dofork();
+ if (childpid < 0)
+ {
+ syserr("%s: cannot fork", label);
+ return (1);
+ }
+ if (childpid > 0)
+ {
+ auto int st;
+
+ /* parent -- wait for child to complete */
+ setproctitle("server %s child wait", CurHostName);
+ st = waitfor(childpid);
+ if (st == -1)
+ syserr("%s: lost child", label);
+ else if (!WIFEXITED(st))
+ syserr("%s: died on signal %d",
+ label, st & 0177);
+
+ /* if we exited on a QUIT command, complete the process */
+ if (WEXITSTATUS(st) == EX_QUIT)
+ {
+ disconnect(1, e);
+ finis();
+ }
+
+ return (1);
+ }
+ else
+ {
+ /* child */
+ InChild = TRUE;
+ QuickAbort = FALSE;
+ clearenvelope(e, FALSE);
+ }
+ }
+
+ /* open alias database */
+ initmaps(FALSE, e);
+
+ return (0);
+}
+
+# endif /* SMTP */
diff --git a/usr.sbin/sendmail/src/stab.c b/usr.sbin/sendmail/src/stab.c
new file mode 100644
index 00000000000..07893e5b5d9
--- /dev/null
+++ b/usr.sbin/sendmail/src/stab.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)stab.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** STAB -- manage the symbol table
+**
+** Parameters:
+** name -- the name to be looked up or inserted.
+** type -- the type of symbol.
+** op -- what to do:
+** ST_ENTER -- enter the name if not
+** already present.
+** ST_FIND -- find it only.
+**
+** Returns:
+** pointer to a STAB entry for this name.
+** NULL if not found and not entered.
+**
+** Side Effects:
+** can update the symbol table.
+*/
+
+# define STABSIZE 400
+
+static STAB *SymTab[STABSIZE];
+
+STAB *
+stab(name, type, op)
+ char *name;
+ int type;
+ int op;
+{
+ register STAB *s;
+ register STAB **ps;
+ register int hfunc;
+ register char *p;
+ extern char lower();
+
+ if (tTd(36, 5))
+ printf("STAB: %s %d ", name, type);
+
+ /*
+ ** Compute the hashing function
+ **
+ ** We could probably do better....
+ */
+
+ hfunc = type;
+ for (p = name; *p != '\0'; p++)
+ hfunc = (((hfunc << 7) | lower(*p)) & 077777) % STABSIZE;
+
+ if (tTd(36, 9))
+ printf("(hfunc=%d) ", hfunc);
+
+ ps = &SymTab[hfunc];
+ while ((s = *ps) != NULL && (strcasecmp(name, s->s_name) || s->s_type != type))
+ ps = &s->s_next;
+
+ /*
+ ** Dispose of the entry.
+ */
+
+ if (s != NULL || op == ST_FIND)
+ {
+ if (tTd(36, 5))
+ {
+ if (s == NULL)
+ printf("not found\n");
+ else
+ {
+ long *lp = (long *) s->s_class;
+
+ printf("type %d val %lx %lx %lx %lx\n",
+ s->s_type, lp[0], lp[1], lp[2], lp[3]);
+ }
+ }
+ return (s);
+ }
+
+ /*
+ ** Make a new entry and link it in.
+ */
+
+ if (tTd(36, 5))
+ printf("entered\n");
+
+ /* make new entry */
+ s = (STAB *) xalloc(sizeof *s);
+ bzero((char *) s, sizeof *s);
+ s->s_name = newstr(name);
+ makelower(s->s_name);
+ s->s_type = type;
+
+ /* link it in */
+ *ps = s;
+
+ return (s);
+}
+ /*
+** STABAPPLY -- apply function to all stab entries
+**
+** Parameters:
+** func -- the function to apply. It will be given one
+** parameter (the stab entry).
+** arg -- an arbitrary argument, passed to func.
+**
+** Returns:
+** none.
+*/
+
+void
+stabapply(func, arg)
+ void (*func)__P((STAB *, int));
+ int arg;
+{
+ register STAB **shead;
+ register STAB *s;
+
+ for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++)
+ {
+ for (s = *shead; s != NULL; s = s->s_next)
+ {
+ if (tTd(38, 90))
+ printf("stabapply: trying %d/%s\n",
+ s->s_type, s->s_name);
+ func(s, arg);
+ }
+ }
+}
diff --git a/usr.sbin/sendmail/src/stats.c b/usr.sbin/sendmail/src/stats.c
new file mode 100644
index 00000000000..2dc68272fbc
--- /dev/null
+++ b/usr.sbin/sendmail/src/stats.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)stats.c 8.3 (Berkeley) 8/28/93";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include "mailstats.h"
+
+struct statistics Stat;
+
+bool GotStats = FALSE; /* set when we have stats to merge */
+
+#define ONE_K 1000 /* one thousand (twenty-four?) */
+#define KBYTES(x) (((x) + (ONE_K - 1)) / ONE_K)
+ /*
+** MARKSTATS -- mark statistics
+*/
+
+markstats(e, to)
+ register ENVELOPE *e;
+ register ADDRESS *to;
+{
+ if (to == NULL)
+ {
+ if (e->e_from.q_mailer != NULL)
+ {
+ Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
+ Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
+ KBYTES(e->e_msgsize);
+ }
+ }
+ else
+ {
+ Stat.stat_nt[to->q_mailer->m_mno]++;
+ Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
+ }
+ GotStats = TRUE;
+}
+ /*
+** POSTSTATS -- post statistics in the statistics file
+**
+** Parameters:
+** sfile -- the name of the statistics file.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** merges the Stat structure with the sfile file.
+*/
+
+poststats(sfile)
+ char *sfile;
+{
+ register int fd;
+ struct statistics stat;
+ extern off_t lseek();
+
+ if (sfile == NULL || !GotStats)
+ return;
+
+ (void) time(&Stat.stat_itime);
+ Stat.stat_size = sizeof Stat;
+
+ fd = open(sfile, O_RDWR);
+ if (fd < 0)
+ {
+ errno = 0;
+ return;
+ }
+ (void) lockfile(fd, sfile, NULL, LOCK_EX);
+ if (read(fd, (char *) &stat, sizeof stat) == sizeof stat &&
+ stat.stat_size == sizeof stat)
+ {
+ /* merge current statistics into statfile */
+ register int i;
+
+ for (i = 0; i < MAXMAILERS; i++)
+ {
+ stat.stat_nf[i] += Stat.stat_nf[i];
+ stat.stat_bf[i] += Stat.stat_bf[i];
+ stat.stat_nt[i] += Stat.stat_nt[i];
+ stat.stat_bt[i] += Stat.stat_bt[i];
+ }
+ }
+ else
+ bcopy((char *) &Stat, (char *) &stat, sizeof stat);
+
+ /* write out results */
+ (void) lseek(fd, (off_t) 0, 0);
+ (void) write(fd, (char *) &stat, sizeof stat);
+ (void) close(fd);
+
+ /* clear the structure to avoid future disappointment */
+ bzero(&Stat, sizeof stat);
+ GotStats = FALSE;
+}
diff --git a/usr.sbin/sendmail/src/sysexits.c b/usr.sbin/sendmail/src/sysexits.c
new file mode 100644
index 00000000000..fff3783f911
--- /dev/null
+++ b/usr.sbin/sendmail/src/sysexits.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)sysexits.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+#include <sysexits.h>
+
+/*
+** SYSEXITS.C -- error messages corresponding to sysexits.h
+**
+** If the first character of the string is a colon, interpolate
+** the current errno after the rest of the string.
+*/
+
+char *SysExMsg[] =
+{
+ /* 64 USAGE */ " 500 Bad usage",
+ /* 65 DATAERR */ " 501 Data format error",
+ /* 66 NOINPUT */ ":550 Cannot open input",
+ /* 67 NOUSER */ " 550 User unknown",
+ /* 68 NOHOST */ " 550 Host unknown",
+ /* 69 UNAVAILABLE */ " 554 Service unavailable",
+ /* 70 SOFTWARE */ ":554 Internal error",
+ /* 71 OSERR */ ":451 Operating system error",
+ /* 72 OSFILE */ ":554 System file missing",
+ /* 73 CANTCREAT */ ":550 Can't create output",
+ /* 74 IOERR */ ":451 I/O error",
+ /* 75 TEMPFAIL */ " 250 Deferred",
+ /* 76 PROTOCOL */ " 554 Remote protocol error",
+ /* 77 NOPERM */ ":550 Insufficient permission",
+ /* 78 CONFIG */ " 554 Local configuration error",
+};
+
+int N_SysEx = sizeof(SysExMsg) / sizeof(SysExMsg[0]);
diff --git a/usr.sbin/sendmail/src/sysexits.h b/usr.sbin/sendmail/src/sysexits.h
new file mode 100644
index 00000000000..464cb11bab2
--- /dev/null
+++ b/usr.sbin/sendmail/src/sysexits.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1987, 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.
+ *
+ * @(#)sysexits.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYSEXITS_H_
+#define _SYSEXITS_H_
+
+/*
+ * SYSEXITS.H -- Exit status codes for system programs.
+ *
+ * This include file attempts to categorize possible error
+ * exit statuses for system programs, notably delivermail
+ * and the Berkeley network.
+ *
+ * Error numbers begin at EX__BASE to reduce the possibility of
+ * clashing with other exit statuses that random programs may
+ * already return. The meaning of the codes is approximately
+ * as follows:
+ *
+ * EX_USAGE -- The command was used incorrectly, e.g., with
+ * the wrong number of arguments, a bad flag, a bad
+ * syntax in a parameter, or whatever.
+ * EX_DATAERR -- The input data was incorrect in some way.
+ * This should only be used for user's data & not
+ * system files.
+ * EX_NOINPUT -- An input file (not a system file) did not
+ * exist or was not readable. This could also include
+ * errors like "No message" to a mailer (if it cared
+ * to catch it).
+ * EX_NOUSER -- The user specified did not exist. This might
+ * be used for mail addresses or remote logins.
+ * EX_NOHOST -- The host specified did not exist. This is used
+ * in mail addresses or network requests.
+ * EX_UNAVAILABLE -- A service is unavailable. This can occur
+ * if a support program or file does not exist. This
+ * can also be used as a catchall message when something
+ * you wanted to do doesn't work, but you don't know
+ * why.
+ * EX_SOFTWARE -- An internal software error has been detected.
+ * This should be limited to non-operating system related
+ * errors as possible.
+ * EX_OSERR -- An operating system error has been detected.
+ * This is intended to be used for such things as "cannot
+ * fork", "cannot create pipe", or the like. It includes
+ * things like getuid returning a user that does not
+ * exist in the passwd file.
+ * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+ * etc.) does not exist, cannot be opened, or has some
+ * sort of error (e.g., syntax error).
+ * EX_CANTCREAT -- A (user specified) output file cannot be
+ * created.
+ * EX_IOERR -- An error occurred while doing I/O on some file.
+ * EX_TEMPFAIL -- temporary failure, indicating something that
+ * is not really an error. In sendmail, this means
+ * that a mailer (e.g.) could not create a connection,
+ * and the request should be reattempted later.
+ * EX_PROTOCOL -- the remote system returned something that
+ * was "not possible" during a protocol exchange.
+ * EX_NOPERM -- You did not have sufficient permission to
+ * perform the operation. This is not intended for
+ * file system problems, which should use NOINPUT or
+ * CANTCREAT, but rather for higher level permissions.
+ */
+
+#define EX_OK 0 /* successful termination */
+
+#define EX__BASE 64 /* base value for error messages */
+
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* configuration error */
+
+#define EX__MAX 78 /* maximum listed value */
+
+#endif /* !_SYSEXITS_H_ */
diff --git a/usr.sbin/sendmail/src/trace.c b/usr.sbin/sendmail/src/trace.c
new file mode 100644
index 00000000000..29421eee3c6
--- /dev/null
+++ b/usr.sbin/sendmail/src/trace.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)trace.c 8.2 (Berkeley) 3/14/94";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+/*
+** TtSETUP -- set up for trace package.
+**
+** Parameters:
+** vect -- pointer to trace vector.
+** size -- number of flags in trace vector.
+** defflags -- flags to set if no value given.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** environment is set up.
+*/
+
+u_char *tTvect;
+int tTsize;
+static char *DefFlags;
+
+tTsetup(vect, size, defflags)
+ u_char *vect;
+ int size;
+ char *defflags;
+{
+ tTvect = vect;
+ tTsize = size;
+ DefFlags = defflags;
+}
+ /*
+** TtFLAG -- process an external trace flag description.
+**
+** Parameters:
+** s -- the trace flag.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sets/clears trace flags.
+*/
+
+tTflag(s)
+ register char *s;
+{
+ unsigned int first, last;
+ register unsigned int i;
+
+ if (*s == '\0')
+ s = DefFlags;
+
+ for (;;)
+ {
+ /* find first flag to set */
+ i = 0;
+ while (isdigit(*s))
+ i = i * 10 + (*s++ - '0');
+ first = i;
+
+ /* find last flag to set */
+ if (*s == '-')
+ {
+ i = 0;
+ while (isdigit(*++s))
+ i = i * 10 + (*s - '0');
+ }
+ last = i;
+
+ /* find the level to set it to */
+ i = 1;
+ if (*s == '.')
+ {
+ i = 0;
+ while (isdigit(*++s))
+ i = i * 10 + (*s - '0');
+ }
+
+ /* clean up args */
+ if (first >= tTsize)
+ first = tTsize - 1;
+ if (last >= tTsize)
+ last = tTsize - 1;
+
+ /* set the flags */
+ while (first <= last)
+ tTvect[first++] = i;
+
+ /* more arguments? */
+ if (*s++ == '\0')
+ return;
+ }
+}
diff --git a/usr.sbin/sendmail/src/udb.c b/usr.sbin/sendmail/src/udb.c
new file mode 100644
index 00000000000..7887cb367c8
--- /dev/null
+++ b/usr.sbin/sendmail/src/udb.c
@@ -0,0 +1,985 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+#include "sendmail.h"
+
+#ifndef lint
+#ifdef USERDB
+static char sccsid [] = "@(#)udb.c 8.8 (Berkeley) 4/14/94 (with USERDB)";
+#else
+static char sccsid [] = "@(#)udb.c 8.8 (Berkeley) 4/14/94 (without USERDB)";
+#endif
+#endif
+
+#ifdef USERDB
+
+#include <errno.h>
+#include <netdb.h>
+#include <db.h>
+
+#ifdef HESIOD
+#include <hesiod.h>
+#endif /* HESIOD */
+
+/*
+** UDB.C -- interface between sendmail and Berkeley User Data Base.
+**
+** This depends on the 4.4BSD db package.
+*/
+
+
+struct udbent
+{
+ char *udb_spec; /* string version of spec */
+ int udb_type; /* type of entry */
+ char *udb_default; /* default host for outgoing mail */
+ union
+ {
+ /* type UE_REMOTE -- do remote call for lookup */
+ struct
+ {
+ struct sockaddr_in _udb_addr; /* address */
+ int _udb_timeout; /* timeout */
+ } udb_remote;
+#define udb_addr udb_u.udb_remote._udb_addr
+#define udb_timeout udb_u.udb_remote._udb_timeout
+
+ /* type UE_FORWARD -- forward message to remote */
+ struct
+ {
+ char *_udb_fwdhost; /* name of forward host */
+ } udb_forward;
+#define udb_fwdhost udb_u.udb_forward._udb_fwdhost
+
+ /* type UE_FETCH -- lookup in local database */
+ struct
+ {
+ char *_udb_dbname; /* pathname of database */
+ DB *_udb_dbp; /* open database ptr */
+ } udb_lookup;
+#define udb_dbname udb_u.udb_lookup._udb_dbname
+#define udb_dbp udb_u.udb_lookup._udb_dbp
+ } udb_u;
+};
+
+#define UDB_EOLIST 0 /* end of list */
+#define UDB_SKIP 1 /* skip this entry */
+#define UDB_REMOTE 2 /* look up in remote database */
+#define UDB_DBFETCH 3 /* look up in local database */
+#define UDB_FORWARD 4 /* forward to remote host */
+#define UDB_HESIOD 5 /* look up via hesiod */
+
+#define MAXUDBENT 10 /* maximum number of UDB entries */
+
+
+struct option
+{
+ char *name;
+ char *val;
+};
+ /*
+** UDBEXPAND -- look up user in database and expand
+**
+** Parameters:
+** a -- address to expand.
+** sendq -- pointer to head of sendq to put the expansions in.
+**
+** Returns:
+** EX_TEMPFAIL -- if something "odd" happened -- probably due
+** to accessing a file on an NFS server that is down.
+** EX_OK -- otherwise.
+**
+** Side Effects:
+** Modifies sendq.
+*/
+
+int UdbPort = 1616;
+int UdbTimeout = 10;
+
+struct udbent UdbEnts[MAXUDBENT + 1];
+int UdbSock = -1;
+bool UdbInitialized = FALSE;
+
+int
+udbexpand(a, sendq, e)
+ register ADDRESS *a;
+ ADDRESS **sendq;
+ register ENVELOPE *e;
+{
+ int i;
+ register char *p;
+ DBT key;
+ DBT info;
+ bool breakout;
+ register struct udbent *up;
+ int keylen;
+ int naddrs;
+ char keybuf[MAXKEY];
+ char buf[BUFSIZ];
+
+ if (tTd(28, 1))
+ printf("udbexpand(%s)\n", a->q_paddr);
+
+ /* make certain we are supposed to send to this address */
+ if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
+ return EX_OK;
+ e->e_to = a->q_paddr;
+
+ /* on first call, locate the database */
+ if (!UdbInitialized)
+ {
+ extern int _udbx_init();
+
+ if (_udbx_init() == EX_TEMPFAIL)
+ return EX_TEMPFAIL;
+ }
+
+ /* short circuit the process if no chance of a match */
+ if (UdbSpec == NULL || UdbSpec[0] == '\0')
+ return EX_OK;
+
+ /* short circuit name begins with '\\' since it can't possibly match */
+ if (a->q_user[0] == '\\')
+ return EX_OK;
+
+ /* if name is too long, assume it won't match */
+ if (strlen(a->q_user) > sizeof keybuf - 12)
+ return EX_OK;
+
+ /* if name begins with a colon, it indicates our metadata */
+ if (a->q_user[0] == ':')
+ return EX_OK;
+
+ /* build actual database key */
+ (void) strcpy(keybuf, a->q_user);
+ (void) strcat(keybuf, ":maildrop");
+ keylen = strlen(keybuf);
+
+ breakout = FALSE;
+ for (up = UdbEnts; !breakout; up++)
+ {
+ char *user;
+
+ /*
+ ** Select action based on entry type.
+ **
+ ** On dropping out of this switch, "class" should
+ ** explain the type of the data, and "user" should
+ ** contain the user information.
+ */
+
+ switch (up->udb_type)
+ {
+ case UDB_DBFETCH:
+ key.data = keybuf;
+ key.size = keylen;
+ if (tTd(28, 80))
+ printf("udbexpand: trying %s (%d) via db\n",
+ keybuf, keylen);
+ i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
+ if (i > 0 || info.size <= 0)
+ {
+ if (tTd(28, 2))
+ printf("udbexpand: no match on %s (%d)\n",
+ keybuf, keylen);
+ continue;
+ }
+ if (tTd(28, 80))
+ printf("udbexpand: match %.*s: %.*s\n",
+ key.size, key.data, info.size, info.data);
+
+ naddrs = 0;
+ a->q_flags &= ~QSELFREF;
+ while (i == 0 && key.size == keylen &&
+ bcmp(key.data, keybuf, keylen) == 0)
+ {
+ if (bitset(EF_VRFYONLY, e->e_flags))
+ {
+ a->q_flags |= QVERIFIED;
+ e->e_nrcpts++;
+ return EX_OK;
+ }
+
+ breakout = TRUE;
+ if (info.size < sizeof buf)
+ user = buf;
+ else
+ user = xalloc(info.size + 1);
+ bcopy(info.data, user, info.size);
+ user[info.size] = '\0';
+
+ message("expanded to %s", user);
+#ifdef LOG
+ if (LogLevel >= 10)
+ syslog(LOG_INFO, "%s: expand %s => %s",
+ e->e_id, e->e_to, user);
+#endif
+ AliasLevel++;
+ naddrs += sendtolist(user, a, sendq, e);
+ AliasLevel--;
+
+ if (user != buf)
+ free(user);
+
+ /* get the next record */
+ i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
+ }
+
+ /* if nothing ever matched, try next database */
+ if (!breakout)
+ continue;
+
+ if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
+ {
+ if (tTd(28, 5))
+ {
+ printf("udbexpand: QDONTSEND ");
+ printaddr(a, FALSE);
+ }
+ a->q_flags |= QDONTSEND;
+ }
+ if (i < 0)
+ {
+ syserr("udbexpand: db-get %.*s stat %d",
+ key.size, key.data, i);
+ return EX_TEMPFAIL;
+ }
+
+ /*
+ ** If this address has a -request address, reflect
+ ** it into the envelope.
+ */
+
+ (void) strcpy(keybuf, a->q_user);
+ (void) strcat(keybuf, ":mailsender");
+ keylen = strlen(keybuf);
+ key.data = keybuf;
+ key.size = keylen;
+ i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
+ if (i != 0 || info.size <= 0)
+ break;
+ a->q_owner = xalloc(info.size + 1);
+ bcopy(info.data, a->q_owner, info.size);
+ a->q_owner[info.size] = '\0';
+
+ /* announce delivery; NORECEIPT bit set later */
+ if (e->e_xfp != NULL)
+ {
+ fprintf(e->e_xfp,
+ "Message delivered to mailing list %s\n",
+ a->q_paddr);
+ e->e_flags |= EF_SENDRECEIPT;
+ }
+ break;
+
+#ifdef HESIOD
+ case UDB_HESIOD:
+ key.data = keybuf;
+ key.size = keylen;
+ if (tTd(28, 80))
+ printf("udbexpand: trying %s (%d) via hesiod\n",
+ keybuf, keylen);
+ /* look up the key via hesiod */
+ i = hes_udb_get(&key, &info);
+ if (i > 0 || info.size <= 0)
+ {
+ if (tTd(28, 2))
+ printf("udbexpand: no match on %s (%d)\n",
+ keybuf, keylen);
+ continue;
+ }
+ if (tTd(28, 80))
+ printf("udbexpand: match %.*s: %.*s\n",
+ key.size, key.data, info.size, info.data);
+ a->q_flags &= ~QSELFREF;
+
+ if (bitset(EF_VRFYONLY, e->e_flags))
+ {
+ a->q_flags |= QVERIFIED;
+ e->e_nrcpts++;
+ free(info.data);
+ return EX_OK;
+ }
+
+ breakout = TRUE;
+ if (info.size < sizeof buf)
+ user = buf;
+ else
+ user = xalloc(info.size + 1);
+ bcopy(info.data, user, info.size);
+ user[info.size] = '\0';
+ free(info.data);
+
+ message("hesioded to %s", user);
+#ifdef LOG
+ if (LogLevel >= 10)
+ syslog(LOG_INFO, "%s: hesiod %s => %s",
+ e->e_id, e->e_to, user);
+#endif
+ AliasLevel++;
+ naddrs = sendtolist(user, a, sendq, e);
+ AliasLevel--;
+
+ if (user != buf)
+ free(user);
+
+ if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
+ {
+ if (tTd(28, 5))
+ {
+ printf("udbexpand: QDONTSEND ");
+ printaddr(a, FALSE);
+ }
+ a->q_flags |= QDONTSEND;
+ }
+ if (i < 0)
+ {
+ syserr("udbexpand: hesiod-get %.*s stat %d",
+ key.size, key.data, i);
+ return EX_TEMPFAIL;
+ }
+
+ /*
+ ** If this address has a -request address, reflect
+ ** it into the envelope.
+ */
+
+ (void) strcpy(keybuf, a->q_user);
+ (void) strcat(keybuf, ":mailsender");
+ keylen = strlen(keybuf);
+ key.data = keybuf;
+ key.size = keylen;
+ i = hes_udb_get(&key, &info);
+ if (i != 0 || info.size <= 0)
+ break;
+ a->q_owner = xalloc(info.size + 1);
+ bcopy(info.data, a->q_owner, info.size);
+ a->q_owner[info.size] = '\0';
+ free(info.data);
+ break;
+#endif /* HESIOD */
+
+ case UDB_REMOTE:
+ /* not yet implemented */
+ continue;
+
+ case UDB_FORWARD:
+ if (bitset(EF_VRFYONLY, e->e_flags))
+ return EX_OK;
+ i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
+ if (i < sizeof buf)
+ user = buf;
+ else
+ user = xalloc(i + 1);
+ (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
+ message("expanded to %s", user);
+ a->q_flags &= ~QSELFREF;
+ AliasLevel++;
+ naddrs = sendtolist(user, a, sendq, e);
+ AliasLevel--;
+ if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
+ {
+ if (tTd(28, 5))
+ {
+ printf("udbexpand: QDONTSEND ");
+ printaddr(a, FALSE);
+ }
+ a->q_flags |= QDONTSEND;
+ }
+ if (user != buf)
+ free(user);
+ breakout = TRUE;
+ break;
+
+ case UDB_EOLIST:
+ breakout = TRUE;
+ continue;
+
+ default:
+ /* unknown entry type */
+ continue;
+ }
+ }
+ return EX_OK;
+}
+ /*
+** UDBSENDER -- return canonical external name of sender, given local name
+**
+** Parameters:
+** sender -- the name of the sender on the local machine.
+**
+** Returns:
+** The external name for this sender, if derivable from the
+** database.
+** NULL -- if nothing is changed from the database.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+udbsender(sender)
+ char *sender;
+{
+ extern char *udbmatch();
+
+ return udbmatch(sender, "mailname");
+}
+
+
+char *
+udbmatch(user, field)
+ char *user;
+ char *field;
+{
+ register char *p;
+ register struct udbent *up;
+ int i;
+ int keylen;
+ DBT key, info;
+ char keybuf[MAXKEY];
+
+ if (tTd(28, 1))
+ printf("udbmatch(%s, %s)\n", user, field);
+
+ if (!UdbInitialized)
+ {
+ if (_udbx_init() == EX_TEMPFAIL)
+ return NULL;
+ }
+
+ /* short circuit if no spec */
+ if (UdbSpec == NULL || UdbSpec[0] == '\0')
+ return NULL;
+
+ /* short circuit name begins with '\\' since it can't possibly match */
+ if (user[0] == '\\')
+ return NULL;
+
+ /* long names can never match and are a pain to deal with */
+ if ((strlen(user) + strlen(field)) > sizeof keybuf - 4)
+ return NULL;
+
+ /* names beginning with colons indicate metadata */
+ if (user[0] == ':')
+ return NULL;
+
+ /* build database key */
+ (void) strcpy(keybuf, user);
+ (void) strcat(keybuf, ":");
+ (void) strcat(keybuf, field);
+ keylen = strlen(keybuf);
+
+ for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
+ {
+ /*
+ ** Select action based on entry type.
+ */
+
+ switch (up->udb_type)
+ {
+ case UDB_DBFETCH:
+ key.data = keybuf;
+ key.size = keylen;
+ i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
+ if (i != 0 || info.size <= 0)
+ {
+ if (tTd(28, 2))
+ printf("udbmatch: no match on %s (%d) via db\n",
+ keybuf, keylen);
+ continue;
+ }
+
+ p = xalloc(info.size + 1);
+ bcopy(info.data, p, info.size);
+ p[info.size] = '\0';
+ if (tTd(28, 1))
+ printf("udbmatch ==> %s\n", p);
+ return p;
+ break;
+
+#ifdef HESIOD
+ case UDB_HESIOD:
+ key.data = keybuf;
+ key.size = keylen;
+ i = hes_udb_get(&key, &info);
+ if (i != 0 || info.size <= 0)
+ {
+ if (tTd(28, 2))
+ printf("udbmatch: no match on %s (%d) via hesiod\n",
+ keybuf, keylen);
+ continue;
+ }
+
+ p = xalloc(info.size + 1);
+ bcopy(info.data, p, info.size);
+ p[info.size] = '\0';
+ free(info.data);
+ if (tTd(28, 1))
+ printf("udbmatch ==> %s\n", p);
+ return p;
+ break;
+#endif /* HESIOD */
+ }
+ }
+
+ if (strcmp(field, "mailname") != 0)
+ return NULL;
+
+ /*
+ ** Nothing yet. Search again for a default case. But only
+ ** use it if we also have a forward (:maildrop) pointer already
+ ** in the database.
+ */
+
+ /* build database key */
+ (void) strcpy(keybuf, user);
+ (void) strcat(keybuf, ":maildrop");
+ keylen = strlen(keybuf);
+
+ for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
+ {
+ switch (up->udb_type)
+ {
+ case UDB_DBFETCH:
+ /* get the default case for this database */
+ if (up->udb_default == NULL)
+ {
+ key.data = ":default:mailname";
+ key.size = strlen(key.data);
+ i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
+ if (i != 0 || info.size <= 0)
+ {
+ /* no default case */
+ up->udb_default = "";
+ continue;
+ }
+
+ /* save the default case */
+ up->udb_default = xalloc(info.size + 1);
+ bcopy(info.data, up->udb_default, info.size);
+ up->udb_default[info.size] = '\0';
+ }
+ else if (up->udb_default[0] == '\0')
+ continue;
+
+ /* we have a default case -- verify user:maildrop */
+ key.data = keybuf;
+ key.size = keylen;
+ i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
+ if (i != 0 || info.size <= 0)
+ {
+ /* nope -- no aliasing for this user */
+ continue;
+ }
+
+ /* they exist -- build the actual address */
+ p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
+ (void) strcpy(p, user);
+ (void) strcat(p, "@");
+ (void) strcat(p, up->udb_default);
+ if (tTd(28, 1))
+ printf("udbmatch ==> %s\n", p);
+ return p;
+ break;
+
+#ifdef HESIOD
+ case UDB_HESIOD:
+ /* get the default case for this database */
+ if (up->udb_default == NULL)
+ {
+ key.data = ":default:mailname";
+ key.size = strlen(key.data);
+ i = hes_udb_get(&key, &info);
+
+ if (i != 0 || info.size <= 0)
+ {
+ /* no default case */
+ up->udb_default = "";
+ continue;
+ }
+
+ /* save the default case */
+ up->udb_default = xalloc(info.size + 1);
+ bcopy(info.data, up->udb_default, info.size);
+ up->udb_default[info.size] = '\0';
+ free(info.data);
+ }
+ else if (up->udb_default[0] == '\0')
+ continue;
+
+ /* we have a default case -- verify user:maildrop */
+ key.data = keybuf;
+ key.size = keylen;
+ i = hes_udb_get(&key, &info);
+ if (i != 0 || info.size <= 0)
+ {
+ /* nope -- no aliasing for this user */
+ continue;
+ }
+
+ free(info.data);
+ /* they exist -- build the actual address */
+ p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
+ (void) strcpy(p, user);
+ (void) strcat(p, "@");
+ (void) strcat(p, up->udb_default);
+ if (tTd(28, 1))
+ printf("udbmatch ==> %s\n", p);
+ return p;
+ break;
+#endif /* HESIOD */
+ }
+ }
+
+ /* still nothing.... too bad */
+ return NULL;
+}
+ /*
+** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
+** database due to a host being down or some similar
+** (recoverable) situation.
+** EX_OK -- otherwise.
+**
+** Side Effects:
+** Fills in the UdbEnts structure from UdbSpec.
+*/
+
+#define MAXUDBOPTS 27
+
+int
+_udbx_init()
+{
+ register char *p;
+ int i;
+ register struct udbent *up;
+ char buf[BUFSIZ];
+
+ if (UdbInitialized)
+ return EX_OK;
+
+# ifdef UDB_DEFAULT_SPEC
+ if (UdbSpec == NULL)
+ UdbSpec = UDB_DEFAULT_SPEC;
+# endif
+
+ p = UdbSpec;
+ up = UdbEnts;
+ while (p != NULL)
+ {
+ char *spec;
+ auto int rcode;
+ int nopts;
+ int nmx;
+ register struct hostent *h;
+ char *mxhosts[MAXMXHOSTS + 1];
+ struct option opts[MAXUDBOPTS + 1];
+
+ while (*p == ' ' || *p == '\t' || *p == ',')
+ p++;
+ if (*p == '\0')
+ break;
+ spec = p;
+ p = strchr(p, ',');
+ if (p != NULL)
+ *p++ = '\0';
+
+ /* extract options */
+ nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
+
+ /*
+ ** Decode database specification.
+ **
+ ** In the sendmail tradition, the leading character
+ ** defines the semantics of the rest of the entry.
+ **
+ ** +hostname -- send a datagram to the udb server
+ ** on host "hostname" asking for the
+ ** home mail server for this user.
+ ** *hostname -- similar to +hostname, except that the
+ ** hostname is searched as an MX record;
+ ** resulting hosts are searched as for
+ ** +mxhostname. If no MX host is found,
+ ** this is the same as +hostname.
+ ** @hostname -- forward email to the indicated host.
+ ** This should be the last in the list,
+ ** since it always matches the input.
+ ** /dbname -- search the named database on the local
+ ** host using the Berkeley db package.
+ */
+
+ switch (*spec)
+ {
+ case '+': /* search remote database */
+ case '*': /* search remote database (expand MX) */
+ if (*spec == '*')
+ {
+#if NAMED_BIND
+ nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
+#else
+ mxhosts[0] = spec + 1;
+ nmx = 1;
+ rcode = 0;
+#endif
+ if (tTd(28, 16))
+ {
+ int i;
+
+ printf("getmxrr(%s): %d", spec + 1, nmx);
+ for (i = 0; i <= nmx; i++)
+ printf(" %s", mxhosts[i]);
+ printf("\n");
+ }
+ }
+ else
+ {
+ nmx = 1;
+ mxhosts[0] = spec + 1;
+ }
+
+ for (i = 0; i < nmx; i++)
+ {
+ h = gethostbyname(mxhosts[i]);
+ if (h == NULL)
+ continue;
+ up->udb_type = UDB_REMOTE;
+ up->udb_addr.sin_family = h->h_addrtype;
+ bcopy(h->h_addr_list[0],
+ (char *) &up->udb_addr.sin_addr,
+ sizeof up->udb_addr.sin_addr);
+ up->udb_addr.sin_port = UdbPort;
+ up->udb_timeout = UdbTimeout;
+ up++;
+ }
+
+ /* set up a datagram socket */
+ if (UdbSock < 0)
+ {
+ UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
+ (void) fcntl(UdbSock, F_SETFD, 1);
+ }
+ break;
+
+ case '@': /* forward to remote host */
+ up->udb_type = UDB_FORWARD;
+ up->udb_fwdhost = spec + 1;
+ up++;
+ break;
+
+ case 'h': /* use hesiod */
+ case 'H':
+#ifdef HESIOD
+ if (strcasecmp(spec, "hesiod") != 0)
+ break;
+ up->udb_type = UDB_HESIOD;
+ up++;
+#endif /* HESIOD */
+ break;
+
+ case '/': /* look up remote name */
+ up->udb_dbname = spec;
+ errno = 0;
+ up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
+ if (up->udb_dbp == NULL)
+ {
+ if (errno != ENOENT && errno != EACCES)
+ {
+#ifdef LOG
+ if (LogLevel > 2)
+ syslog(LOG_ERR, "dbopen(%s): %s",
+ spec, errstring(errno));
+#endif
+ up->udb_type = UDB_EOLIST;
+ goto tempfail;
+ }
+ break;
+ }
+ up->udb_type = UDB_DBFETCH;
+ up++;
+ break;
+ }
+ }
+ up->udb_type = UDB_EOLIST;
+
+ if (tTd(28, 4))
+ {
+ for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
+ {
+ switch (up->udb_type)
+ {
+ case UDB_REMOTE:
+ printf("REMOTE: addr %s, timeo %d\n",
+ anynet_ntoa((SOCKADDR *) &up->udb_addr),
+ up->udb_timeout);
+ break;
+
+ case UDB_DBFETCH:
+ printf("FETCH: file %s\n",
+ up->udb_dbname);
+ break;
+
+ case UDB_FORWARD:
+ printf("FORWARD: host %s\n",
+ up->udb_fwdhost);
+ break;
+
+ case UDB_HESIOD:
+ printf("HESIOD\n");
+ break;
+
+ default:
+ printf("UNKNOWN\n");
+ break;
+ }
+ }
+ }
+
+ UdbInitialized = TRUE;
+ errno = 0;
+ return EX_OK;
+
+ /*
+ ** On temporary failure, back out anything we've already done
+ */
+
+ tempfail:
+ for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
+ {
+ if (up->udb_type == UDB_DBFETCH)
+ {
+ (*up->udb_dbp->close)(up->udb_dbp);
+ }
+ }
+ return EX_TEMPFAIL;
+}
+
+int
+_udb_parsespec(udbspec, opt, maxopts)
+ char *udbspec;
+ struct option opt[];
+ int maxopts;
+{
+ register char *spec;
+ register char *spec_end;
+ register int optnum;
+
+ spec_end = strchr(udbspec, ':');
+ for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
+ {
+ register char *p;
+
+ while (isascii(*spec) && isspace(*spec))
+ spec++;
+ spec_end = strchr(spec, ':');
+ if (spec_end != NULL)
+ *spec_end++ = '\0';
+
+ opt[optnum].name = spec;
+ opt[optnum].val = NULL;
+ p = strchr(spec, '=');
+ if (p != NULL)
+ opt[optnum].val = ++p;
+ }
+ return optnum;
+}
+
+#ifdef HESIOD
+
+int
+hes_udb_get(key, info)
+ DBT *key;
+ DBT *info;
+{
+ char *name, *type;
+ char *p, **hp;
+
+ name = key->data;
+ type = strchr(name, ':');
+ if (type == NULL)
+ return 1;
+
+ *type++ = '\0';
+
+ if (tTd(28, 1))
+ printf("hes_udb_get(%s, %s)\n", name, type);
+
+ /* make the hesiod query */
+ hp = hes_resolve(name, type);
+ if (hp == NULL)
+ {
+ /* network problem or timeout */
+ if (hes_error() == HES_ER_NET)
+ return -1;
+
+ return 1;
+ }
+ else
+ {
+ /*
+ ** If there are multiple matches, just return the
+ ** first one and free the others.
+ **
+ ** XXX These should really be returned; for example,
+ ** XXX it is legal for :maildrop to be multi-valued.
+ */
+
+ for (p = hp[1]; p; p++)
+ free(p);
+
+ info->data = hp[0];
+ info->size = (size_t) strlen(info->data);
+ }
+
+ return 0;
+}
+#endif /* HESIOD */
+
+#else /* not USERDB */
+
+int
+udbexpand(a, sendq, e)
+ ADDRESS *a;
+ ADDRESS **sendq;
+ ENVELOPE *e;
+{
+ return EX_OK;
+}
+
+#endif /* USERDB */
diff --git a/usr.sbin/sendmail/src/useful.h b/usr.sbin/sendmail/src/useful.h
new file mode 100644
index 00000000000..ba33a792db0
--- /dev/null
+++ b/usr.sbin/sendmail/src/useful.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ *
+ * @(#)useful.h 8.2 (Berkeley) 9/24/93
+ */
+
+# include <sys/types.h>
+
+/* support for bool type */
+typedef char bool;
+# define TRUE 1
+# define FALSE 0
+
+# ifndef NULL
+# define NULL 0
+# endif /* NULL */
+
+/* bit hacking */
+# define bitset(bit, word) (((word) & (bit)) != 0)
+
+/* some simple functions */
+# ifndef max
+# define max(a, b) ((a) > (b) ? (a) : (b))
+# define min(a, b) ((a) < (b) ? (a) : (b))
+# endif
+
+/* assertions */
+# ifndef NASSERT
+# define ASSERT(expr, msg, parm)\
+ if (!(expr))\
+ {\
+ fprintf(stderr, "assertion botch: %s:%d: ", __FILE__, __LINE__);\
+ fprintf(stderr, msg, parm);\
+ }
+# else /* NASSERT */
+# define ASSERT(expr, msg, parm)
+# endif /* NASSERT */
+
+/* sccs id's */
+# ifndef lint
+# ifdef __STDC__
+# define SCCSID(arg) static char SccsId[] = #arg;
+# else
+# define SCCSID(arg) static char SccsId[] = "arg";
+# endif
+# else
+# define SCCSID(arg)
+# endif
diff --git a/usr.sbin/sendmail/src/usersmtp.c b/usr.sbin/sendmail/src/usersmtp.c
new file mode 100644
index 00000000000..06acd3f2fc8
--- /dev/null
+++ b/usr.sbin/sendmail/src/usersmtp.c
@@ -0,0 +1,905 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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.
+ */
+
+# include "sendmail.h"
+
+#ifndef lint
+#ifdef SMTP
+static char sccsid[] = "@(#)usersmtp.c 8.18 (Berkeley) 1/24/94 (with SMTP)";
+#else
+static char sccsid[] = "@(#)usersmtp.c 8.18 (Berkeley) 1/24/94 (without SMTP)";
+#endif
+#endif /* not lint */
+
+# include <sysexits.h>
+# include <errno.h>
+
+# ifdef SMTP
+
+/*
+** USERSMTP -- run SMTP protocol from the user end.
+**
+** This protocol is described in RFC821.
+*/
+
+#define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
+#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
+#define SMTPCLOSING 421 /* "Service Shutting Down" */
+
+char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
+char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
+char SmtpError[MAXLINE] = ""; /* save failure error messages */
+int SmtpPid; /* pid of mailer */
+bool SmtpNeedIntro; /* need "while talking" in transcript */
+
+#ifdef __STDC__
+extern smtpmessage(char *f, MAILER *m, MCI *mci, ...);
+#endif
+ /*
+** SMTPINIT -- initialize SMTP.
+**
+** Opens the connection and sends the initial protocol.
+**
+** Parameters:
+** m -- mailer to create connection to.
+** pvp -- pointer to parameter vector to pass to
+** the mailer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** creates connection and sends initial protocol.
+*/
+
+smtpinit(m, mci, e)
+ struct mailer *m;
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ register int r;
+ register char *p;
+ extern void esmtp_check();
+ extern void helo_options();
+
+ if (tTd(18, 1))
+ {
+ printf("smtpinit ");
+ mci_dump(mci, FALSE);
+ }
+
+ /*
+ ** Open the connection to the mailer.
+ */
+
+ SmtpError[0] = '\0';
+ CurHostName = mci->mci_host; /* XXX UGLY XXX */
+ SmtpNeedIntro = TRUE;
+ switch (mci->mci_state)
+ {
+ case MCIS_ACTIVE:
+ /* need to clear old information */
+ smtprset(m, mci, e);
+ /* fall through */
+
+ case MCIS_OPEN:
+ return;
+
+ case MCIS_ERROR:
+ case MCIS_SSD:
+ /* shouldn't happen */
+ smtpquit(m, mci, e);
+ /* fall through */
+
+ case MCIS_CLOSED:
+ syserr("451 smtpinit: state CLOSED");
+ return;
+
+ case MCIS_OPENING:
+ break;
+ }
+
+ mci->mci_state = MCIS_OPENING;
+
+ /*
+ ** Get the greeting message.
+ ** This should appear spontaneously. Give it five minutes to
+ ** happen.
+ */
+
+ SmtpPhase = mci->mci_phase = "client greeting";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check);
+ if (r < 0 || REPLYTYPE(r) == 4)
+ goto tempfail1;
+ if (REPLYTYPE(r) != 2)
+ goto unavailable;
+
+ /*
+ ** Send the HELO command.
+ ** My mother taught me to always introduce myself.
+ */
+
+ if (bitnset(M_ESMTP, m->m_flags))
+ mci->mci_flags |= MCIF_ESMTP;
+
+tryhelo:
+ if (bitset(MCIF_ESMTP, mci->mci_flags))
+ {
+ smtpmessage("EHLO %s", m, mci, MyHostName);
+ SmtpPhase = mci->mci_phase = "client EHLO";
+ }
+ else
+ {
+ smtpmessage("HELO %s", m, mci, MyHostName);
+ SmtpPhase = mci->mci_phase = "client HELO";
+ }
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_helo, helo_options);
+ if (r < 0)
+ goto tempfail1;
+ else if (REPLYTYPE(r) == 5)
+ {
+ if (bitset(MCIF_ESMTP, mci->mci_flags))
+ {
+ /* try old SMTP instead */
+ mci->mci_flags &= ~MCIF_ESMTP;
+ goto tryhelo;
+ }
+ goto unavailable;
+ }
+ else if (REPLYTYPE(r) != 2)
+ goto tempfail1;
+
+ /*
+ ** Check to see if we actually ended up talking to ourself.
+ ** This means we didn't know about an alias or MX, or we managed
+ ** to connect to an echo server.
+ **
+ ** If this code remains at all, "CheckLoopBack" should be
+ ** a mailer flag. This is a MAYBENEXTRELEASE feature.
+ */
+
+ p = strchr(&SmtpReplyBuffer[4], ' ');
+ if (p != NULL)
+ *p = '\0';
+ if (CheckLoopBack && strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
+ {
+ syserr("553 %s config error: mail loops back to myself",
+ MyHostName);
+ mci->mci_exitstat = EX_CONFIG;
+ mci->mci_errno = 0;
+ smtpquit(m, mci, e);
+ return;
+ }
+
+ /*
+ ** If this is expected to be another sendmail, send some internal
+ ** commands.
+ */
+
+ if (bitnset(M_INTERNAL, m->m_flags))
+ {
+ /* tell it to be verbose */
+ smtpmessage("VERB", m, mci);
+ r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
+ if (r < 0)
+ goto tempfail2;
+ }
+
+ if (mci->mci_state != MCIS_CLOSED)
+ {
+ mci->mci_state = MCIS_OPEN;
+ return;
+ }
+
+ /* got a 421 error code during startup */
+
+ tempfail1:
+ tempfail2:
+ mci->mci_exitstat = EX_TEMPFAIL;
+ if (mci->mci_errno == 0)
+ mci->mci_errno = errno;
+ if (mci->mci_state != MCIS_CLOSED)
+ smtpquit(m, mci, e);
+ return;
+
+ unavailable:
+ mci->mci_exitstat = EX_UNAVAILABLE;
+ mci->mci_errno = errno;
+ smtpquit(m, mci, e);
+ return;
+}
+ /*
+** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
+**
+**
+** Parameters:
+** line -- the response line.
+** m -- the mailer.
+** mci -- the mailer connection info.
+** e -- the envelope.
+**
+** Returns:
+** none.
+*/
+
+void
+esmtp_check(line, m, mci, e)
+ char *line;
+ MAILER *m;
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ if (strlen(line) < 5)
+ return;
+ line += 4;
+ if (strncmp(line, "ESMTP ", 6) == 0)
+ mci->mci_flags |= MCIF_ESMTP;
+}
+ /*
+** HELO_OPTIONS -- process the options on a HELO line.
+**
+** Parameters:
+** line -- the response line.
+** m -- the mailer.
+** mci -- the mailer connection info.
+** e -- the envelope.
+**
+** Returns:
+** none.
+*/
+
+void
+helo_options(line, m, mci, e)
+ char *line;
+ MAILER *m;
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ register char *p;
+
+ if (strlen(line) < 5)
+ return;
+ line += 4;
+ p = strchr(line, ' ');
+ if (p != NULL)
+ *p++ = '\0';
+ if (strcasecmp(line, "size") == 0)
+ {
+ mci->mci_flags |= MCIF_SIZE;
+ if (p != NULL)
+ mci->mci_maxsize = atol(p);
+ }
+ else if (strcasecmp(line, "8bitmime") == 0)
+ {
+ mci->mci_flags |= MCIF_8BITMIME;
+ mci->mci_flags &= ~MCIF_7BIT;
+ }
+ else if (strcasecmp(line, "expn") == 0)
+ mci->mci_flags |= MCIF_EXPN;
+}
+ /*
+** SMTPMAILFROM -- send MAIL command
+**
+** Parameters:
+** m -- the mailer.
+** mci -- the mailer connection structure.
+** e -- the envelope (including the sender to specify).
+*/
+
+smtpmailfrom(m, mci, e)
+ struct mailer *m;
+ MCI *mci;
+ ENVELOPE *e;
+{
+ int r;
+ char *bufp;
+ char buf[MAXNAME];
+ char optbuf[MAXLINE];
+
+ if (tTd(18, 2))
+ printf("smtpmailfrom: CurHost=%s\n", CurHostName);
+
+ /* set up appropriate options to include */
+ if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
+ sprintf(optbuf, " SIZE=%ld", e->e_msgsize);
+ else
+ strcpy(optbuf, "");
+
+ /*
+ ** Send the MAIL command.
+ ** Designates the sender.
+ */
+
+ mci->mci_state = MCIS_ACTIVE;
+
+ if (bitset(EF_RESPONSE, e->e_flags) &&
+ !bitnset(M_NO_NULL_FROM, m->m_flags))
+ (void) strcpy(buf, "");
+ else
+ expand("\201g", buf, &buf[sizeof buf - 1], e);
+ if (buf[0] == '<')
+ {
+ /* strip off <angle brackets> (put back on below) */
+ bufp = &buf[strlen(buf) - 1];
+ if (*bufp == '>')
+ *bufp = '\0';
+ bufp = &buf[1];
+ }
+ else
+ bufp = buf;
+ if (e->e_from.q_mailer == LocalMailer ||
+ !bitnset(M_FROMPATH, m->m_flags))
+ {
+ smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
+ }
+ else
+ {
+ smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
+ *bufp == '@' ? ',' : ':', bufp, optbuf);
+ }
+ SmtpPhase = mci->mci_phase = "client MAIL";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_mail, NULL);
+ if (r < 0 || REPLYTYPE(r) == 4)
+ {
+ mci->mci_exitstat = EX_TEMPFAIL;
+ mci->mci_errno = errno;
+ smtpquit(m, mci, e);
+ return EX_TEMPFAIL;
+ }
+ else if (r == 250)
+ {
+ mci->mci_exitstat = EX_OK;
+ return EX_OK;
+ }
+ else if (r == 552)
+ {
+ /* signal service unavailable */
+ mci->mci_exitstat = EX_UNAVAILABLE;
+ smtpquit(m, mci, e);
+ return EX_UNAVAILABLE;
+ }
+
+#ifdef LOG
+ if (LogLevel > 1)
+ {
+ syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s",
+ e->e_id, SmtpReplyBuffer);
+ }
+#endif
+
+ /* protocol error -- close up */
+ smtpquit(m, mci, e);
+ mci->mci_exitstat = EX_PROTOCOL;
+ return EX_PROTOCOL;
+}
+ /*
+** SMTPRCPT -- designate recipient.
+**
+** Parameters:
+** to -- address of recipient.
+** m -- the mailer we are sending to.
+** mci -- the connection info for this transaction.
+** e -- the envelope for this transaction.
+**
+** Returns:
+** exit status corresponding to recipient status.
+**
+** Side Effects:
+** Sends the mail via SMTP.
+*/
+
+smtprcpt(to, m, mci, e)
+ ADDRESS *to;
+ register MAILER *m;
+ MCI *mci;
+ ENVELOPE *e;
+{
+ register int r;
+
+ smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
+
+ SmtpPhase = mci->mci_phase = "client RCPT";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
+ if (r < 0 || REPLYTYPE(r) == 4)
+ return (EX_TEMPFAIL);
+ else if (REPLYTYPE(r) == 2)
+ return (EX_OK);
+ else if (r == 550 || r == 551 || r == 553)
+ return (EX_NOUSER);
+ else if (r == 552 || r == 554)
+ return (EX_UNAVAILABLE);
+
+#ifdef LOG
+ if (LogLevel > 1)
+ {
+ syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s",
+ e->e_id, SmtpReplyBuffer);
+ }
+#endif
+
+ return (EX_PROTOCOL);
+}
+ /*
+** SMTPDATA -- send the data and clean up the transaction.
+**
+** Parameters:
+** m -- mailer being sent to.
+** e -- the envelope for this message.
+**
+** Returns:
+** exit status corresponding to DATA command.
+**
+** Side Effects:
+** none.
+*/
+
+static jmp_buf CtxDataTimeout;
+static int datatimeout();
+
+smtpdata(m, mci, e)
+ struct mailer *m;
+ register MCI *mci;
+ register ENVELOPE *e;
+{
+ register int r;
+ register EVENT *ev;
+ time_t timeout;
+
+ /*
+ ** Send the data.
+ ** First send the command and check that it is ok.
+ ** Then send the data.
+ ** Follow it up with a dot to terminate.
+ ** Finally get the results of the transaction.
+ */
+
+ /* send the command and check ok to proceed */
+ smtpmessage("DATA", m, mci);
+ SmtpPhase = mci->mci_phase = "client DATA 354";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
+ if (r < 0 || REPLYTYPE(r) == 4)
+ {
+ smtpquit(m, mci, e);
+ return (EX_TEMPFAIL);
+ }
+ else if (r == 554)
+ {
+ smtprset(m, mci, e);
+ return (EX_UNAVAILABLE);
+ }
+ else if (r != 354)
+ {
+#ifdef LOG
+ if (LogLevel > 1)
+ {
+ syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s",
+ e->e_id, SmtpReplyBuffer);
+ }
+#endif
+ smtprset(m, mci, e);
+ return (EX_PROTOCOL);
+ }
+
+ /*
+ ** Set timeout around data writes. Make it at least large
+ ** enough for DNS timeouts on all recipients plus some fudge
+ ** factor. The main thing is that it should not be infinite.
+ */
+
+ if (setjmp(CtxDataTimeout) != 0)
+ {
+ mci->mci_errno = errno;
+ mci->mci_exitstat = EX_TEMPFAIL;
+ mci->mci_state = MCIS_ERROR;
+ syserr("451 timeout writing message to %s", mci->mci_host);
+ smtpquit(m, mci, e);
+ return EX_TEMPFAIL;
+ }
+
+ timeout = e->e_msgsize / 16;
+ if (timeout < (time_t) 60)
+ timeout = (time_t) 60;
+ timeout += e->e_nrcpts * 90;
+ ev = setevent(timeout, datatimeout, 0);
+
+ /* now output the actual message */
+ (*e->e_puthdr)(mci, e);
+ putline("\n", mci);
+ (*e->e_putbody)(mci, e, NULL);
+
+ clrevent(ev);
+
+ if (ferror(mci->mci_out))
+ {
+ /* error during processing -- don't send the dot */
+ mci->mci_errno = EIO;
+ mci->mci_exitstat = EX_IOERR;
+ mci->mci_state = MCIS_ERROR;
+ smtpquit(m, mci, e);
+ return EX_IOERR;
+ }
+
+ /* terminate the message */
+ fprintf(mci->mci_out, ".%s", m->m_eol);
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d >>> .\n", getpid());
+ if (Verbose)
+ nmessage(">>> .");
+
+ /* check for the results of the transaction */
+ SmtpPhase = mci->mci_phase = "client DATA 250";
+ setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
+ r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
+ if (r < 0)
+ {
+ smtpquit(m, mci, e);
+ return (EX_TEMPFAIL);
+ }
+ mci->mci_state = MCIS_OPEN;
+ e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
+ if (REPLYTYPE(r) == 4)
+ return (EX_TEMPFAIL);
+ else if (r == 250)
+ return (EX_OK);
+ else if (r == 552 || r == 554)
+ return (EX_UNAVAILABLE);
+#ifdef LOG
+ if (LogLevel > 1)
+ {
+ syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
+ e->e_id, SmtpReplyBuffer);
+ }
+#endif
+ return (EX_PROTOCOL);
+}
+
+
+static int
+datatimeout()
+{
+ longjmp(CtxDataTimeout, 1);
+}
+ /*
+** SMTPQUIT -- close the SMTP connection.
+**
+** Parameters:
+** m -- a pointer to the mailer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sends the final protocol and closes the connection.
+*/
+
+smtpquit(m, mci, e)
+ register MAILER *m;
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ bool oldSuprErrs = SuprErrs;
+
+ /*
+ ** Suppress errors here -- we may be processing a different
+ ** job when we do the quit connection, and we don't want the
+ ** new job to be penalized for something that isn't it's
+ ** problem.
+ */
+
+ SuprErrs = TRUE;
+
+ /* send the quit message if we haven't gotten I/O error */
+ if (mci->mci_state != MCIS_ERROR)
+ {
+ SmtpPhase = "client QUIT";
+ smtpmessage("QUIT", m, mci);
+ (void) reply(m, mci, e, TimeOuts.to_quit, NULL);
+ SuprErrs = oldSuprErrs;
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ SuprErrs = oldSuprErrs;
+ return;
+ }
+ }
+
+ /* now actually close the connection and pick up the zombie */
+ (void) endmailer(mci, e, NULL);
+
+ SuprErrs = oldSuprErrs;
+}
+ /*
+** SMTPRSET -- send a RSET (reset) command
+*/
+
+smtprset(m, mci, e)
+ register MAILER *m;
+ register MCI *mci;
+ ENVELOPE *e;
+{
+ int r;
+
+ SmtpPhase = "client RSET";
+ smtpmessage("RSET", m, mci);
+ r = reply(m, mci, e, TimeOuts.to_rset, NULL);
+ if (r < 0)
+ mci->mci_state = MCIS_ERROR;
+ else if (REPLYTYPE(r) == 2)
+ {
+ mci->mci_state = MCIS_OPEN;
+ return;
+ }
+ smtpquit(m, mci, e);
+}
+ /*
+** SMTPPROBE -- check the connection state
+*/
+
+smtpprobe(mci)
+ register MCI *mci;
+{
+ int r;
+ MAILER *m = mci->mci_mailer;
+ extern ENVELOPE BlankEnvelope;
+ ENVELOPE *e = &BlankEnvelope;
+
+ SmtpPhase = "client probe";
+ smtpmessage("RSET", m, mci);
+ r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
+ if (r < 0 || REPLYTYPE(r) != 2)
+ smtpquit(m, mci, e);
+ return r;
+}
+ /*
+** REPLY -- read arpanet reply
+**
+** Parameters:
+** m -- the mailer we are reading the reply from.
+** mci -- the mailer connection info structure.
+** e -- the current envelope.
+** timeout -- the timeout for reads.
+** pfunc -- processing function for second and subsequent
+** lines of response -- if null, no special
+** processing is done.
+**
+** Returns:
+** reply code it reads.
+**
+** Side Effects:
+** flushes the mail file.
+*/
+
+reply(m, mci, e, timeout, pfunc)
+ MAILER *m;
+ MCI *mci;
+ ENVELOPE *e;
+ time_t timeout;
+ void (*pfunc)();
+{
+ register char *bufp;
+ register int r;
+ bool firstline = TRUE;
+ char junkbuf[MAXLINE];
+
+ if (mci->mci_out != NULL)
+ (void) fflush(mci->mci_out);
+
+ if (tTd(18, 1))
+ printf("reply\n");
+
+ /*
+ ** Read the input line, being careful not to hang.
+ */
+
+ for (bufp = SmtpReplyBuffer;; bufp = junkbuf)
+ {
+ register char *p;
+ extern time_t curtime();
+
+ /* actually do the read */
+ if (e->e_xfp != NULL)
+ (void) fflush(e->e_xfp); /* for debugging */
+
+ /* if we are in the process of closing just give the code */
+ if (mci->mci_state == MCIS_CLOSED)
+ return (SMTPCLOSING);
+
+ if (mci->mci_out != NULL)
+ fflush(mci->mci_out);
+
+ /* get the line from the other side */
+ p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
+ mci->mci_lastuse = curtime();
+
+ if (p == NULL)
+ {
+ bool oldholderrs;
+ extern char MsgBuf[]; /* err.c */
+
+ /* if the remote end closed early, fake an error */
+ if (errno == 0)
+# ifdef ECONNRESET
+ errno = ECONNRESET;
+# else /* ECONNRESET */
+ errno = EPIPE;
+# endif /* ECONNRESET */
+
+ mci->mci_errno = errno;
+ mci->mci_exitstat = EX_TEMPFAIL;
+ oldholderrs = HoldErrs;
+ HoldErrs = TRUE;
+ usrerr("451 reply: read error from %s", mci->mci_host);
+
+ /* if debugging, pause so we can see state */
+ if (tTd(18, 100))
+ pause();
+ mci->mci_state = MCIS_ERROR;
+ smtpquit(m, mci, e);
+#ifdef XDEBUG
+ {
+ char wbuf[MAXLINE];
+ char *p = wbuf;
+ if (e->e_to != NULL)
+ {
+ sprintf(p, "%s... ", e->e_to);
+ p += strlen(p);
+ }
+ sprintf(p, "reply(%s) during %s",
+ mci->mci_host, SmtpPhase);
+ checkfd012(wbuf);
+ }
+#endif
+ HoldErrs = oldholderrs;
+ return (-1);
+ }
+ fixcrlf(bufp, TRUE);
+
+ /* EHLO failure is not a real error */
+ if (e->e_xfp != NULL && (bufp[0] == '4' ||
+ (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
+ {
+ /* serious error -- log the previous command */
+ if (SmtpNeedIntro)
+ {
+ /* inform user who we are chatting with */
+ fprintf(CurEnv->e_xfp,
+ "... while talking to %s:\n",
+ CurHostName);
+ SmtpNeedIntro = FALSE;
+ }
+ if (SmtpMsgBuffer[0] != '\0')
+ fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
+ SmtpMsgBuffer[0] = '\0';
+
+ /* now log the message as from the other side */
+ fprintf(e->e_xfp, "<<< %s\n", bufp);
+ }
+
+ /* display the input for verbose mode */
+ if (Verbose)
+ nmessage("050 %s", bufp);
+
+ /* process the line */
+ if (pfunc != NULL && !firstline)
+ (*pfunc)(bufp, m, mci, e);
+
+ firstline = FALSE;
+
+ /* if continuation is required, we can go on */
+ if (bufp[3] == '-')
+ continue;
+
+ /* ignore improperly formated input */
+ if (!(isascii(bufp[0]) && isdigit(bufp[0])))
+ continue;
+
+ /* decode the reply code */
+ r = atoi(bufp);
+
+ /* extra semantics: 0xx codes are "informational" */
+ if (r >= 100)
+ break;
+ }
+
+ /*
+ ** Now look at SmtpReplyBuffer -- only care about the first
+ ** line of the response from here on out.
+ */
+
+ /* save temporary failure messages for posterity */
+ if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
+ (void) strcpy(SmtpError, SmtpReplyBuffer);
+
+ /* reply code 421 is "Service Shutting Down" */
+ if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
+ {
+ /* send the quit protocol */
+ mci->mci_state = MCIS_SSD;
+ smtpquit(m, mci, e);
+ }
+
+ return (r);
+}
+ /*
+** SMTPMESSAGE -- send message to server
+**
+** Parameters:
+** f -- format
+** m -- the mailer to control formatting.
+** a, b, c -- parameters
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** writes message to mci->mci_out.
+*/
+
+/*VARARGS1*/
+#ifdef __STDC__
+smtpmessage(char *f, MAILER *m, MCI *mci, ...)
+#else
+smtpmessage(f, m, mci, va_alist)
+ char *f;
+ MAILER *m;
+ MCI *mci;
+ va_dcl
+#endif
+{
+ VA_LOCAL_DECL
+
+ VA_START(mci);
+ (void) vsprintf(SmtpMsgBuffer, f, ap);
+ VA_END;
+
+ if (tTd(18, 1) || Verbose)
+ nmessage(">>> %s", SmtpMsgBuffer);
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer);
+ if (mci->mci_out != NULL)
+ {
+ fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
+ m == NULL ? "\r\n" : m->m_eol);
+ }
+ else if (tTd(18, 1))
+ {
+ printf("smtpmessage: NULL mci_out\n");
+ }
+}
+
+# endif /* SMTP */
diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c
new file mode 100644
index 00000000000..3f6e1828855
--- /dev/null
+++ b/usr.sbin/sendmail/src/util.c
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)util.c 8.39.1.5 (Berkeley) 3/5/95";
+#endif /* not lint */
+
+# include "sendmail.h"
+# include <sysexits.h>
+ /*
+** STRIPQUOTES -- Strip quotes & quote bits from a string.
+**
+** Runs through a string and strips off unquoted quote
+** characters and quote bits. This is done in place.
+**
+** Parameters:
+** s -- the string to strip.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+**
+** Called By:
+** deliver
+*/
+
+stripquotes(s)
+ char *s;
+{
+ register char *p;
+ register char *q;
+ register char c;
+
+ if (s == NULL)
+ return;
+
+ p = q = s;
+ do
+ {
+ c = *p++;
+ if (c == '\\')
+ c = *p++;
+ else if (c == '"')
+ continue;
+ *q++ = c;
+ } while (c != '\0');
+}
+ /*
+** XALLOC -- Allocate memory and bitch wildly on failure.
+**
+** THIS IS A CLUDGE. This should be made to give a proper
+** error -- but after all, what can we do?
+**
+** Parameters:
+** sz -- size of area to allocate.
+**
+** Returns:
+** pointer to data region.
+**
+** Side Effects:
+** Memory is allocated.
+*/
+
+char *
+xalloc(sz)
+ register int sz;
+{
+ register char *p;
+
+ /* some systems can't handle size zero mallocs */
+ if (sz <= 0)
+ sz = 1;
+
+ p = malloc((unsigned) sz);
+ if (p == NULL)
+ {
+ syserr("Out of memory!!");
+ abort();
+ /* exit(EX_UNAVAILABLE); */
+ }
+ return (p);
+}
+ /*
+** COPYPLIST -- copy list of pointers.
+**
+** This routine is the equivalent of newstr for lists of
+** pointers.
+**
+** Parameters:
+** list -- list of pointers to copy.
+** Must be NULL terminated.
+** copycont -- if TRUE, copy the contents of the vector
+** (which must be a string) also.
+**
+** Returns:
+** a copy of 'list'.
+**
+** Side Effects:
+** none.
+*/
+
+char **
+copyplist(list, copycont)
+ char **list;
+ bool copycont;
+{
+ register char **vp;
+ register char **newvp;
+
+ for (vp = list; *vp != NULL; vp++)
+ continue;
+
+ vp++;
+
+ newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
+ bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
+
+ if (copycont)
+ {
+ for (vp = newvp; *vp != NULL; vp++)
+ *vp = newstr(*vp);
+ }
+
+ return (newvp);
+}
+ /*
+** COPYQUEUE -- copy address queue.
+**
+** This routine is the equivalent of newstr for address queues
+** addresses marked with QDONTSEND aren't copied
+**
+** Parameters:
+** addr -- list of address structures to copy.
+**
+** Returns:
+** a copy of 'addr'.
+**
+** Side Effects:
+** none.
+*/
+
+ADDRESS *
+copyqueue(addr)
+ ADDRESS *addr;
+{
+ register ADDRESS *newaddr;
+ ADDRESS *ret;
+ register ADDRESS **tail = &ret;
+
+ while (addr != NULL)
+ {
+ if (!bitset(QDONTSEND, addr->q_flags))
+ {
+ newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
+ STRUCTCOPY(*addr, *newaddr);
+ *tail = newaddr;
+ tail = &newaddr->q_next;
+ }
+ addr = addr->q_next;
+ }
+ *tail = NULL;
+
+ return ret;
+}
+ /*
+** PRINTAV -- print argument vector.
+**
+** Parameters:
+** av -- argument vector.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** prints av.
+*/
+
+printav(av)
+ register char **av;
+{
+ while (*av != NULL)
+ {
+ if (tTd(0, 44))
+ printf("\n\t%08x=", *av);
+ else
+ (void) putchar(' ');
+ xputs(*av++);
+ }
+ (void) putchar('\n');
+}
+ /*
+** LOWER -- turn letter into lower case.
+**
+** Parameters:
+** c -- character to turn into lower case.
+**
+** Returns:
+** c, in lower case.
+**
+** Side Effects:
+** none.
+*/
+
+char
+lower(c)
+ register char c;
+{
+ return((isascii(c) && isupper(c)) ? tolower(c) : c);
+}
+ /*
+** XPUTS -- put string doing control escapes.
+**
+** Parameters:
+** s -- string to put.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** output to stdout
+*/
+
+xputs(s)
+ register char *s;
+{
+ register int c;
+ register struct metamac *mp;
+ extern struct metamac MetaMacros[];
+
+ if (s == NULL)
+ {
+ printf("<null>");
+ return;
+ }
+ while ((c = (*s++ & 0377)) != '\0')
+ {
+ if (!isascii(c))
+ {
+ if (c == MATCHREPL || c == MACROEXPAND)
+ {
+ putchar('$');
+ continue;
+ }
+ for (mp = MetaMacros; mp->metaname != '\0'; mp++)
+ {
+ if ((mp->metaval & 0377) == c)
+ {
+ printf("$%c", mp->metaname);
+ break;
+ }
+ }
+ if (mp->metaname != '\0')
+ continue;
+ (void) putchar('\\');
+ c &= 0177;
+ }
+ if (isprint(c))
+ {
+ putchar(c);
+ continue;
+ }
+
+ /* wasn't a meta-macro -- find another way to print it */
+ switch (c)
+ {
+ case '\0':
+ continue;
+
+ case '\n':
+ c = 'n';
+ break;
+
+ case '\r':
+ c = 'r';
+ break;
+
+ case '\t':
+ c = 't';
+ break;
+
+ default:
+ (void) putchar('^');
+ (void) putchar(c ^ 0100);
+ continue;
+ }
+ }
+ (void) fflush(stdout);
+}
+ /*
+** MAKELOWER -- Translate a line into lower case
+**
+** Parameters:
+** p -- the string to translate. If NULL, return is
+** immediate.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** String pointed to by p is translated to lower case.
+**
+** Called By:
+** parse
+*/
+
+makelower(p)
+ register char *p;
+{
+ register char c;
+
+ if (p == NULL)
+ return;
+ for (; (c = *p) != '\0'; p++)
+ if (isascii(c) && isupper(c))
+ *p = tolower(c);
+}
+ /*
+** BUILDFNAME -- build full name from gecos style entry.
+**
+** This routine interprets the strange entry that would appear
+** in the GECOS field of the password file.
+**
+** Parameters:
+** p -- name to build.
+** login -- the login name of this user (for &).
+** buf -- place to put the result.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+buildfname(gecos, login, buf)
+ register char *gecos;
+ char *login;
+ char *buf;
+{
+ register char *p;
+ register char *bp = buf;
+ int l;
+
+ if (*gecos == '*')
+ gecos++;
+
+ /* find length of final string */
+ l = 0;
+ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+ {
+ if (*p == '&')
+ l += strlen(login);
+ else
+ l++;
+ }
+
+ /* now fill in buf */
+ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+ {
+ if (*p == '&')
+ {
+ (void) strcpy(bp, login);
+ *bp = toupper(*bp);
+ while (*bp != '\0')
+ bp++;
+ }
+ else
+ *bp++ = *p;
+ }
+ *bp = '\0';
+}
+ /*
+** SAFEFILE -- return true if a file exists and is safe for a user.
+**
+** Parameters:
+** fn -- filename to check.
+** uid -- user id to compare against.
+** gid -- group id to compare against.
+** uname -- user name to compare against (used for group
+** sets).
+** flags -- modifiers:
+** SFF_MUSTOWN -- "uid" must own this file.
+** SFF_NOSLINK -- file cannot be a symbolic link.
+** mode -- mode bits that must match.
+**
+** Returns:
+** 0 if fn exists, is owned by uid, and matches mode.
+** An errno otherwise. The actual errno is cleared.
+**
+** Side Effects:
+** none.
+*/
+
+#include <grp.h>
+
+#ifndef S_IXOTH
+# define S_IXOTH (S_IEXEC >> 6)
+#endif
+
+#ifndef S_IXGRP
+# define S_IXGRP (S_IEXEC >> 3)
+#endif
+
+#ifndef S_IXUSR
+# define S_IXUSR (S_IEXEC)
+#endif
+
+int
+safefile(fn, uid, gid, uname, flags, mode)
+ char *fn;
+ uid_t uid;
+ gid_t gid;
+ char *uname;
+ int flags;
+ int mode;
+{
+ register char *p;
+ register struct group *gr = NULL;
+ struct stat stbuf;
+
+ if (tTd(54, 4))
+ printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n",
+ fn, uid, gid, flags, mode);
+ errno = 0;
+
+ for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/')
+ {
+ *p = '\0';
+ if (stat(fn, &stbuf) < 0)
+ break;
+ if (uid == 0 && !bitset(SFF_ROOTOK, flags))
+ {
+ if (bitset(S_IXOTH, stbuf.st_mode))
+ continue;
+ break;
+ }
+ if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode))
+ continue;
+ if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode))
+ continue;
+#ifndef NO_GROUP_SET
+ if (uname != NULL &&
+ ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
+ (gr = getgrgid(stbuf.st_gid)) != NULL))
+ {
+ register char **gp;
+
+ for (gp = gr->gr_mem; *gp != NULL; gp++)
+ if (strcmp(*gp, uname) == 0)
+ break;
+ if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode))
+ continue;
+ }
+#endif
+ if (!bitset(S_IXOTH, stbuf.st_mode))
+ break;
+ }
+ if (p != NULL)
+ {
+ int ret = errno;
+
+ if (ret == 0)
+ ret = EACCES;
+ if (tTd(54, 4))
+ printf("\t[dir %s] %s\n", fn, errstring(ret));
+ *p = '/';
+ return ret;
+ }
+
+#ifdef HASLSTAT
+ if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf)
+ : stat(fn, &stbuf)) < 0)
+#else
+ if (stat(fn, &stbuf) < 0)
+#endif
+ {
+ int ret = errno;
+
+ if (tTd(54, 4))
+ printf("\t%s\n", errstring(ret));
+
+ errno = 0;
+ return ret;
+ }
+
+#ifdef S_ISLNK
+ if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode))
+ {
+ if (tTd(54, 4))
+ printf("\t[slink mode %o]\tEPERM\n", stbuf.st_mode);
+ return EPERM;
+ }
+#endif
+
+ if (uid == 0 && !bitset(SFF_ROOTOK, flags))
+ mode >>= 6;
+ else if (stbuf.st_uid != uid)
+ {
+ mode >>= 3;
+ if (stbuf.st_gid == gid)
+ ;
+#ifndef NO_GROUP_SET
+ else if (uname != NULL &&
+ ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
+ (gr = getgrgid(stbuf.st_gid)) != NULL))
+ {
+ register char **gp;
+
+ for (gp = gr->gr_mem; *gp != NULL; gp++)
+ if (strcmp(*gp, uname) == 0)
+ break;
+ if (*gp == NULL)
+ mode >>= 3;
+ }
+#endif
+ else
+ mode >>= 3;
+ }
+ if (tTd(54, 4))
+ printf("\t[uid %d, stat %o, mode %o] ",
+ stbuf.st_uid, stbuf.st_mode, mode);
+ if ((stbuf.st_uid == uid || stbuf.st_uid == 0 ||
+ !bitset(SFF_MUSTOWN, flags)) &&
+ (stbuf.st_mode & mode) == mode)
+ {
+ if (tTd(54, 4))
+ printf("\tOK\n");
+ return 0;
+ }
+ if (tTd(54, 4))
+ printf("\tEACCES\n");
+ return EACCES;
+}
+ /*
+** FIXCRLF -- fix <CR><LF> in line.
+**
+** Looks for the <CR><LF> combination and turns it into the
+** UNIX canonical <NL> character. It only takes one line,
+** i.e., it is assumed that the first <NL> found is the end
+** of the line.
+**
+** Parameters:
+** line -- the line to fix.
+** stripnl -- if true, strip the newline also.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** line is changed in place.
+*/
+
+fixcrlf(line, stripnl)
+ char *line;
+ bool stripnl;
+{
+ register char *p;
+
+ p = strchr(line, '\n');
+ if (p == NULL)
+ return;
+ if (p > line && p[-1] == '\r')
+ p--;
+ if (!stripnl)
+ *p++ = '\n';
+ *p = '\0';
+}
+ /*
+** DFOPEN -- determined file open
+**
+** This routine has the semantics of fopen, except that it will
+** keep trying a few times to make this happen. The idea is that
+** on very loaded systems, we may run out of resources (inodes,
+** whatever), so this tries to get around it.
+*/
+
+#ifndef O_ACCMODE
+# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
+#endif
+
+struct omodes
+{
+ int mask;
+ int mode;
+ char *farg;
+} OpenModes[] =
+{
+ O_ACCMODE, O_RDONLY, "r",
+ O_ACCMODE|O_APPEND, O_WRONLY, "w",
+ O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a",
+ O_TRUNC, 0, "w+",
+ O_APPEND, O_APPEND, "a+",
+ 0, 0, "r+",
+};
+
+FILE *
+dfopen(filename, omode, cmode)
+ char *filename;
+ int omode;
+ int cmode;
+{
+ register int tries;
+ int fd;
+ register struct omodes *om;
+ struct stat st;
+
+ for (om = OpenModes; om->mask != 0; om++)
+ if ((omode & om->mask) == om->mode)
+ break;
+
+ for (tries = 0; tries < 10; tries++)
+ {
+ sleep((unsigned) (10 * tries));
+ errno = 0;
+ fd = open(filename, omode, cmode);
+ if (fd >= 0)
+ break;
+ switch (errno)
+ {
+ case ENFILE: /* system file table full */
+ case EINTR: /* interrupted syscall */
+#ifdef ETXTBSY
+ case ETXTBSY: /* Apollo: net file locked */
+#endif
+ continue;
+ }
+ break;
+ }
+ if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode))
+ {
+ int locktype;
+
+ /* lock the file to avoid accidental conflicts */
+ if ((omode & O_ACCMODE) != O_RDONLY)
+ locktype = LOCK_EX;
+ else
+ locktype = LOCK_SH;
+ (void) lockfile(fd, filename, NULL, locktype);
+ errno = 0;
+ }
+ if (fd < 0)
+ return NULL;
+ else
+ return fdopen(fd, om->farg);
+}
+ /*
+** PUTLINE -- put a line like fputs obeying SMTP conventions
+**
+** This routine always guarantees outputing a newline (or CRLF,
+** as appropriate) at the end of the string.
+**
+** Parameters:
+** l -- line to put.
+** mci -- the mailer connection information.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** output of l to fp.
+*/
+
+putline(l, mci)
+ register char *l;
+ register MCI *mci;
+{
+ register char *p;
+ register char svchar;
+ int slop = 0;
+
+ /* strip out 0200 bits -- these can look like TELNET protocol */
+ if (bitset(MCIF_7BIT, mci->mci_flags))
+ {
+ for (p = l; (svchar = *p) != '\0'; ++p)
+ if (bitset(0200, svchar))
+ *p = svchar &~ 0200;
+ }
+
+ do
+ {
+ /* find the end of the line */
+ p = strchr(l, '\n');
+ if (p == NULL)
+ p = &l[strlen(l)];
+
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d >>> ", getpid());
+
+ /* check for line overflow */
+ while (mci->mci_mailer->m_linelimit > 0 &&
+ (p - l + slop) > mci->mci_mailer->m_linelimit)
+ {
+ register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
+
+ svchar = *q;
+ *q = '\0';
+ if (l[0] == '.' && slop == 0 &&
+ bitnset(M_XDOT, mci->mci_mailer->m_flags))
+ {
+ (void) putc('.', mci->mci_out);
+ if (TrafficLogFile != NULL)
+ (void) putc('.', TrafficLogFile);
+ }
+ fputs(l, mci->mci_out);
+ (void) putc('!', mci->mci_out);
+ fputs(mci->mci_mailer->m_eol, mci->mci_out);
+ (void) putc(' ', mci->mci_out);
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%s!\n%05d >>> ",
+ l, getpid());
+ *q = svchar;
+ l = q;
+ slop = 1;
+ }
+
+ /* output last part */
+ if (l[0] == '.' && slop == 0 &&
+ bitnset(M_XDOT, mci->mci_mailer->m_flags))
+ {
+ (void) putc('.', mci->mci_out);
+ if (TrafficLogFile != NULL)
+ (void) putc('.', TrafficLogFile);
+ }
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%.*s\n", p - l, l);
+ for ( ; l < p; ++l)
+ (void) putc(*l, mci->mci_out);
+ fputs(mci->mci_mailer->m_eol, mci->mci_out);
+ if (*l == '\n')
+ ++l;
+ } while (l[0] != '\0');
+}
+ /*
+** XUNLINK -- unlink a file, doing logging as appropriate.
+**
+** Parameters:
+** f -- name of file to unlink.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** f is unlinked.
+*/
+
+xunlink(f)
+ char *f;
+{
+ register int i;
+
+# ifdef LOG
+ if (LogLevel > 98)
+ syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f);
+# endif /* LOG */
+
+ i = unlink(f);
+# ifdef LOG
+ if (i < 0 && LogLevel > 97)
+ syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
+# endif /* LOG */
+}
+ /*
+** XFCLOSE -- close a file, doing logging as appropriate.
+**
+** Parameters:
+** fp -- file pointer for the file to close
+** a, b -- miscellaneous crud to print for debugging
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** fp is closed.
+*/
+
+xfclose(fp, a, b)
+ FILE *fp;
+ char *a, *b;
+{
+ if (tTd(53, 99))
+ printf("xfclose(%x) %s %s\n", fp, a, b);
+#ifdef XDEBUG
+ if (fileno(fp) == 1)
+ syserr("xfclose(%s %s): fd = 1", a, b);
+#endif
+ if (fclose(fp) < 0 && tTd(53, 99))
+ printf("xfclose FAILURE: %s\n", errstring(errno));
+}
+ /*
+** SFGETS -- "safe" fgets -- times out and ignores random interrupts.
+**
+** Parameters:
+** buf -- place to put the input line.
+** siz -- size of buf.
+** fp -- file to read from.
+** timeout -- the timeout before error occurs.
+** during -- what we are trying to read (for error messages).
+**
+** Returns:
+** NULL on error (including timeout). This will also leave
+** buf containing a null string.
+** buf otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+static jmp_buf CtxReadTimeout;
+static int readtimeout();
+static EVENT *GlobalTimeout = NULL;
+static bool EnableTimeout = FALSE;
+static int ReadProgress;
+
+char *
+sfgets(buf, siz, fp, timeout, during)
+ char *buf;
+ int siz;
+ FILE *fp;
+ time_t timeout;
+ char *during;
+{
+ register EVENT *ev = NULL;
+ register char *p;
+
+ if (fp == NULL)
+ {
+ buf[0] = '\0';
+ return NULL;
+ }
+
+ /* set the timeout */
+ if (timeout != 0)
+ {
+ if (setjmp(CtxReadTimeout) != 0)
+ {
+# ifdef LOG
+ syslog(LOG_NOTICE,
+ "timeout waiting for input from %s during %s\n",
+ CurHostName? CurHostName: "local", during);
+# endif
+ errno = 0;
+ usrerr("451 timeout waiting for input during %s",
+ during);
+ buf[0] = '\0';
+#ifdef XDEBUG
+ checkfd012(during);
+#endif
+ return (NULL);
+ }
+ if (GlobalTimeout == NULL)
+ ev = setevent(timeout, readtimeout, 0);
+ else
+ EnableTimeout = TRUE;
+ }
+
+ /* try to read */
+ p = NULL;
+ while (!feof(fp) && !ferror(fp))
+ {
+ errno = 0;
+ p = fgets(buf, siz, fp);
+ if (p != NULL || errno != EINTR)
+ break;
+ clearerr(fp);
+ }
+
+ /* clear the event if it has not sprung */
+ if (GlobalTimeout == NULL)
+ clrevent(ev);
+ else
+ EnableTimeout = FALSE;
+
+ /* clean up the books and exit */
+ LineNumber++;
+ if (p == NULL)
+ {
+ buf[0] = '\0';
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid());
+ return (NULL);
+ }
+ if (TrafficLogFile != NULL)
+ fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf);
+ if (SevenBit)
+ for (p = buf; *p != '\0'; p++)
+ *p &= ~0200;
+ return (buf);
+}
+
+void
+sfgetset(timeout)
+ time_t timeout;
+{
+ /* cancel pending timer */
+ if (GlobalTimeout != NULL)
+ {
+ clrevent(GlobalTimeout);
+ GlobalTimeout = NULL;
+ }
+
+ /* schedule fresh one if so requested */
+ if (timeout != 0)
+ {
+ ReadProgress = LineNumber;
+ GlobalTimeout = setevent(timeout, readtimeout, timeout);
+ }
+}
+
+static
+readtimeout(timeout)
+ time_t timeout;
+{
+ /* terminate if ordinary timeout */
+ if (GlobalTimeout == NULL)
+ longjmp(CtxReadTimeout, 1);
+
+ /* terminate if no progress was made -- reset state */
+ if (EnableTimeout && (LineNumber <= ReadProgress))
+ {
+ EnableTimeout = FALSE;
+ GlobalTimeout = NULL;
+ longjmp(CtxReadTimeout, 2);
+ }
+
+ /* schedule a new timeout */
+ GlobalTimeout = NULL;
+ sfgetset(timeout);
+}
+ /*
+** FGETFOLDED -- like fgets, but know about folded lines.
+**
+** Parameters:
+** buf -- place to put result.
+** n -- bytes available.
+** f -- file to read from.
+**
+** Returns:
+** input line(s) on success, NULL on error or EOF.
+** This will normally be buf -- unless the line is too
+** long, when it will be xalloc()ed.
+**
+** Side Effects:
+** buf gets lines from f, with continuation lines (lines
+** with leading white space) appended. CRLF's are mapped
+** into single newlines. Any trailing NL is stripped.
+*/
+
+char *
+fgetfolded(buf, n, f)
+ char *buf;
+ register int n;
+ FILE *f;
+{
+ register char *p = buf;
+ char *bp = buf;
+ register int i;
+
+ n--;
+ while ((i = getc(f)) != EOF)
+ {
+ if (i == '\r')
+ {
+ i = getc(f);
+ if (i != '\n')
+ {
+ if (i != EOF)
+ (void) ungetc(i, f);
+ i = '\r';
+ }
+ }
+ if (--n <= 0)
+ {
+ /* allocate new space */
+ char *nbp;
+ int nn;
+
+ nn = (p - bp);
+ if (nn < MEMCHUNKSIZE)
+ nn *= 2;
+ else
+ nn += MEMCHUNKSIZE;
+ nbp = xalloc(nn);
+ bcopy(bp, nbp, p - bp);
+ p = &nbp[p - bp];
+ if (bp != buf)
+ free(bp);
+ bp = nbp;
+ n = nn - (p - bp);
+ }
+ *p++ = i;
+ if (i == '\n')
+ {
+ LineNumber++;
+ i = getc(f);
+ if (i != EOF)
+ (void) ungetc(i, f);
+ if (i != ' ' && i != '\t')
+ break;
+ }
+ }
+ if (p == bp)
+ return (NULL);
+ *--p = '\0';
+ return (bp);
+}
+ /*
+** CURTIME -- return current time.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** the current time.
+**
+** Side Effects:
+** none.
+*/
+
+time_t
+curtime()
+{
+ auto time_t t;
+
+ (void) time(&t);
+ return (t);
+}
+ /*
+** ATOBOOL -- convert a string representation to boolean.
+**
+** Defaults to "TRUE"
+**
+** Parameters:
+** s -- string to convert. Takes "tTyY" as true,
+** others as false.
+**
+** Returns:
+** A boolean representation of the string.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+atobool(s)
+ register char *s;
+{
+ if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
+ return (TRUE);
+ return (FALSE);
+}
+ /*
+** ATOOCT -- convert a string representation to octal.
+**
+** Parameters:
+** s -- string to convert.
+**
+** Returns:
+** An integer representing the string interpreted as an
+** octal number.
+**
+** Side Effects:
+** none.
+*/
+
+atooct(s)
+ register char *s;
+{
+ register int i = 0;
+
+ while (*s >= '0' && *s <= '7')
+ i = (i << 3) | (*s++ - '0');
+ return (i);
+}
+ /*
+** WAITFOR -- wait for a particular process id.
+**
+** Parameters:
+** pid -- process id to wait for.
+**
+** Returns:
+** status of pid.
+** -1 if pid never shows up.
+**
+** Side Effects:
+** none.
+*/
+
+int
+waitfor(pid)
+ int pid;
+{
+#ifdef WAITUNION
+ union wait st;
+#else
+ auto int st;
+#endif
+ int i;
+
+ do
+ {
+ errno = 0;
+ i = wait(&st);
+ } while ((i >= 0 || errno == EINTR) && i != pid);
+ if (i < 0)
+ return -1;
+#ifdef WAITUNION
+ return st.w_status;
+#else
+ return st;
+#endif
+}
+ /*
+** BITINTERSECT -- tell if two bitmaps intersect
+**
+** Parameters:
+** a, b -- the bitmaps in question
+**
+** Returns:
+** TRUE if they have a non-null intersection
+** FALSE otherwise
+**
+** Side Effects:
+** none.
+*/
+
+bool
+bitintersect(a, b)
+ BITMAP a;
+ BITMAP b;
+{
+ int i;
+
+ for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
+ if ((a[i] & b[i]) != 0)
+ return (TRUE);
+ return (FALSE);
+}
+ /*
+** BITZEROP -- tell if a bitmap is all zero
+**
+** Parameters:
+** map -- the bit map to check
+**
+** Returns:
+** TRUE if map is all zero.
+** FALSE if there are any bits set in map.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+bitzerop(map)
+ BITMAP map;
+{
+ int i;
+
+ for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
+ if (map[i] != 0)
+ return (FALSE);
+ return (TRUE);
+}
+ /*
+** STRCONTAINEDIN -- tell if one string is contained in another
+**
+** Parameters:
+** a -- possible substring.
+** b -- possible superstring.
+**
+** Returns:
+** TRUE if a is contained in b.
+** FALSE otherwise.
+*/
+
+bool
+strcontainedin(a, b)
+ register char *a;
+ register char *b;
+{
+ int la;
+ int lb;
+ int c;
+
+ la = strlen(a);
+ lb = strlen(b);
+ c = *a;
+ if (isascii(c) && isupper(c))
+ c = tolower(c);
+ for (; lb-- >= la; b++)
+ {
+ if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
+ continue;
+ if (strncasecmp(a, b, la) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+ /*
+** CHECKFD012 -- check low numbered file descriptors
+**
+** File descriptors 0, 1, and 2 should be open at all times.
+** This routine verifies that, and fixes it if not true.
+**
+** Parameters:
+** where -- a tag printed if the assertion failed
+**
+** Returns:
+** none
+*/
+
+checkfd012(where)
+ char *where;
+{
+#ifdef XDEBUG
+ register int i;
+ struct stat stbuf;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP)
+ {
+ /* oops.... */
+ int fd;
+
+ syserr("%s: fd %d not open", where, i);
+ fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666);
+ if (fd != i)
+ {
+ (void) dup2(fd, i);
+ (void) close(fd);
+ }
+ }
+ }
+#endif /* XDEBUG */
+}
+ /*
+** PRINTOPENFDS -- print the open file descriptors (for debugging)
+**
+** Parameters:
+** logit -- if set, send output to syslog; otherwise
+** print for debugging.
+**
+** Returns:
+** none.
+*/
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+printopenfds(logit)
+ bool logit;
+{
+ register int fd;
+ extern int DtableSize;
+
+ for (fd = 0; fd < DtableSize; fd++)
+ dumpfd(fd, FALSE, logit);
+}
+ /*
+** DUMPFD -- dump a file descriptor
+**
+** Parameters:
+** fd -- the file descriptor to dump.
+** printclosed -- if set, print a notification even if
+** it is closed; otherwise print nothing.
+** logit -- if set, send output to syslog instead of stdout.
+*/
+
+dumpfd(fd, printclosed, logit)
+ int fd;
+ bool printclosed;
+ bool logit;
+{
+ register struct hostent *hp;
+ register char *p;
+ char *fmtstr;
+ struct sockaddr_in sin;
+ auto int slen;
+ struct stat st;
+ char buf[200];
+
+ p = buf;
+ sprintf(p, "%3d: ", fd);
+ p += strlen(p);
+
+ if (fstat(fd, &st) < 0)
+ {
+ if (printclosed || errno != EBADF)
+ {
+ sprintf(p, "CANNOT STAT (%s)", errstring(errno));
+ goto printit;
+ }
+ return;
+ }
+
+ slen = fcntl(fd, F_GETFL, NULL);
+ if (slen != -1)
+ {
+ sprintf(p, "fl=0x%x, ", slen);
+ p += strlen(p);
+ }
+
+ sprintf(p, "mode=%o: ", st.st_mode);
+ p += strlen(p);
+ switch (st.st_mode & S_IFMT)
+ {
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ sprintf(p, "SOCK ");
+ p += strlen(p);
+ slen = sizeof sin;
+ if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0)
+ sprintf(p, "(badsock)");
+ else
+ {
+ hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
+ sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
+ : hp->h_name, ntohs(sin.sin_port));
+ }
+ p += strlen(p);
+ sprintf(p, "->");
+ p += strlen(p);
+ slen = sizeof sin;
+ if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0)
+ sprintf(p, "(badsock)");
+ else
+ {
+ hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
+ sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
+ : hp->h_name, ntohs(sin.sin_port));
+ }
+ break;
+#endif
+
+ case S_IFCHR:
+ sprintf(p, "CHR: ");
+ p += strlen(p);
+ goto defprint;
+
+ case S_IFBLK:
+ sprintf(p, "BLK: ");
+ p += strlen(p);
+ goto defprint;
+
+#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
+ case S_IFIFO:
+ sprintf(p, "FIFO: ");
+ p += strlen(p);
+ goto defprint;
+#endif
+
+#ifdef S_IFDIR
+ case S_IFDIR:
+ sprintf(p, "DIR: ");
+ p += strlen(p);
+ goto defprint;
+#endif
+
+#ifdef S_IFLNK
+ case S_IFLNK:
+ sprintf(p, "LNK: ");
+ p += strlen(p);
+ goto defprint;
+#endif
+
+ default:
+defprint:
+ if (sizeof st.st_size > sizeof (long))
+ fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%qd";
+ else
+ fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld";
+ sprintf(p, fmtstr,
+ major(st.st_dev), minor(st.st_dev), st.st_ino,
+ st.st_nlink, st.st_uid, st.st_gid, st.st_size);
+ break;
+ }
+
+printit:
+#ifdef LOG
+ if (logit)
+ syslog(LOG_DEBUG, "%s", buf);
+ else
+#endif
+ printf("%s\n", buf);
+}
+ /*
+** SHORTENSTRING -- return short version of a string
+**
+** If the string is already short, just return it. If it is too
+** long, return the head and tail of the string.
+**
+** Parameters:
+** s -- the string to shorten.
+** m -- the max length of the string.
+**
+** Returns:
+** Either s or a short version of s.
+*/
+
+#ifndef MAXSHORTSTR
+# define MAXSHORTSTR 203
+#endif
+
+char *
+shortenstring(s, m)
+ register char *s;
+ int m;
+{
+ int l;
+ static char buf[MAXSHORTSTR + 1];
+
+ l = strlen(s);
+ if (l < m)
+ return s;
+ if (m > MAXSHORTSTR)
+ m = MAXSHORTSTR;
+ else if (m < 10)
+ {
+ if (m < 5)
+ {
+ strncpy(buf, s, m);
+ buf[m] = '\0';
+ return buf;
+ }
+ strncpy(buf, s, m - 3);
+ strcpy(buf + m - 3, "...");
+ return buf;
+ }
+ m = (m - 3) / 2;
+ strncpy(buf, s, m);
+ strcpy(buf + m, "...");
+ strcpy(buf + m + 3, s + l - m);
+ return buf;
+}
+ /*
+** CLEANSTRCPY -- copy string keeping out bogus characters
+**
+** Parameters:
+** t -- "to" string.
+** f -- "from" string.
+** l -- length of space available in "to" string.
+**
+** Returns:
+** none.
+*/
+
+void
+cleanstrcpy(t, f, l)
+ register char *t;
+ register char *f;
+ int l;
+{
+#ifdef LOG
+ /* check for newlines and log if necessary */
+ (void) denlstring(f, TRUE, TRUE);
+#endif
+
+ l--;
+ while (l > 0 && *f != '\0')
+ {
+ if (isascii(*f) &&
+ (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
+ {
+ l--;
+ *t++ = *f;
+ }
+ f++;
+ }
+ *t = '\0';
+}
+ /*
+** DENLSTRING -- convert newlines in a string to spaces
+**
+** Parameters:
+** s -- the input string
+** strict -- if set, don't permit continuation lines.
+** logattacks -- if set, log attempted attacks.
+**
+** Returns:
+** A pointer to a version of the string with newlines
+** mapped to spaces. This should be copied.
+*/
+
+char *
+denlstring(s, strict, logattacks)
+ char *s;
+ int strict;
+ int logattacks;
+{
+ register char *p;
+ int l;
+ static char *bp = NULL;
+ static int bl = 0;
+
+ p = s;
+ while ((p = strchr(p, '\n')) != NULL)
+ if (strict || (*++p != ' ' && *p != '\t'))
+ break;
+ if (p == NULL)
+ return s;
+
+ l = strlen(s) + 1;
+ if (bl < l)
+ {
+ /* allocate more space */
+ if (bp != NULL)
+ free(bp);
+ bp = xalloc(l);
+ bl = l;
+ }
+ strcpy(bp, s);
+ for (p = bp; (p = strchr(p, '\n')) != NULL; )
+ *p++ = ' ';
+
+#ifdef LOG
+ if (logattacks)
+ {
+ syslog(LOG_NOTICE, "POSSIBLE ATTACK from %s: newline in string \"%s\"",
+ RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
+ shortenstring(bp, 80));
+ }
+#endif
+
+ return bp;
+}
diff --git a/usr.sbin/sendmail/src/version.c b/usr.sbin/sendmail/src/version.c
new file mode 100644
index 00000000000..ad4dd520c80
--- /dev/null
+++ b/usr.sbin/sendmail/src/version.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * 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 sccsid[] = "@(#)version.c 8.6.12.1 (Berkeley) 3/28/95";
+#endif /* not lint */
+
+char Version[] = "8.6.12";
diff --git a/usr.sbin/sendmail/test/Results b/usr.sbin/sendmail/test/Results
new file mode 100644
index 00000000000..37a1bb2c363
--- /dev/null
+++ b/usr.sbin/sendmail/test/Results
@@ -0,0 +1,53 @@
+The following are results of running t_setreuid on various architectures.
+
+OPSYS VERSION STATUS DATE TESTER/NOTES
+===== ======= ====== ==== ============
+
+SunOS 4.1 OK 93.07.19 eric
+SunOS 4.1.2 OK 93.07.19 eric
+SunOS 4.1.3 OK 93.09.25 Robert Elz
+
+BSD 4.4 OK 93.07.19 eric (wierd results, but functional)
+BSD 4.3Utah OK 93.07.19 eric
+
+Ultrix 4.2A OK 93.07.19 eric
+Ultrix 4.3A OK 93.07.19 Allan Johannesen
+
+HP-UX 8.07 OK 93.07.19 eric (on 7xx series)
+HP-UX 8.02 OK 93.07.19 Michael Corrigan (on 8xx series)
+HP-UX 8.00 OK 93.07.21 Michael Corrigan (on 3xx/4xx series)
+HP-UX 9.01 OK 93.11.19 Cassidy (on 7xx series)
+
+Solaris 2.1
+Solaris 2.2 FAIL 93.07.19 Bill Wisner
+
+OSF/1 T1.3-4 OK 93.07.19 eric (on DEC Alpha)
+OSF/1 1.3 OK 94.12.10 Jeff A. Earickson (on Intel Paragon)
+
+CxOS 11.0 OK 93.01.21 Eric Schnoebelen (CxOS 11.0 beta 1)
+CxOS 10.x OK 93.01.21 Eric Schnoebelen
+
+AIX 3.1.5 FAIL 93.08.07 David J. N. Begley
+AIX 3.2.3e FAIL 93.07.26 Steve Bauer <sbauer@silver.sdsmt.edu>
+AIX 3.2.4 FAIL 93.10.07 David J. N. Begley
+AIX 3.2.5 FAIL 94.05.17 Steve Bauer <sbauer@hpcmmib.hpc.sdsmt.edu>
+
+IRIX 4.0.4 OK 93.09.25 Robert Elz
+IRIX 5.2 OK 94.12.06 Mark Andrews <mandrews@alias.com>
+IRIX 5.3 OK 94.12.06 Mark Andrews <mandrews@alias.com>
+
+SCO 3.2v4.0 OK 93.10.02 Peter Wemm (with -lsocket from 3.2v4 devsys)
+
+NeXT 2.1 OK 93.07.28 eric
+NeXT 3.0 OK 34.05.05 Kevin John Wang <kwang@lore.acs.calpoly.edu>
+
+Linux 0.99p10 OK 93.08.08 Karl London
+Linux 0.99p13 OK 93.09.27 Christian Kuhtz
+Linux 0.99p14 OK 93.11.30 Christian Kuhtz <chk@data-hh.Hanse.DE>
+Linux 1.0 OK 94.03.19 Shayne Smith <snsmith@rastus.brisnet.org.au>
+
+BSD/386 1.0 OK 93.11.13 Tony Sanders
+
+DELL 2.2 OK 93.11.15 Peter Wemm (using -DSETEUID)
+
+Pyramid 5.0d OK 95.01.14 David Miller <davem@nadzieja.rutgers.edu>
diff --git a/usr.sbin/sendmail/test/t_setreuid.c b/usr.sbin/sendmail/test/t_setreuid.c
new file mode 100644
index 00000000000..2d087c3c36e
--- /dev/null
+++ b/usr.sbin/sendmail/test/t_setreuid.c
@@ -0,0 +1,82 @@
+/*
+** This program checks to see if your version of setreuid works.
+** Compile it, make it setuid root, and run it as yourself (NOT as
+** root). If it won't compile or outputs any MAYDAY messages, don't
+** define HASSETREUID in conf.h.
+**
+** Compilation is trivial -- just "cc t_setreuid.c".
+*/
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifdef __hpux
+#define setreuid(r, e) setresuid(r, e, -1)
+#endif
+
+main()
+{
+ uid_t realuid = getuid();
+
+ printuids("initial uids", realuid, 0);
+
+ if (geteuid() != 0)
+ {
+ printf("re-run setuid root\n");
+ exit(1);
+ }
+
+ if (setreuid(0, 1) < 0)
+ printf("setreuid(0, 1) failure\n");
+ printuids("after setreuid(0, 1)", 0, 1);
+
+ if (geteuid() != 1)
+ printf("MAYDAY! Wrong effective uid\n");
+
+ /* do activity here */
+
+ if (setreuid(-1, 0) < 0)
+ printf("setreuid(-1, 0) failure\n");
+ printuids("after setreuid(-1, 0)", 0, 0);
+ if (setreuid(realuid, 0) < 0)
+ printf("setreuid(%d, 0) failure\n", realuid);
+ printuids("after setreuid(realuid, 0)", realuid, 0);
+
+ if (geteuid() != 0)
+ printf("MAYDAY! Wrong effective uid\n");
+ if (getuid() != realuid)
+ printf("MAYDAY! Wrong real uid\n");
+ printf("\n");
+
+ if (setreuid(0, 2) < 0)
+ printf("setreuid(0, 2) failure\n");
+ printuids("after setreuid(0, 2)", 0, 2);
+
+ if (geteuid() != 2)
+ printf("MAYDAY! Wrong effective uid\n");
+
+ /* do activity here */
+
+ if (setreuid(-1, 0) < 0)
+ printf("setreuid(-1, 0) failure\n");
+ printuids("after setreuid(-1, 0)", 0, 0);
+ if (setreuid(realuid, 0) < 0)
+ printf("setreuid(%d, 0) failure\n", realuid);
+ printuids("after setreuid(realuid, 0)", realuid, 0);
+
+ if (geteuid() != 0)
+ printf("MAYDAY! Wrong effective uid\n");
+ if (getuid() != realuid)
+ printf("MAYDAY! Wrong real uid\n");
+
+ exit(0);
+}
+
+printuids(str, r, e)
+ char *str;
+ int r, e;
+{
+ printf("%s (should be %d/%d): r/euid=%d/%d\n", str, r, e,
+ getuid(), geteuid());
+}
diff --git a/usr.sbin/sliplogin/Makefile b/usr.sbin/sliplogin/Makefile
new file mode 100644
index 00000000000..f49ea109527
--- /dev/null
+++ b/usr.sbin/sliplogin/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 5.1 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+
+PROG= sliplogin
+MAN= sliplogin.8
+BINOWN= root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sliplogin/pathnames.h b/usr.sbin/sliplogin/pathnames.h
new file mode 100644
index 00000000000..67d185739a3
--- /dev/null
+++ b/usr.sbin/sliplogin/pathnames.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 1990 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.
+ *
+ * from: @(#)pathnames.h 5.2 (Berkeley) 4/1/91
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_ACCESS "/etc/sliphome/slip.hosts"
+#define _PATH_LOGIN "/etc/sliphome/slip.login"
+#define _PATH_LOGOUT "/etc/sliphome/slip.logout"
diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts
new file mode 100644
index 00000000000..e3e526ac87b
--- /dev/null
+++ b/usr.sbin/sliplogin/slip.hosts
@@ -0,0 +1,11 @@
+#
+# login local-addr remote-addr mask opt1 opt2
+# (compress == link0)
+# (noicmp == link1)
+# (autocomp == link2)
+#
+Shavoc okeeffe havoc 0xffffff00
+Soxford okeeffe oxford-gw 0xffffff00 link0
+Schez okeeffe chez 0xffffff00 link2
+Smjk okeeffe pissaro 0xffffff00 link0
+Smjk2 okeeffe pissaro 0xffffff00 link0 link1
diff --git a/usr.sbin/sliplogin/slip.login b/usr.sbin/sliplogin/slip.login
new file mode 100644
index 00000000000..ed3a67a8cc9
--- /dev/null
+++ b/usr.sbin/sliplogin/slip.login
@@ -0,0 +1,21 @@
+#!/bin/sh -
+#
+# $NetBSD: slip.login,v 1.3 1994/06/30 07:50:26 cgd Exp $
+# @(#)slip.login 5.1 (Berkeley) 7/1/90
+
+#
+# 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
+#
+UNIT=$1
+LOCALADDR=$4
+REMOTEADDR=$5
+NETMASK=$6
+shift 6
+OPTARGS=$*
+
+/sbin/ifconfig sl${UNIT} inet ${LOCALADDR} ${REMOTEADDR} netmask ${NETMASK} \
+ ${OPTARGS}
+exit
diff --git a/usr.sbin/sliplogin/sliplogin.8 b/usr.sbin/sliplogin/sliplogin.8
new file mode 100644
index 00000000000..79c2ab526b5
--- /dev/null
+++ b/usr.sbin/sliplogin/sliplogin.8
@@ -0,0 +1,221 @@
+.\" Copyright (c) 1990, 1991 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.
+.\"
+.\" from: @(#)sliplogin.8 5.4 (Berkeley) 8/5/91
+.\" $Id: sliplogin.8,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+.\"
+.Dd August 5, 1991
+.Dt SLIPLOGIN 8
+.Os
+.Sh NAME
+.Nm sliplogin
+.Nd attach a serial line network interface
+.Sh SYNOPSIS
+.Nm sliplogin
+.Op Ar loginname
+.Sh DESCRIPTION
+.Nm Sliplogin
+is used to turn the terminal line on standard input into
+a Serial Line IP
+.Pq Tn SLIP
+link to a remote host. To do this, the program
+searches the file
+.Pa /etc/sliphome/slip.hosts
+for an entry matching
+.Ar loginname
+(which defaults to the current login name if omitted).
+If a matching entry is found, the line is configured appropriately
+for slip (8-bit transparent i/o) and converted to
+.Tn SLIP
+line
+discipline. Then a shell script is invoked to initialize the slip
+interface with the appropriate local and remote
+.Tn IP
+address,
+netmask, etc.
+.Pp
+The usual initialization script is
+.Pa /etc/sliphome/slip.login
+but, if particular hosts need special initialization, the file
+.Pa /etc/sliphome/slip.login. Ns Ar loginname
+will be executed instead if it exists.
+The script is invoked with the parameters
+.Bl -tag -width slipunit
+.It Em slipunit
+The unit number of the slip interface assigned to this line. E.g.,
+.Sy 0
+for
+.Sy sl0 .
+.It Em speed
+The speed of the line.
+.It Em args
+The arguments from the
+.Pa /etc/sliphome/slip.hosts
+entry, in order starting with
+.Ar loginname .
+.El
+.Pp
+Only the super-user may attach a network interface. The interface is
+automatically detached when the other end hangs up or the
+.Nm sliplogin
+process dies. If the kernel slip
+module has been configured for it, all routes through that interface will
+also disappear at the same time. If there is other processing a site
+would like done on hangup, the file
+.Pa /etc/sliphome/slip.logout
+or
+.Pa /etc/sliphome/slip.logout. Ns Ar loginname
+is executed if it exists. It is given the same arguments as the login script.
+.Ss Format of /etc/sliphome/slip.hosts
+Comments (lines starting with a `#') and blank lines are ignored.
+Other lines must start with a
+.Ar loginname
+but the remaining arguments can be whatever is appropriate for the
+.Pa slip.login
+file that will be executed for that name.
+Arguments are separated by white space and follow normal
+.Xr sh 1
+quoting conventions (however,
+.Ar loginname
+cannot be quoted).
+Usually, lines have the form
+.Bd -literal -offset indent
+loginname local-address remote-address netmask opt-args
+.Ed
+.Pp
+where
+.Em local-address
+and
+.Em remote-address
+are the IP host names or addresses of the local and remote ends of the
+slip line and
+.Em netmask
+is the appropriate IP netmask. These arguments are passed
+directly to
+.Xr ifconfig 8 .
+.Em Opt-args
+are optional arguments used to configure the line.
+.Sh EXAMPLE
+The normal use of
+.Nm sliplogin
+is to create a
+.Pa /etc/passwd
+entry for each legal, remote slip site with
+.Nm sliplogin
+as the shell for that entry. E.g.,
+.Bd -literal
+Sfoo:ikhuy6:2010:1:slip line to foo:/tmp:/usr/sbin/sliplogin
+.Ed
+.Pp
+(Our convention is to name the account used by remote host
+.Ar hostname
+as
+.Em Shostname . )
+Then an entry is added to
+.Pa slip.hosts
+that looks like:
+.Pp
+.Bd -literal -offset indent -compact
+Sfoo `hostname` foo netmask
+.Ed
+.Pp
+where
+.Em `hostname`
+will be evaluated by
+.Xr sh
+to the local host name and
+.Em netmask
+is the local host IP netmask.
+.Pp
+Note that
+.Nm sliplogin
+must be setuid to root and, while not a security hole, moral defectives
+can use it to place terminal lines in an unusable state and/or deny
+access to legitimate users of a remote slip line. To prevent this,
+a site can create a group, say
+.Em slip ,
+that only the slip login accounts are put in then make sure that
+.Pa /usr/sbin/sliplogin
+is in group
+.Em slip
+and mode 4550 (setuid root, only group
+.Em slip
+can execute binary).
+.Sh DIAGNOSTICS
+.Nm Sliplogin
+logs various information to the system log daemon,
+.Xr syslogd 8 ,
+with a facility code of
+.Em daemon .
+The messages are listed here, grouped by severity level.
+.Pp
+.Sy Error Severity
+.Bl -tag -width Ds -compact
+.It Sy ioctl (TCGETS): Em reason
+A
+.Dv TCGETS
+.Fn ioctl
+to get the line parameters failed.
+.Pp
+.It Sy ioctl (TCSETS): Em reason
+A
+.Dv TCSETS
+.Fn ioctl
+to set the line parameters failed.
+.Pp
+.It Sy /etc/sliphome/slip.hosts: Em reason
+The
+.Pa /etc/sliphome/slip.hosts
+file could not be opened.
+.Pp
+.It Sy access denied for Em user
+No entry for
+.Em user
+was found in
+.Pa /etc/sliphome/slip.hosts .
+.El
+.Pp
+.Sy Notice Severity
+.Bl -tag -width Ds -compact
+.It Sy "attaching slip unit" Em unit Sy for Ar loginname
+.Tn SLIP
+unit
+.Em unit
+was successfully attached.
+.El
+.Sh SEE ALSO
+.Xr slattach 8 ,
+.Xr syslogd 8
+.Sh HISTORY
+The
+.Nm
+command
+.Bt
diff --git a/usr.sbin/sliplogin/sliplogin.c b/usr.sbin/sliplogin/sliplogin.c
new file mode 100644
index 00000000000..c4ea6b15fcd
--- /dev/null
+++ b/usr.sbin/sliplogin/sliplogin.c
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1990 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
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)sliplogin.c 5.6 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: sliplogin.c,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * sliplogin.c
+ * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
+ *
+ * This program initializes its own tty port to be an async TCP/IP interface.
+ * It sets the line discipline to slip, invokes a shell script to initialize
+ * the network interface, then pauses forever waiting for hangup.
+ *
+ * It is a remote descendant of several similar programs with incestuous ties:
+ * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
+ * - slattach, probably by Rick Adams but touched by countless hordes.
+ * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
+ *
+ * There are two forms of usage:
+ *
+ * "sliplogin"
+ * Invoked simply as "sliplogin", the program looks up the username
+ * in the file /etc/slip.hosts.
+ * If an entry is found, the line on fd0 is configured for SLIP operation
+ * as specified in the file.
+ *
+ * "sliplogin IPhostlogin </dev/ttyb"
+ * Invoked by root with a username, the name is looked up in the
+ * /etc/slip.hosts file and if found fd0 is configured as in case 1.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/syslog.h>
+#include <netdb.h>
+#include <signal.h>
+
+#if BSD >= 199006
+#define POSIX
+#endif
+#ifdef POSIX
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <ttyent.h>
+#else
+#include <sgtty.h>
+#endif
+#include <net/slip.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+int unit;
+int speed;
+int uid;
+char loginargs[BUFSIZ];
+char loginfile[MAXPATHLEN];
+char loginname[BUFSIZ];
+
+void
+findid(name)
+ char *name;
+{
+ FILE *fp;
+ static char slopt[5][16];
+ static char laddr[16];
+ static char raddr[16];
+ static char mask[16];
+ char user[16];
+ int i, j, n;
+
+ (void)strcpy(loginname, name);
+ if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
+ err(1, "%s", _PATH_ACCESS);
+ }
+ while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
+ if (ferror(fp))
+ break;
+ n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
+ user, laddr, raddr, mask, slopt[0], slopt[1],
+ slopt[2], slopt[3], slopt[4]);
+ if (user[0] == '#' || isspace(user[0]))
+ continue;
+ if (strcmp(user, name) != 0)
+ continue;
+
+ /*
+ * we've found the guy we're looking for -- see if
+ * there's a login file we can use. First check for
+ * one specific to this host. If none found, try for
+ * a generic one.
+ */
+ (void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
+ if (access(loginfile, R_OK|X_OK) != 0) {
+ (void)strcpy(loginfile, _PATH_LOGIN);
+ if (access(loginfile, R_OK|X_OK)) {
+ fputs("access denied - no login file\n",
+ stderr);
+ syslog(LOG_ERR,
+ "access denied for %s - no %s\n",
+ name, _PATH_LOGIN);
+ exit(5);
+ }
+ }
+
+ (void) fclose(fp);
+ return;
+ }
+ syslog(LOG_ERR, "SLIP access denied for %s\n", name);
+ errx(1, "SLIP access denied for %s", name);
+ /* NOTREACHED */
+}
+
+const char *
+sigstr(s)
+ int s;
+{
+ if (s > 0 && s < NSIG)
+ return(sys_signame[s]);
+ else {
+ static char buf[32];
+ (void)sprintf(buf, "sig %d", s);
+ return(buf);
+ }
+}
+
+void
+hup_handler(s)
+ int s;
+{
+ char logoutfile[MAXPATHLEN];
+
+ (void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
+ if (access(logoutfile, R_OK|X_OK) != 0)
+ (void)strcpy(logoutfile, _PATH_LOGOUT);
+ if (access(logoutfile, R_OK|X_OK) == 0) {
+ char logincmd[2*MAXPATHLEN+32];
+
+ (void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
+ loginargs);
+ (void) system(logincmd);
+ }
+ (void) close(0);
+ syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
+ sigstr(s));
+ exit(1);
+ /* NOTREACHED */
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd, s, ldisc, odisc;
+ char *name;
+#ifdef POSIX
+ struct termios tios, otios;
+#else
+ struct sgttyb tty, otty;
+#endif
+ char logincmd[2*BUFSIZ+32];
+ extern uid_t getuid();
+
+ if ((name = strrchr(argv[0], '/')) == NULL)
+ name = argv[0];
+ s = getdtablesize();
+ for (fd = 3 ; fd < s ; fd++)
+ (void) close(fd);
+ openlog(name, LOG_PID, LOG_DAEMON);
+ uid = getuid();
+ if (argc > 1) {
+ findid(argv[1]);
+
+ /*
+ * Disassociate from current controlling terminal, if any,
+ * and ensure that the slip line is our controlling terminal.
+ */
+#ifdef POSIX
+ if (fork() > 0)
+ exit(0);
+ if (setsid() < 0)
+ perror("setsid");
+#else
+ if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
+ extern char *ttyname();
+
+ (void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
+ (void) close(fd);
+ /* open slip tty again to acquire as controlling tty? */
+ fd = open(ttyname(0), O_RDWR, 0);
+ if (fd >= 0)
+ (void) close(fd);
+ }
+ (void) setpgrp(0, getpid());
+#endif
+ if (argc > 2) {
+ if ((fd = open(argv[2], O_RDWR)) == -1) {
+ perror(argv[2]);
+ exit(2);
+ }
+ (void) dup2(fd, 0);
+ if (fd > 2)
+ close(fd);
+ }
+#ifdef TIOCSCTTY
+ if (ioctl(STDIN_FILENO, TIOCSCTTY, (caddr_t)0) != 0)
+ perror("ioctl (TIOCSCTTY)");
+#endif
+ } else {
+ extern char *getlogin();
+
+ if ((name = getlogin()) == NULL) {
+ syslog(LOG_ERR,
+ "access denied - getlogin returned 0\n");
+ errx(1, "access denied - no username");
+ }
+ findid(name);
+ }
+ if (!isatty(STDIN_FILENO)) {
+ syslog(LOG_ERR, "stdin not a tty");
+ errx(1, "stdin not a tty");
+ }
+ (void) fchmod(STDIN_FILENO, 0600);
+ warnx("starting slip login for %s", loginname);
+#ifdef POSIX
+ /* set up the line parameters */
+ if (tcgetattr(STDIN_FILENO, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ exit(1);
+ }
+ otios = tios;
+ cfmakeraw(&tios);
+ tios.c_iflag &= ~IMAXBEL;
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ exit(1);
+ }
+ speed = cfgetispeed(&tios);
+#else
+ /* set up the line parameters */
+ if (ioctl(STDIN_FILENO, TIOCGETP, (caddr_t)&tty) < 0) {
+ syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
+ exit(1);
+ }
+ otty = tty;
+ speed = tty.sg_ispeed;
+ tty.sg_flags = RAW | ANYP;
+ if (ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&tty) < 0) {
+ syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
+ exit(1);
+ }
+#endif
+ /* find out what ldisc we started with */
+ if (ioctl(STDIN_FILENO, TIOCGETD, (caddr_t)&odisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
+ exit(1);
+ }
+ ldisc = SLIPDISC;
+ if (ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&ldisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ exit(1);
+ }
+ /* find out what unit number we were assigned */
+ if (ioctl(STDIN_FILENO, SLIOCGUNIT, (caddr_t)&unit) < 0) {
+ syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
+ exit(1);
+ }
+ (void) signal(SIGHUP, hup_handler);
+ (void) signal(SIGTERM, hup_handler);
+
+ syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
+ (void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
+ loginargs);
+ /*
+ * aim stdout and errout at /dev/null so logincmd output won't
+ * babble into the slip tty line.
+ */
+ (void) close(1);
+ if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
+ if (fd < 0) {
+ syslog(LOG_ERR, "open /dev/null: %m");
+ exit(1);
+ }
+ (void) dup2(fd, 1);
+ (void) close(fd);
+ }
+ (void) dup2(1, 2);
+
+ /*
+ * Run login and logout scripts as root (real and effective);
+ * current route(8) is setuid root, and checks the real uid
+ * to see whether changes are allowed (or just "route get").
+ */
+ (void) setuid(0);
+ if (s = system(logincmd)) {
+ syslog(LOG_ERR, "%s login failed: exit status %d from %s",
+ loginname, s, loginfile);
+ (void) ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&odisc);
+#ifdef POSIX
+ (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &otios);
+#else
+ (void) ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&otty);
+#endif
+ exit(6);
+ }
+
+ /* twiddle thumbs until we get a signal */
+ while (1)
+ sigpause(0);
+
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/slstats/Makefile b/usr.sbin/slstats/Makefile
new file mode 100644
index 00000000000..72099a8183f
--- /dev/null
+++ b/usr.sbin/slstats/Makefile
@@ -0,0 +1,12 @@
+# from: @(#)Makefile 5.6 (Berkeley) 4/23/91
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+
+PROG= slstats
+SRCS= slstats.c
+MAN= slstats.8
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/slstats/slstats.8 b/usr.sbin/slstats/slstats.8
new file mode 100644
index 00000000000..ae2ab8b5511
--- /dev/null
+++ b/usr.sbin/slstats/slstats.8
@@ -0,0 +1,113 @@
+.\" @(#) $Header: /home/cvs/src/usr.sbin/slstats/Attic/slstats.8,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $ (LBL)
+.Dd July 5, 1993
+.Dt SLSTATS 8
+.Sh NAME
+.Nm slstats
+.Nd report slip statistics
+.Sh SYNOPSIS
+.Nm slstats
+.Op Fl v
+.Op Fl i Ar interval
+.Op Ar unit-number
+.Oo
+.Ar system
+.Op Ar core
+.Oc
+.Sh DESCRIPTION
+.Pp
+The
+.Nm slstats
+utility reports slip-related statistics for the
+.Nm sl Ns
+.So
+.Ar unit-number
+.Sc
+interface. If the
+.Nm unit-number
+is unspecified, it defaults to 0. These statistics are displayed at
+regular intervals.
+.Pp
+The display is split horizontally into input and output sections
+containing columns of statistics describing the properties and volume
+of packets received and transmitted by the specified interface.
+.Pp
+The first report will consist of a snapshot of the interface's present
+statistics. All further output will describe activity between report
+intervals.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl v
+Display additional statistics demonstrating the efficacy of VJ header
+compression and providing more explicit information on failure
+distribution.
+.It Fl i
+Specifies the interval between reports. The default interval is 5 seconds.
+.It Ar system
+Extract the name list from the specified system instead of the default
+.Pa /netbsd .
+.It Ar core
+Extract values associated with the name list from the specified
+.Ar core
+instead of the default
+.Pa /dev/kmem .
+.El
+.Pp
+The following fields are printed on the input side:
+.Bl -tag -width search
+.It Li IN
+The total number of bytes received by this interface.
+.It Li PACK
+The total number of packets received by this interface.
+.It Li COMP
+The number of compressed TCP packets received by this interface.
+.It Li UNCOMP
+The number of uncompressed TCP packets received by this interface.
+.It Li ERR
+The number of packets received by this interface of unknown type.
+.It Li TOSS
+The number of packets dropped on reception by this interface. Only
+reported when the
+.Fl v
+option is specified.
+.It Li IP
+The total number of non-TCP packets received by this interface. Only
+reported when the
+.Fl v
+option is specified.
+.El
+.Pp
+The following fields are printed on the output side:
+.Bl -tag -width search
+.It Li OUT
+The total number of bytes transmitted from this interface.
+.It Li PACK
+The total number of packets transmitted from this interface.
+.It Li COMP
+The number of TCP packets compressed and then transmitted from this interface.
+.It Li UNCOMP
+The number of uncompressed TCP packets transmitted from this interface.
+.It Li IP
+The total number of non-TCP packets transmitted from this interface.
+.It Li SEARCH
+The number of searches for the cached header entry for a compressed
+packet. Only reported when the
+.Fl v
+option is specified.
+.It Li MISS
+The number of failed searches for the cached header entry for a
+compressed packet. Only reported when the
+.Fl v
+option is specified.
+.El
+.Sh BUGS
+Should use
+.Fl M Ar core
+and
+.Fl N Ar system
+like most other programs using the kvm library.
+.Pp
+Should take an interface name and not a unit number.
+.Pp
+.Sh SEE ALSO
+.Xr sliplogin 1
diff --git a/usr.sbin/slstats/slstats.c b/usr.sbin/slstats/slstats.c
new file mode 100644
index 00000000000..fbd75c57254
--- /dev/null
+++ b/usr.sbin/slstats/slstats.c
@@ -0,0 +1,261 @@
+/*
+ * print serial line IP statistics:
+ * slstats [-i interval] [-v] [interface] [system] [core]
+ *
+ * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of
+ * California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef lint
+/*static char rcsid[] =
+ "@(#) $Header: /home/cvs/src/usr.sbin/slstats/Attic/slstats.c,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $ (LBL)";*/
+static char rcsid[] = "$Id: slstats.c,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $";
+#endif
+
+#include <stdio.h>
+#include <paths.h>
+#include <nlist.h>
+
+#define INET
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <signal.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <net/slcompress.h>
+#include <net/if_slvar.h>
+
+struct nlist nl[] = {
+#define N_SOFTC 0
+ { "_sl_softc" },
+ "",
+};
+
+char *system = _PATH_UNIX;
+char *kmemf = _PATH_KMEM;
+
+int kflag;
+int vflag;
+unsigned interval = 5;
+int unit;
+
+extern char *malloc();
+extern off_t lseek();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ --argc; ++argv;
+ while (argc > 0) {
+ if (strcmp(argv[0], "-v") == 0) {
+ ++vflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-i") == 0 && argv[1] &&
+ isdigit(argv[1][0])) {
+ interval = atoi(argv[1]);
+ if (interval <= 0)
+ usage();
+ ++argv, --argc;
+ ++argv, --argc;
+ continue;
+ }
+ if (isdigit(argv[0][0])) {
+ unit = atoi(argv[0]);
+ if (unit < 0)
+ usage();
+ ++argv, --argc;
+ continue;
+ }
+ if (kflag)
+ usage();
+
+ system = *argv;
+ ++argv, --argc;
+ if (argc > 0) {
+ kmemf = *argv++;
+ --argc;
+ kflag++;
+ }
+ }
+ if (kopen(system, kmemf, "slstats") < 0)
+ exit(1);
+ if (knlist(system, nl, "slstats") < 0)
+ exit(1);
+ intpr();
+ exit(0);
+}
+
+#define V(offset) ((line % 20)? sc->offset - osc->offset : sc->offset)
+#define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate))
+
+usage()
+{
+ static char umsg[] =
+ "usage: slstats [-i interval] [-v] [unit] [system] [core]\n";
+
+ fprintf(stderr, umsg);
+ exit(1);
+}
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ */
+intpr()
+{
+ register int line = 0;
+ int oldmask;
+ void catchalarm();
+ struct sl_softc *sc, *osc;
+ off_t addr;
+
+ addr = nl[N_SOFTC].n_value + unit * sizeof(struct sl_softc);
+ sc = (struct sl_softc *)malloc(AMT);
+ osc = (struct sl_softc *)malloc(AMT);
+ bzero((char *)osc, AMT);
+
+ while (1) {
+ if (kread(addr, (char *)sc, AMT) < 0)
+ perror("kmem read");
+ (void)signal(SIGALRM, catchalarm);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if ((line % 20) == 0) {
+ printf("%8.8s %6.6s %6.6s %6.6s %6.6s",
+ "IN", "PACK", "COMP", "UNCOMP", "ERR");
+ if (vflag)
+ printf(" %6.6s %6.6s", "TOSS", "IP");
+ printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s",
+ "OUT", "PACK", "COMP", "UNCOMP", "IP");
+ if (vflag)
+ printf(" %6.6s %6.6s", "SEARCH", "MISS");
+ putchar('\n');
+ }
+ printf("%8u %6d %6u %6u %6u",
+ V(sc_if.if_ibytes),
+ V(sc_if.if_ipackets),
+ V(sc_comp.sls_compressedin),
+ V(sc_comp.sls_uncompressedin),
+ V(sc_comp.sls_errorin));
+ if (vflag)
+ printf(" %6u %6u",
+ V(sc_comp.sls_tossed),
+ V(sc_if.if_ipackets) -
+ V(sc_comp.sls_compressedin) -
+ V(sc_comp.sls_uncompressedin) -
+ V(sc_comp.sls_errorin));
+ printf(" | %8u %6d %6u %6u %6u",
+ V(sc_if.if_obytes),
+ V(sc_if.if_opackets),
+ V(sc_comp.sls_compressed),
+ V(sc_comp.sls_packets) - V(sc_comp.sls_compressed),
+ V(sc_if.if_opackets) - V(sc_comp.sls_packets));
+ if (vflag)
+ printf(" %6u %6u",
+ V(sc_comp.sls_searches),
+ V(sc_comp.sls_misses));
+
+ putchar('\n');
+ fflush(stdout);
+ line++;
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (! signalled) {
+ sigpause(0);
+ }
+ sigsetmask(oldmask);
+ signalled = 0;
+ (void)alarm(interval);
+ bcopy((char *)sc, (char *)osc, AMT);
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+void
+catchalarm()
+{
+ signalled = 1;
+}
+
+#include <kvm.h>
+#include <fcntl.h>
+
+kvm_t *kd;
+
+kopen(system, kmemf, errstr)
+ char *system;
+ char *kmemf;
+ char *errstr;
+{
+ if (strcmp(system, _PATH_UNIX) == 0 &&
+ strcmp(kmemf, _PATH_KMEM) == 0) {
+ system = 0;
+ kmemf = 0;
+ }
+ kd = kvm_open(system, kmemf, NULL, O_RDONLY, "slstats");
+ if (kd == NULL)
+ return -1;
+ return 0;
+}
+
+int
+knlist(system, nl, errstr)
+ char *system;
+ struct nlist *nl;
+ char *errstr;
+{
+ if (kd == 0)
+ /* kopen() must be called first */
+ abort();
+
+ if (kvm_nlist(kd, nl) < 0 || nl[0].n_type == 0) {
+ fprintf(stderr, "%s: %s: no namelist\n", errstr, system);
+ return -1;
+ }
+ return 0;
+}
+
+int
+kread(addr, buf, size)
+ off_t addr;
+ char *buf;
+ int size;
+{
+ if (kvm_read(kd, (u_long)addr, buf, size) != size)
+ return -1;
+ return 0;
+}
diff --git a/usr.sbin/spray/Makefile b/usr.sbin/spray/Makefile
new file mode 100644
index 00000000000..60d8b8e766b
--- /dev/null
+++ b/usr.sbin/spray/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+
+PROG= spray
+MAN= spray.8
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/spray/spray.8 b/usr.sbin/spray/spray.8
new file mode 100644
index 00000000000..7e9a4a1705e
--- /dev/null
+++ b/usr.sbin/spray/spray.8
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 1994 James A. Jegers
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd July 10, 1995
+.Dt SPRAY 8
+.Os NetBSD
+.Sh NAME
+.Nm spray
+.Nd send many packets to host
+.Sh SYNOPSIS
+.Nm spray
+.Op Fl c Ar count
+.Op Fl d Ar delay
+.Op Fl l Ar length
+.Ar host
+\&...
+.Ek
+.Sh DESCRIPTION
+.Nm Spray
+sends multiple RPC packets to
+.Ar host
+and records how many of them were correctly received and how long it took.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar count
+Send
+.Ar count
+packets.
+.It Fl d Ar delay
+Pause
+.Ar delay
+microseconds between sending each packet.
+.It Fl l Ar length
+Set the length of the packet that holds the RPC call message to
+.Ar length
+bytes.
+Not all values of
+.Ar length
+are possible because RPC data is encoded using XDR.
+.Nm Spray
+rounds up to the nearest possible value.
+.El
+.Pp
+.Nm Spray
+is intended for use in network testing, measurement, and management.
+This command
+.Bf -emphasis
+can be very hard on a network and should be used with caution.
+.Ef
+.Pp
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ifconfig 8 ,
+.Xr ping 8 ,
+.Xr rpc.sprayd 8
diff --git a/usr.sbin/spray/spray.c b/usr.sbin/spray/spray.c
new file mode 100644
index 00000000000..c6df61e2f14
--- /dev/null
+++ b/usr.sbin/spray/spray.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: spray.c,v 1.1.1.1 1995/10/18 08:48:21 deraadt Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/spray.h>
+
+#ifndef SPRAYOVERHEAD
+#define SPRAYOVERHEAD 86
+#endif
+
+void usage ();
+void print_xferstats ();
+
+/* spray buffer */
+char spray_buffer[SPRAYMAX];
+
+/* RPC timeouts */
+struct timeval NO_DEFAULT = { -1, -1 };
+struct timeval ONE_WAY = { 0, 0 };
+struct timeval TIMEOUT = { 25, 0 };
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ spraycumul host_stats;
+ sprayarr host_array;
+ CLIENT *cl;
+ int c;
+ int i;
+ int count = 0;
+ int delay = 0;
+ int length = 0;
+ double xmit_time; /* time to receive data */
+
+ progname = *argv;
+ while ((c = getopt(argc, argv, "c:d:l:")) != -1) {
+ switch (c) {
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 'd':
+ delay = atoi(optarg);
+ break;
+ case 'l':
+ length = atoi(optarg);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ usage();
+ /* NOTREACHED */
+ }
+
+
+ /* Correct packet length. */
+ if (length > SPRAYMAX) {
+ length = SPRAYMAX;
+ } else if (length < SPRAYOVERHEAD) {
+ length = SPRAYOVERHEAD;
+ } else {
+ /* The RPC portion of the packet is a multiple of 32 bits. */
+ length -= SPRAYOVERHEAD - 3;
+ length &= ~3;
+ length += SPRAYOVERHEAD;
+ }
+
+
+ /*
+ * The default value of count is the number of packets required
+ * to make the total stream size 100000 bytes.
+ */
+ if (!count) {
+ count = 100000 / length;
+ }
+
+ /* Initialize spray argument */
+ host_array.sprayarr_len = length - SPRAYOVERHEAD;
+ host_array.sprayarr_val = spray_buffer;
+
+
+ /* create connection with server */
+ cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp");
+ if (cl == NULL) {
+ clnt_pcreateerror(progname);
+ exit(1);
+ }
+
+
+ /*
+ * For some strange reason, RPC 4.0 sets the default timeout,
+ * thus timeouts specified in clnt_call() are always ignored.
+ *
+ * The following (undocumented) hack resets the internal state
+ * of the client handle.
+ */
+ clnt_control(cl, CLSET_TIMEOUT, (caddr_t)&NO_DEFAULT);
+
+
+ /* Clear server statistics */
+ if (clnt_call(cl, SPRAYPROC_CLEAR, xdr_void, NULL, xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+
+ /* Spray server with packets */
+ printf ("sending %d packets of lnth %d to %s ...", count, length, *argv);
+ fflush (stdout);
+
+ for (i = 0; i < count; i++) {
+ clnt_call(cl, SPRAYPROC_SPRAY, xdr_sprayarr, &host_array, xdr_void, NULL, ONE_WAY);
+
+ if (delay) {
+ usleep(delay);
+ }
+ }
+
+
+ /* Collect statistics from server */
+ if (clnt_call(cl, SPRAYPROC_GET, xdr_void, NULL, xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+ xmit_time = host_stats.clock.sec +
+ (host_stats.clock.usec / 1000000.0);
+
+ printf ("\n\tin %.2f seconds elapsed time\n", xmit_time);
+
+
+ /* report dropped packets */
+ if (host_stats.counter != count) {
+ int packets_dropped = count - host_stats.counter;
+
+ printf("\t%d packets (%.2f%%) dropped\n",
+ packets_dropped,
+ 100.0 * packets_dropped / count );
+ } else {
+ printf("\tno packets dropped\n");
+ }
+
+ printf("Sent:");
+ print_xferstats(count, length, xmit_time);
+
+ printf("Rcvd:");
+ print_xferstats(host_stats.counter, length, xmit_time);
+
+ exit (0);
+}
+
+
+void
+print_xferstats(packets, packetlen, xfertime)
+ int packets;
+ int packetlen;
+ double xfertime;
+{
+ int datalen;
+ double pps; /* packets per second */
+ double bps; /* bytes per second */
+
+ datalen = packets * packetlen;
+ pps = packets / xfertime;
+ bps = datalen / xfertime;
+
+ printf("\t%.0f packets/sec, ", pps);
+
+ if (bps >= 1024)
+ printf ("%.1fK ", bps / 1024);
+ else
+ printf ("%.0f ", bps);
+
+ printf("bytes/sec\n");
+}
+
+
+void
+usage ()
+{
+ fprintf(stderr, "usage: spray [-c count] [-l length] [-d delay] host\n");
+ exit(1);
+}
diff --git a/usr.sbin/sysctl/Makefile b/usr.sbin/sysctl/Makefile
new file mode 100644
index 00000000000..39432099a2c
--- /dev/null
+++ b/usr.sbin/sysctl/Makefile
@@ -0,0 +1,7 @@
+# $NetBSD: Makefile,v 1.3 1995/09/30 07:12:43 thorpej Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sysctl
+MAN= sysctl.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sysctl/pathconf.c b/usr.sbin/sysctl/pathconf.c
new file mode 100644
index 00000000000..ad51f0dfa75
--- /dev/null
+++ b/usr.sbin/sysctl/pathconf.c
@@ -0,0 +1,235 @@
+/* $NetBSD: pathconf.c,v 1.2 1995/09/30 07:12:47 thorpej Exp $ */
+
+/*
+ * 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
+#if 0
+static char sccsid[] = "@(#)pathconf.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: pathconf.c,v 1.2 1995/09/30 07:12:47 thorpej Exp $";
+#endif
+#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/usr.sbin/sysctl/sysctl.8 b/usr.sbin/sysctl/sysctl.8
new file mode 100644
index 00000000000..a67bd234a54
--- /dev/null
+++ b/usr.sbin/sysctl/sysctl.8
@@ -0,0 +1,213 @@
+.\" $NetBSD: sysctl.8,v 1.4 1995/09/30 07:12:49 thorpej Exp $
+.\"
+.\" 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.maxpartitions integer no
+.It kern.rawpartition integer no
+.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.tcp.rfc1323 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/usr.sbin/sysctl/sysctl.c b/usr.sbin/sysctl/sysctl.c
new file mode 100644
index 00000000000..4f0f8ffaafa
--- /dev/null
+++ b/usr.sbin/sysctl/sysctl.c
@@ -0,0 +1,585 @@
+/* $NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $ */
+
+/*
+ * 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
+#if 0
+static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
+#else
+static char *rcsid = "$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $";
+#endif
+#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 <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_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, len;
+ int special = 0;
+ void *newval = 0;
+ int intval, newsize = 0;
+ quad_t quadval;
+ size_t size;
+ 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,
+ "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
+ clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
+ return;
+ }
+ if (special & BOOTTIME) {
+ struct timeval *btp = (struct timeval *)buf;
+ time_t boottime;
+
+ if (!nflag) {
+ boottime = btp->tv_sec;
+ fprintf(stdout, "%s = %s\n", string, ctime(&boottime));
+ } 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], loc, i;
+ size_t size;
+
+ 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 tcpname[] = TCPCTL_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 },
+ { tcpname, TCPCTL_MAXID }, /* 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/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile
new file mode 100644
index 00000000000..17fd943a397
--- /dev/null
+++ b/usr.sbin/syslogd/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 5.7 (Berkeley) 9/30/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:22 deraadt Exp $
+
+PROG= syslogd
+SRCS= syslogd.c ttymsg.c
+.PATH: ${.CURDIR}/../../usr.bin/wall
+MAN= syslogd.8 syslog.conf.5
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/syslogd/pathnames.h b/usr.sbin/syslogd/pathnames.h
new file mode 100644
index 00000000000..d062d253d59
--- /dev/null
+++ b/usr.sbin/syslogd/pathnames.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1989 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.
+ *
+ * from: @(#)pathnames.h 5.4 (Berkeley) 9/29/90
+ * $Id: pathnames.h,v 1.1.1.1 1995/10/18 08:48:22 deraadt Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_KLOG "/dev/klog"
+#define _PATH_LOGCONF "/etc/syslog.conf"
+#define _PATH_LOGPID "/var/run/syslog.pid"
diff --git a/usr.sbin/syslogd/syslog.conf.5 b/usr.sbin/syslogd/syslog.conf.5
new file mode 100644
index 00000000000..8a60ffc25bf
--- /dev/null
+++ b/usr.sbin/syslogd/syslog.conf.5
@@ -0,0 +1,230 @@
+.\" Copyright (c) 1990, 1991 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.
+.\"
+.\" from: @(#)syslog.conf.5 5.3 (Berkeley) 5/10/91
+.\" $Id: syslog.conf.5,v 1.1.1.1 1995/10/18 08:48:22 deraadt Exp $
+.\"
+.Dd May 10, 1991
+.Dt SYSLOG.CONF 5
+.Os
+.Sh NAME
+.Nm syslog.conf
+.Nd
+.Xr syslogd 8
+configuration file
+.Sh DESCRIPTION
+The
+.Nm syslog.conf
+file is the configuration file for the
+.Xr syslogd 8
+program.
+It consists of lines with two fields: the
+.Em selector
+field which specifies the types of messages and priorities to which the
+line applies, and an
+.Em action
+field which specifies the action to be taken if a message
+.Xr syslogd
+receives matches the selection criteria.
+The
+.Em selector
+field is separated from the
+.Em action
+field by one or more tab characters.
+.Pp
+The
+.Em Selectors
+function
+are encoded as a
+.Em facility ,
+a period (``.''), and a
+.Em level ,
+with no intervening white-space.
+Both the
+.Em facility
+and the
+.Em level
+are case insensitive.
+.Pp
+The
+.Em facility
+describes the part of the system generating the message, and is one of
+the following keywords: auth, authpriv, cron, daemon, kern, lpr, mail,
+mark, news, syslog, user, uucp and local0 through local7.
+These keywords (with the exception of mark) correspond to the
+similar
+.Dq Dv LOG_
+values specified to the
+.Xr openlog 3
+and
+.Xr syslog 3
+library routines.
+.Pp
+The
+.Em level
+describes the severity of the message, and is a keyword from the
+following ordered list (higher to lower): emerg, alert, crit, err,
+warning, notice, info and debug.
+These keywords correspond to the
+similar
+.Pq Dv LOG_
+values specified to the
+.Xr syslog
+library routine.
+.Pp
+See
+.Xr syslog 3
+for a further descriptions of both the
+.Em facility
+and
+.Em level
+keywords and their significance.
+.Pp
+If a received message matches the specified
+.Em facility
+and is of the specified
+.Em level
+.Em (or a higher level) ,
+the action specified in the
+.Em action
+field will be taken.
+.Pp
+Multiple
+.Em selectors
+may be specified for a single
+.Em action
+by separating them with semicolon (``;'') characters.
+It is important to note, however, that each
+.Em selector
+can modify the ones preceding it.
+.Pp
+Multiple
+.Em facilities
+may be specified for a single
+.Em level
+by separating them with comma (``,'') characters.
+.Pp
+An asterisk (``*'') can be used to specify all
+.Em facilities
+or all
+.Em levels .
+.Pp
+The special
+.Em facility
+``mark'' receives a message at priority ``info'' every 20 minutes
+(see
+.Xr syslogd 8 ) .
+This is not enabled by a
+.Em facility
+field containing an asterisk.
+.Pp
+The special
+.Em level
+``none'' disables a particular
+.Em facility .
+.Pp
+The
+.Em action
+field of each line specifies the action to be taken when the
+.Em selector
+field selects a message.
+There are four forms:
+.Bl -bullet
+.It
+A pathname (beginning with a leading slash).
+Selected messages are appended to the file.
+.It
+A hostname (preceded by an at (``@'') sign).
+Selected messages are forwarded to the
+.Xr syslogd
+program on the named host.
+.It
+A comma separated list of users.
+Selected messages are written to those users
+if they are logged in.
+.It
+An asterisk.
+Selected messages are written to all logged-in users.
+.El
+.Pp
+Blank lines and lines whose first non-blank character is a hash (``#'')
+character are ignored.
+.Sh EXAMPLES
+.Pp
+A configuration file might appear as follows:
+.Bd -literal
+# Log all kernel messages, authentication messages of
+# level notice or higher and anything of level err or
+# higher to the console.
+# Don't log private authentication messages!
+*.err;kern.*;auth.notice;authpriv.none /dev/console
+
+# Log anything (except mail) of level info or higher.
+# Don't log private authentication messages!
+*.info;mail.none;authpriv.none /var/log/messages
+
+# The authpriv file has restricted access.
+authpriv.* /var/log/secure
+
+# Log all the mail messages in one place.
+mail.* /var/log/maillog
+
+# Everybody gets emergency messages, plus log them on another
+# machine.
+*.emerg *
+*.emerg @arpa.berkeley.edu
+
+# Root and Eric get alert and higher messages.
+*.alert root,eric
+
+# Save mail and news errors of level err and higher in a
+# special file.
+uucp,news.crit /var/log/spoolerr
+.Ed
+.Sh FILES
+.Bl -tag -width /etc/syslog.conf -compact
+.It Pa /etc/syslog.conf
+The
+.Xr syslogd 8
+configuration file.
+.El
+.Sh BUGS
+The effects of multiple selectors are sometimes not intuitive.
+For example ``mail.crit,*.err'' will select ``mail'' facility messages at
+the level of ``err'' or higher, not at the level of ``crit'' or higher.
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr syslogd 8
+.Sh HISTORY
+The
+.Nm syslog.conf
+file format is
+.Ud .
diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8
new file mode 100644
index 00000000000..d2b60981b6e
--- /dev/null
+++ b/usr.sbin/syslogd/syslogd.8
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1983, 1986, 1991 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.
+.\"
+.\" from: @(#)syslogd.8 6.10 (Berkeley) 3/16/91
+.\" $Id: syslogd.8,v 1.1.1.1 1995/10/18 08:48:22 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt SYSLOGD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm syslogd
+.Nd log systems messages
+.Sh SYNOPSIS
+.Nm syslogd
+.Op Fl f Ar config_file
+.Op Fl m Ar mark_interval
+.Op Fl p Ar log_socket
+.Sh DESCRIPTION
+.Nm Syslogd
+reads and logs messages to the system console, log files, other
+machines and/or users as specified by its configuration file.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+Specify the pathname of an alternate configuration file;
+the default is
+.Pa /etc/syslog.conf .
+.It Fl m
+Select the number of minutes between ``mark'' messages;
+the default is 20 minutes.
+.It Fl p
+Specify the pathname of an alternate log socket;
+the default is
+.Pa /dev/log .
+.El
+.Pp
+.Nm Syslogd
+reads its configuration file when it starts up and whenever it
+receives a hangup signal.
+For information on the format of the configuration file,
+see
+.Xr syslog.conf 5 .
+.Pp
+.Nm Syslogd
+reads messages from the
+.Tn UNIX
+domain socket
+.Pa /dev/log ,
+from an Internet domain socket specified in
+.Pa /etc/services ,
+and from the special device
+.Pa /dev/klog
+(to read kernel messages).
+.Pp
+.Nm Syslogd
+creates the file
+.Pa /var/run/syslog.pid ,
+and stores its process
+id there.
+This can be used to kill or reconfigure
+.Nm syslogd .
+.Pp
+The message sent to
+.Nm syslogd
+should consist of a single line.
+The message can contain a priority code, which should be a preceding
+decimal number in angle braces, for example,
+.Sq Aq 5.
+This priority code should map into the priorities defined in the
+include file
+.Aq Pa sys/syslog.h .
+.Sh FILES
+.Bl -tag -width /var/run/syslog.pid -compact
+.It Pa /etc/syslog.conf
+The configuration file.
+.It Pa /var/run/syslog.pid
+The process id of current
+.Nm syslogd .
+.It Pa /dev/log
+Name of the
+.Tn UNIX
+domain datagram log socket.
+.It Pa /dev/klog
+The kernel log device.
+.El
+.Sh SEE ALSO
+.Xr logger 1 ,
+.Xr syslog 3 ,
+.Xr services 5 ,
+.Xr syslog.conf 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c
new file mode 100644
index 00000000000..e243d8cac79
--- /dev/null
+++ b/usr.sbin/syslogd/syslogd.c
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (c) 1983, 1988 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
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)syslogd.c 5.45 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: syslogd.c,v 1.1.1.1 1995/10/18 08:48:22 deraadt Exp $";
+#endif /* not lint */
+
+/*
+ * syslogd -- log system messages
+ *
+ * This program implements a system log. It takes a series of lines.
+ * Each line may have a priority, signified as "<n>" as
+ * the first characters of the line. If this is
+ * not present, a default priority is used.
+ *
+ * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
+ * cause it to reread its configuration file.
+ *
+ * Defined Constants:
+ *
+ * MAXLINE -- the maximimum line length that can be handled.
+ * DEFUPRI -- the default priority for user messages
+ * DEFSPRI -- the default priority for kernel messages
+ *
+ * Author: Eric Allman
+ * extensive changes by Ralph Campbell
+ * more extensive changes by Eric Allman (again)
+ */
+
+#define MAXLINE 1024 /* maximum line length */
+#define MAXSVLINE 120 /* maximum saved line length */
+#define DEFUPRI (LOG_USER|LOG_NOTICE)
+#define DEFSPRI (LOG_KERN|LOG_CRIT)
+#define TIMERINTVL 30 /* interval for checking flush, mark */
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/msgbuf.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/signal.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <utmp.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+#define SYSLOG_NAMES
+#include <sys/syslog.h>
+
+char *LogName = _PATH_LOG;
+char *ConfFile = _PATH_LOGCONF;
+char *PidFile = _PATH_LOGPID;
+char ctty[] = _PATH_CONSOLE;
+
+#define FDMASK(fd) (1 << (fd))
+
+#define dprintf if (Debug) printf
+
+#define MAXUNAMES 20 /* maximum number of user names */
+
+/*
+ * Flags to logmsg().
+ */
+
+#define IGN_CONS 0x001 /* don't print on console */
+#define SYNC_FILE 0x002 /* do fsync on file after printing */
+#define ADDDATE 0x004 /* add a date to the message */
+#define MARK 0x008 /* this message is a mark */
+
+/*
+ * This structure represents the files that will have log
+ * copies printed.
+ */
+
+struct filed {
+ struct filed *f_next; /* next in linked list */
+ short f_type; /* entry type, see below */
+ short f_file; /* file descriptor */
+ time_t f_time; /* time this was last written */
+ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
+ union {
+ char f_uname[MAXUNAMES][UT_NAMESIZE+1];
+ struct {
+ char f_hname[MAXHOSTNAMELEN+1];
+ struct sockaddr_in f_addr;
+ } f_forw; /* forwarding address */
+ char f_fname[MAXPATHLEN];
+ } f_un;
+ char f_prevline[MAXSVLINE]; /* last message logged */
+ char f_lasttime[16]; /* time of last occurrence */
+ char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */
+ int f_prevpri; /* pri of f_prevline */
+ int f_prevlen; /* length of f_prevline */
+ int f_prevcount; /* repetition cnt of prevline */
+ int f_repeatcount; /* number of "repeated" msgs */
+};
+
+/*
+ * Intervals at which we flush out "message repeated" messages,
+ * in seconds after previous message is logged. After each flush,
+ * we move to the next interval until we reach the largest.
+ */
+int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */
+#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
+#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
+#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
+ (f)->f_repeatcount = MAXREPEAT; \
+ }
+
+/* values for f_type */
+#define F_UNUSED 0 /* unused entry */
+#define F_FILE 1 /* regular file */
+#define F_TTY 2 /* terminal */
+#define F_CONSOLE 3 /* console terminal */
+#define F_FORW 4 /* remote machine */
+#define F_USERS 5 /* list of users */
+#define F_WALL 6 /* everyone logged on */
+
+char *TypeNames[7] = {
+ "UNUSED", "FILE", "TTY", "CONSOLE",
+ "FORW", "USERS", "WALL"
+};
+
+struct filed *Files;
+struct filed consfile;
+
+int Debug; /* debug flag */
+char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
+char *LocalDomain; /* our local domain name */
+int InetInuse = 0; /* non-zero if INET sockets are being used */
+int finet; /* Internet datagram socket */
+int LogPort; /* port number for INET connections */
+int Initialized = 0; /* set when we have initialized ourselves */
+int MarkInterval = 20 * 60; /* interval between marks in seconds */
+int MarkSeq = 0; /* mark sequence number */
+
+extern int errno;
+extern char *ctime(), *index(), *calloc();
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ register char *p;
+ int funix, inetm, fklog, klogm, len;
+ struct sockaddr_un sunx, fromunix;
+ struct sockaddr_in sin, frominet;
+ FILE *fp;
+ int ch;
+ char line[MSG_BSIZE + 1];
+ extern int optind;
+ extern char *optarg;
+ void die(), domark(), init(), reapchild();
+
+ while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
+ switch((char)ch) {
+ case 'd': /* debug */
+ Debug++;
+ break;
+ case 'f': /* configuration file */
+ ConfFile = optarg;
+ break;
+ case 'm': /* mark interval */
+ MarkInterval = atoi(optarg) * 60;
+ break;
+ case 'p': /* path */
+ LogName = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ if (argc -= optind)
+ usage();
+
+ if (!Debug)
+ daemon(0, 0);
+ else
+ setlinebuf(stdout);
+
+ consfile.f_type = F_CONSOLE;
+ (void) strcpy(consfile.f_un.f_fname, ctty);
+ (void) gethostname(LocalHostName, sizeof LocalHostName);
+ if (p = index(LocalHostName, '.')) {
+ *p++ = '\0';
+ LocalDomain = p;
+ }
+ else
+ LocalDomain = "";
+ (void) signal(SIGTERM, die);
+ (void) signal(SIGINT, Debug ? die : SIG_IGN);
+ (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
+ (void) signal(SIGCHLD, reapchild);
+ (void) signal(SIGALRM, domark);
+ (void) alarm(TIMERINTVL);
+ (void) unlink(LogName);
+
+ bzero((char *)&sunx, sizeof(sunx));
+ sunx.sun_family = AF_UNIX;
+ (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
+ funix = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
+ sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
+ strlen(sunx.sun_path)) < 0 ||
+ chmod(LogName, 0666) < 0) {
+ (void) sprintf(line, "cannot create %s", LogName);
+ logerror(line);
+ dprintf("cannot create %s (%d)\n", LogName, errno);
+ die(0);
+ }
+ finet = socket(AF_INET, SOCK_DGRAM, 0);
+ if (finet >= 0) {
+ struct servent *sp;
+
+ sp = getservbyname("syslog", "udp");
+ if (sp == NULL) {
+ errno = 0;
+ logerror("syslog/udp: unknown service");
+ die(0);
+ }
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = LogPort = sp->s_port;
+ if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ logerror("bind");
+ if (!Debug)
+ die(0);
+ } else {
+ inetm = FDMASK(finet);
+ InetInuse = 1;
+ }
+ }
+ if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
+ klogm = FDMASK(fklog);
+ else {
+ dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
+ klogm = 0;
+ }
+
+ /* tuck my process id away */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+
+ dprintf("off & running....\n");
+
+ init();
+ (void) signal(SIGHUP, init);
+
+ for (;;) {
+ int nfds, readfds = FDMASK(funix) | inetm | klogm;
+
+ errno = 0;
+ dprintf("readfds = %#x\n", readfds);
+ nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
+ (fd_set *) NULL, (struct timeval *) NULL);
+ if (nfds == 0)
+ continue;
+ if (nfds < 0) {
+ if (errno != EINTR)
+ logerror("select");
+ continue;
+ }
+ dprintf("got a message (%d, %#x)\n", nfds, readfds);
+ if (readfds & klogm) {
+ i = read(fklog, line, sizeof(line) - 1);
+ if (i > 0) {
+ line[i] = '\0';
+ printsys(line);
+ } else if (i < 0 && errno != EINTR) {
+ logerror("klog");
+ fklog = -1;
+ klogm = 0;
+ }
+ }
+ if (readfds & FDMASK(funix)) {
+ len = sizeof fromunix;
+ i = recvfrom(funix, line, MAXLINE, 0,
+ (struct sockaddr *) &fromunix, &len);
+ if (i > 0) {
+ line[i] = '\0';
+ printline(LocalHostName, line);
+ } else if (i < 0 && errno != EINTR)
+ logerror("recvfrom unix");
+ }
+ if (readfds & inetm) {
+ len = sizeof frominet;
+ i = recvfrom(finet, line, MAXLINE, 0,
+ (struct sockaddr *) &frominet, &len);
+ if (i > 0) {
+ extern char *cvthname();
+
+ line[i] = '\0';
+ printline(cvthname(&frominet), line);
+ } else if (i < 0 && errno != EINTR)
+ logerror("recvfrom inet");
+ }
+ }
+}
+
+usage()
+{
+ (void) fprintf(stderr,
+ "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
+ exit(1);
+}
+
+/*
+ * Take a raw input line, decode the message, and print the message
+ * on the appropriate log files.
+ */
+
+printline(hname, msg)
+ char *hname;
+ char *msg;
+{
+ register char *p, *q;
+ register int c;
+ char line[MAXLINE + 1];
+ int pri;
+
+ /* test for special codes */
+ pri = DEFUPRI;
+ p = msg;
+ if (*p == '<') {
+ pri = 0;
+ while (isdigit(*++p))
+ pri = 10 * pri + (*p - '0');
+ if (*p == '>')
+ ++p;
+ }
+ if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFUPRI;
+
+ /* don't allow users to log kernel messages */
+ if (LOG_FAC(pri) == LOG_KERN)
+ pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
+
+ q = line;
+
+ while ((c = *p++ & 0177) != '\0' &&
+ q < &line[sizeof(line) - 1])
+ if (iscntrl(c))
+ if (c == '\n')
+ *q++ = ' ';
+ else if (c == '\t')
+ *q++ = '\t';
+ else {
+ *q++ = '^';
+ *q++ = c ^ 0100;
+ }
+ else
+ *q++ = c;
+ *q = '\0';
+
+ logmsg(pri, line, hname, 0);
+}
+
+/*
+ * Take a raw input line from /dev/klog, split and format similar to syslog().
+ */
+
+printsys(msg)
+ char *msg;
+{
+ register char *p, *q;
+ register int c;
+ char line[MAXLINE + 1];
+ int pri, flags;
+ char *lp;
+
+ (void) strcpy(line, _PATH_UNIX);
+ (void) strcat(line, ": ");
+ lp = line + strlen(line);
+ for (p = msg; *p != '\0'; ) {
+ flags = SYNC_FILE | ADDDATE; /* fsync file after write */
+ pri = DEFSPRI;
+ if (*p == '<') {
+ pri = 0;
+ while (isdigit(*++p))
+ pri = 10 * pri + (*p - '0');
+ if (*p == '>')
+ ++p;
+ } else {
+ /* kernel printf's come out on console */
+ flags |= IGN_CONS;
+ }
+ if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFSPRI;
+ q = lp;
+ while (*p != '\0' && (c = *p++) != '\n' &&
+ q < &line[MAXLINE])
+ *q++ = c;
+ *q = '\0';
+ logmsg(pri, line, LocalHostName, flags);
+ }
+}
+
+time_t now;
+
+/*
+ * Log a message to the appropriate log files, users, etc. based on
+ * the priority.
+ */
+
+logmsg(pri, msg, from, flags)
+ int pri;
+ char *msg, *from;
+ int flags;
+{
+ register struct filed *f;
+ int fac, prilev;
+ int omask, msglen;
+ char *timestamp;
+ time_t time();
+
+ dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
+ pri, flags, from, msg);
+
+ omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
+
+ /*
+ * Check to see if msg looks non-standard.
+ */
+ msglen = strlen(msg);
+ if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
+ msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
+ flags |= ADDDATE;
+
+ (void) time(&now);
+ if (flags & ADDDATE)
+ timestamp = ctime(&now) + 4;
+ else {
+ timestamp = msg;
+ msg += 16;
+ msglen -= 16;
+ }
+
+ /* extract facility and priority level */
+ if (flags & MARK)
+ fac = LOG_NFACILITIES;
+ else
+ fac = LOG_FAC(pri);
+ prilev = LOG_PRI(pri);
+
+ /* log the message to the particular outputs */
+ if (!Initialized) {
+ f = &consfile;
+ f->f_file = open(ctty, O_WRONLY, 0);
+
+ if (f->f_file >= 0) {
+ fprintlog(f, flags, msg);
+ (void) close(f->f_file);
+ }
+ (void) sigsetmask(omask);
+ return;
+ }
+ for (f = Files; f; f = f->f_next) {
+ /* skip messages that are incorrect priority */
+ if (f->f_pmask[fac] < prilev ||
+ f->f_pmask[fac] == INTERNAL_NOPRI)
+ continue;
+
+ if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
+ continue;
+
+ /* don't output marks to recently written files */
+ if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
+ continue;
+
+ /*
+ * suppress duplicate lines to this file
+ */
+ if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
+ !strcmp(msg, f->f_prevline) &&
+ !strcmp(from, f->f_prevhost)) {
+ (void) strncpy(f->f_lasttime, timestamp, 15);
+ f->f_prevcount++;
+ dprintf("msg repeated %d times, %ld sec of %d\n",
+ f->f_prevcount, now - f->f_time,
+ repeatinterval[f->f_repeatcount]);
+ /*
+ * If domark would have logged this by now,
+ * flush it now (so we don't hold isolated messages),
+ * but back off so we'll flush less often
+ * in the future.
+ */
+ if (now > REPEATTIME(f)) {
+ fprintlog(f, flags, (char *)NULL);
+ BACKOFF(f);
+ }
+ } else {
+ /* new line, save it */
+ if (f->f_prevcount)
+ fprintlog(f, 0, (char *)NULL);
+ f->f_repeatcount = 0;
+ f->f_prevpri = pri;
+ (void) strncpy(f->f_lasttime, timestamp, 15);
+ (void) strncpy(f->f_prevhost, from,
+ sizeof(f->f_prevhost));
+ if (msglen < MAXSVLINE) {
+ f->f_prevlen = msglen;
+ (void) strcpy(f->f_prevline, msg);
+ fprintlog(f, flags, (char *)NULL);
+ } else {
+ f->f_prevline[0] = 0;
+ f->f_prevlen = 0;
+ fprintlog(f, flags, msg);
+ }
+ }
+ }
+ (void) sigsetmask(omask);
+}
+
+fprintlog(f, flags, msg)
+ register struct filed *f;
+ int flags;
+ char *msg;
+{
+ struct iovec iov[6];
+ register struct iovec *v;
+ register int l;
+ char line[MAXLINE + 1], repbuf[80], greetings[200];
+
+ v = iov;
+ if (f->f_type == F_WALL) {
+ v->iov_base = greetings;
+ v->iov_len = sprintf(greetings,
+ "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
+ f->f_prevhost, ctime(&now));
+ v++;
+ v->iov_base = "";
+ v->iov_len = 0;
+ v++;
+ } else {
+ v->iov_base = f->f_lasttime;
+ v->iov_len = 15;
+ v++;
+ v->iov_base = " ";
+ v->iov_len = 1;
+ v++;
+ }
+ v->iov_base = f->f_prevhost;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ v->iov_base = " ";
+ v->iov_len = 1;
+ v++;
+
+ if (msg) {
+ v->iov_base = msg;
+ v->iov_len = strlen(msg);
+ } else if (f->f_prevcount > 1) {
+ v->iov_base = repbuf;
+ v->iov_len = sprintf(repbuf, "last message repeated %d times",
+ f->f_prevcount);
+ } else {
+ v->iov_base = f->f_prevline;
+ v->iov_len = f->f_prevlen;
+ }
+ v++;
+
+ dprintf("Logging to %s", TypeNames[f->f_type]);
+ f->f_time = now;
+
+ switch (f->f_type) {
+ case F_UNUSED:
+ dprintf("\n");
+ break;
+
+ case F_FORW:
+ dprintf(" %s\n", f->f_un.f_forw.f_hname);
+ l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
+ iov[0].iov_base, iov[4].iov_base);
+ if (l > MAXLINE)
+ l = MAXLINE;
+ if (sendto(finet, line, l, 0,
+ (struct sockaddr *)&f->f_un.f_forw.f_addr,
+ sizeof f->f_un.f_forw.f_addr) != l) {
+ int e = errno;
+ (void) close(f->f_file);
+ f->f_type = F_UNUSED;
+ errno = e;
+ logerror("sendto");
+ }
+ break;
+
+ case F_CONSOLE:
+ if (flags & IGN_CONS) {
+ dprintf(" (ignored)\n");
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case F_TTY:
+ case F_FILE:
+ dprintf(" %s\n", f->f_un.f_fname);
+ if (f->f_type != F_FILE) {
+ v->iov_base = "\r\n";
+ v->iov_len = 2;
+ } else {
+ v->iov_base = "\n";
+ v->iov_len = 1;
+ }
+ again:
+ if (writev(f->f_file, iov, 6) < 0) {
+ int e = errno;
+ (void) close(f->f_file);
+ /*
+ * Check for errors on TTY's due to loss of tty
+ */
+ if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
+ f->f_file = open(f->f_un.f_fname,
+ O_WRONLY|O_APPEND, 0);
+ if (f->f_file < 0) {
+ f->f_type = F_UNUSED;
+ logerror(f->f_un.f_fname);
+ } else
+ goto again;
+ } else {
+ f->f_type = F_UNUSED;
+ errno = e;
+ logerror(f->f_un.f_fname);
+ }
+ } else if (flags & SYNC_FILE)
+ (void) fsync(f->f_file);
+ break;
+
+ case F_USERS:
+ case F_WALL:
+ dprintf("\n");
+ v->iov_base = "\r\n";
+ v->iov_len = 2;
+ wallmsg(f, iov);
+ break;
+ }
+ f->f_prevcount = 0;
+}
+
+/*
+ * WALLMSG -- Write a message to the world at large
+ *
+ * Write the specified message to either the entire
+ * world, or a list of approved users.
+ */
+
+wallmsg(f, iov)
+ register struct filed *f;
+ struct iovec *iov;
+{
+ static int reenter; /* avoid calling ourselves */
+ register FILE *uf;
+ register int i;
+ struct utmp ut;
+ char *p, *ttymsg();
+
+ if (reenter++)
+ return;
+ if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
+ logerror(_PATH_UTMP);
+ reenter = 0;
+ return;
+ }
+ /* NOSTRICT */
+ while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
+ if (ut.ut_name[0] == '\0')
+ continue;
+ if (f->f_type == F_WALL) {
+ if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
+ errno = 0; /* already in msg */
+ logerror(p);
+ }
+ continue;
+ }
+ /* should we send the message to this user? */
+ for (i = 0; i < MAXUNAMES; i++) {
+ if (!f->f_un.f_uname[i][0])
+ break;
+ if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
+ UT_NAMESIZE)) {
+ if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
+ errno = 0; /* already in msg */
+ logerror(p);
+ }
+ break;
+ }
+ }
+ }
+ (void) fclose(uf);
+ reenter = 0;
+}
+
+void
+reapchild()
+{
+ union wait status;
+
+ while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
+ ;
+}
+
+/*
+ * Return a printable representation of a host address.
+ */
+char *
+cvthname(f)
+ struct sockaddr_in *f;
+{
+ struct hostent *hp;
+ register char *p;
+ extern char *inet_ntoa();
+
+ dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
+
+ if (f->sin_family != AF_INET) {
+ dprintf("Malformed from address\n");
+ return ("???");
+ }
+ hp = gethostbyaddr((char *)&f->sin_addr,
+ sizeof(struct in_addr), f->sin_family);
+ if (hp == 0) {
+ dprintf("Host name for your address (%s) unknown\n",
+ inet_ntoa(f->sin_addr));
+ return (inet_ntoa(f->sin_addr));
+ }
+ if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
+ *p = '\0';
+ return (hp->h_name);
+}
+
+void
+domark()
+{
+ register struct filed *f;
+ time_t time();
+
+ now = time((time_t *)NULL);
+ MarkSeq += TIMERINTVL;
+ if (MarkSeq >= MarkInterval) {
+ logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
+ MarkSeq = 0;
+ }
+
+ for (f = Files; f; f = f->f_next) {
+ if (f->f_prevcount && now >= REPEATTIME(f)) {
+ dprintf("flush %s: repeated %d times, %d sec.\n",
+ TypeNames[f->f_type], f->f_prevcount,
+ repeatinterval[f->f_repeatcount]);
+ fprintlog(f, 0, (char *)NULL);
+ BACKOFF(f);
+ }
+ }
+ (void) alarm(TIMERINTVL);
+}
+
+/*
+ * Print syslogd errors some place.
+ */
+logerror(type)
+ char *type;
+{
+ char buf[100], *strerror();
+
+ if (errno)
+ (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
+ else
+ (void) sprintf(buf, "syslogd: %s", type);
+ errno = 0;
+ dprintf("%s\n", buf);
+ logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
+}
+
+void
+die(sig)
+{
+ register struct filed *f;
+ char buf[100];
+
+ for (f = Files; f != NULL; f = f->f_next) {
+ /* flush any pending output */
+ if (f->f_prevcount)
+ fprintlog(f, 0, (char *)NULL);
+ }
+ if (sig) {
+ dprintf("syslogd: exiting on signal %d\n", sig);
+ (void) sprintf(buf, "exiting on signal %d", sig);
+ errno = 0;
+ logerror(buf);
+ }
+ (void) unlink(LogName);
+ exit(0);
+}
+
+/*
+ * INIT -- Initialize syslogd from configuration table
+ */
+
+void
+init()
+{
+ register int i;
+ register FILE *cf;
+ register struct filed *f, *next, **nextp;
+ register char *p;
+ char cline[BUFSIZ];
+
+ dprintf("init\n");
+
+ /*
+ * Close all open log files.
+ */
+ Initialized = 0;
+ for (f = Files; f != NULL; f = next) {
+ /* flush any pending output */
+ if (f->f_prevcount)
+ fprintlog(f, 0, (char *)NULL);
+
+ switch (f->f_type) {
+ case F_FILE:
+ case F_TTY:
+ case F_CONSOLE:
+ case F_FORW:
+ (void) close(f->f_file);
+ break;
+ }
+ next = f->f_next;
+ free((char *) f);
+ }
+ Files = NULL;
+ nextp = &Files;
+
+ /* open the configuration file */
+ if ((cf = fopen(ConfFile, "r")) == NULL) {
+ dprintf("cannot open %s\n", ConfFile);
+ *nextp = (struct filed *)calloc(1, sizeof(*f));
+ cfline("*.ERR\t/dev/console", *nextp);
+ (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
+ cfline("*.PANIC\t*", (*nextp)->f_next);
+ Initialized = 1;
+ return;
+ }
+
+ /*
+ * Foreach line in the conf table, open that file.
+ */
+ f = NULL;
+ while (fgets(cline, sizeof cline, cf) != NULL) {
+ /*
+ * check for end-of-section, comments, strip off trailing
+ * spaces and newline character.
+ */
+ for (p = cline; isspace(*p); ++p);
+ if (*p == NULL || *p == '#')
+ continue;
+ for (p = index(cline, '\0'); isspace(*--p););
+ *++p = '\0';
+ f = (struct filed *)calloc(1, sizeof(*f));
+ *nextp = f;
+ nextp = &f->f_next;
+ cfline(cline, f);
+ }
+
+ /* close the configuration file */
+ (void) fclose(cf);
+
+ Initialized = 1;
+
+ if (Debug) {
+ for (f = Files; f; f = f->f_next) {
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (f->f_pmask[i] == INTERNAL_NOPRI)
+ printf("X ");
+ else
+ printf("%d ", f->f_pmask[i]);
+ printf("%s: ", TypeNames[f->f_type]);
+ switch (f->f_type) {
+ case F_FILE:
+ case F_TTY:
+ case F_CONSOLE:
+ printf("%s", f->f_un.f_fname);
+ break;
+
+ case F_FORW:
+ printf("%s", f->f_un.f_forw.f_hname);
+ break;
+
+ case F_USERS:
+ for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
+ printf("%s, ", f->f_un.f_uname[i]);
+ break;
+ }
+ printf("\n");
+ }
+ }
+
+ logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
+ dprintf("syslogd: restarted\n");
+}
+
+/*
+ * Crack a configuration file line
+ */
+
+cfline(line, f)
+ char *line;
+ register struct filed *f;
+{
+ register char *p;
+ register char *q;
+ register int i;
+ char *bp;
+ int pri;
+ struct hostent *hp;
+ char buf[MAXLINE], ebuf[100];
+
+ dprintf("cfline(%s)\n", line);
+
+ errno = 0; /* keep strerror() stuff out of logerror messages */
+
+ /* clear out file entry */
+ bzero((char *) f, sizeof *f);
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ f->f_pmask[i] = INTERNAL_NOPRI;
+
+ /* scan through the list of selectors */
+ for (p = line; *p && *p != '\t';) {
+
+ /* find the end of this facility name list */
+ for (q = p; *q && *q != '\t' && *q++ != '.'; )
+ continue;
+
+ /* collect priority name */
+ for (bp = buf; *q && !index("\t,;", *q); )
+ *bp++ = *q++;
+ *bp = '\0';
+
+ /* skip cruft */
+ while (index(", ;", *q))
+ q++;
+
+ /* decode priority name */
+ if (*buf == '*')
+ pri = LOG_PRIMASK + 1;
+ else {
+ pri = decode(buf, prioritynames);
+ if (pri < 0) {
+ (void) sprintf(ebuf,
+ "unknown priority name \"%s\"", buf);
+ logerror(ebuf);
+ return;
+ }
+ }
+
+ /* scan facilities */
+ while (*p && !index("\t.;", *p)) {
+ for (bp = buf; *p && !index("\t,;.", *p); )
+ *bp++ = *p++;
+ *bp = '\0';
+ if (*buf == '*')
+ for (i = 0; i < LOG_NFACILITIES; i++)
+ f->f_pmask[i] = pri;
+ else {
+ i = decode(buf, facilitynames);
+ if (i < 0) {
+ (void) sprintf(ebuf,
+ "unknown facility name \"%s\"",
+ buf);
+ logerror(ebuf);
+ return;
+ }
+ f->f_pmask[i >> 3] = pri;
+ }
+ while (*p == ',' || *p == ' ')
+ p++;
+ }
+
+ p = q;
+ }
+
+ /* skip to action part */
+ while (*p == '\t')
+ p++;
+
+ switch (*p)
+ {
+ case '@':
+ if (!InetInuse)
+ break;
+ (void) strcpy(f->f_un.f_forw.f_hname, ++p);
+ hp = gethostbyname(p);
+ if (hp == NULL) {
+ extern int h_errno;
+
+ logerror(hstrerror(h_errno));
+ break;
+ }
+ bzero((char *) &f->f_un.f_forw.f_addr,
+ sizeof f->f_un.f_forw.f_addr);
+ f->f_un.f_forw.f_addr.sin_family = AF_INET;
+ f->f_un.f_forw.f_addr.sin_port = LogPort;
+ bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
+ f->f_type = F_FORW;
+ break;
+
+ case '/':
+ (void) strcpy(f->f_un.f_fname, p);
+ if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
+ f->f_file = F_UNUSED;
+ logerror(p);
+ break;
+ }
+ if (isatty(f->f_file))
+ f->f_type = F_TTY;
+ else
+ f->f_type = F_FILE;
+ if (strcmp(p, ctty) == 0)
+ f->f_type = F_CONSOLE;
+ break;
+
+ case '*':
+ f->f_type = F_WALL;
+ break;
+
+ default:
+ for (i = 0; i < MAXUNAMES && *p; i++) {
+ for (q = p; *q && *q != ','; )
+ q++;
+ (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
+ if ((q - p) > UT_NAMESIZE)
+ f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
+ else
+ f->f_un.f_uname[i][q - p] = '\0';
+ while (*q == ',' || *q == ' ')
+ q++;
+ p = q;
+ }
+ f->f_type = F_USERS;
+ break;
+ }
+}
+
+
+/*
+ * Decode a symbolic name to a numeric value
+ */
+
+decode(name, codetab)
+ char *name;
+ CODE *codetab;
+{
+ register CODE *c;
+ register char *p;
+ char buf[40];
+
+ if (isdigit(*name))
+ return (atoi(name));
+
+ (void) strcpy(buf, name);
+ for (p = buf; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+ for (c = codetab; c->c_name; c++)
+ if (!strcmp(buf, c->c_name))
+ return (c->c_val);
+
+ return (-1);
+}
diff --git a/usr.sbin/tcpdump/CHANGES b/usr.sbin/tcpdump/CHANGES
new file mode 100644
index 00000000000..78281761384
--- /dev/null
+++ b/usr.sbin/tcpdump/CHANGES
@@ -0,0 +1,197 @@
+$NetBSD: CHANGES,v 1.2 1995/03/06 19:09:42 mycroft Exp $
+@(#) Header: CHANGES,v 1.6 94/06/20 19:34:38 leres Exp (LBL)
+
+v3.0 Mon Jun 20 19:23:27 PDT 1994
+
+- Reorganize protocol dumpers to take const pointers to packets so they
+ never change the contents (i.e., they used to do endian conversions
+ in place). Previously, whenever more than one pass was taken over
+ the packet, the packet contents would be dumped incorrectly (i.e.,
+ the output form -x would be wrong on little endian machines because
+ the protocol dumpers would modify the data). Thanks to Charles Hannum
+ (mycroft@gnu.ai.mit.edu) for reporting this problem.
+
+- Added support for decnet protocol dumping thanks to Jeff Mogul
+ (mogul@pa.dec.com).
+
+- Fix bug that caused length of packet to be incorrectly printed
+ (off by ether header size) for unknown ethernet types thanks
+ to Greg Miller (gmiller@kayak.mitre.org).
+
+- Added support for IPX protocol dumping thanks to Brad Parker
+ (brad@fcr.com).
+
+- Added check to verify IP header checksum under -v thanks to
+ Brad Parker (brad@fcr.com).
+
+- Move packet capture code to new libpcap library (which is
+ packaged separately).
+
+- Prototype everything and assume an ansi compiler.
+
+- print-arp.c: Print hardware ethernet addresses if they're not
+ what we expect.
+
+- print-bootp.c: Decode the cmu vendor field. Add RFC1497 tags.
+ Many helpful suggestions from Gordon Ross (gwr@jericho.mc.com).
+
+- print-fddi.c: Improvements. Thanks to Jeffrey Mogul
+ (mogul@pa.dec.com).
+
+- print-icmp.c: Byte swap netmask before printing. Thanks to
+ Richard Stevens (rstevens@noao.edu). Print icmp type when unknown.
+
+- print-ip.c: Print the inner ip datagram of ip-in-ip encapsulated packets.
+ By default, only the inner packet is dumped, appended with the token
+ "(encap)". Under -v, both the inner and output packets are dumped
+ (on the same line). Note that the filter applies to the original packet,
+ not the encapsulated packet. So if you run tcpdump on a net with an
+ IP Multicast tunnel, you cannot filter out the datagrams using the
+ conventional syntax. (You can filter away all the ip-in-ip traffic
+ with "not ip proto 4".)
+
+- print-nfs.c: Keep pending rpc's in circular table. Add generic
+ nfs header and remove os dependences. Thanks to Jeffrey Mogul.
+
+- print-ospf.c: Improvements. Thanks to Jeffrey Mogul.
+
+- tcpdump.c: Add -T flag allows interpretation of "vat", "wb", "rpc"
+ (sunrpc) and rtp packets. Added "inbound" and "outbound" keywords
+ Add && and || operators
+
+v2.2.1 Tue Jun 6 17:57:22 PDT 1992
+
+- Fix bug with -c flag.
+
+v2.2 Fri May 22 17:19:41 PDT 1992
+
+- savefile.c: Remove hack that shouldn't have been exported. Add
+ truncate checks.
+
+- Added the 'icmp' keyword. For example, 'icmp[0] != 8 and icmp[0] != 0'
+ matches non-echo/reply ICMP packets.
+
+- Many improvements to filter code optimizer.
+
+- Added 'multicast' keyword and extended the 'broadcast' keyword can now be
+ so that protocol qualitfications are allowed. For example, "ip broadcast"
+ and "ether multicast" are valid filters.
+
+- Added support for monitoring the loopback interface (i.e. 'tcpdump -i lo').
+ Jeffrey Honig (jch@MITCHELL.CIT.CORNELL.EDU) contributed the kernel
+ patches to netinet/if_loop.c.
+
+- Added support for the Ungermann-Bass Ethernet on IBM/PC-RTs running AOS.
+ Contact Jeffrey Honig (jch@MITCHELL.CIT.CORNELL.EDU) for the diffs.
+
+- Added EGP and OSPF printers, thanks to Jeffrey Honig.
+
+v2.1 Tue Jan 28 11:00:14 PST 1992
+
+- Internal release (never publically exported).
+
+v2.0.1 Sun Jan 26 21:10:10 PDT
+
+- Various byte ordering fixes.
+
+- Add truncation checks.
+
+- inet.c: Support BSD style SIOCGIFCONF.
+
+- nametoaddr.c: Handle multi addresses for single host.
+
+- optimize.c: Rewritten.
+
+- pcap-bpf.c: don't choke when we get ptraced. only set promiscuous
+ for broadcast nets.
+
+- print-atal.c: Fix an alignment bug (thanks to
+ stanonik@nprdc.navy.mil) Add missing printf() argument.
+
+- print-bootp.c: First attempt at decoding the vendor buffer.
+
+- print-domain.c: Fix truncation checks.
+
+- print-icmp.c: Calculate length of packets from the ip header.
+
+- print-ip.c: Print frag id in decimal (so it's easier to match up
+ with non-frags). Add support for ospf, egp and igmp.
+
+- print-nfs.c: Lots of changes.
+
+- print-ntp.c: Make some verbose output depend on -v.
+
+- print-snmp.c: New version from John LoVerso.
+
+- print-tcp.c: Print rfc1072 tcp options.
+
+- tcpdump.c: Print "0x" prefix for %x formats. Always print 6 digits
+ (microseconds) worth of precision. Fix uid bugs.
+
+- A packet dumper has been added (thanks to Jeff Mogul of DECWRL).
+ With this option, you can create an architecture independent binary
+ trace file in real time, without the overhead of the packet printer.
+ At a later time, the packets can be filtered (again) and printed.
+
+- BSD is supported. You must have BPF in your kernel.
+ Since the filtering is now done in the kernel, fewer packets are
+ dropped. In fact, with BPF and the packet dumper option, a measly
+ Sun 3/50 can keep up with a busy network.
+
+- Compressed SLIP packets can now be dumped, provided you use our
+ SLIP software and BPF. These packets are dumped as any other IP
+ packet; the compressed headers are dumped with the '-e' option.
+
+- Machines with little-endian byte ordering are supported (thanks to
+ Jeff Mogul).
+
+- Ultrix 4.0 is supported (also thanks to Jeff Mogul).
+
+- IBM RT and Stanford Enetfilter support has been added by
+ Rayan Zachariassen <rayan@canet.ca>. Tcpdump has been tested under
+ both the vanilla Enetfilter interface, and the extended interface
+ (#ifdef'd by IBMRTPC) present in the MERIT version of the Enetfilter.
+
+- TFTP packets are now printed (requests only).
+
+- BOOTP packets are now printed.
+
+- SNMP packets are now printed. (thanks to John LoVerso of Xylogics).
+
+- Sparc architectures, including the Sparcstation-1, are now
+ supported thanks to Steve McCanne and Craig Leres.
+
+- SunOS 4 is now supported thanks to Micky Liu of Columbia
+ University (micky@cunixc.cc.columbia.edu).
+
+- IP options are now printed.
+
+- RIP packets are now printed.
+
+- There's a -v flag that prints out more information than the
+ default (e.g., it will enable printing of IP ttl, tos and id)
+ and -q flag that prints out less (e.g., it will disable
+ interpretation of AppleTalk-in-UDP).
+
+- The grammar has undergone substantial changes (if you have an
+ earlier version of tcpdump, you should re-read the manual
+ entry).
+
+ The most useful change is the addition of an expression
+ syntax that lets you filter on arbitrary fields or values in the
+ packet. E.g., "ip[0] > 0x45" would print only packets with IP
+ options, "tcp[13] & 3 != 0" would print only TCP SYN and FIN
+ packets.
+
+ The most painful change is that concatenation no longer means
+ "and" -- e.g., you have to say "host foo and port bar" instead
+ of "host foo port bar". The up side to this down is that
+ repeated qualifiers can be omitted, making most filter
+ expressions shorter. E.g., you can now say "ip host foo and
+ (bar or baz)" to look at ip traffic between hosts foo and bar or
+ between hosts foo and baz. [The old way of saying this was "ip
+ host foo and (ip host bar or ip host baz)".]
+
+v2.0 Sun Jan 13 12:20:40 PST 1991
+
+- Initial public release.
diff --git a/usr.sbin/tcpdump/Makefile b/usr.sbin/tcpdump/Makefile
new file mode 100644
index 00000000000..9d9f4dd4fa2
--- /dev/null
+++ b/usr.sbin/tcpdump/Makefile
@@ -0,0 +1,43 @@
+# $NetBSD: Makefile,v 1.6 1995/03/07 23:18:39 mycroft Exp $
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+# retain the above copyright notice and this paragraph in its entirety, (2)
+# distributions including binary code include the above copyright notice and
+# this paragraph in its entirety in the documentation or other materials
+# provided with the distribution, and (3) all advertising materials mentioning
+# features or use of this software display the following acknowledgement:
+# ``This product includes software developed by the University of California,
+# Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+# @(#) $Header: /home/cvs/src/usr.sbin/tcpdump/Makefile,v 1.1.1.1 1995/10/18 08:48:23 deraadt Exp $ (LBL)
+
+PROG= tcpdump
+MAN= tcpdump.8
+
+CFLAGS+=-DCSLIP -DPPP -DFDDI -DETHER_SERVICE
+
+LDADD+= -lpcap -ll
+DPADD+= ${LIBL} ${LIBPCAP}
+
+SRCS= tcpdump.c addrtoname.c \
+ print-ether.c print-ip.c print-arp.c print-tcp.c print-udp.c \
+ print-atalk.c print-domain.c print-tftp.c print-bootp.c print-nfs.c \
+ print-icmp.c print-sl.c print-ppp.c print-rip.c \
+ print-snmp.c print-ntp.c print-null.c print-egp.c print-ospf.c \
+ print-fddi.c print-llc.c print-sunrpc.c \
+ print-wb.c print-decnet.c print-isoclns.c print-ipx.c \
+ util.c bpf_dump.c parsenfsfh.c version.c
+
+AWKS = atime.awk packetdat.awk send-ack.awk stime.awk
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/tcpdump/README b/usr.sbin/tcpdump/README
new file mode 100644
index 00000000000..b88305fd35d
--- /dev/null
+++ b/usr.sbin/tcpdump/README
@@ -0,0 +1,209 @@
+$NetBSD: README,v 1.3 1995/03/07 23:18:35 mycroft Exp $
+@(#) Header: README,v 1.39 94/06/20 20:15:16 leres Exp (LBL)
+
+TCPDUMP 3.0
+Lawrence Berkeley Laboratory
+Network Research Group
+tcpdump@ee.lbl.gov
+ftp://ftp.ee.lbl.gov/tcpdump-*.tar.Z
+
+This directory contains source code for tcpdump, a tool for network
+monitoring and data acquisition. The original distribution is
+available via anonymous ftp to ftp.ee.lbl.gov, in tcpdump-*.tar.Z.
+
+Tcpdump now uses libcap, a system-independent interface for
+user-level packet capture. Before building tcpdump, you must
+first retrieve and build libpcap, also from LBL, in:
+
+ ftp://ftp.ee.lbl.gov/libpcap-*.tar.Z.
+
+Once libpcap is built (either install it or make sure it's in
+../libpcap), you can build tcpdump using the procedure in the INSTALL
+file.
+
+Tcpdump and libpcap have been built and tested under SGI Irix 4.x & 5.2,
+SunOS 4.x, Solaris 2.3, BSD/386 v1.1, DEC/OSF v1.3 v2.0, and Ultrix 4.x.
+SunOS 3.5, 4.3BSD Reno/Tahoe and 4.4BSD are supported as well, but we
+currently do not have the resources to carry out testing in these
+environments (we suspect you'll run into problems building the most
+recent version under these systems -- please send us the patches if
+you fix any porting problems).
+
+Tcpdump has reportedly been ported to Mach 3.0 and Linux, but we have
+not received patches to integrate back into the master source tree.
+
+The program is loosely based on SMI's "etherfind" although none
+of the etherfind code remains. It was originally written by Van
+Jacobson as part of an ongoing research project to investigate and
+improve tcp and internet gateway performance. The parts of the
+program originally taken from Sun's etherfind were later re-written
+by Steven McCanne of LBL. To insure that there would be no vestige
+of proprietary code in tcpdump, Steve wrote these pieces from the
+specification given by the manual entry, with no access to the
+source of tcpdump or etherfind.
+
+Over the past few years, tcpdump has been steadily improved
+by the excellent contributions from the Internet community
+(just browse through the CHANGES file). We are grateful for
+all the input.
+
+Richard Stevens gives an excellent treatment of the Internet
+protocols in his book ``TCP/IP Illustrated, Volume 1''.
+If you want to learn more about tcpdump and how to interpret
+it's output, pick up this book.
+
+Problems, bugs, questions, desirable enhancements, etc., should be
+sent to the email address "tcpdump@ee.lbl.gov".
+
+ - Steve McCanne (mccanne@ee.lbl.gov)
+ Craig Leres (leres@ee.lbl.gov)
+ Van Jacobson (van@ee.lbl.gov)
+-------------------------------------
+This directory also contains some short awk programs intended as
+examples of ways to reduce tcpdump data when you're tracking
+particular network problems:
+
+send-ack.awk
+ Simplifies the tcpdump trace for an ftp (or other unidirectional
+ tcp transfer). Since we assume that one host only sends and
+ the other only acks, all address information is left off and
+ we just note if the packet is a "send" or an "ack".
+
+ There is one output line per line of the original trace.
+ Field 1 is the packet time in decimal seconds, relative
+ to the start of the conversation. Field 2 is delta-time
+ from last packet. Field 3 is packet type/direction.
+ "Send" means data going from sender to receiver, "ack"
+ means an ack going from the receiver to the sender. A
+ preceding "*" indicates that the data is a retransmission.
+ A preceding "-" indicates a hole in the sequence space
+ (i.e., missing packet(s)), a "#" means an odd-size (not max
+ seg size) packet. Field 4 has the packet flags
+ (same format as raw trace). Field 5 is the sequence
+ number (start seq. num for sender, next expected seq number
+ for acks). The number in parens following an ack is
+ the delta-time from the first send of the packet to the
+ ack. A number in parens following a send is the
+ delta-time from the first send of the packet to the
+ current send (on duplicate packets only). Duplicate
+ sends or acks have a number in square brackets showing
+ the number of duplicates so far.
+
+ Here is a short sample from near the start of an ftp:
+ 3.00 0.20 send . 512
+ 3.20 0.20 ack . 1024 (0.20)
+ 3.20 0.00 send P 1024
+ 3.40 0.20 ack . 1536 (0.20)
+ 3.80 0.40 * send . 0 (3.80) [2]
+ 3.82 0.02 * ack . 1536 (0.62) [2]
+ Three seconds into the conversation, bytes 512 through 1023
+ were sent. 200ms later they were acked. Shortly thereafter
+ bytes 1024-1535 were sent and again acked after 200ms.
+ Then, for no apparent reason, 0-511 is retransmitted, 3.8
+ seconds after its initial send (the round trip time for this
+ ftp was 1sec, +-500ms). Since the receiver is expecting
+ 1536, 1536 is re-acked when 0 arrives.
+
+packetdat.awk
+ Computes chunk summary data for an ftp (or similar
+ unidirectional tcp transfer). [A "chunk" refers to
+ a chunk of the sequence space -- essentially the packet
+ sequence number divided by the max segment size.]
+
+ A summary line is printed showing the number of chunks,
+ the number of packets it took to send that many chunks
+ (if there are no lost or duplicated packets, the number
+ of packets should equal the number of chunks) and the
+ number of acks.
+
+ Following the summary line is one line of information
+ per chunk. The line contains eight fields:
+ 1 - the chunk number
+ 2 - the start sequence number for this chunk
+ 3 - time of first send
+ 4 - time of last send
+ 5 - time of first ack
+ 6 - time of last ack
+ 7 - number of times chunk was sent
+ 8 - number of times chunk was acked
+ (all times are in decimal seconds, relative to the start
+ of the conversation.)
+
+ As an example, here is the first part of the output for
+ an ftp trace:
+
+ # 134 chunks. 536 packets sent. 508 acks.
+ 1 1 0.00 5.80 0.20 0.20 4 1
+ 2 513 0.28 6.20 0.40 0.40 4 1
+ 3 1025 1.16 6.32 1.20 1.20 4 1
+ 4 1561 1.86 15.00 2.00 2.00 6 1
+ 5 2049 2.16 15.44 2.20 2.20 5 1
+ 6 2585 2.64 16.44 2.80 2.80 5 1
+ 7 3073 3.00 16.66 3.20 3.20 4 1
+ 8 3609 3.20 17.24 3.40 5.82 4 11
+ 9 4097 6.02 6.58 6.20 6.80 2 5
+
+ This says that 134 chunks were transferred (about 70K
+ since the average packet size was 512 bytes). It took
+ 536 packets to transfer the data (i.e., on the average
+ each chunk was transmitted four times). Looking at,
+ say, chunk 4, we see it represents the 512 bytes of
+ sequence space from 1561 to 2048. It was first sent
+ 1.86 seconds into the conversation. It was last
+ sent 15 seconds into the conversation and was sent
+ a total of 6 times (i.e., it was retransmitted every
+ 2 seconds on the average). It was acked once, 140ms
+ after it first arrived.
+
+stime.awk
+atime.awk
+ Output one line per send or ack, respectively, in the form
+ <time> <seq. number>
+ where <time> is the time in seconds since the start of the
+ transfer and <seq. number> is the sequence number being sent
+ or acked. I typically plot this data looking for suspicious
+ patterns.
+
+
+The problem I was looking at was the bulk-data-transfer
+throughput of medium delay network paths (1-6 sec. round trip
+time) under typical DARPA Internet conditions. The trace of the
+ftp transfer of a large file was used as the raw data source.
+The method was:
+
+ - On a local host (but not the Sun running tcpdump), connect to
+ the remote ftp.
+
+ - On the monitor Sun, start the trace going. E.g.,
+ tcpdump host local-host and remote-host and port ftp-data >tracefile
+
+ - On local, do either a get or put of a large file (~500KB),
+ preferably to the null device (to minimize effects like
+ closing the receive window while waiting for a disk write).
+
+ - When transfer is finished, stop tcpdump. Use awk to make up
+ two files of summary data (maxsize is the maximum packet size,
+ tracedata is the file of tcpdump tracedata):
+ awk -f send-ack.awk packetsize=avgsize tracedata >sa
+ awk -f packetdat.awk packetsize=avgsize tracedata >pd
+
+ - While the summary data files are printing, take a look at
+ how the transfer behaved:
+ awk -f stime.awk tracedata | xgraph
+ (90% of what you learn seems to happen in this step).
+
+ - Do all of the above steps several times, both directions,
+ at different times of day, with different protocol
+ implementations on the other end.
+
+ - Using one of the Unix data analysis packages (in my case,
+ S and Gary Perlman's Unix|Stat), spend a few months staring
+ at the data.
+
+ - Change something in the local protocol implementation and
+ redo the steps above.
+
+ - Once a week, tell your funding agent that you're discovering
+ wonderful things and you'll write up that research report
+ "real soon now".
+
diff --git a/usr.sbin/tcpdump/addrtoname.c b/usr.sbin/tcpdump/addrtoname.c
new file mode 100644
index 00000000000..d4e3aae843a
--- /dev/null
+++ b/usr.sbin/tcpdump/addrtoname.c
@@ -0,0 +1,724 @@
+/* $NetBSD: addrtoname.c,v 1.4 1995/04/24 13:27:39 cgd Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Internet, ethernet, port, and protocol string to address
+ * and address to string conversion routines
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: addrtoname.c,v 1.37 94/06/16 00:42:28 mccanne Exp (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "llc.h"
+
+static SIGRET nohostname(int);
+#ifdef ETHER_SERVICE
+struct ether_addr;
+extern int ether_ntohost(char *, struct ether_addr *);
+#endif
+
+/*
+ * hash tables for whatever-to-name translations
+ */
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+ u_int32 addr;
+ char *name;
+ struct hnamemem *nxt;
+};
+
+struct hnamemem hnametable[HASHNAMESIZE];
+struct hnamemem tporttable[HASHNAMESIZE];
+struct hnamemem uporttable[HASHNAMESIZE];
+struct hnamemem eprototable[HASHNAMESIZE];
+struct hnamemem dnaddrtable[HASHNAMESIZE];
+struct hnamemem llcsaptable[HASHNAMESIZE];
+
+struct enamemem {
+ u_short e_addr0;
+ u_short e_addr1;
+ u_short e_addr2;
+ char *e_name;
+ u_char *e_nsap; /* used only for nsaptable[] */
+ struct enamemem *e_nxt;
+};
+
+struct enamemem enametable[HASHNAMESIZE];
+struct enamemem nsaptable[HASHNAMESIZE];
+
+struct protoidmem {
+ u_long p_oui;
+ u_short p_proto;
+ char *p_name;
+ struct protoidmem *p_nxt;
+};
+
+struct protoidmem protoidtable[HASHNAMESIZE];
+
+/*
+ * A faster replacement for inet_ntoa().
+ */
+char *
+intoa(u_int32 addr)
+{
+ register char *cp;
+ register u_int byte;
+ register int n;
+ static char buf[sizeof(".xxx.xxx.xxx.xxx")];
+
+ NTOHL(addr);
+ cp = &buf[sizeof buf];
+ *--cp = '\0';
+
+ n = 4;
+ do {
+ byte = addr & 0xff;
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0) {
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0)
+ *--cp = byte + '0';
+ }
+ *--cp = '.';
+ addr >>= 8;
+ } while (--n > 0);
+
+ return cp + 1;
+}
+
+static u_int32 f_netmask;
+static u_int32 f_localnet;
+static u_int32 netmask;
+
+/*
+ * "getname" is written in this atrocious way to make sure we don't
+ * wait forever while trying to get hostnames from yp.
+ */
+#include <setjmp.h>
+
+jmp_buf getname_env;
+
+static SIGRET
+nohostname(int signo)
+{
+ longjmp(getname_env, 1);
+}
+
+/*
+ * Return a name for the IP address pointed to by ap. This address
+ * is assumed to be in network byte order.
+ */
+char *
+getname(const u_char *ap)
+{
+ register struct hostent *hp;
+ register char *cp;
+ u_int32 addr;
+ static struct hnamemem *p; /* static for longjmp() */
+
+#ifndef TCPDUMP_ALIGN
+ addr = *(const u_int32 *)ap;
+#else
+ /*
+ * Deal with alignment.
+ */
+ switch ((long)ap & 3) {
+
+ case 0:
+ addr = *(u_int32 *)ap;
+ break;
+
+ case 2:
+#if BYTE_ORDER == LITTLE_ENDIAN
+ addr = ((u_int32)*(u_short *)(ap + 2) << 16) |
+ (u_int32)*(u_short *)ap;
+#else
+ addr = ((u_int32)*(u_short *)ap << 16) |
+ (u_int32)*(u_short *)(ap + 2);
+#endif
+ break;
+
+ default:
+#if BYTE_ORDER == LITTLE_ENDIAN
+ addr = ((u_int32)ap[0] << 24) |
+ ((u_int32)ap[1] << 16) |
+ ((u_int32)ap[2] << 8) |
+ (u_int32)ap[3];
+#else
+ addr = ((u_int32)ap[3] << 24) |
+ ((u_int32)ap[2] << 16) |
+ ((u_int32)ap[1] << 8) |
+ (u_int32)ap[0];
+#endif
+ break;
+ }
+#endif
+ p = &hnametable[addr & (HASHNAMESIZE-1)];
+ for (; p->nxt; p = p->nxt) {
+ if (p->addr == addr)
+ return (p->name);
+ }
+ p->addr = addr;
+ p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
+
+ /*
+ * Only print names when:
+ * (1) -n was not given.
+ * (2) Address is foreign and -f was given. If -f was not
+ * present, f_netmask and f_local are 0 and the second
+ * test will succeed.
+ * (3) The host portion is not 0 (i.e., a network address).
+ * (4) The host portion is not broadcast.
+ */
+ if (!nflag && (addr & f_netmask) == f_localnet
+ && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) {
+ if (!setjmp(getname_env)) {
+ (void)signal(SIGALRM, nohostname);
+ (void)alarm(20);
+ hp = gethostbyaddr((char *)&addr, 4, AF_INET);
+ (void)alarm(0);
+ if (hp) {
+ char *dotp;
+
+ p->name = savestr(hp->h_name);
+ if (Nflag) {
+ /* Remove domain qualifications */
+ dotp = strchr(p->name, '.');
+ if (dotp)
+ *dotp = 0;
+ }
+ return (p->name);
+ }
+ }
+ }
+ cp = intoa(addr);
+ p->name = savestr(cp);
+ return (p->name);
+}
+
+static char hex[] = "0123456789abcdef";
+
+
+/* Find the hash node that corresponds the ether address 'ep'. */
+
+static inline struct enamemem *
+lookup_emem(const u_char *ep)
+{
+ register u_int i, j, k;
+ struct enamemem *tp;
+
+ k = (ep[0] << 8) | ep[1];
+ j = (ep[2] << 8) | ep[3];
+ i = (ep[4] << 8) | ep[5];
+
+ tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
+ while (tp->e_nxt)
+ if (tp->e_addr0 == i &&
+ tp->e_addr1 == j &&
+ tp->e_addr2 == k)
+ return tp;
+ else
+ tp = tp->e_nxt;
+ tp->e_addr0 = i;
+ tp->e_addr1 = j;
+ tp->e_addr2 = k;
+ tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
+
+ return tp;
+}
+
+/* Find the hash node that corresponds the NSAP 'nsap'. */
+
+static inline struct enamemem *
+lookup_nsap(register const u_char *nsap)
+{
+ register u_int i, j, k;
+ int nlen = *nsap;
+ struct enamemem *tp;
+ const u_char *ensap = nsap + nlen - 6;
+
+ if (nlen > 6) {
+ k = (ensap[0] << 8) | ensap[1];
+ j = (ensap[2] << 8) | ensap[3];
+ i = (ensap[4] << 8) | ensap[5];
+ }
+ else
+ i = j = k = 0;
+
+ tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
+ while (tp->e_nxt)
+ if (tp->e_addr0 == i &&
+ tp->e_addr1 == j &&
+ tp->e_addr2 == k &&
+ tp->e_nsap[0] == nlen &&
+ bcmp((char *)&(nsap[1]),
+ (char *)&(tp->e_nsap[1]), nlen) == 0)
+ return tp;
+ else
+ tp = tp->e_nxt;
+ tp->e_addr0 = i;
+ tp->e_addr1 = j;
+ tp->e_addr2 = k;
+ tp->e_nsap = (u_char *) calloc(1, nlen + 1);
+ bcopy(nsap, tp->e_nsap, nlen + 1);
+ tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
+
+ return tp;
+}
+
+/* Find the hash node that corresponds the protoid 'pi'. */
+
+static inline struct protoidmem *
+lookup_protoid(const u_char *pi)
+{
+ register u_int i, j;
+ struct protoidmem *tp;
+
+ /* 5 octets won't be aligned */
+ i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
+ j = (pi[3] << 8) + pi[4];
+ /* XXX should be endian-insensitive, but do big-endian testing XXX */
+
+ tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
+ while (tp->p_nxt)
+ if (tp->p_oui == i && tp->p_proto == j)
+ return tp;
+ else
+ tp = tp->p_nxt;
+ tp->p_oui = i;
+ tp->p_proto = j;
+ tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
+
+ return tp;
+}
+
+char *
+etheraddr_string(register const u_char *ep)
+{
+ register u_int i, j;
+ register char *cp;
+ register struct enamemem *tp;
+
+ tp = lookup_emem(ep);
+ if (tp->e_name)
+ return (tp->e_name);
+#ifdef ETHER_SERVICE
+ if (!nflag) {
+ char buf[128];
+ if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) {
+ tp->e_name = savestr(buf);
+ return (tp->e_name);
+ }
+ }
+#endif
+ tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
+
+ if ((j = *ep >> 4) != 0)
+ *cp++ = hex[j];
+ *cp++ = hex[*ep++ & 0xf];
+ for (i = 5; (int)--i >= 0;) {
+ *cp++ = ':';
+ if ((j = *ep >> 4) != 0)
+ *cp++ = hex[j];
+ *cp++ = hex[*ep++ & 0xf];
+ }
+ *cp = '\0';
+ return (tp->e_name);
+}
+
+char *
+etherproto_string(u_short port)
+{
+ register char *cp;
+ register struct hnamemem *tp;
+ register u_long i = port;
+
+ for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+ if (tp->addr == i)
+ return (tp->name);
+
+ tp->name = cp = (char *)malloc(sizeof("0000"));
+ tp->addr = i;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
+
+ NTOHS(port);
+ *cp++ = hex[port >> 12 & 0xf];
+ *cp++ = hex[port >> 8 & 0xf];
+ *cp++ = hex[port >> 4 & 0xf];
+ *cp++ = hex[port & 0xf];
+ *cp++ = '\0';
+ return (tp->name);
+}
+
+char *
+protoid_string(register const u_char *pi)
+{
+ register u_int i, j;
+ register char *cp;
+ register struct protoidmem *tp;
+
+ tp = lookup_protoid(pi);
+ if (tp->p_name)
+ return tp->p_name;
+
+ tp->p_name = cp = (char *)malloc(sizeof("00:00:00:00:00"));
+
+ if ((j = *pi >> 4) != 0)
+ *cp++ = hex[j];
+ *cp++ = hex[*pi++ & 0xf];
+ for (i = 4; (int)--i >= 0;) {
+ *cp++ = ':';
+ if ((j = *pi >> 4) != 0)
+ *cp++ = hex[j];
+ *cp++ = hex[*pi++ & 0xf];
+ }
+ *cp = '\0';
+ return (tp->p_name);
+}
+
+char *
+llcsap_string(u_char sap)
+{
+ register char *cp;
+ register struct hnamemem *tp;
+ register u_long i = sap;
+
+ for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+ if (tp->addr == i)
+ return (tp->name);
+
+ tp->name = cp = (char *)malloc(sizeof("sap 00"));
+ tp->addr = i;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
+
+ (void)strcpy(cp, "sap ");
+ cp += strlen(cp);
+ *cp++ = hex[sap >> 4 & 0xf];
+ *cp++ = hex[sap & 0xf];
+ *cp++ = '\0';
+ return (tp->name);
+}
+
+char *
+isonsap_string(const u_char *nsap)
+{
+ register u_int i, nlen = nsap[0];
+ register char *cp;
+ register struct enamemem *tp;
+
+ tp = lookup_nsap(nsap);
+ if (tp->e_name)
+ return tp->e_name;
+
+ tp->e_name = cp = (char *)malloc(nlen * 2 + 2);
+
+ nsap++;
+ *cp++ = '/';
+ for (i = nlen; (int)--i >= 0;) {
+ *cp++ = hex[*nsap >> 4];
+ *cp++ = hex[*nsap++ & 0xf];
+ }
+ *cp = '\0';
+ return (tp->e_name);
+}
+
+char *
+tcpport_string(u_short port)
+{
+ register struct hnamemem *tp;
+ register u_long i = port;
+
+ for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+ if (tp->addr == i)
+ return (tp->name);
+
+ tp->name = (char *)malloc(sizeof("00000"));
+ tp->addr = i;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
+
+ (void)sprintf(tp->name, "%d", i);
+ return (tp->name);
+}
+
+char *
+udpport_string(register u_short port)
+{
+ register struct hnamemem *tp;
+ register u_long i = port;
+
+ for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+ if (tp->addr == i)
+ return (tp->name);
+
+ tp->name = (char *)malloc(sizeof("00000"));
+ tp->addr = i;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+
+ (void)sprintf(tp->name, "%d", i);
+
+ return (tp->name);
+}
+
+static void
+init_servarray(void)
+{
+ struct servent *sv;
+ register struct hnamemem *table;
+ register int i;
+
+ while ((sv = getservent()) != NULL) {
+ int port = ntohs(sv->s_port);
+ i = port & (HASHNAMESIZE-1);
+ if (strcmp(sv->s_proto, "tcp") == 0)
+ table = &tporttable[i];
+ else if (strcmp(sv->s_proto, "udp") == 0)
+ table = &uporttable[i];
+ else
+ continue;
+
+ while (table->name)
+ table = table->nxt;
+ if (nflag) {
+ char buf[32];
+
+ (void)sprintf(buf, "%d", port);
+ table->name = savestr(buf);
+ } else
+ table->name = savestr(sv->s_name);
+ table->addr = port;
+ table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+ }
+ endservent();
+}
+
+/*XXX from libbpfc.a */
+extern struct eproto {
+ char *s;
+ u_short p;
+} eproto_db[];
+
+static void
+init_eprotoarray(void)
+{
+ register int i;
+ register struct hnamemem *table;
+
+ for (i = 0; eproto_db[i].s; i++) {
+ int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
+ table = &eprototable[j];
+ while (table->name)
+ table = table->nxt;
+ table->name = eproto_db[i].s;
+ table->addr = ntohs(eproto_db[i].p);
+ table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+ }
+}
+
+/*
+ * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
+ * types.
+ */
+static void
+init_protoidarray(void)
+{
+ register int i;
+ register struct protoidmem *tp;
+ u_char protoid[5];
+
+ protoid[0] = 0;
+ protoid[1] = 0;
+ protoid[2] = 0;
+ for (i = 0; eproto_db[i].s; i++) {
+ u_short etype = htons(eproto_db[i].p);
+ bcopy((char *)&etype, (char *)&protoid[3], 2);
+ tp = lookup_protoid(protoid);
+ tp->p_name = savestr(eproto_db[i].s);
+ }
+}
+
+static struct etherlist {
+ u_char addr[6];
+ char *name;
+} etherlist[] = {
+ {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
+};
+
+/*
+ * Initialize the ethers hash table. We take two different approaches
+ * depending on whether or not the system provides the ethers name
+ * service. If it does, we just wire in a few names at startup,
+ * and etheraddr_string() fills in the table on demand. If it doesn't,
+ * then we suck in the entire /etc/ethers file at startup. The idea
+ * is that parsing the local file will be fast, but spinning through
+ * all the ethers entries via NIS & next_etherent might be very slow.
+ *
+ * XXX pcap_next_etherent doesn't belong in the pcap interface, but
+ * since the pcap module already does name-to-address translation,
+ * it's already does most of the work for the ethernet address-to-name
+ * translation, so we just pcap_next_etherent as a convenience.
+ */
+static void
+init_etherarray(void)
+{
+ register struct etherlist *el;
+ register struct enamemem *tp;
+#ifndef ETHER_SERVICE
+ register struct pcap_etherent *ep;
+ register FILE *fp;
+
+ /* Suck in entire ethers file */
+ fp = fopen(PCAP_ETHERS_FILE, "r");
+ if (fp != NULL) {
+ while ((ep = pcap_next_etherent(fp)) != NULL) {
+ tp = lookup_emem(ep->addr);
+ tp->e_name = savestr(ep->name);
+ }
+ (void)fclose(fp);
+ }
+#endif
+
+ /* Hardwire some ethernet names */
+ for (el = etherlist; el->name != NULL; ++el) {
+#ifdef ETHER_SERVICE
+ /* Use yp/nis version of name if available */
+ char wrk[256];
+ if (ether_ntohost(wrk, (struct ether_addr *)el->addr) == 0) {
+ tp = lookup_emem(el->addr);
+ tp->e_name = savestr(wrk);
+ }
+#else
+ /* install if not already present */
+ tp = lookup_emem(el->addr);
+ if (tp->e_name == NULL)
+ tp->e_name = el->name;
+#endif
+
+ }
+}
+
+static struct token llcsap_db[] = {
+ { LLCSAP_NULL, "null" },
+ { LLCSAP_8021B_I, "802.1b-gsap" },
+ { LLCSAP_8021B_G, "802.1b-isap" },
+ { LLCSAP_IP, "ip-sap" },
+ { LLCSAP_PROWAYNM, "proway-nm" },
+ { LLCSAP_8021D, "802.1d" },
+ { LLCSAP_RS511, "eia-rs511" },
+ { LLCSAP_ISO8208, "x.25/llc2" },
+ { LLCSAP_PROWAY, "proway" },
+ { LLCSAP_ISONS, "iso-clns" },
+ { LLCSAP_GLOBAL, "global" },
+ { 0, NULL }
+};
+
+static void
+init_llcsaparray(void)
+{
+ register int i;
+ register struct hnamemem *table;
+
+ for (i = 0; llcsap_db[i].s != NULL; i++) {
+ table = &llcsaptable[llcsap_db[i].v];
+ while (table->name)
+ table = table->nxt;
+ table->name = llcsap_db[i].s;
+ table->addr = llcsap_db[i].v;
+ table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+ }
+}
+
+/*
+ * Initialize the address to name translation machinery. We map all
+ * non-local IP addresses to numeric addresses if fflag is true (i.e.,
+ * to prevent blocking on the nameserver). localnet is the IP address
+ * of the local network. mask is its subnet mask.
+ */
+void
+init_addrtoname(int fflag, u_int32 localnet, u_int32 mask)
+{
+ netmask = mask;
+ if (fflag) {
+ f_localnet = localnet;
+ f_netmask = mask;
+ }
+ if (nflag)
+ /*
+ * Simplest way to suppress names.
+ */
+ return;
+
+ init_etherarray();
+ init_servarray();
+ init_eprotoarray();
+ init_llcsaparray();
+ init_protoidarray();
+}
+
+char *
+dnaddr_string(u_short dnaddr)
+{
+ register struct hnamemem *tp;
+
+ for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0;
+ tp = tp->nxt)
+ if (tp->addr == dnaddr)
+ return (tp->name);
+
+ tp->addr = dnaddr;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+ if (nflag)
+ tp->name = dnnum_string(dnaddr);
+ else
+ tp->name = dnname_string(dnaddr);
+
+ return(tp->name);
+}
diff --git a/usr.sbin/tcpdump/addrtoname.h b/usr.sbin/tcpdump/addrtoname.h
new file mode 100644
index 00000000000..74a6ba0baa0
--- /dev/null
+++ b/usr.sbin/tcpdump/addrtoname.h
@@ -0,0 +1,37 @@
+/* $NetBSD: addrtoname.h,v 1.2 1995/03/06 19:09:50 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: addrtoname.h,v 1.11 94/06/14 20:11:41 leres Exp (LBL)
+ */
+
+/* Name to address translation routines. */
+
+extern char *etheraddr_string(const u_char *);
+extern char *etherproto_string(u_short);
+extern char *tcpport_string(u_short);
+extern char *udpport_string(u_short);
+extern char *getname(const u_char *);
+extern char *intoa(u_int32);
+
+extern void init_addrtoname(int, u_int32, u_int32);
+
+#define ipaddr_string(p) getname((const u_char *)(p))
diff --git a/usr.sbin/tcpdump/appletalk.h b/usr.sbin/tcpdump/appletalk.h
new file mode 100644
index 00000000000..d0941667d02
--- /dev/null
+++ b/usr.sbin/tcpdump/appletalk.h
@@ -0,0 +1,169 @@
+/* $NetBSD: appletalk.h,v 1.2 1995/03/06 19:09:51 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * AppleTalk protocol formats (courtesy Bill Croft of Stanford/SUMEX).
+ *
+ * @(#) Header: appletalk.h,v 1.10 94/06/14 20:11:44 leres Exp (LBL)
+ */
+
+struct LAP {
+ u_char dst;
+ u_char src;
+ u_char type;
+};
+#define lapShortDDP 1 /* short DDP type */
+#define lapDDP 2 /* DDP type */
+#define lapKLAP 'K' /* Kinetics KLAP type */
+
+/* Datagram Delivery Protocol */
+
+struct atDDP {
+ u_short length;
+ u_short checksum;
+ u_short dstNet;
+ u_short srcNet;
+ u_char dstNode;
+ u_char srcNode;
+ u_char dstSkt;
+ u_char srcSkt;
+ u_char type;
+};
+
+struct atShortDDP {
+ u_short length;
+ u_char dstSkt;
+ u_char srcSkt;
+ u_char type;
+};
+
+#define ddpMaxWKS 0x7F
+#define ddpMaxData 586
+#define ddpLengthMask 0x3FF
+#define ddpHopShift 10
+#define ddpSize 13 /* size of DDP header (avoid struct padding) */
+#define ddpSSize 5
+#define ddpWKS 128 /* boundary of DDP well known sockets */
+#define ddpRTMP 1 /* RTMP type */
+#define ddpRTMPrequest 5 /* RTMP request type */
+#define ddpNBP 2 /* NBP type */
+#define ddpATP 3 /* ATP type */
+#define ddpECHO 4 /* ECHO type */
+#define ddpIP 22 /* IP type */
+#define ddpARP 23 /* ARP type */
+#define ddpKLAP 0x4b /* Kinetics KLAP type */
+
+
+/* AppleTalk Transaction Protocol */
+
+struct atATP {
+ u_char control;
+ u_char bitmap;
+ u_short transID;
+ int32 userData;
+};
+
+#define atpReqCode 0x40
+#define atpRspCode 0x80
+#define atpRelCode 0xC0
+#define atpXO 0x20
+#define atpEOM 0x10
+#define atpSTS 0x08
+#define atpFlagMask 0x3F
+#define atpControlMask 0xF8
+#define atpMaxNum 8
+#define atpMaxData 578
+
+
+/* AppleTalk Echo Protocol */
+
+struct atEcho {
+ u_char echoFunction;
+ u_char *echoData;
+};
+
+#define echoSkt 4 /* the echoer socket */
+#define echoSize 1 /* size of echo header */
+#define echoRequest 1 /* echo request */
+#define echoReply 2 /* echo request */
+
+
+/* Name Binding Protocol */
+
+struct atNBP {
+ u_char control;
+ u_char id;
+};
+
+struct atNBPtuple {
+ u_short net;
+ u_char node;
+ u_char skt;
+ u_char enumerator;
+};
+
+#define nbpBrRq 0x10
+#define nbpLkUp 0x20
+#define nbpLkUpReply 0x30
+
+#define nbpNIS 2
+#define nbpTupleMax 15
+
+#define nbpHeaderSize 2
+#define nbpTupleSize 5
+
+#define nbpSkt 2 /* NIS */
+
+
+/* Routing Table Maint. Protocol */
+
+#define rtmpSkt 1 /* number of RTMP socket */
+#define rtmpSize 4 /* minimum size */
+#define rtmpTupleSize 3
+
+
+/* Zone Information Protocol */
+
+struct zipHeader {
+ u_char command;
+ u_char netcount;
+};
+
+#define zipHeaderSize 2
+#define zipQuery 1
+#define zipReply 2
+#define zipTakedown 3
+#define zipBringup 4
+#define ddpZIP 6
+#define zipSkt 6
+#define GetMyZone 7
+#define GetZoneList 8
+
+/*
+ * UDP port range used for ddp-in-udp encapsulation is 16512-16639
+ * for client sockets (128-255) and 200-327 for server sockets
+ * (0-127). We also try to recognize the pre-April 88 server
+ * socket range of 768-895.
+ */
+#define atalk_port(p) \
+ (((unsigned)((p) - 16512) < 128) || \
+ ((unsigned)((p) - 200) < 128) || \
+ ((unsigned)((p) - 768) < 128))
diff --git a/usr.sbin/tcpdump/atime.awk b/usr.sbin/tcpdump/atime.awk
new file mode 100644
index 00000000000..9f5d9d145a6
--- /dev/null
+++ b/usr.sbin/tcpdump/atime.awk
@@ -0,0 +1,20 @@
+# $NetBSD: atime.awk,v 1.2 1995/03/06 19:09:52 mycroft Exp $
+
+$6 ~ /^ack/ && $5 !~ /[SFR]/ {
+ # given a tcpdump ftp trace, output one line for each ack
+ # in the form
+ # <ack time> <seq no>
+ # where <ack time> is the time packet was acked (in seconds with
+ # zero at time of first packet) and <seq no> is the tcp sequence
+ # number of the ack divided by 1024 (i.e., Kbytes acked).
+ #
+ # convert time to seconds
+ n = split ($1,t,":")
+ tim = t[1]*3600 + t[2]*60 + t[3]
+ if (! tzero) {
+ tzero = tim
+ OFS = "\t"
+ }
+ # get packet sequence number
+ printf "%7.2f\t%g\n", tim-tzero, $7/1024
+ }
diff --git a/usr.sbin/tcpdump/bootp.h b/usr.sbin/tcpdump/bootp.h
new file mode 100644
index 00000000000..6e2a328f414
--- /dev/null
+++ b/usr.sbin/tcpdump/bootp.h
@@ -0,0 +1,111 @@
+/* $NetBSD: bootp.h,v 1.2 1995/03/06 19:09:54 mycroft Exp $ */
+
+/* @(#) Header: bootp.h,v 1.6 94/01/13 19:06:29 leres Exp (LBL) */
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1048.
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ * Copyright 1988 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University. Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+
+struct bootp {
+ unsigned char bp_op; /* packet opcode type */
+ unsigned char bp_htype; /* hardware addr type */
+ unsigned char bp_hlen; /* hardware addr length */
+ unsigned char bp_hops; /* gateway hops */
+ u_int32 bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_unused;
+ struct in_addr bp_ciaddr; /* client IP address */
+ struct in_addr bp_yiaddr; /* 'your' IP address */
+ struct in_addr bp_siaddr; /* server IP address */
+ struct in_addr bp_giaddr; /* gateway IP address */
+ unsigned char bp_chaddr[16]; /* client hardware address */
+ unsigned char bp_sname[64]; /* server host name */
+ unsigned char bp_file[128]; /* boot file name */
+ unsigned char bp_vend[64]; /* vendor-specific area */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define IPPORT_BOOTPS 67
+#define IPPORT_BOOTPC 68
+
+#define BOOTREPLY 2
+#define BOOTREQUEST 1
+
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048 { 99, 130, 83, 99 }
+
+
+
+/*
+ * RFC1048 tag values used to specify what information is being supplied in
+ * the vendor field of the packet.
+ */
+
+#define TAG_PAD ((unsigned char) 0)
+#define TAG_SUBNET_MASK ((unsigned char) 1)
+#define TAG_TIME_OFFSET ((unsigned char) 2)
+#define TAG_GATEWAY ((unsigned char) 3)
+#define TAG_TIME_SERVER ((unsigned char) 4)
+#define TAG_NAME_SERVER ((unsigned char) 5)
+#define TAG_DOMAIN_SERVER ((unsigned char) 6)
+#define TAG_LOG_SERVER ((unsigned char) 7)
+#define TAG_COOKIE_SERVER ((unsigned char) 8)
+#define TAG_LPR_SERVER ((unsigned char) 9)
+#define TAG_IMPRESS_SERVER ((unsigned char) 10)
+#define TAG_RLP_SERVER ((unsigned char) 11)
+#define TAG_HOSTNAME ((unsigned char) 12)
+#define TAG_BOOTSIZE ((unsigned char) 13)
+#define TAG_END ((unsigned char) 255)
+/* RFC1497 tags */
+#define TAG_DUMPPATH ((unsigned char) 14)
+#define TAG_DOMAINNAME ((unsigned char) 15)
+#define TAG_SWAP_SERVER ((unsigned char) 16)
+#define TAG_ROOTPATH ((unsigned char) 17)
+#define TAG_EXTPATH ((unsigned char) 18)
+
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ unsigned char v_magic[4]; /* magic number */
+ u_int32 v_flags; /* flags/opcodes, etc. */
+ struct in_addr v_smask; /* Subnet mask */
+ struct in_addr v_dgate; /* Default gateway */
+ struct in_addr v_dns1, v_dns2; /* Domain name servers */
+ struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
+ struct in_addr v_ts1, v_ts2; /* Time servers */
+ unsigned char v_unused[24]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/usr.sbin/tcpdump/bpf_dump.c b/usr.sbin/tcpdump/bpf_dump.c
new file mode 100644
index 00000000000..100d147db81
--- /dev/null
+++ b/usr.sbin/tcpdump/bpf_dump.c
@@ -0,0 +1,67 @@
+/* $NetBSD: bpf_dump.c,v 1.2 1995/03/06 19:09:55 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: bpf_dump.c,v 1.6 94/06/06 14:31:21 leres Exp (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <pcap.h>
+#include <stdio.h>
+
+#include "interface.h"
+
+extern void bpf_dump(struct bpf_program *, int);
+
+void
+bpf_dump(struct bpf_program *p, int option)
+{
+ struct bpf_insn *insn;
+ int i;
+ int n = p->bf_len;
+
+ insn = p->bf_insns;
+ if (option > 2) {
+ printf("%d\n", n);
+ for (i = 0; i < n; ++insn, ++i) {
+ printf("%lu %lu %lu %lu\n", insn->code,
+ insn->jt, insn->jf, insn->k);
+ }
+ return ;
+ }
+ if (option > 1) {
+ for (i = 0; i < n; ++insn, ++i)
+ printf("{ 0x%x, %d, %d, 0x%08x },\n",
+ insn->code, insn->jt, insn->jf, insn->k);
+ return;
+ }
+ for (i = 0; i < n; ++insn, ++i) {
+#ifdef BDEBUG
+ extern int bids[];
+ printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1);
+#endif
+ puts(bpf_image(insn, i));
+ }
+}
diff --git a/usr.sbin/tcpdump/decnet.h b/usr.sbin/tcpdump/decnet.h
new file mode 100644
index 00000000000..5965f77dfde
--- /dev/null
+++ b/usr.sbin/tcpdump/decnet.h
@@ -0,0 +1,482 @@
+/* $NetBSD: decnet.h,v 1.2 1995/03/06 19:09:58 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: decnet.h,v 1.3 94/06/14 20:11:44 leres Exp (LBL)
+ */
+
+typedef unsigned char byte[1]; /* single byte field */
+typedef unsigned char word[2]; /* 2 byte field */
+typedef unsigned char longword[4]; /* 4 bytes field */
+
+/*
+ * Definitions for DECNET Phase IV protocol headers
+ */
+union etheraddress {
+ unsigned char dne_addr[6]; /* full ethernet address */
+ struct {
+ unsigned char dne_hiord[4]; /* DECnet HIORD prefix */
+ unsigned char dne_nodeaddr[2]; /* DECnet node address */
+ } dne_remote;
+};
+
+typedef union etheraddress etheraddr; /* Ethernet address */
+
+#define HIORD 0x000400aa /* high 32-bits of address (swapped) */
+
+#define AREAMASK 0176000 /* mask for area field */
+#define AREASHIFT 10 /* bit-offset for area field */
+#define NODEMASK 01777 /* mask for node address field */
+
+#define DN_MAXADDL 20 /* max size of DECnet address */
+struct dn_naddr {
+ unsigned short a_len; /* length of address */
+ unsigned char a_addr[DN_MAXADDL]; /* address as bytes */
+};
+
+/*
+ * Define long and short header formats.
+ */
+struct shorthdr
+ {
+ byte sh_flags; /* route flags */
+ word sh_dst; /* destination node address */
+ word sh_src; /* source node address */
+ byte sh_visits; /* visit count */
+ };
+
+struct longhdr
+ {
+ byte lg_flags; /* route flags */
+ byte lg_darea; /* destination area (reserved) */
+ byte lg_dsarea; /* destination subarea (reserved) */
+ etheraddr lg_dst; /* destination id */
+ byte lg_sarea; /* source area (reserved) */
+ byte lg_ssarea; /* source subarea (reserved) */
+ etheraddr lg_src; /* source id */
+ byte lg_nextl2; /* next level 2 router (reserved) */
+ byte lg_visits; /* visit count */
+ byte lg_service; /* service class (reserved) */
+ byte lg_pt; /* protocol type (reserved) */
+ };
+
+union routehdr
+ {
+ struct shorthdr rh_short; /* short route header */
+ struct longhdr rh_long; /* long route header */
+ };
+
+/*
+ * Define the values of various fields in the protocol messages.
+ *
+ * 1. Data packet formats.
+ */
+#define RMF_MASK 7 /* mask for message type */
+#define RMF_SHORT 2 /* short message format */
+#define RMF_LONG 6 /* long message format */
+#ifndef RMF_RQR
+#define RMF_RQR 010 /* request return to sender */
+#define RMF_RTS 020 /* returning to sender */
+#define RMF_IE 040 /* intra-ethernet packet */
+#endif /* RMR_RQR */
+#define RMF_FVER 0100 /* future version flag */
+#define RMF_PAD 0200 /* pad field */
+#define RMF_PADMASK 0177 /* pad field mask */
+
+#define VIS_MASK 077 /* visit field mask */
+
+/*
+ * 2. Control packet formats.
+ */
+#define RMF_CTLMASK 017 /* mask for message type */
+#define RMF_CTLMSG 01 /* control message indicator */
+#define RMF_INIT 01 /* initialisation message */
+#define RMF_VER 03 /* verification message */
+#define RMF_TEST 05 /* hello and test message */
+#define RMF_L1ROUT 07 /* level 1 routing message */
+#define RMF_L2ROUT 011 /* level 2 routing message */
+#define RMF_RHELLO 013 /* router hello message */
+#define RMF_EHELLO 015 /* endnode hello message */
+
+#define TI_L2ROUT 01 /* level 2 router */
+#define TI_L1ROUT 02 /* level 1 router */
+#define TI_ENDNODE 03 /* endnode */
+#define TI_VERIF 04 /* verification required */
+#define TI_BLOCK 010 /* blocking requested */
+
+#define VE_VERS 2 /* version number (2) */
+#define VE_ECO 0 /* ECO number */
+#define VE_UECO 0 /* user ECO number (0) */
+
+#define P3_VERS 1 /* phase III version number (1) */
+#define P3_ECO 3 /* ECO number (3) */
+#define P3_UECO 0 /* user ECO number (0) */
+
+#define II_L2ROUT 01 /* level 2 router */
+#define II_L1ROUT 02 /* level 1 router */
+#define II_ENDNODE 03 /* endnode */
+#define II_VERIF 04 /* verification required */
+#define II_NOMCAST 040 /* no multicast traffic accepted */
+#define II_BLOCK 0100 /* blocking requested */
+#define II_TYPEMASK 03 /* mask for node type */
+
+#define TESTDATA 0252 /* test data bytes */
+#define TESTLEN 1 /* length of transmitted test data */
+
+/*
+ * Define control message formats.
+ */
+struct initmsgIII /* phase III initialisation message */
+ {
+ byte inIII_flags; /* route flags */
+ word inIII_src; /* source node address */
+ byte inIII_info; /* routing layer information */
+ word inIII_blksize; /* maximum data link block size */
+ byte inIII_vers; /* version number */
+ byte inIII_eco; /* ECO number */
+ byte inIII_ueco; /* user ECO number */
+ byte inIII_rsvd; /* reserved image field */
+ };
+
+struct initmsg /* initialisation message */
+ {
+ byte in_flags; /* route flags */
+ word in_src; /* source node address */
+ byte in_info; /* routing layer information */
+ word in_blksize; /* maximum data link block size */
+ byte in_vers; /* version number */
+ byte in_eco; /* ECO number */
+ byte in_ueco; /* user ECO number */
+ word in_hello; /* hello timer */
+ byte in_rsvd; /* reserved image field */
+ };
+
+struct verifmsg /* verification message */
+ {
+ byte ve_flags; /* route flags */
+ word ve_src; /* source node address */
+ byte ve_fcnval; /* function value image field */
+ };
+
+struct testmsg /* hello and test message */
+ {
+ byte te_flags; /* route flags */
+ word te_src; /* source node address */
+ byte te_data; /* test data image field */
+ };
+
+struct l1rout /* level 1 routing message */
+ {
+ byte r1_flags; /* route flags */
+ word r1_src; /* source node address */
+ byte r1_rsvd; /* reserved field */
+ };
+
+struct l2rout /* level 2 routing message */
+ {
+ byte r2_flags; /* route flags */
+ word r2_src; /* source node address */
+ byte r2_rsvd; /* reserved field */
+ };
+
+struct rhellomsg /* router hello message */
+ {
+ byte rh_flags; /* route flags */
+ byte rh_vers; /* version number */
+ byte rh_eco; /* ECO number */
+ byte rh_ueco; /* user ECO number */
+ etheraddr rh_src; /* source id */
+ byte rh_info; /* routing layer information */
+ word rh_blksize; /* maximum data link block size */
+ byte rh_priority; /* router's priority */
+ byte rh_area; /* reserved */
+ word rh_hello; /* hello timer */
+ byte rh_mpd; /* reserved */
+ };
+
+struct ehellomsg /* endnode hello message */
+ {
+ byte eh_flags; /* route flags */
+ byte eh_vers; /* version number */
+ byte eh_eco; /* ECO number */
+ byte eh_ueco; /* user ECO number */
+ etheraddr eh_src; /* source id */
+ byte eh_info; /* routing layer information */
+ word eh_blksize; /* maximum data link block size */
+ byte eh_area; /* area (reserved) */
+ byte eh_seed[8]; /* verification seed */
+ etheraddr eh_router; /* designated router */
+ word eh_hello; /* hello timer */
+ byte eh_mpd; /* (reserved) */
+ byte eh_data; /* test data image field */
+ };
+
+union controlmsg
+ {
+ struct initmsg cm_init; /* initialisation message */
+ struct verifmsg cm_ver; /* verification message */
+ struct testmsg cm_test; /* hello and test message */
+ struct l1rout cm_l1rou; /* level 1 routing message */
+ struct l2rout cm_l2rout; /* level 2 routing message */
+ struct rhellomsg cm_rhello; /* router hello message */
+ struct ehellomsg cm_ehello; /* endnode hello message */
+ };
+
+/* Macros for decoding routing-info fields */
+#define RI_COST(x) ((x)&0777)
+#define RI_HOPS(x) (((x)>>10)&037)
+
+/*
+ * NSP protocol fields and values.
+ */
+
+#define NSP_TYPEMASK 014 /* mask to isolate type code */
+#define NSP_SUBMASK 0160 /* mask to isolate subtype code */
+#define NSP_SUBSHFT 4 /* shift to move subtype code */
+
+#define MFT_DATA 0 /* data message */
+#define MFT_ACK 04 /* acknowledgement message */
+#define MFT_CTL 010 /* control message */
+
+#define MFS_ILS 020 /* data or I/LS indicator */
+#define MFS_BOM 040 /* beginning of message (data) */
+#define MFS_MOM 0 /* middle of message (data) */
+#define MFS_EOM 0100 /* end of message (data) */
+#define MFS_INT 040 /* interrupt message */
+
+#define MFS_DACK 0 /* data acknowledgement */
+#define MFS_IACK 020 /* I/LS acknowledgement */
+#define MFS_CACK 040 /* connect acknowledgement */
+
+#define MFS_NOP 0 /* no operation */
+#define MFS_CI 020 /* connect initiate */
+#define MFS_CC 040 /* connect confirm */
+#define MFS_DI 060 /* disconnect initiate */
+#define MFS_DC 0100 /* disconnect confirm */
+#define MFS_RCI 0140 /* retransmitted connect initiate */
+
+#define SGQ_ACK 0100000 /* ack */
+#define SGQ_NAK 0110000 /* negative ack */
+#define SGQ_OACK 0120000 /* other channel ack */
+#define SGQ_ONAK 0130000 /* other channel negative ack */
+#define SGQ_MASK 07777 /* mask to isolate seq # */
+#define SGQ_OTHER 020000 /* other channel qualifier */
+#define SGQ_DELAY 010000 /* ack delay flag */
+
+#define SGQ_EOM 0100000 /* pseudo flag for end-of-message */
+
+#define LSM_MASK 03 /* mask for modifier field */
+#define LSM_NOCHANGE 0 /* no change */
+#define LSM_DONOTSEND 1 /* do not send data */
+#define LSM_SEND 2 /* send data */
+
+#define LSI_MASK 014 /* mask for interpretation field */
+#define LSI_DATA 0 /* data segment or message count */
+#define LSI_INTR 4 /* interrupt request count */
+#define LSI_INTM 0377 /* funny marker for int. message */
+
+#define COS_MASK 014 /* mask for flow control field */
+#define COS_NONE 0 /* no flow control */
+#define COS_SEGMENT 04 /* segment flow control */
+#define COS_MESSAGE 010 /* message flow control */
+#define COS_CRYPTSER 020 /* cryptographic services requested */
+#define COS_DEFAULT 1 /* default value for field */
+
+#define COI_MASK 3 /* mask for version field */
+#define COI_32 0 /* version 3.2 */
+#define COI_31 1 /* version 3.1 */
+#define COI_40 2 /* version 4.0 */
+#define COI_41 3 /* version 4.1 */
+
+#define MNU_MASK 140 /* mask for session control version */
+#define MNU_10 000 /* session V1.0 */
+#define MNU_20 040 /* session V2.0 */
+#define MNU_ACCESS 1 /* access control present */
+#define MNU_USRDATA 2 /* user data field present */
+#define MNU_INVKPROXY 4 /* invoke proxy field present */
+#define MNU_UICPROXY 8 /* use uic-based proxy */
+
+#define DC_NORESOURCES 1 /* no resource reason code */
+#define DC_NOLINK 41 /* no link terminate reason code */
+#define DC_COMPLETE 42 /* disconnect complete reason code */
+
+#define DI_NOERROR 0 /* user disconnect */
+#define DI_SHUT 3 /* node is shutting down */
+#define DI_NOUSER 4 /* destination end user does not exist */
+#define DI_INVDEST 5 /* invalid end user destination */
+#define DI_REMRESRC 6 /* insufficient remote resources */
+#define DI_TPA 8 /* third party abort */
+#define DI_PROTOCOL 7 /* protocol error discovered */
+#define DI_ABORT 9 /* user abort */
+#define DI_LOCALRESRC 32 /* insufficient local resources */
+#define DI_REMUSERRESRC 33 /* insufficient remote user resources */
+#define DI_BADACCESS 34 /* bad access control information */
+#define DI_BADACCNT 36 /* bad ACCOUNT information */
+#define DI_CONNECTABORT 38 /* connect request cancelled */
+#define DI_TIMEDOUT 38 /* remote node or user crashed */
+#define DI_UNREACHABLE 39 /* local timers expired due to ... */
+#define DI_BADIMAGE 43 /* bad image data in connect */
+#define DI_SERVMISMATCH 54 /* cryptographic service mismatch */
+
+#define UC_OBJREJECT 0 /* object rejected connect */
+#define UC_USERDISCONNECT 0 /* user disconnect */
+#define UC_RESOURCES 1 /* insufficient resources (local or remote) */
+#define UC_NOSUCHNODE 2 /* unrecognised node name */
+#define UC_REMOTESHUT 3 /* remote node shutting down */
+#define UC_NOSUCHOBJ 4 /* unrecognised object */
+#define UC_INVOBJFORMAT 5 /* invalid object name format */
+#define UC_OBJTOOBUSY 6 /* object too busy */
+#define UC_NETWORKABORT 8 /* network abort */
+#define UC_USERABORT 9 /* user abort */
+#define UC_INVNODEFORMAT 10 /* invalid node name format */
+#define UC_LOCALSHUT 11 /* local node shutting down */
+#define UC_ACCESSREJECT 34 /* invalid access control information */
+#define UC_NORESPONSE 38 /* no response from object */
+#define UC_UNREACHABLE 39 /* node unreachable */
+
+/*
+ * NSP message formats.
+ */
+struct nsphdr /* general nsp header */
+ {
+ byte nh_flags; /* message flags */
+ word nh_dst; /* destination link address */
+ word nh_src; /* source link address */
+ };
+
+struct seghdr /* data segment header */
+ {
+ byte sh_flags; /* message flags */
+ word sh_dst; /* destination link address */
+ word sh_src; /* source link address */
+ word sh_seq[3]; /* sequence numbers */
+ };
+
+struct minseghdr /* minimum data segment header */
+ {
+ byte ms_flags; /* message flags */
+ word ms_dst; /* destination link address */
+ word ms_src; /* source link address */
+ word ms_seq; /* sequence number */
+ };
+
+struct lsmsg /* link service message (after hdr) */
+ {
+ byte ls_lsflags; /* link service flags */
+ byte ls_fcval; /* flow control value */
+ };
+
+struct ackmsg /* acknowledgement message */
+ {
+ byte ak_flags; /* message flags */
+ word ak_dst; /* destination link address */
+ word ak_src; /* source link address */
+ word ak_acknum[2]; /* acknowledgement numbers */
+ };
+
+struct minackmsg /* minimum acknowledgement message */
+ {
+ byte mk_flags; /* message flags */
+ word mk_dst; /* destination link address */
+ word mk_src; /* source link address */
+ word mk_acknum; /* acknowledgement number */
+ };
+
+struct ciackmsg /* connect acknowledgement message */
+ {
+ byte ck_flags; /* message flags */
+ word ck_dst; /* destination link address */
+ };
+
+struct cimsg /* connect initiate message */
+ {
+ byte ci_flags; /* message flags */
+ word ci_dst; /* destination link address (0) */
+ word ci_src; /* source link address */
+ byte ci_services; /* requested services */
+ byte ci_info; /* information */
+ word ci_segsize; /* maximum segment size */
+ };
+
+struct ccmsg /* connect confirm message */
+ {
+ byte cc_flags; /* message flags */
+ word cc_dst; /* destination link address */
+ word cc_src; /* source link address */
+ byte cc_services; /* requested services */
+ byte cc_info; /* information */
+ word cc_segsize; /* maximum segment size */
+ byte cc_optlen; /* optional data length */
+ };
+
+struct cnmsg /* generic connect message */
+ {
+ byte cn_flags; /* message flags */
+ word cn_dst; /* destination link address */
+ word cn_src; /* source link address */
+ byte cn_services; /* requested services */
+ byte cn_info; /* information */
+ word cn_segsize; /* maximum segment size */
+ };
+
+struct dimsg /* disconnect initiate message */
+ {
+ byte di_flags; /* message flags */
+ word di_dst; /* destination link address */
+ word di_src; /* source link address */
+ word di_reason; /* reason code */
+ byte di_optlen; /* optional data length */
+ };
+
+struct dcmsg /* disconnect confirm message */
+ {
+ byte dc_flags; /* message flags */
+ word dc_dst; /* destination link address */
+ word dc_src; /* source link address */
+ word dc_reason; /* reason code */
+ };
+
+/*
+ * Like the macros in extract.h, except that since DECNET is a little-endian
+ * protocol, the BYTEORDER sense is reversed.
+ */
+#define EXTRACT_8BITS(p) (*(p))
+#if BYTEORDER == BIG_ENDIAN
+#define EXTRACT_16BITS(p)\
+ ((u_short)\
+ (*((u_char *)p+1)<<8|\
+ *((u_char *)p+0)<<0))
+#define EXTRACT_32BITS(p)\
+ (*((u_char *)p+3)<<24|\
+ *((u_char *)p+2)<<16|\
+ *((u_char *)p+1)<<8|\
+ *((u_char *)p+0)<<0)
+#else
+#define EXTRACT_16BITS(p)\
+ ((u_short)\
+ (*((u_char *)p+0)<<8|\
+ *((u_char *)p+1)<<0))
+#define EXTRACT_32BITS(p)\
+ (*((u_char *)p+0)<<24|\
+ *((u_char *)p+1)<<16|\
+ *((u_char *)p+2)<<8|\
+ *((u_char *)p+3)<<0)
+#endif
diff --git a/usr.sbin/tcpdump/ethertype.h b/usr.sbin/tcpdump/ethertype.h
new file mode 100644
index 00000000000..c4ec760218f
--- /dev/null
+++ b/usr.sbin/tcpdump/ethertype.h
@@ -0,0 +1,72 @@
+/* $NetBSD: ethertype.h,v 1.2 1995/03/06 19:10:06 mycroft Exp $ */
+
+/*
+ * Copyright (c) 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: ethertype.h,v 1.4 94/06/14 20:11:45 leres Exp (LBL)
+ */
+
+/* Map between Ethernet protocol types and names */
+
+/* Add other Ethernet packet types here */
+#ifndef ETHERTYPE_SPRITE
+#define ETHERTYPE_SPRITE 0x0500
+#endif
+#ifndef ETHERTYPE_MOPDL
+#define ETHERTYPE_MOPDL 0x6001
+#endif
+#ifndef ETHERTYPE_MOPRC
+#define ETHERTYPE_MOPRC 0x6002
+#endif
+#ifndef ETHERTYPE_DN
+#define ETHERTYPE_DN 0x6003
+#endif
+#ifndef ETHERTYPE_LAT
+#define ETHERTYPE_LAT 0x6004
+#endif
+#ifndef ETHERTYPE_LANBRIDGE
+#define ETHERTYPE_LANBRIDGE 0x8038
+#endif
+#ifndef ETHERTYPE_DECDNS
+#define ETHERTYPE_DECDNS 0x803c
+#endif
+#ifndef ETHERTYPE_DECDTS
+#define ETHERTYPE_DECDTS 0x803e
+#endif
+#ifndef ETHERTYPE_VEXP
+#define ETHERTYPE_VEXP 0x805b
+#endif
+#ifndef ETHERTYPE_VPROD
+#define ETHERTYPE_VPROD 0x805c
+#endif
+#ifndef ETHERTYPE_LOOPBACK
+#define ETHERTYPE_LOOPBACK 0x9000
+#endif
+
+#ifndef ETHERTYPE_ATALK
+#define ETHERTYPE_ATALK 0x809b
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP 0x80f3
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS 0x0600
+#endif
+
diff --git a/usr.sbin/tcpdump/extract.h b/usr.sbin/tcpdump/extract.h
new file mode 100644
index 00000000000..2288ca55d58
--- /dev/null
+++ b/usr.sbin/tcpdump/extract.h
@@ -0,0 +1,51 @@
+/* $NetBSD: extract.h,v 1.2 1995/03/06 19:10:08 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: extract.h,v 1.7 94/06/14 20:11:45 leres Exp (LBL)
+ */
+
+#ifdef TCPDUMP_ALIGN
+#if BYTEORDER == LITTLE_ENDIAN
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+1)<<8|\
+ (u_short)*((u_char *)p+0)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_int32)*((u_char *)p+3)<<24|\
+ (u_int32)*((u_char *)p+2)<<16|\
+ (u_int32)*((u_char *)p+1)<<8|\
+ (u_int32)*((u_char *)p+0)<<0)
+#else
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+0)<<8|\
+ (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_int32)*((u_char *)p+0)<<24|\
+ (u_int32)*((u_char *)p+1)<<16|\
+ (u_int32)*((u_char *)p+2)<<8|\
+ (u_int32)*((u_char *)p+3)<<0)
+#endif
+#else
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p))
+#endif
diff --git a/usr.sbin/tcpdump/fddi.h b/usr.sbin/tcpdump/fddi.h
new file mode 100644
index 00000000000..2d91b70454f
--- /dev/null
+++ b/usr.sbin/tcpdump/fddi.h
@@ -0,0 +1,78 @@
+/* $NetBSD: fddi.h,v 1.2 1995/03/06 19:10:10 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: fddi.h,v 1.6 94/06/14 20:12:35 leres Exp (LBL)
+ */
+
+/*
+ * Based on Ultrix if_fddi.h
+ */
+
+/*
+ * This stuff should come from a system header file, but there's no
+ * obviously portable way to do that and it's not really going
+ * to change from system to system (except for the padding business).
+ */
+
+struct fddi_header {
+#if defined(ultrix) || defined(__alpha)
+ /* Ultrix pads to make everything line up on a nice boundary */
+#define FDDIPAD 3
+ u_char fddi_ph[FDDIPAD];
+#else
+#define FDDIPAD 0
+#endif
+ u_char fddi_fc; /* frame control */
+ u_char fddi_dhost[6];
+ u_char fddi_shost[6];
+};
+
+
+/* Useful values for fddi_fc (frame control) field */
+
+/*
+ * FDDI Frame Control bits
+ */
+#define FDDIFC_C 0x80 /* Class bit */
+#define FDDIFC_L 0x40 /* Address length bit */
+#define FDDIFC_F 0x30 /* Frame format bits */
+#define FDDIFC_Z 0x0f /* Control bits */
+
+/*
+ * FDDI Frame Control values. (48-bit addressing only).
+ */
+#define FDDIFC_VOID 0x40 /* Void frame */
+#define FDDIFC_NRT 0x80 /* Nonrestricted token */
+#define FDDIFC_RT 0xc0 /* Restricted token */
+#define FDDIFC_SMT_INFO 0x41 /* SMT Info */
+#define FDDIFC_SMT_NSA 0x4F /* SMT Next station adrs */
+#define FDDIFC_MAC_BEACON 0xc2 /* MAC Beacon frame */
+#define FDDIFC_MAC_CLAIM 0xc3 /* MAC Claim frame */
+#define FDDIFC_LLC_ASYNC 0x50 /* Async. LLC frame */
+#define FDDIFC_LLC_SYNC 0xd0 /* Sync. LLC frame */
+#define FDDIFC_IMP_ASYNC 0x60 /* Implementor Async. */
+#define FDDIFC_IMP_SYNC 0xe0 /* Implementor Synch. */
+#define FDDIFC_SMT 0x40 /* SMT frame */
+#define FDDIFC_MAC 0xc0 /* MAC frame */
+
+#define FDDIFC_CLFF 0xF0 /* Class/Length/Format bits */
+#define FDDIFC_ZZZZ 0x0F /* Control bits */
diff --git a/usr.sbin/tcpdump/interface.h b/usr.sbin/tcpdump/interface.h
new file mode 100644
index 00000000000..2e321153116
--- /dev/null
+++ b/usr.sbin/tcpdump/interface.h
@@ -0,0 +1,152 @@
+/* $NetBSD: interface.h,v 1.2 1995/03/06 19:10:18 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: interface.h,v 1.66 94/06/14 20:21:37 leres Exp (LBL)
+ */
+
+#ifdef __GNUC__
+#define inline __inline
+#ifndef __dead
+#define __dead volatile
+#endif
+#else
+#define inline
+#define __dead
+#endif
+
+#include "os.h" /* operating system stuff */
+#include "md.h" /* machine dependent stuff */
+
+#ifndef SIGRET
+#define SIGRET void /* default */
+#endif
+
+struct token {
+ int v; /* value */
+ char *s; /* string */
+};
+
+extern int dflag; /* print filter code */
+extern int eflag; /* print ethernet header */
+extern int nflag; /* leave addresses as numbers */
+extern int Nflag; /* remove domains from printed host names */
+extern int qflag; /* quick (shorter) output */
+extern int Sflag; /* print raw TCP sequence numbers */
+extern int tflag; /* print packet arrival time */
+extern int vflag; /* verbose */
+extern int xflag; /* print packet in hex */
+
+extern char *program_name; /* used to generate self-identifying messages */
+
+extern int snaplen;
+/* global pointers to beginning and end of current packet (during printing) */
+extern const u_char *packetp;
+extern const u_char *snapend;
+
+extern int fddipad; /* alignment offset for FDDI headers, in bytes */
+
+/* Eliminate some bogus warnings. */
+struct timeval;
+
+typedef void (*printfunc)(u_char *, struct timeval *, int, int);
+
+extern void ts_print(const struct timeval *);
+extern int clock_sigfigs(void);
+int gmt2local(void);
+
+extern int fn_print(const u_char *, const u_char *);
+extern int fn_printn(const u_char *, u_int, const u_char *);
+extern const char *tok2str(const struct token *, const char *, int);
+extern char *dnaddr_string(u_short);
+extern char *savestr(const char *);
+
+extern int initdevice(char *, int, int *);
+extern void wrapup(int);
+
+extern __dead void error(char *, ...);
+extern void warning(char *, ...);
+
+extern char *read_infile(char *);
+extern char *copy_argv(char **);
+
+extern void usage(void);
+extern char *isonsap_string(const u_char *);
+extern char *llcsap_string(u_char);
+extern char *protoid_string(const u_char *);
+extern char *dnname_string(u_short);
+extern char *dnnum_string(u_short);
+
+/* The printer routines. */
+
+struct pcap_pkthdr;
+
+extern void ether_if_print(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char*);
+extern void null_if_print(u_char *, const struct pcap_pkthdr *, const u_char*);
+extern void ppp_if_print(u_char *, const struct pcap_pkthdr *, const u_char *);
+extern void sl_if_print(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+extern void arp_print(const u_char *, int, int);
+extern void ip_print(const u_char *, int);
+extern void tcp_print(const u_char *, int, const u_char *);
+extern void udp_print(const u_char *, int, const u_char *);
+extern void icmp_print(const u_char *, const u_char *);
+extern void default_print(const u_char *, int);
+extern void default_print_unaligned(const u_char *, int);
+
+extern void aarp_print(const u_char *, int);
+extern void atalk_print(const u_char *, int);
+extern void bootp_print(const u_char *, int, u_short, u_short);
+extern void decnet_print(const u_char *, int, int);
+extern void egp_print(const u_char *, int, const u_char *);
+extern int ether_encap_print(u_short, const u_char *, int, int);
+extern void ipx_print(const u_char *, int length);
+extern void isoclns_print(const u_char *, int, int,
+ const u_char *, const u_char *);
+extern int llc_print(const u_char *, int, int, const u_char *, const u_char *);
+extern void nfsreply_print(const u_char *, int, const u_char *);
+extern void nfsreq_print(const u_char *, int, const u_char *);
+extern void ns_print(const u_char *, int);
+extern void ntp_print(const u_char *, int);
+extern void ospf_print(const u_char *, int, const u_char *);
+extern void rip_print(const u_char *, int);
+extern void snmp_print(const u_char *, int);
+extern void sunrpcrequest_print(const u_char *, int, const u_char *);
+extern void tftp_print(const u_char *, int);
+extern void wb_print(const void *, int);
+
+#define min(a,b) ((a)>(b)?(b):(a))
+#define max(a,b) ((b)>(a)?(b):(a))
+
+/*
+ * The default snapshot length. This value allows most printers to print
+ * useful information while keeping the amount of unwanted data down.
+ * In particular, it allows for an ethernet header, tcp/ip header, and
+ * 14 bytes of data (assuming no ip options).
+ */
+#define DEFAULT_SNAPLEN 68
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#endif
diff --git a/usr.sbin/tcpdump/ipx.h b/usr.sbin/tcpdump/ipx.h
new file mode 100644
index 00000000000..e943f6e7673
--- /dev/null
+++ b/usr.sbin/tcpdump/ipx.h
@@ -0,0 +1,31 @@
+/* $NetBSD: ipx.h,v 1.2 1995/03/06 19:10:19 mycroft Exp $ */
+
+/*
+ * IPX protocol formats
+ *
+ * @(#) Header: ipx.h,v 1.1 94/06/09 11:47:03 mccanne Exp
+ */
+
+/* well-known sockets */
+#define IPX_SKT_NCP 0x0451
+#define IPX_SKT_SAP 0x0452
+#define IPX_SKT_RIP 0x0453
+#define IPX_SKT_NETBIOS 0x0455
+#define IPX_SKT_DIAGNOSTICS 0x0456
+
+/* IPX transport header */
+struct ipxHdr {
+ u_short cksum; /* Checksum */
+ u_short length; /* Length, in bytes, including header */
+ u_char tCtl; /* Transport Control (i.e. hop count) */
+ u_char pType; /* Packet Type (i.e. level 2 protocol) */
+ u_short dstNet[2]; /* destination net */
+ u_char dstNode[6]; /* destination node */
+ u_short dstSkt; /* destination socket */
+ u_short srcNet[2]; /* source net */
+ u_char srcNode[6]; /* source node */
+ u_short srcSkt; /* source socket */
+} ipx_hdr_t;
+
+#define ipxSize 30
+
diff --git a/usr.sbin/tcpdump/llc.h b/usr.sbin/tcpdump/llc.h
new file mode 100644
index 00000000000..2712fda70a1
--- /dev/null
+++ b/usr.sbin/tcpdump/llc.h
@@ -0,0 +1,122 @@
+/* $NetBSD: llc.h,v 1.2 1995/03/06 19:10:20 mycroft Exp $ */
+
+/*
+ * Copyright (c) 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: llc.h,v 1.4 94/06/14 20:11:46 leres Exp (LBL)
+ */
+
+/*
+ * This stuff should come from a system header file, but there's no
+ * obviously portable way to do that and it's not really going
+ * to change from system to system.
+ */
+
+/*
+ * A somewhat abstracted view of the LLC header
+ */
+
+struct llc {
+ u_char dsap;
+ u_char ssap;
+ union {
+ u_char u_ctl;
+ u_short is_ctl;
+ struct {
+ u_char snap_ui;
+ u_char snap_pi[5];
+ } snap;
+ struct {
+ u_char snap_ui;
+ u_char snap_orgcode[3];
+ u_char snap_ethertype[2];
+ } snap_ether;
+ } ctl;
+};
+
+#define llcui ctl.snap.snap_ui
+#define llcpi ctl.snap.snap_pi
+#define orgcode ctl.snap_ether.snap_orgcode
+#define ethertype ctl.snap_ether.snap_ethertype
+#define llcis ctl.is_ctl
+#define llcu ctl.u_ctl
+
+#define LLC_U_FMT 3
+#define LLC_GSAP 1
+#define LLC_S_FMT 1
+
+#define LLC_U_POLL 0x10
+#define LLC_IS_POLL 0x0001
+#define LLC_XID_FI 0x81
+
+#define LLC_U_CMD(u) ((u) & 0xef)
+#define LLC_UI 0x03
+#define LLC_UA 0x63
+#define LLC_DISC 0x43
+#define LLC_DM 0x0f
+#define LLC_SABME 0x6f
+#define LLC_TEST 0xe3
+#define LLC_XID 0xaf
+#define LLC_FRMR 0x87
+
+#define LLC_S_CMD(is) (((is) >> 10) & 0x03)
+#define LLC_RR 0x0100
+#define LLC_RNR 0x0500
+#define LLC_REJ 0x0900
+
+#define LLC_IS_NR(is) (((is) >> 9) & 0x7f)
+#define LLC_I_NS(is) (((is) >> 1) & 0x7f)
+
+#ifndef LLCSAP_NULL
+#define LLCSAP_NULL 0x00
+#endif
+#ifndef LLCSAP_GLOBAL
+#define LLCSAP_GLOBAL 0xff
+#endif
+#ifndef LLCSAP_8021B
+#define LLCSAP_8021B_I 0x02
+#endif
+#ifndef LLCSAP_8021B
+#define LLCSAP_8021B_G 0x03
+#endif
+#ifndef LLCSAP_IP
+#define LLCSAP_IP 0x06
+#endif
+#ifndef LLCSAP_PROWAYNM
+#define LLCSAP_PROWAYNM 0x0e
+#endif
+#ifndef LLCSAP_8021D
+#define LLCSAP_8021D 0x42
+#endif
+#ifndef LLCSAP_RS511
+#define LLCSAP_RS511 0x4e
+#endif
+#ifndef LLCSAP_ISO8208
+#define LLCSAP_ISO8208 0x7e
+#endif
+#ifndef LLCSAP_PROWAY
+#define LLCSAP_PROWAY 0x8e
+#endif
+#ifndef LLCSAP_SNAP
+#define LLCSAP_SNAP 0xaa
+#endif
+#ifndef LLCSAP_ISONS
+#define LLCSAP_ISONS 0xfe
+#endif
diff --git a/usr.sbin/tcpdump/makemib b/usr.sbin/tcpdump/makemib
new file mode 100644
index 00000000000..debab1f3763
--- /dev/null
+++ b/usr.sbin/tcpdump/makemib
@@ -0,0 +1,175 @@
+#!/bin/sh
+#
+# $NetBSD: makemib,v 1.2 1995/03/06 19:10:22 mycroft Exp $
+#
+# Copyright (c) 1990, by John Robert LoVerso.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that the above copyright notice and this paragraph are
+# duplicated in all such forms and that any documentation,
+# advertising materials, and other materials related to such
+# distribution and use acknowledge that the software was developed
+# by John Robert LoVerso.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+# @(#) Id: makemib,v 2.1 90/07/10 23:51:54 loverso Exp Locker: loverso (jlv
+)
+
+#
+# This script will read either ASN.1-style MIB files or the ".defs" files
+# created by the ISODE "mosy" program on such files.
+#
+# The output of this script is the "mib.h" file used by tcpdumps' ASN.1/SNMP
+# decoding code.
+#
+# This script needs to be run by "gawk" (GNU awk). "nawk" will work, but
+# dump will get a recursion error if you process LARGE mibs. While it would
+# by farily easy to rewrite this not to use recursion (and also easy to
+# eliminate use of gsub and functions to use classic "awk"), you have to
+# order the structure declarations in defined-first order for the compiler
+# not to barf; too bad tsort doesn't take arguments.
+#
+
+cat << EOF
+/*
+ * This file was generated by tcpdump/makemib on `date`
+ * You probably don't want to edit this by hand!
+ *
+ * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer
+};
+ */
+
+EOF
+
+# use sed to make the ASN.1 easier to parse
+# I should really just use a recursive descent parser in awk, but...
+sed \
+ -e 's/--\*.*\*--//' \
+ -e 's/--.*//' \
+ -e 's/\([{}]\)/ \1 /g' \
+ $@ \
+| gawk '
+BEGIN {
+ # for sanity, we prep the namespace with objects from RFC-1155
+ # (we manually establish the root)
+ oid["iso"]=1
+ oidadd("org", "iso", 3)
+ oidadd("dod", "org", 6)
+ oidadd("internet", "dod", 1)
+ oidadd("directory", "internet", 1)
+ oidadd("mgmt", "internet", 2)
+ oidadd("mib", "mgmt", 1)
+ oidadd("experimental", "internet", 3)
+ oidadd("private", "internet", 4)
+ oidadd("enterprises", "private", 1)
+
+ holddesc="none"
+}
+
+#
+# Read mosy "*.defs" file. mosy does all the parsing work; we just read
+# its simple and straightforward output. It would not be too hard to make
+# tcpdump directly read mosy output, but...
+#
+
+NF > 1 && index($2,".")>0 {
+ # currently ignore items of the form "{ iso.3.6.1 }"
+ if (split($2, p, ".") == 2)
+ oidadd($1, p[1], p[2])
+ next
+}
+
+#
+# this next section is simple and naive, but does the job 100%
+#
+
+$2$3$4 == "OBJECTIDENTIFIER::=" {
+ holddesc="none"
+ if (NF == 8)
+ oidadd($1, $6, $7)
+}
+$2 == "OBJECT-TYPE" {
+ holddesc=$1
+}
+$1 == "::=" && holddesc != "none" && NF == 5 {
+ oidadd(holddesc, $3, $4)
+ holddesc="none"
+}
+
+#
+# End of the road - output the data.
+#
+
+END {
+ print "struct obj"
+ dump("iso")
+ print "*mibroot = &_iso_obj;"
+}
+
+#
+# add a new object to the tree
+#
+# new OBJECT IDENTIFIER ::= { parent value }
+#
+
+function oidadd(new, parent, value) {
+ # use safe C identifiers
+ gsub(/[-&\/]/,"",new)
+ gsub(/[-&\/]/,"",parent)
+ # check if parent missing
+ if (oid[parent] == 0) {
+ printf "/* parse problem: no parent for %s.%s(%d) */\n", \
+ parent, new, value
+ return
+ }
+ # check if parent.value already exists
+ if (oid[new] > 0 && oid[new] != value) {
+ printf "/* parse problem: dup %s.%s(%d) != old (%d) */\n", \
+ parent, new, value, oid[new]
+ return
+ }
+ # check for new name for parent.value
+ if (child[parent] != "") {
+ for (sib = child[parent]; sib != ""; sib = sibling[sib])
+ if (oid[sib] == value) {
+ printf "/* parse problem: new name \"%s\"" \
+ " for %s.%s(%d) ignored */\n", \
+ new, parent, sib, value
+ return
+ }
+ }
+
+ oid[new]=value
+ if (child[parent] == "") {
+ child[parent] = new
+ } else {
+ sibling[new] = child[parent]
+ child[parent] = new
+ }
+}
+
+#
+# old(?) routine to recurse down the tree (in postfix order for convenience)
+#
+
+function dump(item, c, s) {
+# newitem=sofar"."item"("oid[item]")"
+# printf "/* %s c=%s s=%s */\n", newitem, child[item], sibling[item]
+ c="NULL"
+ if (child[item] != "") {
+ dump(child[item])
+ c = "&_"child[item]"_obj"
+ }
+ s="NULL"
+ if (sibling[item] != "") {
+ dump(sibling[item])
+ s = "&_"sibling[item]"_obj"
+ }
+ printf "_%s_obj = {\n\t\"%s\", %d, 0,\n\t%s, %s\n},\n", \
+ item, item, oid[item], c, s
+}
+'
+exit 0
diff --git a/usr.sbin/tcpdump/md.h b/usr.sbin/tcpdump/md.h
new file mode 100644
index 00000000000..35306653f23
--- /dev/null
+++ b/usr.sbin/tcpdump/md.h
@@ -0,0 +1,35 @@
+/* $NetBSD: md.h,v 1.2 1995/03/06 19:10:33 mycroft Exp $ */
+
+/*
+ * Copyright (c) 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: md-i386.h,v 1.5 94/06/14 20:14:40 leres Exp (LBL)
+ */
+
+#define TCPDUMP_ALIGN
+
+#include <machine/endian.h>
+
+/* 32-bit data types */
+/* N.B.: this doesn't address printf()'s %d vs. %ld formats */
+typedef int32_t int32; /* signed 32-bit integer */
+#ifndef AUTH_UNIX
+typedef u_int32_t u_int32; /* unsigned 32-bit integer */
+#endif
diff --git a/usr.sbin/tcpdump/mib.h b/usr.sbin/tcpdump/mib.h
new file mode 100644
index 00000000000..747af862f9c
--- /dev/null
+++ b/usr.sbin/tcpdump/mib.h
@@ -0,0 +1,1258 @@
+/* $NetBSD: mib.h,v 1.2 1995/03/06 19:10:34 mycroft Exp $ */
+
+/*
+ * This file was generated by tcpdump/makemib on Wed Sep 26 12:12:31 EDT 1990
+ * You probably don't want to edit this by hand!
+ *
+ * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer
+};
+ */
+
+/* parse problem: new name "mib" for mgmt.mib(1) ignored */
+/* parse problem: no parent for 0.nullSpecific(0) */
+struct obj
+_proteon_obj = {
+ "proteon", 1, 0,
+ NULL, NULL
+},
+_ibm_obj = {
+ "ibm", 2, 0,
+ NULL, &_proteon_obj
+},
+_cmu_obj = {
+ "cmu", 3, 0,
+ NULL, &_ibm_obj
+},
+_unix_obj = {
+ "unix", 4, 0,
+ NULL, &_cmu_obj
+},
+_acc_obj = {
+ "acc", 5, 0,
+ NULL, &_unix_obj
+},
+_twg_obj = {
+ "twg", 6, 0,
+ NULL, &_acc_obj
+},
+_cayman_obj = {
+ "cayman", 7, 0,
+ NULL, &_twg_obj
+},
+_nysernet_obj = {
+ "nysernet", 8, 0,
+ NULL, &_cayman_obj
+},
+_cisco_obj = {
+ "cisco", 9, 0,
+ NULL, &_nysernet_obj
+},
+_nsc_obj = {
+ "nsc", 10, 0,
+ NULL, &_cisco_obj
+},
+_hp_obj = {
+ "hp", 11, 0,
+ NULL, &_nsc_obj
+},
+_epilogue_obj = {
+ "epilogue", 12, 0,
+ NULL, &_hp_obj
+},
+_utennessee_obj = {
+ "utennessee", 13, 0,
+ NULL, &_epilogue_obj
+},
+_bbn_obj = {
+ "bbn", 14, 0,
+ NULL, &_utennessee_obj
+},
+_xylogics_obj = {
+ "xylogics", 15, 0,
+ NULL, &_bbn_obj
+},
+_unisys_obj = {
+ "unisys", 16, 0,
+ NULL, &_xylogics_obj
+},
+_canstar_obj = {
+ "canstar", 17, 0,
+ NULL, &_unisys_obj
+},
+_wellfleet_obj = {
+ "wellfleet", 18, 0,
+ NULL, &_canstar_obj
+},
+_trw_obj = {
+ "trw", 19, 0,
+ NULL, &_wellfleet_obj
+},
+_mit_obj = {
+ "mit", 20, 0,
+ NULL, &_trw_obj
+},
+_eon_obj = {
+ "eon", 21, 0,
+ NULL, &_mit_obj
+},
+_spartacus_obj = {
+ "spartacus", 22, 0,
+ NULL, &_eon_obj
+},
+_excelan_obj = {
+ "excelan", 23, 0,
+ NULL, &_spartacus_obj
+},
+_spider_obj = {
+ "spider", 24, 0,
+ NULL, &_excelan_obj
+},
+_nsfnet_obj = {
+ "nsfnet", 25, 0,
+ NULL, &_spider_obj
+},
+_sytek_obj = {
+ "sytek", 26, 0,
+ NULL, &_nsfnet_obj
+},
+_intergraph_obj = {
+ "intergraph", 27, 0,
+ NULL, &_sytek_obj
+},
+_interlan_obj = {
+ "interlan", 28, 0,
+ NULL, &_intergraph_obj
+},
+_vitalink_obj = {
+ "vitalink", 29, 0,
+ NULL, &_interlan_obj
+},
+_ulana_obj = {
+ "ulana", 30, 0,
+ NULL, &_vitalink_obj
+},
+_nswc_obj = {
+ "nswc", 31, 0,
+ NULL, &_ulana_obj
+},
+_santacruzoperation_obj = {
+ "santacruzoperation", 32, 0,
+ NULL, &_nswc_obj
+},
+_xyplex_obj = {
+ "xyplex", 33, 0,
+ NULL, &_santacruzoperation_obj
+},
+_cray_obj = {
+ "cray", 34, 0,
+ NULL, &_xyplex_obj
+},
+_bellnorthernresearch_obj = {
+ "bellnorthernresearch", 35, 0,
+ NULL, &_cray_obj
+},
+_dec_obj = {
+ "dec", 36, 0,
+ NULL, &_bellnorthernresearch_obj
+},
+_touch_obj = {
+ "touch", 37, 0,
+ NULL, &_dec_obj
+},
+_networkresearchcorp_obj = {
+ "networkresearchcorp", 38, 0,
+ NULL, &_touch_obj
+},
+_baylor_obj = {
+ "baylor", 39, 0,
+ NULL, &_networkresearchcorp_obj
+},
+_nmfeccllnl_obj = {
+ "nmfeccllnl", 40, 0,
+ NULL, &_baylor_obj
+},
+_sri_obj = {
+ "sri", 41, 0,
+ NULL, &_nmfeccllnl_obj
+},
+_sun_obj = {
+ "sun", 42, 0,
+ NULL, &_sri_obj
+},
+_3com_obj = {
+ "3com", 43, 0,
+ NULL, &_sun_obj
+},
+_cmc_obj = {
+ "cmc", 44, 0,
+ NULL, &_3com_obj
+},
+_synoptics_obj = {
+ "synoptics", 45, 0,
+ NULL, &_cmc_obj
+},
+_cheyenne_obj = {
+ "cheyenne", 46, 0,
+ NULL, &_synoptics_obj
+},
+_prime_obj = {
+ "prime", 47, 0,
+ NULL, &_cheyenne_obj
+},
+_mcnc_obj = {
+ "mcnc", 48, 0,
+ NULL, &_prime_obj
+},
+_chipcom_obj = {
+ "chipcom", 49, 0,
+ NULL, &_mcnc_obj
+},
+_opticaldatasystems_obj = {
+ "opticaldatasystems", 50, 0,
+ NULL, &_chipcom_obj
+},
+_gated_obj = {
+ "gated", 51, 0,
+ NULL, &_opticaldatasystems_obj
+},
+_cabletron_obj = {
+ "cabletron", 52, 0,
+ NULL, &_gated_obj
+},
+_apollo_obj = {
+ "apollo", 53, 0,
+ NULL, &_cabletron_obj
+},
+_desktalksystems_obj = {
+ "desktalksystems", 54, 0,
+ NULL, &_apollo_obj
+},
+_ssds_obj = {
+ "ssds", 55, 0,
+ NULL, &_desktalksystems_obj
+},
+_castlerock_obj = {
+ "castlerock", 56, 0,
+ NULL, &_ssds_obj
+},
+_mips_obj = {
+ "mips", 57, 0,
+ NULL, &_castlerock_obj
+},
+_tgv_obj = {
+ "tgv", 58, 0,
+ NULL, &_mips_obj
+},
+_silicongraphics_obj = {
+ "silicongraphics", 59, 0,
+ NULL, &_tgv_obj
+},
+_ubc_obj = {
+ "ubc", 60, 0,
+ NULL, &_silicongraphics_obj
+},
+_merit_obj = {
+ "merit", 61, 0,
+ NULL, &_ubc_obj
+},
+_fibercom_obj = {
+ "fibercom", 62, 0,
+ NULL, &_merit_obj
+},
+_apple_obj = {
+ "apple", 63, 0,
+ NULL, &_fibercom_obj
+},
+_gandalf_obj = {
+ "gandalf", 64, 0,
+ NULL, &_apple_obj
+},
+_dartmouth_obj = {
+ "dartmouth", 65, 0,
+ NULL, &_gandalf_obj
+},
+_davidsystems_obj = {
+ "davidsystems", 66, 0,
+ NULL, &_dartmouth_obj
+},
+_reuter_obj = {
+ "reuter", 67, 0,
+ NULL, &_davidsystems_obj
+},
+_cornell_obj = {
+ "cornell", 68, 0,
+ NULL, &_reuter_obj
+},
+_tmac_obj = {
+ "tmac", 69, 0,
+ NULL, &_cornell_obj
+},
+_locus_obj = {
+ "locus", 70, 0,
+ NULL, &_tmac_obj
+},
+_nasa_obj = {
+ "nasa", 71, 0,
+ NULL, &_locus_obj
+},
+_retix_obj = {
+ "retix", 72, 0,
+ NULL, &_nasa_obj
+},
+_boeing_obj = {
+ "boeing", 73, 0,
+ NULL, &_retix_obj
+},
+_att_obj = {
+ "att", 74, 0,
+ NULL, &_boeing_obj
+},
+_ungermannbass_obj = {
+ "ungermannbass", 75, 0,
+ NULL, &_att_obj
+},
+_digitalanalysis_obj = {
+ "digitalanalysis", 76, 0,
+ NULL, &_ungermannbass_obj
+},
+_hplanman_obj = {
+ "hplanman", 77, 0,
+ NULL, &_digitalanalysis_obj
+},
+_netlabs_obj = {
+ "netlabs", 78, 0,
+ NULL, &_hplanman_obj
+},
+_icl_obj = {
+ "icl", 79, 0,
+ NULL, &_netlabs_obj
+},
+_auspex_obj = {
+ "auspex", 80, 0,
+ NULL, &_icl_obj
+},
+_lannet_obj = {
+ "lannet", 81, 0,
+ NULL, &_auspex_obj
+},
+_ncd_obj = {
+ "ncd", 82, 0,
+ NULL, &_lannet_obj
+},
+_raycom_obj = {
+ "raycom", 83, 0,
+ NULL, &_ncd_obj
+},
+_pirellifocom_obj = {
+ "pirellifocom", 84, 0,
+ NULL, &_raycom_obj
+},
+_datability_obj = {
+ "datability", 85, 0,
+ NULL, &_pirellifocom_obj
+},
+_networkappltech_obj = {
+ "networkappltech", 86, 0,
+ NULL, &_datability_obj
+},
+_link_obj = {
+ "link", 87, 0,
+ NULL, &_networkappltech_obj
+},
+_nyu_obj = {
+ "nyu", 88, 0,
+ NULL, &_link_obj
+},
+_rnd_obj = {
+ "rnd", 89, 0,
+ NULL, &_nyu_obj
+},
+_intercon_obj = {
+ "intercon", 90, 0,
+ NULL, &_rnd_obj
+},
+_learningtree_obj = {
+ "learningtree", 91, 0,
+ NULL, &_intercon_obj
+},
+_webstercomputer_obj = {
+ "webstercomputer", 92, 0,
+ NULL, &_learningtree_obj
+},
+_frontier_obj = {
+ "frontier", 93, 0,
+ NULL, &_webstercomputer_obj
+},
+_nokia_obj = {
+ "nokia", 94, 0,
+ NULL, &_frontier_obj
+},
+_allenbradley_obj = {
+ "allenbradley", 95, 0,
+ NULL, &_nokia_obj
+},
+_cern_obj = {
+ "cern", 96, 0,
+ NULL, &_allenbradley_obj
+},
+_sigma_obj = {
+ "sigma", 97, 0,
+ NULL, &_cern_obj
+},
+_emergingtech_obj = {
+ "emergingtech", 98, 0,
+ NULL, &_sigma_obj
+},
+_snmpresearch_obj = {
+ "snmpresearch", 99, 0,
+ NULL, &_emergingtech_obj
+},
+_ohiostate_obj = {
+ "ohiostate", 100, 0,
+ NULL, &_snmpresearch_obj
+},
+_ultra_obj = {
+ "ultra", 101, 0,
+ NULL, &_ohiostate_obj
+},
+_ccur_obj = {
+ "ccur", 136, 0,
+ NULL, &_ultra_obj
+},
+_enterprises_obj = {
+ "enterprises", 1, 0,
+ &_ccur_obj, NULL
+},
+_snmpInPkts_obj = {
+ "snmpInPkts", 1, 0,
+ NULL, NULL
+},
+_snmpOutPkts_obj = {
+ "snmpOutPkts", 2, 0,
+ NULL, &_snmpInPkts_obj
+},
+_snmpInBadVersions_obj = {
+ "snmpInBadVersions", 3, 0,
+ NULL, &_snmpOutPkts_obj
+},
+_snmpInBadCommunityNames_obj = {
+ "snmpInBadCommunityNames", 4, 0,
+ NULL, &_snmpInBadVersions_obj
+},
+_snmpInBadCommunityUses_obj = {
+ "snmpInBadCommunityUses", 5, 0,
+ NULL, &_snmpInBadCommunityNames_obj
+},
+_snmpInASNParseErrs_obj = {
+ "snmpInASNParseErrs", 6, 0,
+ NULL, &_snmpInBadCommunityUses_obj
+},
+_snmpInBadTypes_obj = {
+ "snmpInBadTypes", 7, 0,
+ NULL, &_snmpInASNParseErrs_obj
+},
+_snmpInTooBigs_obj = {
+ "snmpInTooBigs", 8, 0,
+ NULL, &_snmpInBadTypes_obj
+},
+_snmpInNoSuchNames_obj = {
+ "snmpInNoSuchNames", 9, 0,
+ NULL, &_snmpInTooBigs_obj
+},
+_snmpInBadValues_obj = {
+ "snmpInBadValues", 10, 0,
+ NULL, &_snmpInNoSuchNames_obj
+},
+_snmpInReadOnlys_obj = {
+ "snmpInReadOnlys", 11, 0,
+ NULL, &_snmpInBadValues_obj
+},
+_snmpInGenErrs_obj = {
+ "snmpInGenErrs", 12, 0,
+ NULL, &_snmpInReadOnlys_obj
+},
+_snmpInTotalReqVars_obj = {
+ "snmpInTotalReqVars", 13, 0,
+ NULL, &_snmpInGenErrs_obj
+},
+_snmpInTotalSetVars_obj = {
+ "snmpInTotalSetVars", 14, 0,
+ NULL, &_snmpInTotalReqVars_obj
+},
+_snmpInGetRequests_obj = {
+ "snmpInGetRequests", 15, 0,
+ NULL, &_snmpInTotalSetVars_obj
+},
+_snmpInGetNexts_obj = {
+ "snmpInGetNexts", 16, 0,
+ NULL, &_snmpInGetRequests_obj
+},
+_snmpInSetRequests_obj = {
+ "snmpInSetRequests", 17, 0,
+ NULL, &_snmpInGetNexts_obj
+},
+_snmpInGetResponses_obj = {
+ "snmpInGetResponses", 18, 0,
+ NULL, &_snmpInSetRequests_obj
+},
+_snmpInTraps_obj = {
+ "snmpInTraps", 19, 0,
+ NULL, &_snmpInGetResponses_obj
+},
+_snmpOutTooBigs_obj = {
+ "snmpOutTooBigs", 20, 0,
+ NULL, &_snmpInTraps_obj
+},
+_snmpOutNoSuchNames_obj = {
+ "snmpOutNoSuchNames", 21, 0,
+ NULL, &_snmpOutTooBigs_obj
+},
+_snmpOutBadValues_obj = {
+ "snmpOutBadValues", 22, 0,
+ NULL, &_snmpOutNoSuchNames_obj
+},
+_snmpOutReadOnlys_obj = {
+ "snmpOutReadOnlys", 23, 0,
+ NULL, &_snmpOutBadValues_obj
+},
+_snmpOutGenErrs_obj = {
+ "snmpOutGenErrs", 24, 0,
+ NULL, &_snmpOutReadOnlys_obj
+},
+_snmpOutGetRequests_obj = {
+ "snmpOutGetRequests", 25, 0,
+ NULL, &_snmpOutGenErrs_obj
+},
+_snmpOutGetNexts_obj = {
+ "snmpOutGetNexts", 26, 0,
+ NULL, &_snmpOutGetRequests_obj
+},
+_snmpOutSetRequests_obj = {
+ "snmpOutSetRequests", 27, 0,
+ NULL, &_snmpOutGetNexts_obj
+},
+_snmpOutGetResponses_obj = {
+ "snmpOutGetResponses", 28, 0,
+ NULL, &_snmpOutSetRequests_obj
+},
+_snmpOutTraps_obj = {
+ "snmpOutTraps", 29, 0,
+ NULL, &_snmpOutGetResponses_obj
+},
+_snmpEnableAuthTraps_obj = {
+ "snmpEnableAuthTraps", 30, 0,
+ NULL, &_snmpOutTraps_obj
+},
+_egpNeighState_obj = {
+ "egpNeighState", 1, 0,
+ NULL, NULL
+},
+_egpNeighAddr_obj = {
+ "egpNeighAddr", 2, 0,
+ NULL, &_egpNeighState_obj
+},
+_egpNeighAs_obj = {
+ "egpNeighAs", 3, 0,
+ NULL, &_egpNeighAddr_obj
+},
+_egpNeighInMsgs_obj = {
+ "egpNeighInMsgs", 4, 0,
+ NULL, &_egpNeighAs_obj
+},
+_egpNeighInErrs_obj = {
+ "egpNeighInErrs", 5, 0,
+ NULL, &_egpNeighInMsgs_obj
+},
+_egpNeighOutMsgs_obj = {
+ "egpNeighOutMsgs", 6, 0,
+ NULL, &_egpNeighInErrs_obj
+},
+_egpNeighOutErrs_obj = {
+ "egpNeighOutErrs", 7, 0,
+ NULL, &_egpNeighOutMsgs_obj
+},
+_egpNeighInErrMsgs_obj = {
+ "egpNeighInErrMsgs", 8, 0,
+ NULL, &_egpNeighOutErrs_obj
+},
+_egpNeighOutErrMsgs_obj = {
+ "egpNeighOutErrMsgs", 9, 0,
+ NULL, &_egpNeighInErrMsgs_obj
+},
+_egpNeighStateUps_obj = {
+ "egpNeighStateUps", 10, 0,
+ NULL, &_egpNeighOutErrMsgs_obj
+},
+_egpNeighStateDowns_obj = {
+ "egpNeighStateDowns", 11, 0,
+ NULL, &_egpNeighStateUps_obj
+},
+_egpNeighIntervalHello_obj = {
+ "egpNeighIntervalHello", 12, 0,
+ NULL, &_egpNeighStateDowns_obj
+},
+_egpNeighIntervalPoll_obj = {
+ "egpNeighIntervalPoll", 13, 0,
+ NULL, &_egpNeighIntervalHello_obj
+},
+_egpNeighMode_obj = {
+ "egpNeighMode", 14, 0,
+ NULL, &_egpNeighIntervalPoll_obj
+},
+_egpNeighEventTrigger_obj = {
+ "egpNeighEventTrigger", 15, 0,
+ NULL, &_egpNeighMode_obj
+},
+_egpNeighEntry_obj = {
+ "egpNeighEntry", 1, 0,
+ &_egpNeighEventTrigger_obj, NULL
+},
+_egpInMsgs_obj = {
+ "egpInMsgs", 1, 0,
+ NULL, NULL
+},
+_egpInErrors_obj = {
+ "egpInErrors", 2, 0,
+ NULL, &_egpInMsgs_obj
+},
+_egpOutMsgs_obj = {
+ "egpOutMsgs", 3, 0,
+ NULL, &_egpInErrors_obj
+},
+_egpOutErrors_obj = {
+ "egpOutErrors", 4, 0,
+ NULL, &_egpOutMsgs_obj
+},
+_egpNeighTable_obj = {
+ "egpNeighTable", 5, 0,
+ &_egpNeighEntry_obj, &_egpOutErrors_obj
+},
+_egpAs_obj = {
+ "egpAs", 6, 0,
+ NULL, &_egpNeighTable_obj
+},
+_udpLocalAddress_obj = {
+ "udpLocalAddress", 1, 0,
+ NULL, NULL
+},
+_udpLocalPort_obj = {
+ "udpLocalPort", 2, 0,
+ NULL, &_udpLocalAddress_obj
+},
+_udpEntry_obj = {
+ "udpEntry", 1, 0,
+ &_udpLocalPort_obj, NULL
+},
+_udpInDatagrams_obj = {
+ "udpInDatagrams", 1, 0,
+ NULL, NULL
+},
+_udpNoPorts_obj = {
+ "udpNoPorts", 2, 0,
+ NULL, &_udpInDatagrams_obj
+},
+_udpInErrors_obj = {
+ "udpInErrors", 3, 0,
+ NULL, &_udpNoPorts_obj
+},
+_udpOutDatagrams_obj = {
+ "udpOutDatagrams", 4, 0,
+ NULL, &_udpInErrors_obj
+},
+_udpTable_obj = {
+ "udpTable", 5, 0,
+ &_udpEntry_obj, &_udpOutDatagrams_obj
+},
+_tcpConnState_obj = {
+ "tcpConnState", 1, 0,
+ NULL, NULL
+},
+_tcpConnLocalAddress_obj = {
+ "tcpConnLocalAddress", 2, 0,
+ NULL, &_tcpConnState_obj
+},
+_tcpConnLocalPort_obj = {
+ "tcpConnLocalPort", 3, 0,
+ NULL, &_tcpConnLocalAddress_obj
+},
+_tcpConnRemAddress_obj = {
+ "tcpConnRemAddress", 4, 0,
+ NULL, &_tcpConnLocalPort_obj
+},
+_tcpConnRemPort_obj = {
+ "tcpConnRemPort", 5, 0,
+ NULL, &_tcpConnRemAddress_obj
+},
+_tcpConnEntry_obj = {
+ "tcpConnEntry", 1, 0,
+ &_tcpConnRemPort_obj, NULL
+},
+_tcpRtoAlgorithm_obj = {
+ "tcpRtoAlgorithm", 1, 0,
+ NULL, NULL
+},
+_tcpRtoMin_obj = {
+ "tcpRtoMin", 2, 0,
+ NULL, &_tcpRtoAlgorithm_obj
+},
+_tcpRtoMax_obj = {
+ "tcpRtoMax", 3, 0,
+ NULL, &_tcpRtoMin_obj
+},
+_tcpMaxConn_obj = {
+ "tcpMaxConn", 4, 0,
+ NULL, &_tcpRtoMax_obj
+},
+_tcpActiveOpens_obj = {
+ "tcpActiveOpens", 5, 0,
+ NULL, &_tcpMaxConn_obj
+},
+_tcpPassiveOpens_obj = {
+ "tcpPassiveOpens", 6, 0,
+ NULL, &_tcpActiveOpens_obj
+},
+_tcpAttemptFails_obj = {
+ "tcpAttemptFails", 7, 0,
+ NULL, &_tcpPassiveOpens_obj
+},
+_tcpEstabResets_obj = {
+ "tcpEstabResets", 8, 0,
+ NULL, &_tcpAttemptFails_obj
+},
+_tcpCurrEstab_obj = {
+ "tcpCurrEstab", 9, 0,
+ NULL, &_tcpEstabResets_obj
+},
+_tcpInSegs_obj = {
+ "tcpInSegs", 10, 0,
+ NULL, &_tcpCurrEstab_obj
+},
+_tcpOutSegs_obj = {
+ "tcpOutSegs", 11, 0,
+ NULL, &_tcpInSegs_obj
+},
+_tcpRetransSegs_obj = {
+ "tcpRetransSegs", 12, 0,
+ NULL, &_tcpOutSegs_obj
+},
+_tcpConnTable_obj = {
+ "tcpConnTable", 13, 0,
+ &_tcpConnEntry_obj, &_tcpRetransSegs_obj
+},
+_tcpInErrs_obj = {
+ "tcpInErrs", 14, 0,
+ NULL, &_tcpConnTable_obj
+},
+_tcpOutRsts_obj = {
+ "tcpOutRsts", 15, 0,
+ NULL, &_tcpInErrs_obj
+},
+_icmpInMsgs_obj = {
+ "icmpInMsgs", 1, 0,
+ NULL, NULL
+},
+_icmpInErrors_obj = {
+ "icmpInErrors", 2, 0,
+ NULL, &_icmpInMsgs_obj
+},
+_icmpInDestUnreachs_obj = {
+ "icmpInDestUnreachs", 3, 0,
+ NULL, &_icmpInErrors_obj
+},
+_icmpInTimeExcds_obj = {
+ "icmpInTimeExcds", 4, 0,
+ NULL, &_icmpInDestUnreachs_obj
+},
+_icmpInParmProbs_obj = {
+ "icmpInParmProbs", 5, 0,
+ NULL, &_icmpInTimeExcds_obj
+},
+_icmpInSrcQuenchs_obj = {
+ "icmpInSrcQuenchs", 6, 0,
+ NULL, &_icmpInParmProbs_obj
+},
+_icmpInRedirects_obj = {
+ "icmpInRedirects", 7, 0,
+ NULL, &_icmpInSrcQuenchs_obj
+},
+_icmpInEchos_obj = {
+ "icmpInEchos", 8, 0,
+ NULL, &_icmpInRedirects_obj
+},
+_icmpInEchoReps_obj = {
+ "icmpInEchoReps", 9, 0,
+ NULL, &_icmpInEchos_obj
+},
+_icmpInTimestamps_obj = {
+ "icmpInTimestamps", 10, 0,
+ NULL, &_icmpInEchoReps_obj
+},
+_icmpInTimestampReps_obj = {
+ "icmpInTimestampReps", 11, 0,
+ NULL, &_icmpInTimestamps_obj
+},
+_icmpInAddrMasks_obj = {
+ "icmpInAddrMasks", 12, 0,
+ NULL, &_icmpInTimestampReps_obj
+},
+_icmpInAddrMaskReps_obj = {
+ "icmpInAddrMaskReps", 13, 0,
+ NULL, &_icmpInAddrMasks_obj
+},
+_icmpOutMsgs_obj = {
+ "icmpOutMsgs", 14, 0,
+ NULL, &_icmpInAddrMaskReps_obj
+},
+_icmpOutErrors_obj = {
+ "icmpOutErrors", 15, 0,
+ NULL, &_icmpOutMsgs_obj
+},
+_icmpOutDestUnreachs_obj = {
+ "icmpOutDestUnreachs", 16, 0,
+ NULL, &_icmpOutErrors_obj
+},
+_icmpOutTimeExcds_obj = {
+ "icmpOutTimeExcds", 17, 0,
+ NULL, &_icmpOutDestUnreachs_obj
+},
+_icmpOutParmProbs_obj = {
+ "icmpOutParmProbs", 18, 0,
+ NULL, &_icmpOutTimeExcds_obj
+},
+_icmpOutSrcQuenchs_obj = {
+ "icmpOutSrcQuenchs", 19, 0,
+ NULL, &_icmpOutParmProbs_obj
+},
+_icmpOutRedirects_obj = {
+ "icmpOutRedirects", 20, 0,
+ NULL, &_icmpOutSrcQuenchs_obj
+},
+_icmpOutEchos_obj = {
+ "icmpOutEchos", 21, 0,
+ NULL, &_icmpOutRedirects_obj
+},
+_icmpOutEchoReps_obj = {
+ "icmpOutEchoReps", 22, 0,
+ NULL, &_icmpOutEchos_obj
+},
+_icmpOutTimestamps_obj = {
+ "icmpOutTimestamps", 23, 0,
+ NULL, &_icmpOutEchoReps_obj
+},
+_icmpOutTimestampReps_obj = {
+ "icmpOutTimestampReps", 24, 0,
+ NULL, &_icmpOutTimestamps_obj
+},
+_icmpOutAddrMasks_obj = {
+ "icmpOutAddrMasks", 25, 0,
+ NULL, &_icmpOutTimestampReps_obj
+},
+_icmpOutAddrMaskReps_obj = {
+ "icmpOutAddrMaskReps", 26, 0,
+ NULL, &_icmpOutAddrMasks_obj
+},
+_ipNetToMediaIfIndex_obj = {
+ "ipNetToMediaIfIndex", 1, 0,
+ NULL, NULL
+},
+_ipNetToMediaPhysAddress_obj = {
+ "ipNetToMediaPhysAddress", 2, 0,
+ NULL, &_ipNetToMediaIfIndex_obj
+},
+_ipNetToMediaNetAddress_obj = {
+ "ipNetToMediaNetAddress", 3, 0,
+ NULL, &_ipNetToMediaPhysAddress_obj
+},
+_ipNetToMediaType_obj = {
+ "ipNetToMediaType", 4, 0,
+ NULL, &_ipNetToMediaNetAddress_obj
+},
+_ipNetToMediaEntry_obj = {
+ "ipNetToMediaEntry", 1, 0,
+ &_ipNetToMediaType_obj, NULL
+},
+_ipRouteDest_obj = {
+ "ipRouteDest", 1, 0,
+ NULL, NULL
+},
+_ipRouteIfIndex_obj = {
+ "ipRouteIfIndex", 2, 0,
+ NULL, &_ipRouteDest_obj
+},
+_ipRouteMetric1_obj = {
+ "ipRouteMetric1", 3, 0,
+ NULL, &_ipRouteIfIndex_obj
+},
+_ipRouteMetric2_obj = {
+ "ipRouteMetric2", 4, 0,
+ NULL, &_ipRouteMetric1_obj
+},
+_ipRouteMetric3_obj = {
+ "ipRouteMetric3", 5, 0,
+ NULL, &_ipRouteMetric2_obj
+},
+_ipRouteMetric4_obj = {
+ "ipRouteMetric4", 6, 0,
+ NULL, &_ipRouteMetric3_obj
+},
+_ipRouteNextHop_obj = {
+ "ipRouteNextHop", 7, 0,
+ NULL, &_ipRouteMetric4_obj
+},
+_ipRouteType_obj = {
+ "ipRouteType", 8, 0,
+ NULL, &_ipRouteNextHop_obj
+},
+_ipRouteProto_obj = {
+ "ipRouteProto", 9, 0,
+ NULL, &_ipRouteType_obj
+},
+_ipRouteAge_obj = {
+ "ipRouteAge", 10, 0,
+ NULL, &_ipRouteProto_obj
+},
+_ipRouteMask_obj = {
+ "ipRouteMask", 11, 0,
+ NULL, &_ipRouteAge_obj
+},
+_ipRouteEntry_obj = {
+ "ipRouteEntry", 1, 0,
+ &_ipRouteMask_obj, NULL
+},
+_ipAdEntAddr_obj = {
+ "ipAdEntAddr", 1, 0,
+ NULL, NULL
+},
+_ipAdEntIfIndex_obj = {
+ "ipAdEntIfIndex", 2, 0,
+ NULL, &_ipAdEntAddr_obj
+},
+_ipAdEntNetMask_obj = {
+ "ipAdEntNetMask", 3, 0,
+ NULL, &_ipAdEntIfIndex_obj
+},
+_ipAdEntBcastAddr_obj = {
+ "ipAdEntBcastAddr", 4, 0,
+ NULL, &_ipAdEntNetMask_obj
+},
+_ipAdEntReasmMaxSize_obj = {
+ "ipAdEntReasmMaxSize", 5, 0,
+ NULL, &_ipAdEntBcastAddr_obj
+},
+_ipAddrEntry_obj = {
+ "ipAddrEntry", 1, 0,
+ &_ipAdEntReasmMaxSize_obj, NULL
+},
+_ipForwarding_obj = {
+ "ipForwarding", 1, 0,
+ NULL, NULL
+},
+_ipDefaultTTL_obj = {
+ "ipDefaultTTL", 2, 0,
+ NULL, &_ipForwarding_obj
+},
+_ipInReceives_obj = {
+ "ipInReceives", 3, 0,
+ NULL, &_ipDefaultTTL_obj
+},
+_ipInHdrErrors_obj = {
+ "ipInHdrErrors", 4, 0,
+ NULL, &_ipInReceives_obj
+},
+_ipInAddrErrors_obj = {
+ "ipInAddrErrors", 5, 0,
+ NULL, &_ipInHdrErrors_obj
+},
+_ipForwDatagrams_obj = {
+ "ipForwDatagrams", 6, 0,
+ NULL, &_ipInAddrErrors_obj
+},
+_ipInUnknownProtos_obj = {
+ "ipInUnknownProtos", 7, 0,
+ NULL, &_ipForwDatagrams_obj
+},
+_ipInDiscards_obj = {
+ "ipInDiscards", 8, 0,
+ NULL, &_ipInUnknownProtos_obj
+},
+_ipInDelivers_obj = {
+ "ipInDelivers", 9, 0,
+ NULL, &_ipInDiscards_obj
+},
+_ipOutRequests_obj = {
+ "ipOutRequests", 10, 0,
+ NULL, &_ipInDelivers_obj
+},
+_ipOutDiscards_obj = {
+ "ipOutDiscards", 11, 0,
+ NULL, &_ipOutRequests_obj
+},
+_ipOutNoRoutes_obj = {
+ "ipOutNoRoutes", 12, 0,
+ NULL, &_ipOutDiscards_obj
+},
+_ipReasmTimeout_obj = {
+ "ipReasmTimeout", 13, 0,
+ NULL, &_ipOutNoRoutes_obj
+},
+_ipReasmReqds_obj = {
+ "ipReasmReqds", 14, 0,
+ NULL, &_ipReasmTimeout_obj
+},
+_ipReasmOKs_obj = {
+ "ipReasmOKs", 15, 0,
+ NULL, &_ipReasmReqds_obj
+},
+_ipReasmFails_obj = {
+ "ipReasmFails", 16, 0,
+ NULL, &_ipReasmOKs_obj
+},
+_ipFragOKs_obj = {
+ "ipFragOKs", 17, 0,
+ NULL, &_ipReasmFails_obj
+},
+_ipFragFails_obj = {
+ "ipFragFails", 18, 0,
+ NULL, &_ipFragOKs_obj
+},
+_ipFragCreates_obj = {
+ "ipFragCreates", 19, 0,
+ NULL, &_ipFragFails_obj
+},
+_ipAddrTable_obj = {
+ "ipAddrTable", 20, 0,
+ &_ipAddrEntry_obj, &_ipFragCreates_obj
+},
+_ipRoutingTable_obj = {
+ "ipRoutingTable", 21, 0,
+ &_ipRouteEntry_obj, &_ipAddrTable_obj
+},
+_ipNetToMediaTable_obj = {
+ "ipNetToMediaTable", 22, 0,
+ &_ipNetToMediaEntry_obj, &_ipRoutingTable_obj
+},
+_atIfIndex_obj = {
+ "atIfIndex", 1, 0,
+ NULL, NULL
+},
+_atPhysAddress_obj = {
+ "atPhysAddress", 2, 0,
+ NULL, &_atIfIndex_obj
+},
+_atNetAddress_obj = {
+ "atNetAddress", 3, 0,
+ NULL, &_atPhysAddress_obj
+},
+_atEntry_obj = {
+ "atEntry", 1, 0,
+ &_atNetAddress_obj, NULL
+},
+_atTable_obj = {
+ "atTable", 1, 0,
+ &_atEntry_obj, NULL
+},
+_ifIndex_obj = {
+ "ifIndex", 1, 0,
+ NULL, NULL
+},
+_ifDescr_obj = {
+ "ifDescr", 2, 0,
+ NULL, &_ifIndex_obj
+},
+_ifType_obj = {
+ "ifType", 3, 0,
+ NULL, &_ifDescr_obj
+},
+_ifMtu_obj = {
+ "ifMtu", 4, 0,
+ NULL, &_ifType_obj
+},
+_ifSpeed_obj = {
+ "ifSpeed", 5, 0,
+ NULL, &_ifMtu_obj
+},
+_ifPhysAddress_obj = {
+ "ifPhysAddress", 6, 0,
+ NULL, &_ifSpeed_obj
+},
+_ifAdminStatus_obj = {
+ "ifAdminStatus", 7, 0,
+ NULL, &_ifPhysAddress_obj
+},
+_ifOperStatus_obj = {
+ "ifOperStatus", 8, 0,
+ NULL, &_ifAdminStatus_obj
+},
+_ifLastChange_obj = {
+ "ifLastChange", 9, 0,
+ NULL, &_ifOperStatus_obj
+},
+_ifInOctets_obj = {
+ "ifInOctets", 10, 0,
+ NULL, &_ifLastChange_obj
+},
+_ifInUcastPkts_obj = {
+ "ifInUcastPkts", 11, 0,
+ NULL, &_ifInOctets_obj
+},
+_ifInNUcastPkts_obj = {
+ "ifInNUcastPkts", 12, 0,
+ NULL, &_ifInUcastPkts_obj
+},
+_ifInDiscards_obj = {
+ "ifInDiscards", 13, 0,
+ NULL, &_ifInNUcastPkts_obj
+},
+_ifInErrors_obj = {
+ "ifInErrors", 14, 0,
+ NULL, &_ifInDiscards_obj
+},
+_ifInUnknownProtos_obj = {
+ "ifInUnknownProtos", 15, 0,
+ NULL, &_ifInErrors_obj
+},
+_ifOutOctets_obj = {
+ "ifOutOctets", 16, 0,
+ NULL, &_ifInUnknownProtos_obj
+},
+_ifOutUcastPkts_obj = {
+ "ifOutUcastPkts", 17, 0,
+ NULL, &_ifOutOctets_obj
+},
+_ifOutNUcastPkts_obj = {
+ "ifOutNUcastPkts", 18, 0,
+ NULL, &_ifOutUcastPkts_obj
+},
+_ifOutDiscards_obj = {
+ "ifOutDiscards", 19, 0,
+ NULL, &_ifOutNUcastPkts_obj
+},
+_ifOutErrors_obj = {
+ "ifOutErrors", 20, 0,
+ NULL, &_ifOutDiscards_obj
+},
+_ifOutQLen_obj = {
+ "ifOutQLen", 21, 0,
+ NULL, &_ifOutErrors_obj
+},
+_ifSpecific_obj = {
+ "ifSpecific", 22, 0,
+ NULL, &_ifOutQLen_obj
+},
+_ifEntry_obj = {
+ "ifEntry", 1, 0,
+ &_ifSpecific_obj, NULL
+},
+_ifNumber_obj = {
+ "ifNumber", 1, 0,
+ NULL, NULL
+},
+_ifTable_obj = {
+ "ifTable", 2, 0,
+ &_ifEntry_obj, &_ifNumber_obj
+},
+_sysDescr_obj = {
+ "sysDescr", 1, 0,
+ NULL, NULL
+},
+_sysObjectID_obj = {
+ "sysObjectID", 2, 0,
+ NULL, &_sysDescr_obj
+},
+_sysUpTime_obj = {
+ "sysUpTime", 3, 0,
+ NULL, &_sysObjectID_obj
+},
+_sysContact_obj = {
+ "sysContact", 4, 0,
+ NULL, &_sysUpTime_obj
+},
+_sysName_obj = {
+ "sysName", 5, 0,
+ NULL, &_sysContact_obj
+},
+_sysLocation_obj = {
+ "sysLocation", 6, 0,
+ NULL, &_sysName_obj
+},
+_sysServices_obj = {
+ "sysServices", 7, 0,
+ NULL, &_sysLocation_obj
+},
+_system_obj = {
+ "system", 1, 0,
+ &_sysServices_obj, NULL
+},
+_interfaces_obj = {
+ "interfaces", 2, 0,
+ &_ifTable_obj, &_system_obj
+},
+_at_obj = {
+ "at", 3, 0,
+ &_atTable_obj, &_interfaces_obj
+},
+_ip_obj = {
+ "ip", 4, 0,
+ &_ipNetToMediaTable_obj, &_at_obj
+},
+_icmp_obj = {
+ "icmp", 5, 0,
+ &_icmpOutAddrMaskReps_obj, &_ip_obj
+},
+_tcp_obj = {
+ "tcp", 6, 0,
+ &_tcpOutRsts_obj, &_icmp_obj
+},
+_udp_obj = {
+ "udp", 7, 0,
+ &_udpTable_obj, &_tcp_obj
+},
+_egp_obj = {
+ "egp", 8, 0,
+ &_egpAs_obj, &_udp_obj
+},
+_transmission_obj = {
+ "transmission", 10, 0,
+ NULL, &_egp_obj
+},
+_snmp_obj = {
+ "snmp", 11, 0,
+ &_snmpEnableAuthTraps_obj, &_transmission_obj
+},
+_mib_obj = {
+ "mib", 1, 0,
+ &_snmp_obj, NULL
+},
+_directory_obj = {
+ "directory", 1, 0,
+ NULL, NULL
+},
+_mgmt_obj = {
+ "mgmt", 2, 0,
+ &_mib_obj, &_directory_obj
+},
+_experimental_obj = {
+ "experimental", 3, 0,
+ NULL, &_mgmt_obj
+},
+_private_obj = {
+ "private", 4, 0,
+ &_enterprises_obj, &_experimental_obj
+},
+_internet_obj = {
+ "internet", 1, 0,
+ &_private_obj, NULL
+},
+_dod_obj = {
+ "dod", 6, 0,
+ &_internet_obj, NULL
+},
+_org_obj = {
+ "org", 3, 0,
+ &_dod_obj, NULL
+},
+_iso_obj = {
+ "iso", 1, 0,
+ &_org_obj, NULL
+},
+*mibroot = &_iso_obj;
diff --git a/usr.sbin/tcpdump/nfsfh.h b/usr.sbin/tcpdump/nfsfh.h
new file mode 100644
index 00000000000..5d6ff780203
--- /dev/null
+++ b/usr.sbin/tcpdump/nfsfh.h
@@ -0,0 +1,36 @@
+/* $NetBSD: nfsfh.h,v 1.2 1995/03/06 19:10:39 mycroft Exp $ */
+
+/*
+ * Header: nfsfh.h,v 1.3 94/06/12 14:32:58 leres Exp
+ *
+ * nfsfh.h - NFS file handle definitions (for portable use)
+ *
+ * Jeffrey C. Mogul
+ * Digital Equipment Corporation
+ * Western Research Laboratory
+ */
+
+/*
+ * Internal representation of dev_t, because different NFS servers
+ * that we might be spying upon use different external representations.
+ */
+typedef struct {
+ u_long Minor; /* upper case to avoid clashing with macro names */
+ u_long Major;
+} my_devt;
+
+#define dev_eq(a,b) ((a.Minor == b.Minor) && (a.Major == b.Major))
+
+/*
+ * Many file servers now use a large file system ID. This is
+ * our internal representation of that.
+ */
+typedef struct {
+ my_devt fsid_dev;
+ u_long fsid_code;
+} my_fsid;
+
+#define fsid_eq(a,b) ((a.fsid_code == b.fsid_code) &&\
+ dev_eq(a.fsid_dev, b.fsid_dev))
+
+extern void Parse_fh(caddr_t *, my_fsid *, ino_t *, char **, char **, int);
diff --git a/usr.sbin/tcpdump/nfsv2.h b/usr.sbin/tcpdump/nfsv2.h
new file mode 100644
index 00000000000..e8cdba97dca
--- /dev/null
+++ b/usr.sbin/tcpdump/nfsv2.h
@@ -0,0 +1,262 @@
+/* $NetBSD: nfsv2.h,v 1.2 1995/03/06 19:10:40 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * 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.
+ *
+ * @(#)nfsv2.h 7.11 (Berkeley) 9/30/92
+ */
+
+/*
+ * nfs definitions as per the version 2 specs
+ */
+
+/*
+ * Constants as defined in the Sun NFS Version 2 spec.
+ * "NFS: Network File System Protocol Specification" RFC1094
+ */
+
+#define NFS_PORT 2049
+#define NFS_PROG 100003
+#define NFS_VER2 2
+#define NFS_MAXDGRAMDATA 8192
+#define NFS_MAXDATA 32768
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_MAXPKTHDR 404
+#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA)
+#define NFS_MINPACKET 20
+#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
+
+/* Stat numbers for rpc returns */
+#define NFS_OK 0
+#define NFSERR_PERM 1
+#define NFSERR_NOENT 2
+#define NFSERR_IO 5
+#define NFSERR_NXIO 6
+#define NFSERR_ACCES 13
+#define NFSERR_EXIST 17
+#define NFSERR_NODEV 19
+#define NFSERR_NOTDIR 20
+#define NFSERR_ISDIR 21
+#define NFSERR_FBIG 27
+#define NFSERR_NOSPC 28
+#define NFSERR_ROFS 30
+#define NFSERR_NAMETOL 63
+#define NFSERR_NOTEMPTY 66
+#define NFSERR_DQUOT 69
+#define NFSERR_STALE 70
+#define NFSERR_WFLUSH 99
+
+/* Sizes in bytes of various nfs rpc components */
+#define NFSX_FH 32
+#define NFSX_UNSIGNED 4
+#define NFSX_NFSFATTR 68
+#define NFSX_NQFATTR 92
+#define NFSX_NFSSATTR 32
+#define NFSX_NQSATTR 44
+#define NFSX_COOKIE 4
+#define NFSX_NFSSTATFS 20
+#define NFSX_NQSTATFS 28
+#define NFSX_FATTR(isnq) ((isnq) ? NFSX_NQFATTR : NFSX_NFSFATTR)
+#define NFSX_SATTR(isnq) ((isnq) ? NFSX_NQSATTR : NFSX_NFSSATTR)
+#define NFSX_STATFS(isnq) ((isnq) ? NFSX_NQSTATFS : NFSX_NFSSTATFS)
+
+/* nfs rpc procedure numbers */
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_NOOP 3
+#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */
+#define NFSPROC_LOOKUP 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */
+#define NFSPROC_WRITE 8
+#define NFSPROC_CREATE 9
+#define NFSPROC_REMOVE 10
+#define NFSPROC_RENAME 11
+#define NFSPROC_LINK 12
+#define NFSPROC_SYMLINK 13
+#define NFSPROC_MKDIR 14
+#define NFSPROC_RMDIR 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_STATFS 17
+
+/* NQ nfs numbers */
+#define NQNFSPROC_READDIRLOOK 18
+#define NQNFSPROC_GETLEASE 19
+#define NQNFSPROC_VACATED 20
+#define NQNFSPROC_EVICTED 21
+#define NQNFSPROC_ACCESS 22
+
+#define NFS_NPROCS 23
+/* Conversion macros */
+extern int vttoif_tab[];
+#define vtonfs_mode(t,m) \
+ txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \
+ MAKEIMODE((t), (m)))
+#define nfstov_mode(a) (fxdr_unsigned(u_short, (a))&07777)
+#define vtonfs_type(a) txdr_unsigned(nfs_type[((long)(a))])
+#define nfstov_type(a) ntov_type[fxdr_unsigned(u_long,(a))&0x7]
+
+/* File types */
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 } nfstype;
+
+/* Structs for common parts of the rpc's */
+struct nfsv2_time {
+ u_long nfs_sec;
+ u_long nfs_usec;
+};
+
+struct nqnfs_time {
+ u_long nq_sec;
+ u_long nq_nsec;
+};
+
+/*
+ * File attributes and setable attributes. These structures cover both
+ * NFS version 2 and the NQNFS protocol. Note that the union is only
+ * used to that one pointer can refer to both variants. These structures
+ * go out on the wire and must be densely packed, so no quad data types
+ * are used. (all fields are longs or u_longs or structures of same)
+ * NB: You can't do sizeof(struct nfsv2_fattr), you must use the
+ * NFSX_FATTR(isnq) macro.
+ */
+struct nfsv2_fattr {
+ u_long fa_type;
+ u_long fa_mode;
+ u_long fa_nlink;
+ u_long fa_uid;
+ u_long fa_gid;
+ union {
+ struct {
+ u_long nfsfa_size;
+ u_long nfsfa_blocksize;
+ u_long nfsfa_rdev;
+ u_long nfsfa_blocks;
+ u_long nfsfa_fsid;
+ u_long nfsfa_fileid;
+ struct nfsv2_time nfsfa_atime;
+ struct nfsv2_time nfsfa_mtime;
+ struct nfsv2_time nfsfa_ctime;
+ } fa_nfsv2;
+ struct {
+ struct {
+ u_long nqfa_qsize[2];
+ } nqfa_size;
+ u_long nqfa_blocksize;
+ u_long nqfa_rdev;
+ struct {
+ u_long nqfa_qbytes[2];
+ } nqfa_bytes;
+ u_long nqfa_fsid;
+ u_long nqfa_fileid;
+ struct nqnfs_time nqfa_atime;
+ struct nqnfs_time nqfa_mtime;
+ struct nqnfs_time nqfa_ctime;
+ u_long nqfa_flags;
+ u_long nqfa_gen;
+ struct {
+ u_long nqfa_qfilerev[2];
+ } nqfa_filerev;
+ } fa_nqnfs;
+ } fa_un;
+};
+
+/* and some ugly defines for accessing union components */
+#define fa_nfssize fa_un.fa_nfsv2.nfsfa_size
+#define fa_nfsblocksize fa_un.fa_nfsv2.nfsfa_blocksize
+#define fa_nfsrdev fa_un.fa_nfsv2.nfsfa_rdev
+#define fa_nfsblocks fa_un.fa_nfsv2.nfsfa_blocks
+#define fa_nfsfsid fa_un.fa_nfsv2.nfsfa_fsid
+#define fa_nfsfileid fa_un.fa_nfsv2.nfsfa_fileid
+#define fa_nfsatime fa_un.fa_nfsv2.nfsfa_atime
+#define fa_nfsmtime fa_un.fa_nfsv2.nfsfa_mtime
+#define fa_nfsctime fa_un.fa_nfsv2.nfsfa_ctime
+#define fa_nqsize fa_un.fa_nqnfs.nqfa_size
+#define fa_nqblocksize fa_un.fa_nqnfs.nqfa_blocksize
+#define fa_nqrdev fa_un.fa_nqnfs.nqfa_rdev
+#define fa_nqbytes fa_un.fa_nqnfs.nqfa_bytes
+#define fa_nqfsid fa_un.fa_nqnfs.nqfa_fsid
+#define fa_nqfileid fa_un.fa_nqnfs.nqfa_fileid
+#define fa_nqatime fa_un.fa_nqnfs.nqfa_atime
+#define fa_nqmtime fa_un.fa_nqnfs.nqfa_mtime
+#define fa_nqctime fa_un.fa_nqnfs.nqfa_ctime
+#define fa_nqflags fa_un.fa_nqnfs.nqfa_flags
+#define fa_nqgen fa_un.fa_nqnfs.nqfa_gen
+#define fa_nqfilerev fa_un.fa_nqnfs.nqfa_filerev
+
+struct nfsv2_sattr {
+ u_long sa_mode;
+ u_long sa_uid;
+ u_long sa_gid;
+ union {
+ struct {
+ u_long nfssa_size;
+ struct nfsv2_time nfssa_atime;
+ struct nfsv2_time nfssa_mtime;
+ } sa_nfsv2;
+ struct {
+ struct {
+ u_long nqsa_qsize[2];
+ } nqsa_size;
+ struct nqnfs_time nqsa_atime;
+ struct nqnfs_time nqsa_mtime;
+ u_long nqsa_flags;
+ u_long nqsa_rdev;
+ } sa_nqnfs;
+ } sa_un;
+};
+
+/* and some ugly defines for accessing the unions */
+#define sa_nfssize sa_un.sa_nfsv2.nfssa_size
+#define sa_nfsatime sa_un.sa_nfsv2.nfssa_atime
+#define sa_nfsmtime sa_un.sa_nfsv2.nfssa_mtime
+#define sa_nqsize sa_un.sa_nqnfs.nqsa_size
+#define sa_nqatime sa_un.sa_nqnfs.nqsa_atime
+#define sa_nqmtime sa_un.sa_nqnfs.nqsa_mtime
+#define sa_nqflags sa_un.sa_nqnfs.nqsa_flags
+#define sa_nqrdev sa_un.sa_nqnfs.nqsa_rdev
+
+struct nfsv2_statfs {
+ u_long sf_tsize;
+ u_long sf_bsize;
+ u_long sf_blocks;
+ u_long sf_bfree;
+ u_long sf_bavail;
+ u_long sf_files; /* Nqnfs only */
+ u_long sf_ffree; /* ditto */
+};
diff --git a/usr.sbin/tcpdump/ntp.h b/usr.sbin/tcpdump/ntp.h
new file mode 100644
index 00000000000..7443ce6e80c
--- /dev/null
+++ b/usr.sbin/tcpdump/ntp.h
@@ -0,0 +1,119 @@
+/* $NetBSD: ntp.h,v 1.2 1995/03/06 19:10:41 mycroft Exp $ */
+
+/* Header: ntp.h,v 1.2 93/11/12 21:43:36 mccanne Exp */
+
+/*
+ * Based on ntp.h from the U of MD implementation
+ * This file is based on Version 2 of the NTP spec (RFC1119).
+ */
+
+/*
+ * Definitions for the masses
+ */
+#define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
+
+/*
+ * Structure definitions for NTP fixed point values
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Integer Part |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Fraction Part |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Integer Part | Fraction Part |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct l_fixedpt {
+ u_int32 int_part;
+ u_int32 fraction;
+};
+
+struct s_fixedpt {
+ u_short int_part;
+ u_short fraction;
+};
+
+/* ================= Table 3.3. Packet Variables ================= */
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |LI | VN | Mode| Stratum | Poll | Precision |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Synchronizing Distance |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Synchronizing Dispersion |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reference Clock Identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Reference Timestamp (64 bits) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Originate Timestamp (64 bits) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Receive Timestamp (64 bits) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Transmit Timestamp (64 bits) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct ntpdata {
+ u_char status; /* status of local clock and leap info */
+ u_char stratum; /* Stratum level */
+ u_char ppoll; /* poll value */
+ int precision:8;
+ struct s_fixedpt distance;
+ struct s_fixedpt dispersion;
+ u_int32 refid;
+ struct l_fixedpt reftime;
+ struct l_fixedpt org;
+ struct l_fixedpt rec;
+ struct l_fixedpt xmt;
+};
+/*
+ * Leap Second Codes (high order two bits)
+ */
+#define NO_WARNING 0x00 /* no warning */
+#define PLUS_SEC 0x40 /* add a second (61 seconds) */
+#define MINUS_SEC 0x80 /* minus a second (59 seconds) */
+#define ALARM 0xc0 /* alarm condition (clock unsynchronized) */
+
+/*
+ * Clock Status Bits that Encode Version
+ */
+#define NTPVERSION_1 0x08
+#define VERSIONMASK 0x38
+#define LEAPMASK 0xc0
+#define MODEMASK 0x07
+
+/*
+ * Code values
+ */
+#define MODE_UNSPEC 0 /* unspecified */
+#define MODE_SYM_ACT 1 /* symmetric active */
+#define MODE_SYM_PAS 2 /* symmetric passive */
+#define MODE_CLIENT 3 /* client */
+#define MODE_SERVER 4 /* server */
+#define MODE_BROADCAST 5 /* broadcast */
+#define MODE_RES1 6 /* reserved */
+#define MODE_RES2 7 /* reserved */
+
+/*
+ * Stratum Definitions
+ */
+#define UNSPECIFIED 0
+#define PRIM_REF 1 /* radio clock */
+#define INFO_QUERY 62 /* **** THIS implementation dependent **** */
+#define INFO_REPLY 63 /* **** THIS implementation dependent **** */
diff --git a/usr.sbin/tcpdump/os.h b/usr.sbin/tcpdump/os.h
new file mode 100644
index 00000000000..9f807522041
--- /dev/null
+++ b/usr.sbin/tcpdump/os.h
@@ -0,0 +1,62 @@
+/* $NetBSD: os.h,v 1.2 1995/03/06 19:10:56 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) Header: os-bsd.h,v 1.18 94/06/14 20:15:17 leres Exp (LBL)
+ */
+
+#include <sys/param.h>
+
+#ifndef BSD
+#define BSD
+#endif
+
+#define SHA(ap) ((ap)->arp_sha)
+#define SPA(ap) ((ap)->arp_spa)
+#define THA(ap) ((ap)->arp_tha)
+#define TPA(ap) ((ap)->arp_tpa)
+
+#define EDST(ep) ((ep)->ether_dhost)
+#define ESRC(ep) ((ep)->ether_shost)
+
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP 0x8035
+#endif
+
+#ifndef IPPROTO_ND
+/* From <netinet/in.h> on a Sun somewhere. */
+#define IPPROTO_ND 77
+#endif
+
+#ifndef REVARP_REQUEST
+#define REVARP_REQUEST 3
+#endif
+#ifndef REVARP_REPLY
+#define REVARP_REPLY 4
+#endif
+
+/* newish RIP commands */
+#ifndef RIPCMD_POLL
+#define RIPCMD_POLL 5
+#endif
+#ifndef RIPCMD_POLLENTRY
+#define RIPCMD_POLLENTRY 6
+#endif
diff --git a/usr.sbin/tcpdump/ospf.h b/usr.sbin/tcpdump/ospf.h
new file mode 100644
index 00000000000..3a6d2b5632f
--- /dev/null
+++ b/usr.sbin/tcpdump/ospf.h
@@ -0,0 +1,225 @@
+/* $NetBSD: ospf.h,v 1.2 1995/03/06 19:10:57 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
+ */
+#define OSPF_TYPE_UMD 0 /* UMd's special monitoring packets */
+#define OSPF_TYPE_HELLO 1 /* Hello */
+#define OSPF_TYPE_DB 2 /* Database Description */
+#define OSPF_TYPE_LSR 3 /* Link State Request */
+#define OSPF_TYPE_LSU 4 /* Link State Update */
+#define OSPF_TYPE_LSA 5 /* Link State Ack */
+#define OSPF_TYPE_MAX 6
+
+/* Options *_options */
+#define OSPF_OPTION_T 0x01 /* T bit: TOS support */
+#define OSPF_OPTION_E 0x02 /* E bit: External routes advertised */
+#define OSPF_OPTION_MC 0x04 /* MC bit: Multicast capable */
+
+/* ospf_authtype */
+#define OSPF_AUTH_NONE 0 /* No auth-data */
+#define OSPF_AUTH_SIMPLE 1 /* Simple password */
+
+/* db_flags */
+#define OSPF_DB_INIT 0x04 /* */
+#define OSPF_DB_MORE 0x02
+#define OSPF_DB_MASTER 0x01
+
+/* ls_type */
+#define LS_TYPE_ROUTER 1 /* router link */
+#define LS_TYPE_NETWORK 2 /* network link */
+#define LS_TYPE_SUM_IP 3 /* summary link */
+#define LS_TYPE_SUM_ABR 4 /* summary area link */
+#define LS_TYPE_ASE 5 /* ASE */
+#define LS_TYPE_GROUP 6 /* Group membership (multicast */
+ /* extensions 23 July 1991) */
+#define LS_TYPE_MAX 7
+
+/*************************************************
+ *
+ * is the above a bug in the documentation?
+ *
+ *************************************************/
+
+
+/* rla_link.link_type */
+#define RLA_TYPE_ROUTER 1 /* point-to-point to another router */
+#define RLA_TYPE_TRANSIT 2 /* connection to transit network */
+#define RLA_TYPE_STUB 3 /* connection to stub network */
+#define RLA_TYPE_VIRTUAL 4 /* virtual link */
+
+/* rla_flags */
+#define RLA_FLAG_B 0x01
+#define RLA_FLAG_E 0x02
+#define RLA_FLAG_W1 0x04
+#define RLA_FLAG_W2 0x08
+
+/* sla_tosmetric breakdown */
+#define SLA_MASK_TOS 0x7f000000
+#define SLA_MASK_METRIC 0x00ffffff
+#define SLA_SHIFT_TOS 24
+
+/* asla_tosmetric breakdown */
+#define ASLA_FLAG_EXTERNAL 0x80000000
+#define ASLA_MASK_TOS 0x7f000000
+#define ASLA_SHIFT_TOS 24
+#define ASLA_MASK_METRIC 0x00ffffff
+
+/* multicast vertex type */
+#define MCLA_VERTEX_ROUTER 1
+#define MCLA_VERTEX_NETWORK 2
+
+/* link state advertisement header */
+struct lsa_hdr {
+ u_short ls_age;
+ u_char ls_options;
+ u_char ls_type;
+ struct in_addr ls_stateid;
+ struct in_addr ls_router;
+ u_int32 ls_seq;
+ u_short ls_chksum;
+ u_short ls_length;
+} ;
+
+/* link state advertisement */
+struct lsa {
+ struct lsa_hdr ls_hdr;
+
+ /* Link state types */
+ union {
+ /* Router links advertisements */
+ struct {
+ u_char rla_flags;
+ u_char rla_zero[1];
+ u_short rla_count;
+ struct rlalink {
+ struct in_addr link_id;
+ struct in_addr link_data;
+ u_char link_type;
+ u_char link_toscount;
+ u_short link_tos0metric;
+ } rla_link[1]; /* may repeat */
+ } un_rla;
+
+ /* Network links advertisements */
+ struct {
+ struct in_addr nla_mask;
+ struct in_addr nla_router[1]; /* may repeat */
+ } un_nla;
+
+ /* Summary links advertisements */
+ struct {
+ struct in_addr sla_mask;
+ u_int32 sla_tosmetric[1]; /* may repeat */
+ } un_sla;
+
+ /* AS external links advertisements */
+ struct {
+ struct in_addr asla_mask;
+ struct aslametric {
+ u_int32 asla_tosmetric;
+ struct in_addr asla_forward;
+ struct in_addr asla_tag;
+ } asla_metric[1]; /* may repeat */
+ } un_asla;
+
+ /* Multicast group membership */
+ struct mcla {
+ u_int32 mcla_vtype;
+ struct in_addr mcla_vid;
+ } un_mcla[1];
+ } lsa_un;
+} ;
+
+
+/*
+ * TOS metric struct (will be 0 or more in router links update)
+ */
+struct tos_metric {
+ u_char tos_type;
+ u_char tos_zero;
+ u_short tos_metric;
+} ;
+
+#define OSPF_AUTH_SIZE 8
+
+/*
+ * the main header
+ */
+struct ospfhdr {
+ u_char ospf_version;
+ u_char ospf_type;
+ u_short ospf_len;
+ struct in_addr ospf_routerid;
+ struct in_addr ospf_areaid;
+ u_short ospf_chksum;
+ u_short ospf_authtype;
+ u_char ospf_authdata[OSPF_AUTH_SIZE];
+ union {
+
+ /* Hello packet */
+ struct {
+ struct in_addr hello_mask;
+ u_short hello_helloint;
+ u_char hello_options;
+ u_char hello_priority;
+ u_int32 hello_deadint;
+ struct in_addr hello_dr;
+ struct in_addr hello_bdr;
+ struct in_addr hello_neighbor[1]; /* may repeat */
+ } un_hello;
+
+ /* Database Description packet */
+ struct {
+ u_char db_zero[2];
+ u_char db_options;
+ u_char db_flags;
+ u_int32 db_seq;
+ struct lsa_hdr db_lshdr[1]; /* may repeat */
+ } un_db;
+
+ /* Link State Request */
+ struct lsr {
+ u_int32 ls_type;
+ struct in_addr ls_stateid;
+ struct in_addr ls_router;
+ } un_lsr[1]; /* may repeat */
+
+ /* Link State Update */
+ struct {
+ u_int32 lsu_count;
+ struct lsa lsu_lsa[1]; /* may repeat */
+ } un_lsu;
+
+ /* Link State Acknowledment */
+ struct {
+ struct lsa_hdr lsa_lshdr[1]; /* may repeat */
+ } un_lsa ;
+ } ospf_un ;
+} ;
+
+#define ospf_hello ospf_un.un_hello
+#define ospf_db ospf_un.un_db
+#define ospf_lsr ospf_un.un_lsr
+#define ospf_lsu ospf_un.un_lsu
+#define ospf_lsa ospf_un.un_lsa
+
diff --git a/usr.sbin/tcpdump/packetdat.awk b/usr.sbin/tcpdump/packetdat.awk
new file mode 100644
index 00000000000..97746525f46
--- /dev/null
+++ b/usr.sbin/tcpdump/packetdat.awk
@@ -0,0 +1,63 @@
+# $NetBSD: packetdat.awk,v 1.2 1995/03/06 19:10:59 mycroft Exp $
+
+BEGIN {
+ # we need to know (usual) packet size to convert byte numbers
+ # to packet numbers
+ if (packetsize <= 0)
+ packetsize = 512
+ }
+$5 !~ /[SR]/ {
+ # print out per-packet data in the form:
+ # <packet #>
+ # <start sequence #>
+ # <1st send time>
+ # <last send time>
+ # <1st ack time>
+ # <last ack time>
+ # <# sends>
+ # <# acks>
+
+ n = split ($1,t,":")
+ tim = t[1]*3600 + t[2]*60 + t[3]
+ if ($6 != "ack") {
+ i = index($6,":")
+ strtSeq = substr($6,1,i-1)
+ id = 1.5 + (strtSeq - 1) / packetsize
+ id -= id % 1
+ if (maxId < id)
+ maxId = id
+ if (firstSend[id] == 0) {
+ firstSend[id] = tim
+ seqNo[id] = strtSeq
+ }
+ lastSend[id] = tim
+ timesSent[id]++
+ totalPackets++
+ } else {
+ id = 1 + ($7 - 2) / packetsize
+ id -= id % 1
+ timesAcked[id]++
+ if (firstAck[id] == 0)
+ firstAck[id] = tim
+ lastAck[id] = tim
+ totalAcks++
+ }
+ }
+END {
+ print "# " maxId " chunks. " totalPackets " packets sent. " \
+ totalAcks " acks."
+ # for packets that were implicitly acked, make the ack time
+ # be the ack time of next explicitly acked packet.
+ for (i = maxId-1; i > 0; --i)
+ while (i > 0 && firstAck[i] == 0) {
+ lastAck[i] = firstAck[i] = firstAck[i+1]
+ --i
+ }
+ tzero = firstSend[1]
+ for (i = 1; i <= maxId; i++)
+ printf "%d\t%d\t%.2f\t%.2f\t%.2f\t%.2f\t%d\t%d\n",\
+ i, seqNo[i], \
+ firstSend[i] - tzero, lastSend[i] - tzero,\
+ firstAck[i] - tzero, lastAck[i] - tzero,\
+ timesSent[i], timesAcked[i]
+ }
diff --git a/usr.sbin/tcpdump/parsenfsfh.c b/usr.sbin/tcpdump/parsenfsfh.c
new file mode 100644
index 00000000000..bff083088d9
--- /dev/null
+++ b/usr.sbin/tcpdump/parsenfsfh.c
@@ -0,0 +1,427 @@
+/* $NetBSD: parsenfsfh.c,v 1.2 1995/03/06 19:11:00 mycroft Exp $ */
+
+#ifndef lint
+static char *RCSid = "Header: parsenfsfh.c,v 1.5 94/01/13 19:06:41 leres Exp";
+#endif
+
+/*
+ * parsenfsfh.c - portable parser for NFS file handles
+ * uses all sorts of heuristics
+ *
+ * Jeffrey C. Mogul
+ * Digital Equipment Corporation
+ * Western Research Laboratory
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "interface.h"
+#include "nfsfh.h"
+
+/*
+ * Make sure that we use 32-bit integers when necessary. The "x"
+ * suffix is to avoid possible identifier conflicts.
+ */
+
+typedef int int32x;
+typedef unsigned int u_int32x;
+
+/*
+ * This routine attempts to parse a file handle (in network byte order),
+ * using heuristics to guess what kind of format it is in. See the
+ * file "fhandle_layouts" for a detailed description of the various
+ * patterns we know about.
+ *
+ * The file handle is parsed into our internal representation of a
+ * file-system id, and an internal representation of an inode-number.
+ */
+
+#define FHT_UNKNOWN 0
+#define FHT_AUSPEX 1
+#define FHT_DECOSF 2
+#define FHT_IRIX4 3
+#define FHT_IRIX5 4
+#define FHT_SUNOS3 5
+#define FHT_SUNOS4 6
+#define FHT_ULTRIX 7
+#define FHT_VMSUCX 8
+#define FHT_SUNOS5 9
+#define FHT_AIX32 10
+#define FHT_HPUX9 11
+
+#ifdef ultrix
+/* Nasty hack to keep the Ultrix C compiler from emitting bogus warnings */
+#define XFF(x) ((unsigned long)(x))
+#else
+#define XFF(x) (x)
+#endif
+
+#define make_uint32(msb,b,c,lsb)\
+ (XFF(lsb) + (XFF(c)<<8) + (XFF(b)<<16) + (XFF(msb)<<24))
+
+#define make_uint24(msb,b, lsb)\
+ (XFF(lsb) + (XFF(b)<<8) + (XFF(msb)<<16))
+
+#define make_uint16(msb,lsb)\
+ (XFF(lsb) + (XFF(msb)<<8))
+
+#ifdef __alpha
+ /* or other 64-bit systems */
+#define make_uint48(msb,b,c,d,e,lsb)\
+ ((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24) + ((b)<<32) + ((msb)<<40))
+#else
+ /* on 32-bit systems ignore high-order bits */
+#define make_uint48(msb,b,c,d,e,lsb)\
+ ((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24))
+#endif
+
+static int is_UCX(unsigned char *);
+
+void
+Parse_fh(fh, fsidp, inop, osnamep, fsnamep, ourself)
+register caddr_t *fh;
+my_fsid *fsidp;
+ino_t *inop;
+char **osnamep; /* if non-NULL, return OS name here */
+char **fsnamep; /* if non-NULL, return server fs name here (for VMS) */
+int ourself; /* true if file handle was generated on this host */
+{
+ register unsigned char *fhp = (unsigned char *)fh;
+ u_int32x temp;
+ int fhtype = FHT_UNKNOWN;
+
+ if (ourself) {
+ /* File handle generated on this host, no need for guessing */
+#if defined(IRIX40)
+ fhtype = FHT_IRIX4;
+#endif
+#if defined(IRIX50)
+ fhtype = FHT_IRIX5;
+#endif
+#if defined(IRIX51)
+ fhtype = FHT_IRIX5;
+#endif
+#if defined(SUNOS4)
+ fhtype = FHT_SUNOS4;
+#endif
+#if defined(SUNOS5)
+ fhtype = FHT_SUNOS5;
+#endif
+#if defined(ultrix)
+ fhtype = FHT_ULTRIX;
+#endif
+#if defined(__osf__)
+ fhtype = FHT_DECOSF;
+#endif
+ }
+ /*
+ * This is basically a big decision tree
+ */
+ else if ((fhp[0] == 0) && (fhp[1] == 0)) {
+ /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
+ /* probably rules out HP-UX, AIX unless they allow major=0 */
+ if ((fhp[2] == 0) && (fhp[3] == 0)) {
+ /* bytes[2,3] == (0,0); must be Auspex */
+ /* XXX or could be Ultrix+MASSBUS "hp" disk? */
+ fhtype = FHT_AUSPEX;
+ }
+ else {
+ /*
+ * bytes[2,3] != (0,0); rules out Auspex, could be
+ * DECOSF, SUNOS4, or IRIX4
+ */
+ if ((fhp[4] != 0) && (fhp[5] == 0) &&
+ (fhp[8] == 12) && (fhp[9] == 0)) {
+ /* seems to be DECOSF, with minor == 0 */
+ fhtype = FHT_DECOSF;
+ }
+ else {
+ /* could be SUNOS4 or IRIX4 */
+ /* XXX the test of fhp[5] == 8 could be wrong */
+ if ((fhp[4] == 0) && (fhp[5] == 8) && (fhp[6] == 0) &&
+ (fhp[7] == 0)) {
+ /* looks like a length, not a file system typecode */
+ fhtype = FHT_IRIX4;
+ }
+ else {
+ /* by elimination */
+ fhtype = FHT_SUNOS4;
+ }
+ }
+ }
+ }
+ else {
+ /*
+ * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
+ * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
+ * could be AIX, HP-UX
+ */
+ if ((fhp[2] == 0) && (fhp[3] == 0)) {
+ /*
+ * bytes[2,3] == (0,0); rules out OSF, probably not UCX
+ * (unless the exported device name is just one letter!),
+ * could be Ultrix, IRIX5, AIX, or SUNOS5
+ * might be HP-UX (depends on their values for minor devs)
+ */
+ /*XXX we probably only need to test of these two bytes */
+ if ((fhp[21] == 0) && (fhp[23] == 0)) {
+ fhtype = FHT_ULTRIX;
+ }
+ else {
+ /* Could be SUNOS5/IRIX5, maybe AIX */
+ /* XXX no obvious difference between SUNOS5 and IRIX5 */
+ if (fhp[9] == 10)
+ fhtype = FHT_SUNOS5;
+ /* XXX what about AIX? */
+ }
+ }
+ else {
+ /*
+ * bytes[2,3] != (0,0); rules out Ultrix, could be
+ * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
+ */
+ if ((fhp[8] == 12) && (fhp[9] == 0)) {
+ fhtype = FHT_DECOSF;
+ }
+ else if ((fhp[8] == 0) && (fhp[9] == 10)) {
+ /* could be SUNOS5/IRIX5, AIX, HP-UX */
+ if ((fhp[7] == 0) && (fhp[6] == 0) &&
+ (fhp[5] == 0) && (fhp[4] == 0)) {
+ /* XXX is this always true of HP-UX? */
+ fhtype = FHT_HPUX9;
+ }
+ else if (fhp[7] == 2) {
+ /* This would be MNT_NFS on AIX, which is impossible */
+ fhtype = FHT_SUNOS5; /* or maybe IRIX5 */
+ }
+ else {
+ /*
+ * XXX Could be SUNOS5/IRIX5 or AIX. I don't
+ * XXX see any way to disambiguate these, so
+ * XXX I'm going with the more likely guess.
+ * XXX Sorry, Big Blue.
+ */
+ fhtype = FHT_SUNOS5; /* or maybe IRIX5 */
+ }
+ }
+ else {
+ if (is_UCX(fhp)) {
+ fhtype = FHT_VMSUCX;
+ }
+ else {
+ fhtype = FHT_UNKNOWN;
+ }
+ }
+ }
+ }
+
+ /* XXX still needs to handle SUNOS3 */
+
+ switch (fhtype) {
+ case FHT_AUSPEX:
+ fsidp->fsid_dev.Minor = fhp[7];
+ fsidp->fsid_dev.Major = fhp[6];
+ fsidp->fsid_code = 0;
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "Auspex";
+ break;
+
+ case FHT_DECOSF:
+ fsidp->fsid_code = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
+ /* XXX could ignore 3 high-order bytes */
+
+ temp = make_uint32(fhp[3], fhp[2], fhp[1], fhp[0]);
+ fsidp->fsid_dev.Minor = temp & 0xFFFFF;
+ fsidp->fsid_dev.Major = (temp>>20) & 0xFFF;
+
+ temp = make_uint32(fhp[15], fhp[14], fhp[13], fhp[12]);
+ *inop = temp;
+ if (osnamep)
+ *osnamep = "OSF";
+ break;
+
+ case FHT_IRIX4:
+ fsidp->fsid_dev.Minor = fhp[3];
+ fsidp->fsid_dev.Major = fhp[2];
+ fsidp->fsid_code = 0;
+
+ temp = make_uint32(fhp[8], fhp[9], fhp[10], fhp[11]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "IRIX4";
+ break;
+
+ case FHT_IRIX5:
+ fsidp->fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
+ fsidp->fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
+ fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "IRIX5";
+ break;
+
+ case FHT_SUNOS3:
+ if (osnamep)
+ *osnamep = "SUNOS3";
+ break;
+
+ case FHT_SUNOS4:
+ fsidp->fsid_dev.Minor = fhp[3];
+ fsidp->fsid_dev.Major = fhp[2];
+ fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "SUNOS4";
+ break;
+
+ case FHT_SUNOS5:
+ temp = make_uint16(fhp[0], fhp[1]);
+ fsidp->fsid_dev.Major = (temp>>2) & 0x3FFF;
+ temp = make_uint24(fhp[1], fhp[2], fhp[3]);
+ fsidp->fsid_dev.Minor = temp & 0x3FFFF;
+ fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "SUNOS5";
+ break;
+
+ case FHT_ULTRIX:
+ fsidp->fsid_code = 0;
+ fsidp->fsid_dev.Minor = fhp[0];
+ fsidp->fsid_dev.Major = fhp[1];
+
+ temp = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
+ *inop = temp;
+ if (osnamep)
+ *osnamep = "Ultrix";
+ break;
+
+ case FHT_VMSUCX:
+ /* No numeric file system ID, so hash on the device-name */
+ if (sizeof(*fsidp) >= 14) {
+ if (sizeof(*fsidp) > 14)
+ bzero((char *)fsidp, sizeof(*fsidp));
+ bcopy(fh, (char *)fsidp, 14); /* just use the whole thing */
+ }
+ else {
+ u_long tempa[4]; /* at least 16 bytes, maybe more */
+
+ bzero((char *)tempa, sizeof(tempa));
+ bcopy(fh, (char *)tempa, 14); /* ensure alignment */
+ fsidp->fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
+ fsidp->fsid_dev.Major = tempa[2] + (tempa[3]<<1);
+ fsidp->fsid_code = 0;
+ }
+
+ /* VMS file ID is: (RVN, FidHi, FidLo) */
+ *inop = make_uint32(fhp[26], fhp[27], fhp[23], fhp[22]);
+
+ /* Caller must save (and null-terminate?) this value */
+ if (fsnamep)
+ *fsnamep = (char *)&(fhp[1]);
+
+ if (osnamep)
+ *osnamep = "VMS";
+ break;
+
+ case FHT_AIX32:
+ fsidp->fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
+ fsidp->fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
+ fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "AIX32";
+ break;
+
+ case FHT_HPUX9:
+ fsidp->fsid_dev.Major = fhp[0];
+ temp = make_uint24(fhp[1], fhp[2], fhp[3]);
+ fsidp->fsid_dev.Minor = temp;
+ fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
+
+ temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
+ *inop = temp;
+
+ if (osnamep)
+ *osnamep = "HPUX9";
+ break;
+
+ case FHT_UNKNOWN:
+#ifdef DEBUG
+ {
+ /* XXX debugging */
+ int i;
+ for (i=0; i<32;i++) fprintf(stderr, "%x.", fhp[i]);
+ fprintf(stderr, "\n");
+ }
+#endif
+ /* XXX for now, give "bogus" values to aid debugging */
+ fsidp->fsid_code = 0;
+ fsidp->fsid_dev.Minor = 257;
+ fsidp->fsid_dev.Major = 257;
+ *inop = 1;
+
+ /* display will show this string instead of (257,257) */
+ if (fsnamep)
+ *fsnamep = "Unknown";
+
+ if (osnamep)
+ *osnamep = "Unknown";
+ break;
+
+ }
+}
+
+/*
+ * Is this a VMS UCX file handle?
+ * Check for:
+ * (1) leading code byte [XXX not yet]
+ * (2) followed by string of printing chars & spaces
+ * (3) followed by string of nulls
+ */
+static int
+is_UCX(fhp)
+unsigned char *fhp;
+{
+ register int i;
+ int seen_null = 0;
+
+ for (i = 1; i < 14; i++) {
+ if (isprint(fhp[i])) {
+ if (seen_null)
+ return(0);
+ else
+ continue;
+ }
+ else if (fhp[i] == 0) {
+ seen_null = 1;
+ continue;
+ }
+ else
+ return(0);
+ }
+
+ return(1);
+}
diff --git a/usr.sbin/tcpdump/print-arp.c b/usr.sbin/tcpdump/print-arp.c
new file mode 100644
index 00000000000..f9636a66282
--- /dev/null
+++ b/usr.sbin/tcpdump/print-arp.c
@@ -0,0 +1,123 @@
+/* $NetBSD: print-arp.c,v 1.2 1995/03/06 19:11:02 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-arp.c,v 1.28 94/06/14 20:17:36 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static u_char ezero[6];
+
+void
+arp_print(register const u_char *bp, int length, int caplen)
+{
+ register const struct ether_arp *ap;
+ register const struct ether_header *eh;
+ const u_char *p;
+ int pro, hrd, op;
+
+ ap = (struct ether_arp *)bp;
+ if ((u_char *)(ap + 1) > snapend) {
+ printf("[|arp]");
+ return;
+ }
+ if (length < sizeof(struct ether_arp)) {
+ (void)printf("truncated-arp");
+ default_print((u_char *)ap, length);
+ return;
+ }
+ /*
+ * Don't assume alignment.
+ */
+ p = (u_char*)&ap->arp_pro;
+ pro = (p[0] << 8) | p[1];
+ p = (u_char*)&ap->arp_hrd;
+ hrd = (p[0] << 8) | p[1];
+ p = (u_char*)&ap->arp_op;
+ op = (p[0] << 8) | p[1];
+
+ if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL)
+ || ap->arp_hln != sizeof(SHA(ap))
+ || ap->arp_pln != sizeof(SPA(ap))) {
+ (void)printf("arp-#%d for proto #%d (%d) hardware #%d (%d)",
+ op, pro, ap->arp_pln,
+ hrd, ap->arp_hln);
+ return;
+ }
+ if (pro == ETHERTYPE_TRAIL)
+ (void)printf("trailer-");
+ eh = (struct ether_header *)packetp;
+ switch (op) {
+
+ case ARPOP_REQUEST:
+ (void)printf("arp who-has %s", ipaddr_string(TPA(ap)));
+ if (bcmp((char *)ezero, (char *)THA(ap), 6) != 0)
+ (void)printf(" (%s)", etheraddr_string(THA(ap)));
+ (void)printf(" tell %s", ipaddr_string(SPA(ap)));
+ if (bcmp((char *)ESRC(eh), (char *)SHA(ap), 6) != 0)
+ (void)printf(" (%s)", etheraddr_string(SHA(ap)));
+ break;
+
+ case ARPOP_REPLY:
+ (void)printf("arp reply %s", ipaddr_string(SPA(ap)));
+ if (bcmp((char *)ESRC(eh), (char *)SHA(ap), 6) != 0)
+ (void)printf(" (%s)", etheraddr_string(SHA(ap)));
+ (void)printf(" is-at %s", etheraddr_string(SHA(ap)));
+ if (bcmp((char *)EDST(eh), (char *)THA(ap), 6) != 0)
+ (void)printf(" (%s)", etheraddr_string(THA(ap)));
+ break;
+
+ case REVARP_REQUEST:
+ (void)printf("rarp who-is %s tell %s",
+ etheraddr_string(THA(ap)),
+ etheraddr_string(SHA(ap)));
+ break;
+
+ case REVARP_REPLY:
+ (void)printf("rarp reply %s at %s",
+ etheraddr_string(THA(ap)),
+ ipaddr_string(TPA(ap)));
+ break;
+
+ default:
+ (void)printf("arp-#%d", op);
+ default_print((u_char *)ap, caplen);
+ return;
+ }
+ if (hrd != ARPHRD_ETHER)
+ printf(" hardware #%d", ap->arp_hrd);
+}
diff --git a/usr.sbin/tcpdump/print-atalk.c b/usr.sbin/tcpdump/print-atalk.c
new file mode 100644
index 00000000000..89807fa7257
--- /dev/null
+++ b/usr.sbin/tcpdump/print-atalk.c
@@ -0,0 +1,573 @@
+/* $NetBSD: print-atalk.c,v 1.3 1995/03/06 19:11:04 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print AppleTalk packets.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-atalk.c,v 1.36 94/06/20 19:44:34 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ethertype.h"
+#include "extract.h" /* must come after interface.h */
+#include "appletalk.h"
+
+static struct token type2str[] = {
+ { ddpRTMP, "rtmp" },
+ { ddpRTMPrequest, "rtmpReq" },
+ { ddpECHO, "echo" },
+ { ddpIP, "IP" },
+ { ddpARP, "ARP" },
+ { ddpKLAP, "KLAP" },
+ { 0, NULL }
+};
+
+struct aarp {
+ u_short htype, ptype;
+ u_char halen, palen;
+ u_short op;
+ u_char hsaddr[6];
+ u_char psaddr[4];
+ u_char hdaddr[6];
+ u_char pdaddr[4];
+};
+
+static char tstr[] = "[|atalk]";
+
+static void atp_print(const struct atATP *, int);
+static void atp_bitmap_print(u_char);
+static void nbp_print(const struct atNBP *, int, u_short, u_char, u_char);
+static const char *print_cstring(const char *, const u_char *);
+static const struct atNBPtuple *nbp_tuple_print(const struct atNBPtuple *,
+ const u_char *,
+ u_short, u_char, u_char);
+static const struct atNBPtuple *nbp_name_print(const struct atNBPtuple *,
+ const u_char *);
+static const char *ataddr_string(u_short, u_char);
+static void ddp_print(const u_char *, int, int, u_short, u_char, u_char);
+static const char *ddpskt_string(int);
+
+/*
+ * Print AppleTalk Datagram Delivery Protocol packets.
+ */
+void
+atalk_print(register const u_char *bp, int length)
+{
+ register const struct LAP *lp;
+ register const struct atDDP *dp;
+ register const struct atShortDDP *sdp;
+ u_short snet;
+
+ lp = (struct LAP *)bp;
+ bp += sizeof(*lp);
+ length -= sizeof(*lp);
+ switch (lp->type) {
+
+ case lapShortDDP:
+ if (length < ddpSSize) {
+ (void)printf(" [|sddp %d]", length);
+ return;
+ }
+ sdp = (const struct atShortDDP *)bp;
+ printf("%s.%s",
+ ataddr_string(0, lp->src), ddpskt_string(sdp->srcSkt));
+ printf(" > %s.%s:",
+ ataddr_string(0, lp->dst), ddpskt_string(sdp->dstSkt));
+ bp += ddpSSize;
+ length -= ddpSSize;
+ ddp_print(bp, length, sdp->type, 0, lp->src, sdp->srcSkt);
+ break;
+
+ case lapDDP:
+ if (length < ddpSize) {
+ (void)printf(" [|ddp %d]", length);
+ return;
+ }
+ dp = (const struct atDDP *)bp;
+ snet = EXTRACT_SHORT(&dp->srcNet);
+ printf("%s.%s", ataddr_string(snet, dp->srcNode),
+ ddpskt_string(dp->srcSkt));
+ printf(" > %s.%s:",
+ ataddr_string(EXTRACT_SHORT(&dp->dstNet), dp->dstNode),
+ ddpskt_string(dp->dstSkt));
+ bp += ddpSize;
+ length -= ddpSize;
+ ddp_print(bp, length, dp->type, snet, dp->srcNode, dp->srcSkt);
+ break;
+
+#ifdef notdef
+ case lapKLAP:
+ klap_print(bp, length);
+ break;
+#endif
+
+ default:
+ printf("%d > %d at-lap#%d %d",
+ lp->src, lp->dst, lp->type, length);
+ break;
+ }
+}
+
+/* XXX should probably pass in the snap header and do checks like arp_print() */
+void
+aarp_print(register const u_char *bp, int length)
+{
+ register const struct aarp *ap;
+
+#define AT(member) ataddr_string((ap->member[1]<<8)|ap->member[2],ap->member[3])
+
+ printf("aarp ");
+ ap = (const struct aarp *)bp;
+ if (ap->htype == 1 && ap->ptype == ETHERTYPE_ATALK &&
+ ap->halen == 6 && ap->palen == 4 )
+ switch (ap->op) {
+
+ case 1: /* request */
+ (void)printf("who-has %s tell %s",
+ AT(pdaddr), AT(psaddr));
+ return;
+
+ case 2: /* response */
+ (void)printf("reply %s is-at %s",
+ AT(pdaddr), etheraddr_string(ap->hdaddr));
+ return;
+
+ case 3: /* probe (oy!) */
+ (void)printf("probe %s tell %s",
+ AT(pdaddr), AT(psaddr));
+ return;
+ }
+ (void)printf("len %d op %d htype %d ptype %#x halen %d palen %d",
+ length, ap->op, ap->htype, ap->ptype, ap->halen, ap->palen );
+}
+
+static void
+ddp_print(register const u_char *bp, register int length, register int t,
+ register u_short snet, register u_char snode, u_char skt)
+{
+
+ switch (t) {
+
+ case ddpNBP:
+ nbp_print((const struct atNBP *)bp, length, snet, snode, skt);
+ break;
+
+ case ddpATP:
+ atp_print((const struct atATP *)bp, length);
+ break;
+
+ default:
+ (void)printf(" at-%s %d", tok2str(type2str, NULL, t), length);
+ break;
+ }
+}
+
+static void
+atp_print(register const struct atATP *ap, int length)
+{
+ char c;
+ u_int32 data;
+
+ if ((const u_char *)(ap + 1) > snapend) {
+ /* Just bail if we don't have the whole chunk. */
+ fputs(tstr, stdout);
+ return;
+ }
+ length -= sizeof(*ap);
+ switch (ap->control & 0xc0) {
+
+ case atpReqCode:
+ (void)printf(" atp-req%s %d",
+ ap->control & atpXO? " " : "*",
+ EXTRACT_SHORT(&ap->transID));
+
+ atp_bitmap_print(ap->bitmap);
+
+ if (length != 0)
+ (void)printf(" [len=%d]", length);
+
+ switch (ap->control & (atpEOM|atpSTS)) {
+ case atpEOM:
+ (void)printf(" [EOM]");
+ break;
+ case atpSTS:
+ (void)printf(" [STS]");
+ break;
+ case atpEOM|atpSTS:
+ (void)printf(" [EOM,STS]");
+ break;
+ }
+ break;
+
+ case atpRspCode:
+ (void)printf(" atp-resp%s%d:%d (%d)",
+ ap->control & atpEOM? "*" : " ",
+ EXTRACT_SHORT(&ap->transID), ap->bitmap, length);
+ switch (ap->control & (atpXO|atpSTS)) {
+ case atpXO:
+ (void)printf(" [XO]");
+ break;
+ case atpSTS:
+ (void)printf(" [STS]");
+ break;
+ case atpXO|atpSTS:
+ (void)printf(" [XO,STS]");
+ break;
+ }
+ break;
+
+ case atpRelCode:
+ (void)printf(" atp-rel %d", EXTRACT_SHORT(&ap->transID));
+
+ atp_bitmap_print(ap->bitmap);
+
+ /* length should be zero */
+ if (length)
+ (void)printf(" [len=%d]", length);
+
+ /* there shouldn't be any control flags */
+ if (ap->control & (atpXO|atpEOM|atpSTS)) {
+ c = '[';
+ if (ap->control & atpXO) {
+ (void)printf("%cXO", c);
+ c = ',';
+ }
+ if (ap->control & atpEOM) {
+ (void)printf("%cEOM", c);
+ c = ',';
+ }
+ if (ap->control & atpSTS) {
+ (void)printf("%cSTS", c);
+ c = ',';
+ }
+ (void)printf("]");
+ }
+ break;
+
+ default:
+ (void)printf(" atp-0x%x %d (%d)", ap->control,
+ EXTRACT_SHORT(&ap->transID), length);
+ break;
+ }
+ data = EXTRACT_LONG(&ap->userData);
+ if (data != 0)
+ (void)printf(" 0x%x", data);
+}
+
+static void
+atp_bitmap_print(register u_char bm)
+{
+ register char c;
+ register int i;
+
+ /*
+ * The '& 0xff' below is needed for compilers that want to sign
+ * extend a u_char, which is the case with the Ultrix compiler.
+ * (gcc is smart enough to eliminate it, at least on the Sparc).
+ */
+ if ((bm + 1) & (bm & 0xff)) {
+ c = '<';
+ for (i = 0; bm; ++i) {
+ if (bm & 1) {
+ (void)printf("%c%d", c, i);
+ c = ',';
+ }
+ bm >>= 1;
+ }
+ (void)printf(">");
+ } else {
+ for (i = 0; bm; ++i)
+ bm >>= 1;
+ if (i > 1)
+ (void)printf("<0-%d>", i - 1);
+ else
+ (void)printf("<0>");
+ }
+}
+
+static void
+nbp_print(register const struct atNBP *np, int length, register u_short snet,
+ register u_char snode, register u_char skt)
+{
+ register const struct atNBPtuple *tp =
+ (struct atNBPtuple *)((u_char *)np + nbpHeaderSize);
+ int i = length;
+ const u_char *ep;
+
+ length -= nbpHeaderSize;
+ if (length < 8) {
+ /* must be room for at least one tuple */
+ (void)printf(" truncated-nbp %d", length + nbpHeaderSize);
+ return;
+ }
+ /* ep points to end of available data */
+ ep = snapend;
+ if ((const u_char *)tp > ep) {
+ fputs(tstr, stdout);
+ return;
+ }
+ switch (i = np->control & 0xf0) {
+
+ case nbpBrRq:
+ case nbpLkUp:
+ (void)printf(i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:",
+ np->id);
+ if ((const u_char *)(tp + 1) > ep) {
+ fputs(tstr, stdout);
+ return;
+ }
+ (void)nbp_name_print(tp, ep);
+ /*
+ * look for anomalies: the spec says there can only
+ * be one tuple, the address must match the source
+ * address and the enumerator should be zero.
+ */
+ if ((np->control & 0xf) != 1)
+ (void)printf(" [ntup=%d]", np->control & 0xf);
+ if (tp->enumerator)
+ (void)printf(" [enum=%d]", tp->enumerator);
+ if (EXTRACT_SHORT(&tp->net) != snet ||
+ tp->node != snode || tp->skt != skt)
+ (void)printf(" [addr=%s.%d]",
+ ataddr_string(EXTRACT_SHORT(&tp->net),
+ tp->node), tp->skt);
+ break;
+
+ case nbpLkUpReply:
+ (void)printf(" nbp-reply %d:", np->id);
+
+ /* print each of the tuples in the reply */
+ for (i = np->control & 0xf; --i >= 0 && tp; )
+ tp = nbp_tuple_print(tp, ep, snet, snode, skt);
+ break;
+
+ default:
+ (void)printf(" nbp-0x%x %d (%d)", np->control, np->id,
+ length);
+ break;
+ }
+}
+
+/* print a counted string */
+static const char *
+print_cstring(register const char *cp, register const u_char *ep)
+{
+ register int length;
+
+ if (cp >= (const char *)ep) {
+ fputs(tstr, stdout);
+ return (0);
+ }
+ length = *cp++;
+
+ /* Spec says string can be at most 32 bytes long */
+ if (length < 0 || length > 32) {
+ (void)printf("[len=%d]", length);
+ return (0);
+ }
+ while (--length >= 0) {
+ if (cp >= (char *)ep) {
+ fputs(tstr, stdout);
+ return (0);
+ }
+ putchar(*cp++);
+ }
+ return (cp);
+}
+
+static const struct atNBPtuple *
+nbp_tuple_print(register const struct atNBPtuple *tp,
+ register const u_char *ep,
+ register u_short snet, register u_char snode,
+ register u_char skt)
+{
+ register const struct atNBPtuple *tpn;
+
+ if ((const u_char *)(tp + 1) > ep) {
+ fputs(tstr, stdout);
+ return 0;
+ }
+ tpn = nbp_name_print(tp, ep);
+
+ /* if the enumerator isn't 1, print it */
+ if (tp->enumerator != 1)
+ (void)printf("(%d)", tp->enumerator);
+
+ /* if the socket doesn't match the src socket, print it */
+ if (tp->skt != skt)
+ (void)printf(" %d", tp->skt);
+
+ /* if the address doesn't match the src address, it's an anomaly */
+ if (EXTRACT_SHORT(&tp->net) != snet || tp->node != snode)
+ (void)printf(" [addr=%s]",
+ ataddr_string(EXTRACT_SHORT(&tp->net), tp->node));
+
+ return (tpn);
+}
+
+static const struct atNBPtuple *
+nbp_name_print(const struct atNBPtuple *tp, register const u_char *ep)
+{
+ register const char *cp = (const char *)tp + nbpTupleSize;
+
+ putchar(' ');
+
+ /* Object */
+ putchar('"');
+ if ((cp = print_cstring(cp, ep)) != NULL) {
+ /* Type */
+ putchar(':');
+ if ((cp = print_cstring(cp, ep)) != NULL) {
+ /* Zone */
+ putchar('@');
+ if ((cp = print_cstring(cp, ep)) != NULL)
+ putchar('"');
+ }
+ }
+ return ((const struct atNBPtuple *)cp);
+}
+
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+ int addr;
+ char *name;
+ struct hnamemem *nxt;
+};
+
+static struct hnamemem hnametable[HASHNAMESIZE];
+
+static const char *
+ataddr_string(u_short atnet, u_char athost)
+{
+ register struct hnamemem *tp, *tp2;
+ register int i = (atnet << 8) | athost;
+ char nambuf[256];
+ static int first = 1;
+ FILE *fp;
+
+ /*
+ * if this is the first call, see if there's an AppleTalk
+ * number to name map file.
+ */
+ if (first && (first = 0, !nflag)
+ && (fp = fopen("/etc/atalk.names", "r"))) {
+ char line[256];
+ int i1, i2, i3;
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (line[0] == '\n' || line[0] == 0 || line[0] == '#')
+ continue;
+ if (sscanf(line, "%d.%d.%d %s", &i1, &i2, &i3,
+ nambuf) == 4)
+ /* got a hostname. */
+ i3 |= ((i1 << 8) | i2) << 8;
+ else if (sscanf(line, "%d.%d %s", &i1, &i2,
+ nambuf) == 3)
+ /* got a net name */
+ i3 = (((i1 << 8) | i2) << 8) | 255;
+ else
+ continue;
+
+ for (tp = &hnametable[i3 & (HASHNAMESIZE-1)];
+ tp->nxt; tp = tp->nxt)
+ ;
+ tp->addr = i3;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+ tp->name = savestr(nambuf);
+ }
+ fclose(fp);
+ }
+
+ for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+ if (tp->addr == i)
+ return (tp->name);
+
+ /* didn't have the node name -- see if we've got the net name */
+ i |= 255;
+ for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt)
+ if (tp2->addr == i) {
+ tp->addr = (atnet << 8) | athost;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+ (void)sprintf(nambuf, "%s.%d", tp2->name, athost);
+ tp->name = savestr(nambuf);
+ return (tp->name);
+ }
+
+ tp->addr = (atnet << 8) | athost;
+ tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+ if (athost != 255)
+ (void)sprintf(nambuf, "%d.%d.%d",
+ atnet >> 8, atnet & 0xff, athost);
+ else
+ (void)sprintf(nambuf, "%d.%d", atnet >> 8, atnet & 0xff);
+ i = strlen(nambuf) + 1;
+ tp->name = strcpy(malloc((u_int) i), nambuf);
+
+ return (tp->name);
+}
+
+static struct token skt2str[] = {
+ { rtmpSkt, "rtmp" }, /* routing table maintenance */
+ { nbpSkt, "nis" }, /* name info socket */
+ { echoSkt, "echo" }, /* AppleTalk echo protocol */
+ { zipSkt, "zip" }, /* zone info protocol */
+ { 0, NULL }
+};
+
+static const char *
+ddpskt_string(register int skt)
+{
+ static char buf[8];
+
+ if (nflag) {
+ (void)sprintf(buf, "%d", skt);
+ return (buf);
+ }
+ return (tok2str(skt2str, "%d", skt));
+}
diff --git a/usr.sbin/tcpdump/print-bootp.c b/usr.sbin/tcpdump/print-bootp.c
new file mode 100644
index 00000000000..2e641419222
--- /dev/null
+++ b/usr.sbin/tcpdump/print-bootp.c
@@ -0,0 +1,359 @@
+/* $NetBSD: print-bootp.c,v 1.2 1995/03/06 19:11:05 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print bootp packets.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-bootp.c,v 1.30 94/06/14 20:17:37 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "bootp.h"
+
+static void rfc1048_print(const u_char *, int);
+static void cmu_print(const u_char *, int);
+
+static char tstr[] = " [|bootp]";
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(register const u_char *cp, int length,
+ u_short sport, u_short dport)
+{
+ register const struct bootp *bp;
+ static u_char vm_cmu[4] = VM_CMU;
+ static u_char vm_rfc1048[4] = VM_RFC1048;
+ const u_char *ep;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ bp = (struct bootp *)cp;
+ /* 'ep' points to the end of avaible data. */
+ ep = snapend;
+
+ TCHECK(bp->bp_op, sizeof(bp->bp_op));
+ switch (bp->bp_op) {
+
+ case BOOTREQUEST:
+ /* Usually, a request goes from a client to a server */
+ if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
+ printf(" (request)");
+ break;
+
+ case BOOTREPLY:
+ /* Usually, a reply goes from a server to a client */
+ if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
+ printf(" (reply)");
+ break;
+
+ default:
+ printf(" bootp-#%d", bp->bp_op);
+ }
+
+ TCHECK(bp->bp_secs, sizeof(bp->bp_secs));
+
+ /* The usual hardware address type is 1 (10Mb Ethernet) */
+ if (bp->bp_htype != 1)
+ printf(" htype-#%d", bp->bp_htype);
+
+ /* The usual length for 10Mb Ethernet address is 6 bytes */
+ if (bp->bp_htype != 1 || bp->bp_hlen != 6)
+ printf(" hlen:%d", bp->bp_hlen);
+
+ /* Only print interesting fields */
+ if (bp->bp_hops)
+ printf(" hops:%d", bp->bp_hops);
+ if (bp->bp_xid)
+ printf(" xid:0x%x", ntohl(bp->bp_xid));
+ if (bp->bp_secs)
+ printf(" secs:%d", ntohs(bp->bp_secs));
+
+ /* Client's ip address */
+ TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
+ if (bp->bp_ciaddr.s_addr)
+ printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
+
+ /* 'your' ip address (bootp client) */
+ TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
+ if (bp->bp_yiaddr.s_addr)
+ printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
+
+ /* Server's ip address */
+ TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
+ if (bp->bp_siaddr.s_addr)
+ printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
+
+ /* Gateway's ip address */
+ TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
+ if (bp->bp_giaddr.s_addr)
+ printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
+
+ /* Client's Ethernet address */
+ if (bp->bp_htype == 1 && bp->bp_hlen == 6) {
+ register const struct ether_header *eh;
+ register const char *e;
+
+ TCHECK(bp->bp_chaddr[0], 6);
+ eh = (struct ether_header *)packetp;
+ if (bp->bp_op == BOOTREQUEST)
+ e = (const char *)ESRC(eh);
+ else if (bp->bp_op == BOOTREPLY)
+ e = (const char *)EDST(eh);
+ else
+ e = 0;
+ if (e == 0 || bcmp((char *)bp->bp_chaddr, e, 6) != 0)
+ printf(" ether %s", etheraddr_string(bp->bp_chaddr));
+ }
+
+ TCHECK(bp->bp_sname[0], 1); /* check first char only */
+ if (*bp->bp_sname) {
+ printf(" sname ");
+ if (fn_print(bp->bp_sname, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ TCHECK(bp->bp_sname[0], 1); /* check first char only */
+ if (*bp->bp_file) {
+ printf(" file ");
+ if (fn_print(bp->bp_file, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+
+ /* Decode the vendor buffer */
+ TCHECK(bp->bp_vend[0], sizeof(bp->bp_vend));
+ length -= sizeof(*bp) - sizeof(bp->bp_vend);
+ if (bcmp((char *)bp->bp_vend, (char *)vm_rfc1048,
+ sizeof(u_int32)) == 0)
+ rfc1048_print(bp->bp_vend, length);
+ else if (bcmp((char *)bp->bp_vend, (char *)vm_cmu,
+ sizeof(u_int32)) == 0)
+ cmu_print(bp->bp_vend, length);
+ else {
+ u_int32 ul;
+
+ bcopy((char *)bp->bp_vend, (char *)&ul, sizeof(ul));
+ if (ul != 0)
+ printf("vend-#0x%x", ul);
+ }
+
+ return;
+trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
+
+/* The first character specifies the format to print */
+static struct token tag2str[] = {
+/* RFC1048 tags */
+ { TAG_PAD, " PAD" },
+ { TAG_SUBNET_MASK, "iSM" }, /* subnet mask (RFC950) */
+ { TAG_TIME_OFFSET, "lTZ" }, /* seconds from UTC */
+ { TAG_GATEWAY, "iDG" }, /* default gateway */
+ { TAG_TIME_SERVER, "iTS" }, /* time servers (RFC868) */
+ { TAG_NAME_SERVER, "iIEN" }, /* IEN name servers (IEN116) */
+ { TAG_DOMAIN_SERVER, "iNS" }, /* domain name (RFC1035) */
+ { TAG_LOG_SERVER, "iLOG" }, /* MIT log servers */
+ { TAG_COOKIE_SERVER, "iCS" }, /* cookie servers (RFC865) */
+ { TAG_LPR_SERVER, "iLPR" }, /* lpr server (RFC1179) */
+ { TAG_IMPRESS_SERVER, "iIM" }, /* impress servers (Imagen) */
+ { TAG_RLP_SERVER, "iRL" }, /* resource location (RFC887) */
+ { TAG_HOSTNAME, "aHN" }, /* ascii hostname */
+ { TAG_BOOTSIZE, "sBS" }, /* 512 byte blocks */
+ { TAG_END, " END" },
+/* RFC1497 tags */
+ { TAG_DUMPPATH, "aDP" },
+ { TAG_DOMAINNAME, "aDN" },
+ { TAG_SWAP_SERVER, "iSS" },
+ { TAG_ROOTPATH, "aRP" },
+ { TAG_EXTPATH, "aEP" },
+ { 0, NULL }
+};
+
+static void
+rfc1048_print(register const u_char *bp, register int length)
+{
+ register u_char tag;
+ register const u_char *ep;
+ register u_int len, size;
+ register const char *cp;
+ register char c;
+ int first;
+ u_int32 ul;
+ u_short us;
+
+ printf(" vend-rfc1048");
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Step over magic cookie */
+ bp += sizeof(int32);
+
+ /* Loop while we there is a tag left in the buffer */
+ while (bp + 1 < ep) {
+ tag = *bp++;
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ cp = tok2str(tag2str, "?T%d", tag);
+ c = *cp++;
+ printf(" %s:", cp);
+
+ /* Get the length; check for truncation */
+ if (bp + 1 >= ep) {
+ fputs(tstr, stdout);
+ return;
+ }
+ len = *bp++;
+ if (bp + len >= ep) {
+ fputs(tstr, stdout);
+ return;
+ }
+
+ /* Print data */
+ size = len;
+ if (c == '?') {
+ /* Base default formats for unknown tags on data size */
+ if (size & 1)
+ c = 'b';
+ else if (size & 2)
+ c = 's';
+ else
+ c = 'l';
+ }
+ first = 1;
+ switch (c) {
+
+ case 'a':
+ /* ascii strings */
+ (void)fn_printn(bp, size, NULL);
+ bp += size;
+ size = 0;
+ break;
+
+ case 'i':
+ case 'l':
+ /* ip addresses/32-bit words */
+ while (size >= sizeof(ul)) {
+ if (!first)
+ putchar(',');
+ bcopy((char *)bp, (char *)&ul, sizeof(ul));
+ if (c == 'i')
+ printf("%s", ipaddr_string(&ul));
+ else
+ printf("%lu", ul);
+ bp += sizeof(ul);
+ size -= sizeof(ul);
+ first = 0;
+ }
+ break;
+
+ case 's':
+ /* shorts */
+ while (size >= sizeof(us)) {
+ if (!first)
+ putchar(',');
+ bcopy((char *)bp, (char *)&us, sizeof(us));
+ printf("%d", us);
+ bp += sizeof(us);
+ size -= sizeof(us);
+ first = 0;
+ }
+ break;
+
+ case 'b':
+ default:
+ /* Bytes */
+ while (size > 0) {
+ if (!first)
+ putchar('.');
+ printf("%d", *bp);
+ ++bp;
+ --size;
+ first = 0;
+ }
+ break;
+ }
+ /* Data left over? */
+ if (size)
+ printf("[len %d]", len);
+ }
+}
+
+static void
+cmu_print(register const u_char *bp, register int length)
+{
+ register const struct cmu_vend *cmu;
+ register const u_char *ep;
+ char *fmt = " %s:%s";
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+#define PRINTCMUADDR(m, s) { TCHECK(cmu->m, sizeof(cmu->m)); \
+ if (cmu->m.s_addr != 0) \
+ printf(fmt, s, ipaddr_string(&cmu->m.s_addr)); }
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ printf(" vend-cmu");
+ cmu = (struct cmu_vend *)bp;
+
+ /* Only print if there are unknown bits */
+ TCHECK(cmu->v_flags, sizeof(cmu->v_flags));
+ if ((cmu->v_flags & ~(VF_SMASK)) != 0)
+ printf(" F:0x%x", cmu->v_flags);
+ PRINTCMUADDR(v_dgate, "DG");
+ PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*");
+ PRINTCMUADDR(v_dns1, "NS1");
+ PRINTCMUADDR(v_dns2, "NS2");
+ PRINTCMUADDR(v_ins1, "IEN1");
+ PRINTCMUADDR(v_ins2, "IEN2");
+ PRINTCMUADDR(v_ts1, "TS1");
+ PRINTCMUADDR(v_ts2, "TS2");
+ return;
+
+trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+#undef PRINTCMUADDR
+}
diff --git a/usr.sbin/tcpdump/print-decnet.c b/usr.sbin/tcpdump/print-decnet.c
new file mode 100644
index 00000000000..2e0a419cea5
--- /dev/null
+++ b/usr.sbin/tcpdump/print-decnet.c
@@ -0,0 +1,765 @@
+/* $NetBSD: print-decnet.c,v 1.2 1995/03/06 19:11:07 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-decnet.c,v 1.15 94/06/20 19:44:38 leres Exp (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#ifdef DECNETLIB
+#include <netdnet/dnetdb.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+
+#include "decnet.h"
+#include "interface.h"
+#include "addrtoname.h"
+
+/* Forwards */
+static void print_decnet_ctlmsg(const union routehdr *, int);
+static void print_t_info(int);
+static void print_l1_routes(const char *, int);
+static void print_l2_routes(const char *, int);
+static void print_i_info(int);
+static void print_elist(const char *, int);
+static void print_nsp(const u_char *, int);
+static void print_reason(int);
+#ifdef PRINT_NSPDATA
+static void pdata(u_char *, int);
+#endif
+
+#ifdef DECNETLIB
+extern char *dnet_htoa(struct dn_naddr *);
+#endif
+
+void
+decnet_print(register const u_char *ap, register int length,
+ register int caplen)
+{
+ static union routehdr rhcopy;
+ register union routehdr *rhp = &rhcopy;
+ register int mflags;
+ int dst, src, hops;
+ int rhlen;
+ const u_char *nspp;
+ int nsplen;
+ int pktlen;
+
+ if (length < sizeof(struct shorthdr)) {
+ (void)printf("[|decnet]");
+ return;
+ }
+
+ pktlen = EXTRACT_16BITS(ap);
+
+ rhlen = min(length, caplen);
+ rhlen = min(rhlen, sizeof(*rhp));
+ bcopy(&(ap[sizeof(short)]), rhp, rhlen);
+
+ mflags = EXTRACT_8BITS(rhp->rh_short.sh_flags);
+
+ if (mflags & RMF_PAD) {
+ /* pad bytes of some sort in front of message */
+ int padlen = mflags & RMF_PADMASK;
+ if (vflag)
+ (void) printf("[pad:%d] ", padlen);
+ ap += padlen;
+ length -= padlen;
+ caplen -= padlen;
+ rhlen = min(length, caplen);
+ rhlen = min(rhlen, sizeof(*rhp));
+ bcopy(&(ap[sizeof(short)]), rhp, rhlen);
+ mflags = EXTRACT_8BITS(rhp->rh_short.sh_flags);
+ }
+
+ if (mflags & RMF_FVER) {
+ (void) printf("future-version-decnet");
+ default_print(ap, length);
+ return;
+ }
+
+ /* is it a control message? */
+ if (mflags & RMF_CTLMSG) {
+ print_decnet_ctlmsg(rhp, min(length, caplen));
+ return;
+ }
+
+ switch (mflags & RMF_MASK) {
+ case RMF_LONG:
+ dst = EXTRACT_16BITS(rhp->rh_long.lg_dst.dne_remote.dne_nodeaddr);
+ src = EXTRACT_16BITS(rhp->rh_long.lg_src.dne_remote.dne_nodeaddr);
+ hops = EXTRACT_8BITS(rhp->rh_long.lg_visits);
+ nspp = &(ap[sizeof(short) + sizeof(struct longhdr)]);
+ nsplen = min((length - sizeof(struct longhdr)),
+ (caplen - sizeof(struct longhdr)));
+ break;
+ case RMF_SHORT:
+ dst = EXTRACT_16BITS(rhp->rh_short.sh_dst);
+ src = EXTRACT_16BITS(rhp->rh_short.sh_src);
+ hops = (EXTRACT_8BITS(rhp->rh_short.sh_visits) & VIS_MASK)+1;
+ nspp = &(ap[sizeof(short) + sizeof(struct shorthdr)]);
+ nsplen = min((length - sizeof(struct shorthdr)),
+ (caplen - sizeof(struct shorthdr)));
+ break;
+ default:
+ (void) printf("unknown message flags under mask");
+ default_print((u_char *)ap, length);
+ return;
+ }
+
+ (void)printf("%s > %s %d ",
+ dnaddr_string(src), dnaddr_string(dst), pktlen);
+ if (vflag) {
+ if (mflags & RMF_RQR)
+ (void)printf("RQR ");
+ if (mflags & RMF_RTS)
+ (void)printf("RTS ");
+ if (mflags & RMF_IE)
+ (void)printf("IE ");
+ (void)printf("%d hops ", hops);
+ }
+
+ print_nsp(nspp, nsplen);
+}
+
+static void
+print_decnet_ctlmsg(register const union routehdr *rhp, int length)
+{
+ int mflags = EXTRACT_8BITS(rhp->rh_short.sh_flags);
+ register union controlmsg *cmp = (union controlmsg *)rhp;
+ int src, dst, info, blksize, eco, ueco, hello, other, vers;
+ etheraddr srcea, rtea;
+ int priority;
+ char *rhpx = (char *)rhp;
+
+ switch (mflags & RMF_CTLMASK) {
+ case RMF_INIT:
+ (void)printf("init ");
+ src = EXTRACT_16BITS(cmp->cm_init.in_src);
+ info = EXTRACT_8BITS(cmp->cm_init.in_info);
+ blksize = EXTRACT_16BITS(cmp->cm_init.in_blksize);
+ vers = EXTRACT_8BITS(cmp->cm_init.in_vers);
+ eco = EXTRACT_8BITS(cmp->cm_init.in_eco);
+ ueco = EXTRACT_8BITS(cmp->cm_init.in_ueco);
+ hello = EXTRACT_16BITS(cmp->cm_init.in_hello);
+ print_t_info(info);
+ (void)printf(
+ "src %sblksize %d vers %d eco %d ueco %d hello %d",
+ dnaddr_string(src), blksize, vers, eco, ueco,
+ hello);
+ break;
+ case RMF_VER:
+ (void)printf("verification ");
+ src = EXTRACT_16BITS(cmp->cm_ver.ve_src);
+ other = EXTRACT_8BITS(cmp->cm_ver.ve_fcnval);
+ (void)printf("src %s fcnval %o", dnaddr_string(src), other);
+ break;
+ case RMF_TEST:
+ (void)printf("test ");
+ src = EXTRACT_16BITS(cmp->cm_test.te_src);
+ other = EXTRACT_8BITS(cmp->cm_test.te_data);
+ (void)printf("src %s data %o", dnaddr_string(src), other);
+ break;
+ case RMF_L1ROUT:
+ (void)printf("lev-1-routing ");
+ src = EXTRACT_16BITS(cmp->cm_l1rou.r1_src);
+ (void)printf("src %s ", dnaddr_string(src));
+ print_l1_routes(&(rhpx[sizeof(struct l1rout)]),
+ length - sizeof(struct l1rout));
+ break;
+ case RMF_L2ROUT:
+ (void)printf("lev-2-routing ");
+ src = EXTRACT_16BITS(cmp->cm_l2rout.r2_src);
+ (void)printf("src %s ", dnaddr_string(src));
+ print_l2_routes(&(rhpx[sizeof(struct l2rout)]),
+ length - sizeof(struct l2rout));
+ break;
+ case RMF_RHELLO:
+ (void)printf("router-hello ");
+ vers = EXTRACT_8BITS(cmp->cm_rhello.rh_vers);
+ eco = EXTRACT_8BITS(cmp->cm_rhello.rh_eco);
+ ueco = EXTRACT_8BITS(cmp->cm_rhello.rh_ueco);
+ bcopy(&(cmp->cm_rhello.rh_src), &srcea, sizeof(srcea));
+ src = EXTRACT_16BITS(srcea.dne_remote.dne_nodeaddr);
+ info = EXTRACT_8BITS(cmp->cm_rhello.rh_info);
+ blksize = EXTRACT_16BITS(cmp->cm_rhello.rh_blksize);
+ priority = EXTRACT_8BITS(cmp->cm_rhello.rh_priority);
+ hello = EXTRACT_16BITS(cmp->cm_rhello.rh_hello);
+ print_i_info(info);
+ (void)printf(
+ "vers %d eco %d ueco %d src %s blksize %d pri %d hello %d",
+ vers, eco, ueco, dnaddr_string(src),
+ blksize, priority, hello);
+ print_elist(&(rhpx[sizeof(struct rhellomsg)]),
+ length - sizeof(struct rhellomsg));
+ break;
+ case RMF_EHELLO:
+ (void)printf("endnode-hello ");
+ vers = EXTRACT_8BITS(cmp->cm_ehello.eh_vers);
+ eco = EXTRACT_8BITS(cmp->cm_ehello.eh_eco);
+ ueco = EXTRACT_8BITS(cmp->cm_ehello.eh_ueco);
+ bcopy(&(cmp->cm_ehello.eh_src), &srcea, sizeof(srcea));
+ src = EXTRACT_16BITS(srcea.dne_remote.dne_nodeaddr);
+ info = EXTRACT_8BITS(cmp->cm_ehello.eh_info);
+ blksize = EXTRACT_16BITS(cmp->cm_ehello.eh_blksize);
+ /*seed*/
+ bcopy(&(cmp->cm_ehello.eh_router), &rtea, sizeof(rtea));
+ dst = EXTRACT_16BITS(rtea.dne_remote.dne_nodeaddr);
+ hello = EXTRACT_16BITS(cmp->cm_ehello.eh_hello);
+ other = EXTRACT_8BITS(cmp->cm_ehello.eh_data);
+ print_i_info(info);
+ (void)printf(
+ "vers %d eco %d ueco %d src %s blksize %d rtr %s hello %d data %o",
+ vers, eco, ueco, dnaddr_string(src),
+ blksize, dnaddr_string(dst), hello, other);
+ break;
+
+ default:
+ (void)printf("unknown control message");
+ default_print((u_char *)rhp, length);
+ break;
+ }
+}
+
+static void
+print_t_info(int info)
+{
+ int ntype = info & 3;
+ switch (ntype) {
+ case 0: (void)printf("reserved-ntype? "); break;
+ case TI_L2ROUT: (void)printf("l2rout "); break;
+ case TI_L1ROUT: (void)printf("l1rout "); break;
+ case TI_ENDNODE: (void)printf("endnode "); break;
+ }
+ if (info & TI_VERIF)
+ (void)printf("verif ");
+ if (info & TI_BLOCK)
+ (void)printf("blo ");
+}
+
+static void
+print_l1_routes(const char *rp, int len)
+{
+ int count;
+ int id;
+ int info;
+
+ /* The last short is a checksum */
+ while (len > (3 * sizeof(short))) {
+ count = EXTRACT_16BITS(rp);
+ if (count > 1024)
+ return; /* seems to be bogus from here on */
+ rp += sizeof(short);
+ len -= sizeof(short);
+ id = EXTRACT_16BITS(rp);
+ rp += sizeof(short);
+ len -= sizeof(short);
+ info = EXTRACT_16BITS(rp);
+ rp += sizeof(short);
+ len -= sizeof(short);
+ (void)printf("{ids %d-%d cost %d hops %d} ", id, id + count,
+ RI_COST(info), RI_HOPS(info));
+ }
+}
+
+static void
+print_l2_routes(const char *rp, int len)
+{
+ int count;
+ int area;
+ int info;
+
+ /* The last short is a checksum */
+ while (len > (3 * sizeof(short))) {
+ count = EXTRACT_16BITS(rp);
+ if (count > 1024)
+ return; /* seems to be bogus from here on */
+ rp += sizeof(short);
+ len -= sizeof(short);
+ area = EXTRACT_16BITS(rp);
+ rp += sizeof(short);
+ len -= sizeof(short);
+ info = EXTRACT_16BITS(rp);
+ rp += sizeof(short);
+ len -= sizeof(short);
+ (void)printf("{areas %d-%d cost %d hops %d} ", area, area + count,
+ RI_COST(info), RI_HOPS(info));
+ }
+}
+
+static void
+print_i_info(int info)
+{
+ int ntype = info & II_TYPEMASK;
+ switch (ntype) {
+ case 0: (void)printf("reserved-ntype? "); break;
+ case II_L2ROUT: (void)printf("l2rout "); break;
+ case II_L1ROUT: (void)printf("l1rout "); break;
+ case II_ENDNODE: (void)printf("endnode "); break;
+ }
+ if (info & II_VERIF)
+ (void)printf("verif ");
+ if (info & II_NOMCAST)
+ (void)printf("nomcast ");
+ if (info & II_BLOCK)
+ (void)printf("blo ");
+}
+
+static void
+print_elist(const char *elp, int len)
+{
+ /* Not enough examples available for me to debug this */
+}
+
+static void
+print_nsp(const u_char *nspp, int nsplen)
+{
+ const struct nsphdr *nsphp = (struct nsphdr *)nspp;
+ int dst, src, flags;
+
+ flags = EXTRACT_8BITS(nsphp->nh_flags);
+ dst = EXTRACT_16BITS(nsphp->nh_dst);
+ src = EXTRACT_16BITS(nsphp->nh_src);
+
+ switch (flags & NSP_TYPEMASK) {
+ case MFT_DATA:
+ switch (flags & NSP_SUBMASK) {
+ case MFS_BOM:
+ case MFS_MOM:
+ case MFS_EOM:
+ case MFS_BOM+MFS_EOM:
+ printf("data %d>%d ", src, dst);
+ {
+ struct seghdr *shp = (struct seghdr *)nspp;
+ int ack;
+#ifdef PRINT_NSPDATA
+ u_char *dp;
+#endif
+ int data_off = sizeof(struct minseghdr);
+
+ ack = EXTRACT_16BITS(shp->sh_seq[0]);
+ if (ack & SGQ_ACK) { /* acknum field */
+ if ((ack & SGQ_NAK) == SGQ_NAK)
+ (void)printf("nak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[1]);
+ data_off += sizeof(short);
+ if (ack & SGQ_OACK) { /* ackoth field */
+ if ((ack & SGQ_ONAK) == SGQ_ONAK)
+ (void)printf("onak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("oack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[2]);
+ data_off += sizeof(short);
+ }
+ }
+ (void)printf("seg %d ", ack & SGQ_MASK);
+#ifdef PRINT_NSPDATA
+ dp = &(nspp[data_off]);
+ pdata(dp, 10);
+#endif
+ }
+ break;
+ case MFS_ILS+MFS_INT:
+ printf("intr ");
+ {
+ struct seghdr *shp = (struct seghdr *)nspp;
+ int ack;
+#ifdef PRINT_NSPDATA
+ u_char *dp;
+#endif
+ int data_off = sizeof(struct minseghdr);
+
+ ack = EXTRACT_16BITS(shp->sh_seq[0]);
+ if (ack & SGQ_ACK) { /* acknum field */
+ if ((ack & SGQ_NAK) == SGQ_NAK)
+ (void)printf("nak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[1]);
+ data_off += sizeof(short);
+ if (ack & SGQ_OACK) { /* ackdat field */
+ if ((ack & SGQ_ONAK) == SGQ_ONAK)
+ (void)printf("nakdat %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ackdat %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[2]);
+ data_off += sizeof(short);
+ }
+ }
+ (void)printf("seg %d ", ack & SGQ_MASK);
+#ifdef PRINT_NSPDATA
+ dp = &(nspp[data_off]);
+ pdata(dp, 10);
+#endif
+ }
+ break;
+ case MFS_ILS:
+ (void)printf("link-service %d>%d ", src, dst);
+ {
+ struct seghdr *shp = (struct seghdr *)nspp;
+ struct lsmsg *lsmp =
+ (struct lsmsg *)&(nspp[sizeof(struct seghdr)]);
+ int ack;
+ int lsflags, fcval;
+
+ ack = EXTRACT_16BITS(shp->sh_seq[0]);
+ if (ack & SGQ_ACK) { /* acknum field */
+ if ((ack & SGQ_NAK) == SGQ_NAK)
+ (void)printf("nak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[1]);
+ if (ack & SGQ_OACK) { /* ackdat field */
+ if ((ack & SGQ_ONAK) == SGQ_ONAK)
+ (void)printf("nakdat %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ackdat %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(shp->sh_seq[2]);
+ }
+ }
+ (void)printf("seg %d ", ack & SGQ_MASK);
+ lsflags = EXTRACT_8BITS(lsmp->ls_lsflags);
+ fcval = EXTRACT_8BITS(lsmp->ls_fcval);
+ switch (lsflags & LSI_MASK) {
+ case LSI_DATA:
+ (void)printf("dat seg count %d ", fcval);
+ switch (lsflags & LSM_MASK) {
+ case LSM_NOCHANGE:
+ break;
+ case LSM_DONOTSEND:
+ (void)printf("donotsend-data ");
+ break;
+ case LSM_SEND:
+ (void)printf("send-data ");
+ break;
+ default:
+ (void)printf("reserved-fcmod? %x", lsflags);
+ break;
+ }
+ break;
+ case LSI_INTR:
+ (void)printf("intr req count %d ", fcval);
+ break;
+ default:
+ (void)printf("reserved-fcval-int? %x", lsflags);
+ break;
+ }
+ }
+ break;
+ default:
+ (void)printf("reserved-subtype? %x %d > %d", flags, src, dst);
+ break;
+ }
+ break;
+ case MFT_ACK:
+ switch (flags & NSP_SUBMASK) {
+ case MFS_DACK:
+ (void)printf("data-ack %d>%d ", src, dst);
+ {
+ struct ackmsg *amp = (struct ackmsg *)nspp;
+ int ack;
+
+ ack = EXTRACT_16BITS(amp->ak_acknum[0]);
+ if (ack & SGQ_ACK) { /* acknum field */
+ if ((ack & SGQ_NAK) == SGQ_NAK)
+ (void)printf("nak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(amp->ak_acknum[1]);
+ if (ack & SGQ_OACK) { /* ackoth field */
+ if ((ack & SGQ_ONAK) == SGQ_ONAK)
+ (void)printf("onak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("oack %d ", ack & SGQ_MASK);
+ }
+ }
+ }
+ break;
+ case MFS_IACK:
+ (void)printf("ils-ack %d>%d ", src, dst);
+ {
+ struct ackmsg *amp = (struct ackmsg *)nspp;
+ int ack;
+
+ ack = EXTRACT_16BITS(amp->ak_acknum[0]);
+ if (ack & SGQ_ACK) { /* acknum field */
+ if ((ack & SGQ_NAK) == SGQ_NAK)
+ (void)printf("nak %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ack %d ", ack & SGQ_MASK);
+ ack = EXTRACT_16BITS(amp->ak_acknum[1]);
+ if (ack & SGQ_OACK) { /* ackdat field */
+ if ((ack & SGQ_ONAK) == SGQ_ONAK)
+ (void)printf("nakdat %d ", ack & SGQ_MASK);
+ else
+ (void)printf("ackdat %d ", ack & SGQ_MASK);
+ }
+ }
+ }
+ break;
+ case MFS_CACK:
+ (void)printf("conn-ack %d", dst);
+ break;
+ default:
+ (void)printf("reserved-acktype? %x %d > %d", flags, src, dst);
+ break;
+ }
+ break;
+ case MFT_CTL:
+ switch (flags & NSP_SUBMASK) {
+ case MFS_CI:
+ case MFS_RCI:
+ if ((flags & NSP_SUBMASK) == MFS_CI)
+ (void)printf("conn-initiate ");
+ else
+ (void)printf("retrans-conn-initiate ");
+ (void)printf("%d>%d ", src, dst);
+ {
+ struct cimsg *cimp = (struct cimsg *)nspp;
+ int services, info, segsize;
+#ifdef PRINT_NSPDATA
+ u_char *dp;
+#endif
+
+ services = EXTRACT_8BITS(cimp->ci_services);
+ info = EXTRACT_8BITS(cimp->ci_info);
+ segsize = EXTRACT_16BITS(cimp->ci_segsize);
+
+ switch (services & COS_MASK) {
+ case COS_NONE:
+ break;
+ case COS_SEGMENT:
+ (void)printf("seg ");
+ break;
+ case COS_MESSAGE:
+ (void)printf("msg ");
+ break;
+ case COS_CRYPTSER:
+ (void)printf("crypt ");
+ break;
+ }
+ switch (info & COI_MASK) {
+ case COI_32:
+ (void)printf("ver 3.2 ");
+ break;
+ case COI_31:
+ (void)printf("ver 3.1 ");
+ break;
+ case COI_40:
+ (void)printf("ver 4.0 ");
+ break;
+ case COI_41:
+ (void)printf("ver 4.1 ");
+ break;
+ }
+ (void)printf("segsize %d ", segsize);
+#ifdef PRINT_NSPDATA
+ dp = &(nspp[sizeof(struct cimsg)]);
+ pdata(dp, nsplen - sizeof(struct cimsg));
+#endif
+ }
+ break;
+ case MFS_CC:
+ (void)printf("conn-confirm %d>%d ", src, dst);
+ {
+ struct ccmsg *ccmp = (struct ccmsg *)nspp;
+ int services, info, segsize, optlen;
+#ifdef PRINT_NSPDATA
+ u_char *dp;
+#endif
+
+ services = EXTRACT_8BITS(ccmp->cc_services);
+ info = EXTRACT_8BITS(ccmp->cc_info);
+ segsize = EXTRACT_16BITS(ccmp->cc_segsize);
+ optlen = EXTRACT_8BITS(ccmp->cc_optlen);
+
+ switch (services & COS_MASK) {
+ case COS_NONE:
+ break;
+ case COS_SEGMENT:
+ (void)printf("seg ");
+ break;
+ case COS_MESSAGE:
+ (void)printf("msg ");
+ break;
+ case COS_CRYPTSER:
+ (void)printf("crypt ");
+ break;
+ }
+ switch (info & COI_MASK) {
+ case COI_32:
+ (void)printf("ver 3.2 ");
+ break;
+ case COI_31:
+ (void)printf("ver 3.1 ");
+ break;
+ case COI_40:
+ (void)printf("ver 4.0 ");
+ break;
+ case COI_41:
+ (void)printf("ver 4.1 ");
+ break;
+ }
+ (void)printf("segsize %d ", segsize);
+ if (optlen) {
+ (void)printf("optlen %d ", optlen);
+#ifdef PRINT_NSPDATA
+ optlen = min(optlen, nsplen - sizeof(struct ccmsg));
+ dp = &(nspp[sizeof(struct ccmsg)]);
+ pdata(dp, optlen);
+#endif
+ }
+ }
+ break;
+ case MFS_DI:
+ (void)printf("disconn-initiate %d>%d ", src, dst);
+ {
+ struct dimsg *dimp = (struct dimsg *)nspp;
+ int reason, optlen;
+#ifdef PRINT_NSPDATA
+ u_char *dp;
+#endif
+
+ reason = EXTRACT_16BITS(dimp->di_reason);
+ optlen = EXTRACT_8BITS(dimp->di_optlen);
+
+ print_reason(reason);
+ if (optlen) {
+ (void)printf("optlen %d ", optlen);
+#ifdef PRINT_NSPDATA
+ optlen = min(optlen, nsplen - sizeof(struct dimsg));
+ dp = &(nspp[sizeof(struct dimsg)]);
+ pdata(dp, optlen);
+#endif
+ }
+ }
+ break;
+ case MFS_DC:
+ (void)printf("disconn-confirm %d>%d ", src, dst);
+ {
+ struct dcmsg *dcmp = (struct dcmsg *)nspp;
+ int reason;
+
+ reason = EXTRACT_16BITS(dcmp->dc_reason);
+
+ print_reason(reason);
+ }
+ break;
+ default:
+ (void)printf("reserved-ctltype? %x %d > %d", flags, src, dst);
+ break;
+ }
+ break;
+ default:
+ (void)printf("reserved-type? %x %d > %d", flags, src, dst);
+ break;
+ }
+}
+
+struct token reason2str[] = {
+ { UC_OBJREJECT, "object rejected connect" },
+ { UC_RESOURCES, "insufficient resources" },
+ { UC_NOSUCHNODE, "unrecognized node name" },
+ { DI_SHUT, "node is shutting down" },
+ { UC_NOSUCHOBJ, "unrecognized object" },
+ { UC_INVOBJFORMAT, "invalid object name format" },
+ { UC_OBJTOOBUSY, "object too busy" },
+ { DI_PROTOCOL, "protocol error discovered" },
+ { DI_TPA, "third party abort" },
+ { UC_USERABORT, "user abort" },
+ { UC_INVNODEFORMAT, "invalid node name format" },
+ { UC_LOCALSHUT, "local node shutting down" },
+ { DI_LOCALRESRC, "insufficient local resources" },
+ { DI_REMUSERRESRC, "insufficient remote user resources" },
+ { UC_ACCESSREJECT, "invalid access control information" },
+ { DI_BADACCNT, "bad ACCOUNT information" },
+ { UC_NORESPONSE, "no response from object" },
+ { UC_UNREACHABLE, "node unreachable" },
+ { DC_NOLINK, "no link terminate" },
+ { DC_COMPLETE, "disconnect complete" },
+ { DI_BADIMAGE, "bad image data in connect" },
+ { DI_SERVMISMATCH, "cryptographic service mismatch" },
+ { 0, NULL }
+};
+
+static void
+print_reason(register int reason)
+{
+ printf("%s ", tok2str(reason2str, "reason-%d", reason));
+}
+
+char *
+dnnum_string(u_short dnaddr)
+{
+ char *str;
+ int area = (dnaddr & AREAMASK) >> AREASHIFT;
+ int node = dnaddr & NODEMASK;
+
+ str = (char *)malloc(sizeof("00.0000"));
+ sprintf(str, "%d.%d", area, node);
+ return(str);
+}
+
+char *
+dnname_string(u_short dnaddr)
+{
+#ifdef DECNETLIB
+ struct dn_naddr dna;
+
+ dna.a_len = sizeof(short);
+ bcopy((char *)&dnaddr, dna.a_addr, sizeof(short));
+ return (savestr(dnet_htoa(&dna)));
+#else
+ return(dnnum_string(dnaddr)); /* punt */
+#endif
+}
+
+#ifdef PRINT_NSPDATA
+static void
+pdata(u_char *dp, int maxlen)
+{
+ char c;
+ int x = maxlen;
+
+ while (x-- > 0) {
+ c = *dp++;
+ if (isprint(c))
+ putchar(c);
+ else
+ printf("\\%o", c & 0xFF);
+ }
+}
+#endif
diff --git a/usr.sbin/tcpdump/print-domain.c b/usr.sbin/tcpdump/print-domain.c
new file mode 100644
index 00000000000..bc2cab3db3e
--- /dev/null
+++ b/usr.sbin/tcpdump/print-domain.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-domain.c,v 1.23 94/06/14 20:17:38 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#undef NOERROR /* Solaris sucks */
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static char *ns_ops[] = {
+ "", " inv_q", " stat", " op3", " op4", " op5", " op6", " op7",
+ " op8", " updataA", " updateD", " updateDA",
+ " updateM", " updateMA", " zoneInit", " zoneRef",
+};
+
+static char *ns_resp[] = {
+ "", " FormErr", " ServFail", " NXDomain",
+ " NotImp", " Refused", " Resp6", " Resp7",
+ " Resp8", " Resp9", " Resp10", " Resp11",
+ " Resp12", " Resp13", " Resp14", " NoChange",
+};
+
+/* skip over a domain name */
+static const u_char *
+ns_nskip(register const u_char *cp)
+{
+ register u_char i;
+
+ if (((i = *cp++) & 0xc0) == 0xc0)
+ return (cp + 1);
+ while (i) {
+ cp += i;
+ i = *cp++;
+ }
+ return (cp);
+}
+
+/* print a domain name */
+static void
+ns_nprint(register const u_char *cp, register const u_char *bp,
+ register const u_char *ep)
+{
+ register u_int i;
+
+ putchar(' ');
+ if ((i = *cp++) != 0)
+ while (i && cp < ep) {
+ if ((i & 0xc0) == 0xc0) {
+ cp = bp + (((i << 8) | *cp) & 0x3fff);
+ i = *cp++;
+ continue;
+ }
+ do {
+ putchar(*cp++);
+ } while (--i);
+ putchar('.');
+ i = *cp++;
+ }
+ else
+ putchar('.');
+}
+
+static struct token type2str[] = {
+ { T_A, "A" },
+ { T_NS, "NS" },
+ { T_MD, "MD" },
+ { T_MF, "MF" },
+ { T_CNAME, "CNAME" },
+ { T_SOA, "SOA" },
+ { T_MB, "MB" },
+ { T_MG, "MG" },
+ { T_MR, "MR" },
+ { T_NULL, "NULL" },
+ { T_WKS, "WKS" },
+ { T_PTR, "PTR" },
+ { T_HINFO, "HINFO" },
+ { T_MINFO, "MINFO" },
+ { T_MX, "MX" },
+ { T_UINFO, "UINFO" },
+ { T_UID, "UID" },
+ { T_GID, "GID" },
+#ifdef T_UNSPEC
+ { T_UNSPEC, "UNSPEC" },
+#endif
+ { T_AXFR, "AXFR" },
+ { T_MAILB, "MAILB" },
+ { T_MAILA, "MAILA" },
+ { T_ANY, "ANY" },
+ { 0, NULL }
+};
+
+/* print a query */
+static void
+ns_qprint(register const u_char *cp, register const u_char *bp,
+ register const u_char *ep)
+{
+ const u_char *np = cp;
+ register u_int i;
+
+ cp = ns_nskip(cp);
+
+ if (cp + 4 > ep)
+ return;
+
+ /* print the qtype and qclass (if it's not IN) */
+ i = *cp++ << 8;
+ i |= *cp++;
+ printf(" %s", tok2str(type2str, "Type%d", i));
+ i = *cp++ << 8;
+ if ((i |= *cp++) != C_IN)
+ if (i == C_ANY)
+ printf("(c_any)");
+ else
+ printf("(Class %d)", i);
+
+ putchar('?');
+ ns_nprint(np, bp, ep);
+}
+
+
+/* print a reply */
+static void
+ns_rprint(register const u_char *cp, register const u_char *bp,
+ register const u_char *ep)
+{
+ register u_int i;
+ u_short typ;
+
+ cp = ns_nskip(cp);
+
+ if (cp + 10 > ep)
+ return;
+
+ /* print the type/qtype and class (if it's not IN) */
+ typ = *cp++ << 8;
+ typ |= *cp++;
+ i = *cp++ << 8;
+ if ((i |= *cp++) != C_IN)
+ if (i == C_ANY)
+ printf("(c_any)");
+ else
+ printf("(Class %d)", i);
+
+ /* ignore ttl & len */
+ cp += 6;
+ printf(" %s", tok2str(type2str, "Type%d", typ));
+ switch (typ) {
+
+ case T_A:
+ printf(" %s", ipaddr_string(cp));
+ break;
+
+ case T_NS:
+ case T_CNAME:
+ case T_PTR:
+ ns_nprint(cp, bp, ep);
+ break;
+
+ case T_MX:
+ ns_nprint(cp+2, bp, ep);
+#ifndef TCPDUMP_ALIGN
+ printf(" %d", *(short *)cp);
+#else
+ {
+ u_short x = *cp | cp[1] << 8;
+ printf(" %d", ntohs(x));
+ }
+#endif
+ break;
+ }
+}
+
+void
+ns_print(register const u_char *bp, int length)
+{
+ register const HEADER *np;
+ int qdcount, ancount, nscount, arcount;
+ const u_char *ep = snapend;
+
+ np = (const HEADER *)bp;
+ /* get the byte-order right */
+ qdcount = ntohs(np->qdcount);
+ ancount = ntohs(np->ancount);
+ nscount = ntohs(np->nscount);
+ arcount = ntohs(np->arcount);
+
+ if (np->qr) {
+ /* this is a response */
+ printf(" %d%s%s%s%s%s",
+ ntohs(np->id),
+ ns_ops[np->opcode],
+ ns_resp[np->rcode],
+ np->aa? "*" : "",
+ np->ra? "" : "-",
+ np->tc? "|" : "");
+ if (qdcount != 1)
+ printf(" [%dq]", qdcount);
+ printf(" %d/%d/%d", ancount, nscount, arcount);
+ if (ancount)
+ ns_rprint(ns_nskip((const u_char *)(np + 1)) + 4,
+ (const u_char *)np, ep);
+ }
+ else {
+ /* this is a request */
+ printf(" %d%s%s",
+ ntohs(np->id),
+ ns_ops[np->opcode],
+ np->rd? "+" : "");
+
+ /* any weirdness? */
+ if (*(((u_short *)np)+1) & htons(0x6ff))
+ printf(" [b2&3=0x%x]", ntohs(*(((u_short *)np)+1)));
+
+ if (np->opcode == IQUERY) {
+ if (qdcount)
+ printf(" [%dq]", qdcount);
+ if (ancount != 1)
+ printf(" [%da]", ancount);
+ }
+ else {
+ if (ancount)
+ printf(" [%da]", ancount);
+ if (qdcount != 1)
+ printf(" [%dq]", qdcount);
+ }
+ if (nscount)
+ printf(" [%dn]", nscount);
+ if (arcount)
+ printf(" [%dau]", arcount);
+
+ ns_qprint((const u_char *)(np + 1), (const u_char *)np, ep);
+ }
+ printf(" (%d)", length);
+}
diff --git a/usr.sbin/tcpdump/print-egp.c b/usr.sbin/tcpdump/print-egp.c
new file mode 100644
index 00000000000..97fc2c3818f
--- /dev/null
+++ b/usr.sbin/tcpdump/print-egp.c
@@ -0,0 +1,358 @@
+/* $NetBSD: print-egp.c,v 1.2 1995/03/06 19:11:09 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Lawrence Berkeley Laboratory,
+ * Berkeley, CA. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU).
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-egp.c,v 1.14 94/06/20 19:44:38 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <netdb.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+struct egp_packet {
+ u_char egp_version;
+#define EGP_VERSION 2
+ u_char egp_type;
+#define EGPT_ACQUIRE 3
+#define EGPT_REACH 5
+#define EGPT_POLL 2
+#define EGPT_UPDATE 1
+#define EGPT_ERROR 8
+ u_char egp_code;
+#define EGPC_REQUEST 0
+#define EGPC_CONFIRM 1
+#define EGPC_REFUSE 2
+#define EGPC_CEASE 3
+#define EGPC_CEASEACK 4
+#define EGPC_HELLO 0
+#define EGPC_HEARDU 1
+ u_char egp_status;
+#define EGPS_UNSPEC 0
+#define EGPS_ACTIVE 1
+#define EGPS_PASSIVE 2
+#define EGPS_NORES 3
+#define EGPS_ADMIN 4
+#define EGPS_GODOWN 5
+#define EGPS_PARAM 6
+#define EGPS_PROTO 7
+#define EGPS_INDET 0
+#define EGPS_UP 1
+#define EGPS_DOWN 2
+#define EGPS_UNSOL 0x80
+ u_short egp_checksum;
+ u_short egp_as;
+ u_short egp_sequence;
+ union {
+ u_short egpu_hello;
+ u_char egpu_gws[2];
+ u_short egpu_reason;
+#define EGPR_UNSPEC 0
+#define EGPR_BADHEAD 1
+#define EGPR_BADDATA 2
+#define EGPR_NOREACH 3
+#define EGPR_XSPOLL 4
+#define EGPR_NORESP 5
+#define EGPR_UVERSION 6
+ } egp_handg;
+#define egp_hello egp_handg.egpu_hello
+#define egp_intgw egp_handg.egpu_gws[0]
+#define egp_extgw egp_handg.egpu_gws[1]
+#define egp_reason egp_handg.egpu_reason
+ union {
+ u_short egpu_poll;
+ u_int32 egpu_sourcenet;
+ } egp_pands;
+#define egp_poll egp_pands.egpu_poll
+#define egp_sourcenet egp_pands.egpu_sourcenet
+};
+
+char *egp_acquire_codes[] = {
+ "request",
+ "confirm",
+ "refuse",
+ "cease",
+ "cease_ack"
+};
+
+char *egp_acquire_status[] = {
+ "unspecified",
+ "active_mode",
+ "passive_mode",
+ "insufficient_resources",
+ "administratively_prohibited",
+ "going_down",
+ "parameter_violation",
+ "protocol_violation"
+};
+
+char *egp_reach_codes[] = {
+ "hello",
+ "i-h-u"
+};
+
+char *egp_status_updown[] = {
+ "indeterminate",
+ "up",
+ "down"
+};
+
+char *egp_reasons[] = {
+ "unspecified",
+ "bad_EGP_header_format",
+ "bad_EGP_data_field_format",
+ "reachability_info_unavailable",
+ "excessive_polling_rate",
+ "no_response",
+ "unsupported_version"
+};
+
+static void
+egpnrprint(register const struct egp_packet *egp, register int length)
+{
+ register const u_char *cp, *ep;
+#define TCHECK(n) if (cp > ep - n) goto trunc
+ register u_int32 addr;
+ register u_int32 net;
+ register int netlen;
+ int gateways, distances, networks;
+ int t_gateways;
+ char *comma;
+
+ addr = egp->egp_sourcenet;
+ if (IN_CLASSA(addr)) {
+ net = addr & IN_CLASSA_NET;
+ netlen = 1;
+ } else if (IN_CLASSB(addr)) {
+ net = addr & IN_CLASSB_NET;
+ netlen = 2;
+ } else if (IN_CLASSC(addr)) {
+ net = addr & IN_CLASSC_NET;
+ netlen = 3;
+ } else {
+ net = 0;
+ netlen = 0;
+ }
+ cp = (u_char *)(egp + 1);
+ ep = snapend;
+
+ t_gateways = egp->egp_intgw + egp->egp_extgw;
+ for (gateways = 0; gateways < t_gateways; ++gateways) {
+ /* Pickup host part of gateway address */
+ addr = 0;
+ TCHECK(4 - netlen);
+ switch (netlen) {
+
+ case 1:
+ addr = *cp++;
+ /* fall through */
+ case 2:
+ addr = (addr << 8) | *cp++;
+ /* fall through */
+ case 3:
+ addr = (addr << 8) | *cp++;
+ }
+ addr |= net;
+ TCHECK(1);
+ distances = *cp++;
+ printf(" %s %s ",
+ gateways < egp->egp_intgw ? "int" : "ext",
+ intoa(addr));
+
+ comma = "";
+ putchar('(');
+ while (--distances >= 0) {
+ TCHECK(2);
+ printf("%sd%d:", comma, (int)*cp++);
+ comma = ", ";
+ networks = *cp++;
+ while (--networks >= 0) {
+ /* Pickup network number */
+ TCHECK(1);
+ addr = (u_int32)*cp++ << 24;
+ if (IN_CLASSB(addr)) {
+ TCHECK(1);
+ addr |= (u_int32)*cp++ << 16;
+ } else if (!IN_CLASSA(addr)) {
+ TCHECK(2);
+ addr |= (u_int32)*cp++ << 16;
+ addr |= (u_int32)*cp++ << 8;
+ }
+ printf(" %s", intoa(addr));
+ }
+ }
+ putchar(')');
+ }
+ return;
+trunc:
+ fputs("[|]", stdout);
+}
+
+void
+egp_print(register const u_char *bp, register int length,
+ register const u_char *bp2)
+{
+ register const struct egp_packet *egp;
+ register const struct ip *ip;
+ register int status;
+ register int code;
+ register int type;
+
+ egp = (struct egp_packet *)bp;
+ ip = (struct ip *)bp2;
+ (void)printf("%s > %s: egp: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+
+ if (egp->egp_version != EGP_VERSION) {
+ printf("[version %d]", egp->egp_version);
+ return;
+ }
+ printf("as:%d seq:%d", ntohs(egp->egp_as), ntohs(egp->egp_sequence));
+
+ type = egp->egp_type;
+ code = egp->egp_code;
+ status = egp->egp_status;
+
+ switch (type) {
+ case EGPT_ACQUIRE:
+ printf(" acquire");
+ switch (code) {
+ case EGPC_REQUEST:
+ case EGPC_CONFIRM:
+ printf(" %s", egp_acquire_codes[code]);
+ switch (status) {
+ case EGPS_UNSPEC:
+ case EGPS_ACTIVE:
+ case EGPS_PASSIVE:
+ printf(" %s", egp_acquire_status[status]);
+ break;
+
+ default:
+ printf(" [status %d]", status);
+ break;
+ }
+ printf(" hello:%d poll:%d",
+ ntohs(egp->egp_hello),
+ ntohs(egp->egp_poll));
+ break;
+
+ case EGPC_REFUSE:
+ case EGPC_CEASE:
+ case EGPC_CEASEACK:
+ printf(" %s", egp_acquire_codes[code]);
+ switch (status ) {
+ case EGPS_UNSPEC:
+ case EGPS_NORES:
+ case EGPS_ADMIN:
+ case EGPS_GODOWN:
+ case EGPS_PARAM:
+ case EGPS_PROTO:
+ printf(" %s", egp_acquire_status[status]);
+ break;
+
+ default:
+ printf("[status %d]", status);
+ break;
+ }
+ break;
+
+ default:
+ printf("[code %d]", code);
+ break;
+ }
+ break;
+
+ case EGPT_REACH:
+ switch (code) {
+
+ case EGPC_HELLO:
+ case EGPC_HEARDU:
+ printf(" %s", egp_reach_codes[code]);
+ if (status <= EGPS_DOWN)
+ printf(" state:%s", egp_status_updown[status]);
+ else
+ printf(" [status %d]", status);
+ break;
+
+ default:
+ printf("[reach code %d]", code);
+ break;
+ }
+ break;
+
+ case EGPT_POLL:
+ printf(" poll");
+ if (egp->egp_status <= EGPS_DOWN)
+ printf(" state:%s", egp_status_updown[status]);
+ else
+ printf(" [status %d]", status);
+ printf(" net:%s", intoa(egp->egp_sourcenet));
+ break;
+
+ case EGPT_UPDATE:
+ printf(" update");
+ if (status & EGPS_UNSOL) {
+ status &= ~EGPS_UNSOL;
+ printf(" unsolicited");
+ }
+ if (status <= EGPS_DOWN)
+ printf(" state:%s", egp_status_updown[status]);
+ else
+ printf(" [status %d]", status);
+ printf(" %s int %d ext %d",
+ intoa(egp->egp_sourcenet),
+ egp->egp_intgw,
+ egp->egp_extgw);
+ if (vflag)
+ egpnrprint(egp, length);
+ break;
+
+ case EGPT_ERROR:
+ printf(" error");
+ if (status <= EGPS_DOWN)
+ printf(" state:%s", egp_status_updown[status]);
+ else
+ printf(" [status %d]", status);
+
+ if (ntohs(egp->egp_reason) <= EGPR_UVERSION)
+ printf(" %s", egp_reasons[ntohs(egp->egp_reason)]);
+ else
+ printf(" [reason %d]", ntohs(egp->egp_reason));
+ break;
+
+ default:
+ printf("[type %d]", type);
+ break;
+ }
+}
diff --git a/usr.sbin/tcpdump/print-ether.c b/usr.sbin/tcpdump/print-ether.c
new file mode 100644
index 00000000000..d32ceca2213
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ether.c
@@ -0,0 +1,194 @@
+/* $NetBSD: print-ether.c,v 1.3 1995/03/06 19:11:10 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-ether.c,v 1.37 94/06/10 17:01:29 mccanne Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <stdio.h>
+#include <pcap.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ethertype.h"
+
+const u_char *packetp;
+const u_char *snapend;
+
+static inline void
+ether_print(register const u_char *bp, int length)
+{
+ register const struct ether_header *ep;
+
+ ep = (const struct ether_header *)bp;
+ if (qflag)
+ (void)printf("%s %s %d: ",
+ etheraddr_string(ESRC(ep)),
+ etheraddr_string(EDST(ep)),
+ length);
+ else
+ (void)printf("%s %s %s %d: ",
+ etheraddr_string(ESRC(ep)),
+ etheraddr_string(EDST(ep)),
+ etherproto_string(ep->ether_type),
+ length);
+}
+
+/*
+ * This is the top level routine of the printer. 'p' is the points
+ * to the ether header of the packet, 'tvp' is the timestamp,
+ * 'length' is the length of the packet off the wire, and 'caplen'
+ * is the number of bytes actually captured.
+ */
+void
+ether_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ int caplen = h->caplen;
+ int length = h->len;
+ struct ether_header *ep;
+ u_short ether_type;
+ extern u_short extracted_ethertype;
+
+ ts_print(&h->ts);
+
+ if (caplen < sizeof(struct ether_header)) {
+ printf("[|ether]");
+ goto out;
+ }
+
+ if (eflag)
+ ether_print(p, length);
+
+ /*
+ * Some printers want to get back at the ethernet addresses,
+ * and/or check that they're not walking off the end of the packet.
+ * Rather than pass them all the way down, we set these globals.
+ */
+ packetp = p;
+ snapend = p + caplen;
+
+ length -= sizeof(struct ether_header);
+ caplen -= sizeof(struct ether_header);
+ ep = (struct ether_header *)p;
+ p += sizeof(struct ether_header);
+
+ ether_type = ntohs(ep->ether_type);
+
+ /*
+ * Is it (gag) an 802.3 encapsulation?
+ */
+ extracted_ethertype = 0;
+ if (ether_type < ETHERMTU) {
+ /* Try to print the LLC-layer header & higher layers */
+ if (llc_print(p, length, caplen, ESRC(ep), EDST(ep)) == 0) {
+ /* ether_type not known, print raw packet */
+ if (!eflag)
+ ether_print((u_char *)ep, length);
+ if (extracted_ethertype) {
+ printf("(LLC %s) ",
+ etherproto_string(htons(extracted_ethertype)));
+ }
+ if (!xflag && !qflag)
+ default_print(p, caplen);
+ }
+ } else if (ether_encap_print(ether_type, p, length, caplen) == 0) {
+ /* ether_type not known, print raw packet */
+ if (!eflag)
+ ether_print((u_char *)ep, length + sizeof(*ep));
+ if (!xflag && !qflag)
+ default_print(p, caplen);
+ }
+ if (xflag)
+ default_print(p, caplen);
+ out:
+ putchar('\n');
+}
+
+/*
+ * Prints the packet encapsulated in an Ethernet data segment
+ * (or an equivalent encapsulation), given the Ethernet type code.
+ *
+ * Returns non-zero if it can do so, zero if the ethertype is unknown.
+ *
+ * Stuffs the ether type into a global for the benefit of lower layers
+ * that might want to know what it is.
+ */
+
+u_short extracted_ethertype;
+
+int
+ether_encap_print(u_short ethertype, const u_char *p, int length, int caplen)
+{
+ extracted_ethertype = ethertype;
+
+ switch (ethertype) {
+
+ case ETHERTYPE_IP:
+ ip_print(p, length);
+ return (1);
+
+ case ETHERTYPE_ARP:
+ case ETHERTYPE_REVARP:
+ arp_print(p, length, caplen);
+ return (1);
+
+ case ETHERTYPE_DN:
+ decnet_print(p, length, caplen);
+ return (1);
+
+ case ETHERTYPE_ATALK:
+ if (vflag)
+ fputs("et1 ", stdout);
+ atalk_print(p, length);
+ return (1);
+
+ case ETHERTYPE_AARP:
+ aarp_print(p, length);
+ return (1);
+
+ case ETHERTYPE_LAT:
+ case ETHERTYPE_MOPRC:
+ case ETHERTYPE_MOPDL:
+ /* default_print for now */
+ default:
+ return (0);
+ }
+}
+
diff --git a/usr.sbin/tcpdump/print-fddi.c b/usr.sbin/tcpdump/print-fddi.c
new file mode 100644
index 00000000000..0d5c0501ccc
--- /dev/null
+++ b/usr.sbin/tcpdump/print-fddi.c
@@ -0,0 +1,353 @@
+/* $NetBSD: print-fddi.c,v 1.2 1995/03/06 19:11:12 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-fddi.c,v 1.21 94/06/10 17:01:29 mccanne Exp (LBL)";
+#endif
+
+#ifdef FDDI
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ethertype.h"
+
+#include "fddi.h"
+
+int fddipad = FDDIPAD; /* for proper alignment of header */
+
+/*
+ * Some FDDI interfaces use bit-swapped addresses.
+ */
+#if defined(ultrix) || defined(__alpha)
+int fddi_bitswap = 0;
+#else
+int fddi_bitswap = 1;
+#endif
+
+/*
+ * FDDI support for tcpdump, by Jeffrey Mogul [DECWRL], June 1992
+ *
+ * Based in part on code by Van Jacobson, which bears this note:
+ *
+ * NOTE: This is a very preliminary hack for FDDI support.
+ * There are all sorts of wired in constants & nothing (yet)
+ * to print SMT packets as anything other than hex dumps.
+ * Most of the necessary changes are waiting on my redoing
+ * the "header" that a kernel fddi driver supplies to bpf: I
+ * want it to look like one byte of 'direction' (0 or 1
+ * depending on whether the packet was inbound or outbound),
+ * two bytes of system/driver dependent data (anything an
+ * implementor thinks would be useful to filter on and/or
+ * save per-packet, then the real 21-byte FDDI header.
+ * Steve McCanne & I have also talked about adding the
+ * 'direction' byte to all bpf headers (e.g., in the two
+ * bytes of padding on an ethernet header). It's not clear
+ * we could do this in a backwards compatible way & we hate
+ * the idea of an incompatible bpf change. Discussions are
+ * proceeding.
+ *
+ * Also, to really support FDDI (and better support 802.2
+ * over ethernet) we really need to re-think the rather simple
+ * minded assumptions about fixed length & fixed format link
+ * level headers made in gencode.c. One day...
+ *
+ * - vj
+ */
+
+#define FDDI_HDRLEN (sizeof(struct fddi_header))
+
+static u_char fddi_bit_swap[] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+/*
+ * Print FDDI frame-control bits
+ */
+static inline void
+print_fddi_fc(u_char fc)
+{
+ switch (fc) {
+
+ case FDDIFC_VOID: /* Void frame */
+ printf("void ");
+ break;
+
+ case FDDIFC_NRT: /* Nonrestricted token */
+ printf("nrt ");
+ break;
+
+ case FDDIFC_RT: /* Restricted token */
+ printf("rt ");
+ break;
+
+ case FDDIFC_SMT_INFO: /* SMT Info */
+ printf("info ");
+ break;
+
+ case FDDIFC_SMT_NSA: /* SMT Next station adrs */
+ printf("nsa ");
+ break;
+
+ case FDDIFC_MAC_BEACON: /* MAC Beacon frame */
+ printf("beacon ");
+ break;
+
+ case FDDIFC_MAC_CLAIM: /* MAC Claim frame */
+ printf("claim ");
+ break;
+
+ default:
+ switch (fc & FDDIFC_CLFF) {
+
+ case FDDIFC_MAC:
+ printf("mac%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ case FDDIFC_SMT:
+ printf("smt%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ case FDDIFC_LLC_ASYNC:
+ printf("async%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ case FDDIFC_LLC_SYNC:
+ printf("sync%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ case FDDIFC_IMP_ASYNC:
+ printf("imp_async%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ case FDDIFC_IMP_SYNC:
+ printf("imp_sync%1x ", fc & FDDIFC_ZZZZ);
+ break;
+
+ default:
+ printf("%02x ", fc);
+ break;
+ }
+ }
+}
+
+/* Extract src, dst addresses */
+static inline void
+extract_fddi_addrs(const struct fddi_header *fddip, char *fsrc, char *fdst)
+{
+ register int i;
+
+ if (fddi_bitswap) {
+ /*
+ * bit-swap the fddi addresses (isn't the IEEE standards
+ * process wonderful!) then convert them to names.
+ */
+ for (i = 0; i < 6; ++i)
+ fdst[i] = fddi_bit_swap[fddip->fddi_dhost[i]];
+ for (i = 0; i < 6; ++i)
+ fsrc[i] = fddi_bit_swap[fddip->fddi_shost[i]];
+ }
+ else {
+ bcopy(fddip->fddi_dhost, fdst, 6);
+ bcopy(fddip->fddi_shost, fsrc, 6);
+ }
+}
+
+/*
+ * Print the FDDI MAC header
+ */
+static inline void
+fddi_print(register const struct fddi_header *fddip, register int length,
+ register const u_char *fsrc, register const u_char *fdst)
+{
+ char *srcname, *dstname;
+
+ srcname = etheraddr_string(fsrc);
+ dstname = etheraddr_string(fdst);
+
+ if (vflag)
+ (void) printf("%02x %s %s %d: ",
+ fddip->fddi_fc,
+ srcname, dstname,
+ length);
+ else if (qflag)
+ printf("%s %s %d: ", srcname, dstname, length);
+ else {
+ (void) print_fddi_fc(fddip->fddi_fc);
+ (void) printf("%s %s %d: ", srcname, dstname, length);
+ }
+}
+
+static inline void
+fddi_smt_print(const u_char *p, int length)
+{
+ printf("<SMT printer not yet implemented>");
+}
+
+/*
+ * This is the top level routine of the printer. 'sp' is the points
+ * to the FDDI header of the packet, 'tvp' is the timestamp,
+ * 'length' is the length of the packet off the wire, and 'caplen'
+ * is the number of bytes actually captured.
+ */
+void
+fddi_if_print(u_char *pcap, const struct pcap_pkthdr *h,
+ register const u_char *p)
+{
+ int caplen = h->caplen;
+ int length = h->len;
+ const struct fddi_header *fddip = (struct fddi_header *)p;
+ extern u_short extracted_ethertype;
+ struct ether_header ehdr;
+
+ ts_print(&h->ts);
+
+ if (caplen < FDDI_HDRLEN) {
+ printf("[|fddi]");
+ goto out;
+ }
+ /*
+ * Get the FDDI addresses into a canonical form
+ */
+ extract_fddi_addrs(fddip, (char*)ESRC(&ehdr), (char*)EDST(&ehdr));
+ /*
+ * Some printers want to get back at the link level addresses,
+ * and/or check that they're not walking off the end of the packet.
+ * Rather than pass them all the way down, we set these globals.
+ */
+ snapend = p + caplen;
+ /*
+ * Actually, the only printer that uses packetp is print-bootp.c,
+ * and it assumes that packetp points to an Ethernet header. The
+ * right thing to do is to fix print-bootp.c to know which link
+ * type is in use when it excavates. XXX
+ */
+ packetp = (u_char *)&ehdr;
+
+ if (eflag)
+ fddi_print(fddip, length, ESRC(&ehdr), EDST(&ehdr));
+
+ /* Skip over FDDI MAC header */
+ length -= FDDI_HDRLEN;
+ p += FDDI_HDRLEN;
+ caplen -= FDDI_HDRLEN;
+
+ /* Frame Control field determines interpretation of packet */
+ extracted_ethertype = 0;
+ if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_LLC_ASYNC) {
+ /* Try to print the LLC-layer header & higher layers */
+ if (llc_print(p, length, caplen, ESRC(&ehdr), EDST(&ehdr))
+ == 0) {
+ /*
+ * Some kinds of LLC packet we cannot
+ * handle intelligently
+ */
+ if (!eflag)
+ fddi_print(fddip, length,
+ ESRC(&ehdr), EDST(&ehdr));
+ if (extracted_ethertype) {
+ printf("(LLC %s) ",
+ etherproto_string(htons(extracted_ethertype)));
+ }
+ if (!xflag && !qflag)
+ default_print(p, caplen);
+ }
+ } else if ((fddip->fddi_fc & FDDIFC_CLFF) == FDDIFC_SMT)
+ fddi_smt_print(p, caplen);
+ else {
+ /* Some kinds of FDDI packet we cannot handle intelligently */
+ if (!eflag)
+ fddi_print(fddip, length, ESRC(&ehdr), EDST(&ehdr));
+ if (!xflag && !qflag)
+ default_print(p, caplen);
+ }
+ if (xflag)
+ default_print(p, caplen);
+out:
+ putchar('\n');
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+void
+fddi_if_print(u_char *pcap, struct pcap_pkthdr *h, register u_char *p)
+{
+
+ error("not configured for fddi");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/print-icmp.c b/usr.sbin/tcpdump/print-icmp.c
new file mode 100644
index 00000000000..e4154315b4c
--- /dev/null
+++ b/usr.sbin/tcpdump/print-icmp.c
@@ -0,0 +1,217 @@
+/* $NetBSD: print-icmp.c,v 1.3 1995/03/06 19:11:13 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-icmp.c,v 1.20 94/06/14 20:17:39 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+icmp_print(register const u_char *bp, register const u_char *bp2)
+{
+ register const struct icmp *dp;
+ register const struct ip *ip;
+ register const char *str;
+ register const struct ip *oip;
+ register const struct udphdr *ouh;
+ register int hlen, dport;
+ register const u_char *ep;
+ char buf[256];
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ dp = (struct icmp *)bp;
+ ip = (struct ip *)bp2;
+ str = buf;
+ /* 'ep' points to the end of avaible data. */
+ ep = snapend;
+
+ (void)printf("%s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+
+ TCHECK(dp->icmp_code, sizeof(dp->icmp_code));
+ switch (dp->icmp_type) {
+ case ICMP_ECHOREPLY:
+ str = "echo reply";
+ break;
+ case ICMP_UNREACH:
+ TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+ switch (dp->icmp_code) {
+ case ICMP_UNREACH_NET:
+ (void)sprintf(buf, "net %s unreachable",
+ ipaddr_string(&dp->icmp_ip.ip_dst));
+ break;
+ case ICMP_UNREACH_HOST:
+ (void)sprintf(buf, "host %s unreachable",
+ ipaddr_string(&dp->icmp_ip.ip_dst));
+ break;
+ case ICMP_UNREACH_PROTOCOL:
+ TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p));
+ (void)sprintf(buf, "%s protocol %d unreachable",
+ ipaddr_string(&dp->icmp_ip.ip_dst),
+ dp->icmp_ip.ip_p);
+ break;
+ case ICMP_UNREACH_PORT:
+ TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p));
+ oip = &dp->icmp_ip;
+ hlen = oip->ip_hl * 4;
+ ouh = (struct udphdr *)(((u_char *)oip) + hlen);
+ dport = ntohs(ouh->uh_dport);
+ switch (oip->ip_p) {
+ case IPPROTO_TCP:
+ (void)sprintf(buf,
+ "%s tcp port %s unreachable",
+ ipaddr_string(&oip->ip_dst),
+ tcpport_string(dport));
+ break;
+ case IPPROTO_UDP:
+ (void)sprintf(buf,
+ "%s udp port %s unreachable",
+ ipaddr_string(&oip->ip_dst),
+ udpport_string(dport));
+ break;
+ default:
+ (void)sprintf(buf,
+ "%s protocol %d port %d unreachable",
+ ipaddr_string(&oip->ip_dst),
+ oip->ip_p, dport);
+ break;
+ }
+ break;
+ case ICMP_UNREACH_NEEDFRAG:
+ (void)sprintf(buf, "%s unreachable - need to frag",
+ ipaddr_string(&dp->icmp_ip.ip_dst));
+ break;
+ case ICMP_UNREACH_SRCFAIL:
+ (void)sprintf(buf,
+ "%s unreachable - source route failed",
+ ipaddr_string(&dp->icmp_ip.ip_dst));
+ break;
+ }
+ break;
+ case ICMP_SOURCEQUENCH:
+ str = "source quench";
+ break;
+ case ICMP_REDIRECT:
+ TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+ switch (dp->icmp_code) {
+ case ICMP_REDIRECT_NET:
+ (void)sprintf(buf, "redirect %s to net %s",
+ ipaddr_string(&dp->icmp_ip.ip_dst),
+ ipaddr_string(&dp->icmp_gwaddr));
+ break;
+ case ICMP_REDIRECT_HOST:
+ (void)sprintf(buf, "redirect %s to host %s",
+ ipaddr_string(&dp->icmp_ip.ip_dst),
+ ipaddr_string(&dp->icmp_gwaddr));
+ break;
+ case ICMP_REDIRECT_TOSNET:
+ (void)sprintf(buf, "redirect-tos %s to net %s",
+ ipaddr_string(&dp->icmp_ip.ip_dst),
+ ipaddr_string(&dp->icmp_gwaddr));
+ break;
+ case ICMP_REDIRECT_TOSHOST:
+ (void)sprintf(buf, "redirect-tos %s to host %s",
+ ipaddr_string(&dp->icmp_ip.ip_dst),
+ ipaddr_string(&dp->icmp_gwaddr));
+ break;
+ }
+ break;
+ case ICMP_ECHO:
+ str = "echo request";
+ break;
+ case ICMP_TIMXCEED:
+ TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+ switch (dp->icmp_code) {
+ case ICMP_TIMXCEED_INTRANS:
+ str = "time exceeded in-transit";
+ break;
+ case ICMP_TIMXCEED_REASS:
+ str = "ip reassembly time exceeded";
+ break;
+ }
+ break;
+ case ICMP_PARAMPROB:
+ if (dp->icmp_code)
+ (void)sprintf(buf, "parameter problem - code %d",
+ dp->icmp_code);
+ else {
+ TCHECK(dp->icmp_pptr, sizeof(dp->icmp_pptr));
+ (void)sprintf(buf, "parameter problem - octet %d",
+ dp->icmp_pptr);
+ }
+ break;
+ case ICMP_TSTAMP:
+ str = "time stamp request";
+ break;
+ case ICMP_TSTAMPREPLY:
+ str = "time stamp reply";
+ break;
+ case ICMP_IREQ:
+ str = "information request";
+ break;
+ case ICMP_IREQREPLY:
+ str = "information reply";
+ break;
+ case ICMP_MASKREQ:
+ str = "address mask request";
+ break;
+ case ICMP_MASKREPLY:
+ TCHECK(dp->icmp_mask, sizeof(dp->icmp_mask));
+ (void)sprintf(buf, "address mask is 0x%08x",
+ ntohl(dp->icmp_mask));
+ break;
+ default:
+ (void)sprintf(buf, "type-#%d", dp->icmp_type);
+ break;
+ }
+ (void)printf("icmp: %s", str);
+ return;
+trunc:
+ fputs("[|icmp]", stdout);
+#undef TCHECK
+}
diff --git a/usr.sbin/tcpdump/print-ip.c b/usr.sbin/tcpdump/print-ip.c
new file mode 100644
index 00000000000..4c43bcf32fa
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ip.c
@@ -0,0 +1,364 @@
+/* $NetBSD: print-ip.c,v 1.4 1995/04/24 13:27:43 cgd Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-ip.c,v 1.38 94/06/14 20:17:40 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static void
+igmp_print(register const u_char *bp, register int len,
+ register const u_char *bp2)
+{
+ register const struct ip *ip;
+ register const u_char *ep;
+
+ ip = (const struct ip *)bp2;
+ ep = (const u_char *)snapend;
+ (void)printf("%s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+
+ if (bp + 7 > ep) {
+ (void)printf("[|igmp]");
+ return;
+ }
+ switch (bp[0] & 0xf) {
+ case 1:
+ (void)printf("igmp query");
+ if (*(int *)&bp[4])
+ (void)printf(" [gaddr %s]", ipaddr_string(&bp[4]));
+ if (len != 8)
+ (void)printf(" [len %d]", len);
+ break;
+ case 2:
+ (void)printf("igmp report %s", ipaddr_string(&bp[4]));
+ if (len != 8)
+ (void)printf(" [len %d]", len);
+ break;
+ case 3:
+ (void)printf("igmp dvmrp %s", ipaddr_string(&bp[4]));
+ if (len < 8)
+ (void)printf(" [len %d]", len);
+ break;
+ default:
+ (void)printf("igmp-%d", bp[0] & 0xf);
+ break;
+ }
+ if ((bp[0] >> 4) != 1)
+ (void)printf(" [v%d]", bp[0] >> 4);
+ if (bp[1])
+ (void)printf(" [b1=0x%x]", bp[1]);
+}
+
+/*
+ * print the recorded route in an IP RR, LSRR or SSRR option.
+ */
+static void
+ip_printroute(const char *type, register const u_char *cp, int length)
+{
+ int ptr = cp[2] - 1;
+ int len;
+
+ printf(" %s{", type);
+ if ((length + 1) & 3)
+ printf(" [bad length %d]", length);
+ if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
+ printf(" [bad ptr %d]", cp[2]);
+
+ type = "";
+ for (len = 3; len < length; len += 4) {
+ if (ptr == len)
+ type = "#";
+#ifdef TCPDUMP_ALIGN
+ {
+ struct in_addr addr;
+ bcopy((char *)&cp[len], (char *)&addr, sizeof(addr));
+ printf("%s%s", type, ipaddr_string(&addr));
+ }
+#else
+ printf("%s%s", type, ipaddr_string(&cp[len]));
+#endif
+ type = " ";
+ }
+ printf("%s}", ptr == len? "#" : "");
+}
+
+/*
+ * print IP options.
+ */
+static void
+ip_optprint(register const u_char *cp, int length)
+{
+ int len;
+
+ for (; length > 0; cp += len, length -= len) {
+ int tt = *cp;
+
+ len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
+ if (&cp[1] >= snapend || cp + len > snapend) {
+ printf("[|ip]");
+ return;
+ }
+ switch (tt) {
+
+ case IPOPT_EOL:
+ printf(" EOL");
+ if (length > 1)
+ printf("-%d", length - 1);
+ return;
+
+ case IPOPT_NOP:
+ printf(" NOP");
+ break;
+
+ case IPOPT_TS:
+ printf(" TS{%d}", len);
+ break;
+
+ case IPOPT_SECURITY:
+ printf(" SECURITY{%d}", len);
+ break;
+
+ case IPOPT_RR:
+ printf(" RR{%d}=", len);
+ ip_printroute("RR", cp, len);
+ break;
+
+ case IPOPT_SSRR:
+ ip_printroute("SSRR", cp, len);
+ break;
+
+ case IPOPT_LSRR:
+ ip_printroute("LSRR", cp, len);
+ break;
+
+ default:
+ printf(" IPOPT-%d{%d}", cp[0], len);
+ break;
+ }
+ }
+}
+
+/*
+ * compute an IP header checksum.
+ * don't modifiy the packet.
+ */
+static int
+in_cksum(const struct ip *ip)
+{
+ register const u_short *sp = (u_short *)ip;
+ register u_int32 sum = 0;
+ register int count;
+
+ /*
+ * No need for endian conversions.
+ */
+ for (count = ip->ip_hl * 2; --count >= 0; )
+ sum += *sp++;
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = ~sum & 0xffff;
+
+ return (sum);
+}
+
+/*
+ * print an IP datagram.
+ */
+void
+ip_print(register const u_char *bp, register int length)
+{
+ register const struct ip *ip;
+ register int hlen;
+ register int len;
+ register int off;
+ register const u_char *cp;
+
+ ip = (const struct ip *)bp;
+#ifdef TCPDUMP_ALIGN
+ /*
+ * The IP header is not word aligned, so copy into abuf.
+ * This will never happen with BPF. It does happen raw packet
+ * dumps from -r.
+ */
+ if ((long)ip & (sizeof(long)-1)) {
+ static u_char *abuf;
+
+ if (abuf == 0)
+ abuf = (u_char *)malloc(snaplen);
+ bcopy((char *)ip, (char *)abuf, min(length, snaplen));
+ snapend += abuf - (u_char *)ip;
+ packetp = abuf;
+ ip = (struct ip *)abuf;
+ }
+#endif
+ if ((u_char *)(ip + 1) > snapend) {
+ printf("[|ip]");
+ return;
+ }
+ if (length < sizeof (struct ip)) {
+ (void)printf("truncated-ip %d", length);
+ return;
+ }
+ hlen = ip->ip_hl * 4;
+
+ len = ntohs(ip->ip_len);
+ if (length < len)
+ (void)printf("truncated-ip - %d bytes missing!",
+ len - length);
+ len -= hlen;
+
+ /*
+ * If this is fragment zero, hand it to the next higher
+ * level protocol.
+ */
+ off = ntohs(ip->ip_off);
+ if ((off & 0x1fff) == 0) {
+ cp = (const u_char *)ip + hlen;
+ switch (ip->ip_p) {
+
+ case IPPROTO_TCP:
+ tcp_print(cp, len, (const u_char *)ip);
+ break;
+ case IPPROTO_UDP:
+ udp_print(cp, len, (const u_char *)ip);
+ break;
+ case IPPROTO_ICMP:
+ icmp_print(cp, (const u_char *)ip);
+ break;
+ case IPPROTO_ND:
+ (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ (void)printf(" nd %d", len);
+ break;
+ case IPPROTO_EGP:
+ egp_print(cp, len, (const u_char *)ip);
+ break;
+#ifndef IPPROTO_OSPF
+#define IPPROTO_OSPF 89
+#endif
+ case IPPROTO_OSPF:
+ ospf_print(cp, len, (const u_char *)ip);
+ break;
+#ifndef IPPROTO_IGMP
+#define IPPROTO_IGMP 2
+#endif
+ case IPPROTO_IGMP:
+ igmp_print(cp, len, (const u_char *)ip);
+ break;
+#ifndef IPPROTO_ENCAP
+#define IPPROTO_ENCAP 4
+#endif
+ case IPPROTO_ENCAP:
+ /* ip-in-ip encapsulation */
+ if (vflag)
+ (void)printf("%s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ ip_print(cp, len);
+ if (! vflag) {
+ printf(" (encap)");
+ return;
+ }
+ break;
+ default:
+ (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ (void)printf(" ip-proto-%d %d", ip->ip_p, len);
+ break;
+ }
+ }
+ /*
+ * for fragmented datagrams, print id:size@offset. On all
+ * but the last stick a "+". For unfragmented datagrams, note
+ * the don't fragment flag.
+ */
+ if (off & 0x3fff) {
+ /*
+ * if this isn't the first frag, we're missing the
+ * next level protocol header. print the ip addr.
+ */
+ if (off & 0x1fff)
+ (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ (void)printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), len,
+ (off & 0x1fff) * 8,
+ (off & IP_MF)? "+" : "");
+ } else if (off & IP_DF)
+ (void)printf(" (DF)");
+
+ if (ip->ip_tos)
+ (void)printf(" [tos 0x%x]", (int)ip->ip_tos);
+ if (ip->ip_ttl <= 1)
+ (void)printf(" [ttl %d]", (int)ip->ip_ttl);
+
+ if (vflag) {
+ int sum;
+ char *sep = "";
+
+ printf(" (");
+ if (ip->ip_ttl > 1) {
+ (void)printf("%sttl %d", sep, (int)ip->ip_ttl);
+ sep = ", ";
+ }
+ if ((off & 0x3fff) == 0) {
+ (void)printf("%sid %d", sep, (int)ntohs(ip->ip_id));
+ sep = ", ";
+ }
+ sum = in_cksum(ip);
+ if (sum != 0) {
+ (void)printf("%sbad cksum %x!", sep,
+ ntohs(ip->ip_sum));
+ sep = ", ";
+ }
+ if ((hlen -= sizeof(struct ip)) > 0) {
+ (void)printf("%soptlen=%d", sep, hlen);
+ ip_optprint((u_char *)(ip + 1), hlen);
+ }
+ printf(")");
+ }
+}
diff --git a/usr.sbin/tcpdump/print-ipx.c b/usr.sbin/tcpdump/print-ipx.c
new file mode 100644
index 00000000000..7872e6a6554
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ipx.c
@@ -0,0 +1,214 @@
+/* $NetBSD: print-ipx.c,v 1.2 1995/03/06 19:11:16 mycroft Exp $ */
+
+/*
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Format and print Novell IPX packets.
+ * Contributed by Brad Parker (brad@fcr.com).
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-ipx.c,v 1.6 94/06/20 19:44:38 leres Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ipx.h"
+#include "extract.h"
+
+
+static const char *ipxaddr_string(u_int32 net, const u_char *node);
+void ipx_decode(const struct ipxHdr *ipx, const u_char *datap, int length);
+void ipx_sap_print(const u_short *ipx, int length);
+void ipx_rip_print(const u_short *ipx, int length);
+
+/*
+ * Print IPX datagram packets.
+ */
+void
+ipx_print(const u_char *p, int length)
+{
+ const struct ipxHdr *ipx = (const struct ipxHdr *)p;
+
+ if (length < ipxSize) {
+ (void)printf(" truncated-ipx %d", length);
+ return;
+ }
+ (void)printf("%s.%x > ",
+ ipxaddr_string(EXTRACT_LONG(ipx->srcNet), ipx->srcNode),
+ EXTRACT_SHORT(&ipx->srcSkt));
+
+ (void)printf("%s.%x:",
+ ipxaddr_string(EXTRACT_LONG(ipx->dstNet), ipx->dstNode),
+ EXTRACT_SHORT(&ipx->dstSkt));
+
+ if ((u_char *)(ipx + 1) > snapend) {
+ printf(" [|ipx]");
+ return;
+ }
+
+ /* take length from ipx header */
+ length = EXTRACT_SHORT(&ipx->length);
+
+ ipx_decode(ipx, (u_char *)ipx + ipxSize, length - ipxSize);
+}
+
+static const char *
+ipxaddr_string(u_int32 net, const u_char *node)
+{
+ static char line[256];
+
+ sprintf(line, "%lu.%02x:%02x:%02x:%02x:%02x:%02x",
+ net, node[0], node[1], node[2], node[3], node[4], node[5]);
+
+ return line;
+}
+
+void
+ipx_decode(const struct ipxHdr *ipx, const u_char *datap, int length)
+{
+ switch (EXTRACT_SHORT(&ipx->dstSkt)) {
+ case IPX_SKT_NCP:
+ (void)printf(" ipx-ncp %d", length);
+ break;
+ case IPX_SKT_SAP:
+ ipx_sap_print((u_short *)datap, length);
+ break;
+ case IPX_SKT_RIP:
+ ipx_rip_print((u_short *)datap, length);
+ break;
+ case IPX_SKT_NETBIOS:
+ (void)printf(" ipx-netbios %d", length);
+ break;
+ case IPX_SKT_DIAGNOSTICS:
+ (void)printf(" ipx-diags %d", length);
+ break;
+ default:
+ (void)printf(" ipx-#%x %d", ipx->dstSkt, length);
+ break;
+ }
+}
+
+void
+ipx_sap_print(const u_short *ipx, int length)
+{
+ int command, i;
+
+ if (length < 2) {
+ (void)printf(" truncated-sap %d", length);
+ return;
+ }
+
+ command = EXTRACT_SHORT(ipx);
+ ipx++;
+ length -= 2;
+
+ switch (command) {
+ case 1:
+ case 3:
+ if (command == 1)
+ (void)printf("ipx-sap-req");
+ else
+ (void)printf("ipx-sap-nearest-req");
+
+ if (length > 0)
+ (void)printf(" %x '%.48s'", EXTRACT_SHORT(&ipx[0]),
+ (char*)&ipx[1]);
+ break;
+
+ case 2:
+ case 4:
+ if (command == 2)
+ (void)printf("ipx-sap-resp");
+ else
+ (void)printf("ipx-sap-nearest-resp");
+
+ for (i = 0; i < 8 && length > 0; i++) {
+ (void)printf(" %x '%.48s' addr %s",
+ EXTRACT_SHORT(&ipx[0]), (char *)&ipx[1],
+ ipxaddr_string(EXTRACT_LONG(&ipx[25]),
+ (u_char *)&ipx[27]));
+ ipx += 32;
+ length -= 64;
+ }
+ break;
+ default:
+ (void)printf("ipx-sap-?%x", command);
+ break;
+ }
+}
+
+void
+ipx_rip_print(const u_short *ipx, int length)
+{
+ int command, i;
+
+ if (length < 2) {
+ (void)printf(" truncated-ipx %d", length);
+ return;
+ }
+
+ command = EXTRACT_SHORT(ipx);
+ ipx++;
+ length -= 2;
+
+ switch (command) {
+ case 1:
+ (void)printf("ipx-rip-req");
+ if (length > 0)
+ (void)printf(" %lu/%d.%d", EXTRACT_LONG(&ipx[0]),
+ EXTRACT_SHORT(&ipx[2]), EXTRACT_SHORT(&ipx[3]));
+ break;
+ case 2:
+ (void)printf("ipx-rip-resp");
+ for (i = 0; i < 50 && length > 0; i++) {
+ (void)printf(" %lu/%d.%d", EXTRACT_LONG(&ipx[0]),
+ EXTRACT_SHORT(&ipx[2]), EXTRACT_SHORT(&ipx[3]));
+
+ ipx += 4;
+ length -= 8;
+ }
+ break;
+ default:
+ (void)printf("ipx-rip-?%x", command);
+ }
+}
+
diff --git a/usr.sbin/tcpdump/print-isoclns.c b/usr.sbin/tcpdump/print-isoclns.c
new file mode 100644
index 00000000000..670ecaf7c72
--- /dev/null
+++ b/usr.sbin/tcpdump/print-isoclns.c
@@ -0,0 +1,317 @@
+/* $NetBSD: print-isoclns.c,v 1.2 1995/03/06 19:11:17 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Original code by Matt Thomas, Digital Equipment Corporation
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-isoclns.c,v 1.9 94/06/14 20:18:44 leres Exp (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ethertype.h"
+
+#define CLNS 129
+#define ESIS 130
+#define ISIS 131
+#define NULLNS 0
+
+static int osi_cksum(const u_char *, int, const u_char *, u_char *, u_char *);
+static void esis_print(const u_char *, int);
+
+void
+isoclns_print(const u_char *p, int length, int caplen,
+ const u_char *esrc, const u_char *edst)
+{
+ if (caplen < 1) {
+ printf("[|iso-clns] ");
+ if (!eflag)
+ printf("%s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ return;
+ }
+
+ switch (*p) {
+
+ case CLNS:
+ /* esis_print(&p, &length); */
+ printf("iso-clns");
+ if (!eflag)
+ (void)printf(" %s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ break;
+
+ case ESIS:
+ printf("iso-esis");
+ if (!eflag)
+ (void)printf(" %s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ esis_print(p, length);
+ return;
+
+ case ISIS:
+ printf("iso-isis");
+ if (!eflag)
+ (void)printf(" %s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ /* isis_print(&p, &length); */
+ (void)printf(" len=%d ", length);
+ if (caplen > 1)
+ default_print_unaligned(p, caplen);
+ break;
+
+ case NULLNS:
+ printf("iso-nullns");
+ if (!eflag)
+ (void)printf(" %s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ break;
+
+ default:
+ printf("iso-clns %02x", p[0]);
+ if (!eflag)
+ (void)printf(" %s > %s",
+ etheraddr_string(esrc),
+ etheraddr_string(edst));
+ (void)printf(" len=%d ", length);
+ if (caplen > 1)
+ default_print_unaligned(p, caplen);
+ break;
+ }
+}
+
+#define ESIS_REDIRECT 6
+#define ESIS_ESH 2
+#define ESIS_ISH 4
+
+struct esis_hdr {
+ u_char version;
+ u_char reserved;
+ u_char type;
+ u_char tmo[2];
+ u_char cksum[2];
+};
+
+static void
+esis_print(const u_char *p, int length)
+{
+ const u_char *ep;
+ int li = p[1];
+ const struct esis_hdr *eh = (const struct esis_hdr *) &p[2];
+ u_char cksum[2];
+ u_char off[2];
+
+ if (length == 2) {
+ if (qflag)
+ printf(" bad pkt!");
+ else
+ printf(" no header at all!");
+ return;
+ }
+ ep = p + li;
+ if (li > length) {
+ if (qflag)
+ printf(" bad pkt!");
+ else
+ printf(" LI(%d) > PDU size (%d)!", li, length);
+ return;
+ }
+ if (li < sizeof(struct esis_hdr) + 2) {
+ if (qflag)
+ printf(" bad pkt!");
+ else {
+ printf(" too short for esis header %d:", li);
+ while (--length >= 0)
+ printf("%02X", *p++);
+ }
+ return;
+ }
+ switch (eh->type & 0x1f) {
+
+ case ESIS_REDIRECT:
+ printf(" redirect");
+ break;
+
+ case ESIS_ESH:
+ printf(" esh");
+ break;
+
+ case ESIS_ISH:
+ printf(" ish");
+ break;
+
+ default:
+ printf(" type %d", eh->type & 0x1f);
+ break;
+ }
+ off[0] = eh->cksum[0];
+ off[1] = eh->cksum[1];
+ if (vflag && osi_cksum(p, li, eh->cksum, cksum, off)) {
+ printf(" bad cksum (got %02x%02x want %02x%02x)",
+ eh->cksum[1], eh->cksum[0], cksum[1], cksum[0]);
+ return;
+ }
+ if (eh->version != 1) {
+ printf(" unsupported version %d", eh->version);
+ return;
+ }
+ p += sizeof(*eh) + 2;
+ li -= sizeof(*eh) + 2; /* protoid * li */
+
+ switch (eh->type & 0x1f) {
+ case ESIS_REDIRECT: {
+ const u_char *dst, *snpa, *is;
+
+ dst = p; p += *p + 1;
+ if (p > snapend)
+ return;
+ printf(" %s", isonsap_string(dst));
+ snpa = p; p += *p + 1;
+ is = p; p += *p + 1;
+ if (p > snapend)
+ return;
+ if (p > ep) {
+ printf(" [bad li]");
+ return;
+ }
+ if (is[0] == 0)
+ printf(" > %s", etheraddr_string(&snpa[1]));
+ else
+ printf(" > %s", isonsap_string(is));
+ li = ep - p;
+ break;
+ }
+#if 0
+ case ESIS_ESH:
+ printf(" esh");
+ break;
+#endif
+ case ESIS_ISH: {
+ const u_char *is;
+
+ is = p; p += *p + 1;
+ if (p > ep) {
+ printf(" [bad li]");
+ return;
+ }
+ if (p > snapend)
+ return;
+ printf(" %s", isonsap_string(is));
+ li = ep - p;
+ break;
+ }
+
+ default:
+ (void)printf(" len=%d", length);
+ if (length && p < snapend) {
+ length = snapend - p;
+ default_print(p, length);
+ }
+ return;
+ }
+ if (vflag)
+ while (p < ep && li) {
+ int op, opli;
+ const u_char *q;
+
+ if (snapend - p < 2)
+ return;
+ if (li < 2) {
+ printf(" bad opts/li");
+ return;
+ }
+ op = *p++;
+ opli = *p++;
+ li -= 2;
+ if (opli > li) {
+ printf(" opt (%d) too long", op);
+ return;
+ }
+ li -= opli;
+ q = p;
+ p += opli;
+ if (snapend < p)
+ return;
+ if (op == 198 && opli == 2) {
+ printf(" tmo=%d", q[0] * 256 + q[1]);
+ continue;
+ }
+ printf (" %d:<", op);
+ while (--opli >= 0)
+ printf("%02x", *q++);
+ printf (">");
+ }
+}
+
+static int
+osi_cksum(register const u_char *p, register int len,
+ const u_char *toff, u_char *cksum, u_char *off)
+{
+ int x, y, f = (len - ((toff - p) + 1));
+ long c0 = 0, c1 = 0;
+
+ if ((cksum[0] = off[0]) == 0 && (cksum[1] = off[1]) == 0)
+ return 0;
+
+ off[0] = off[1] = 0;
+ while (--len >= 0) {
+ c0 += *p++;
+ c1 += c0;
+ c0 %= 255;
+ c1 %= 255;
+ }
+ x = (c0 * f - c1);
+ if (x < 0)
+ x = 255 - (-x % 255);
+ else
+ x %= 255;
+ y = -1 * (x + c0);
+ if (y < 0)
+ y = 255 - (-y % 255);
+ else
+ y %= 255;
+
+ off[0] = x;
+ off[1] = y;
+
+ return (off[0] != cksum[0] || off[1] != cksum[1]);
+}
diff --git a/usr.sbin/tcpdump/print-llc.c b/usr.sbin/tcpdump/print-llc.c
new file mode 100644
index 00000000000..a6c036620d2
--- /dev/null
+++ b/usr.sbin/tcpdump/print-llc.c
@@ -0,0 +1,198 @@
+/* $NetBSD: print-llc.c,v 1.2 1995/03/06 19:11:19 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Code by Matt Thomas, Digital Equipment Corporation
+ * with an awful lot of hacking by Jeffrey Mogul, DECWRL
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-llc.c,v 1.13 94/06/14 20:18:45 leres Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "extract.h" /* must come after interface.h */
+
+#include "llc.h"
+
+static struct token cmd2str[] = {
+ { LLC_UI, "ui" },
+ { LLC_TEST, "test" },
+ { LLC_XID, "xid" },
+ { LLC_UA, "ua" },
+ { LLC_DISC, "disc" },
+ { LLC_DM, "dm" },
+ { LLC_SABME, "sabme" },
+ { LLC_FRMR, "frmr" },
+ { 0, NULL }
+};
+
+/*
+ * Returns non-zero IFF it succeeds in printing the header
+ */
+int
+llc_print(const u_char *p, int length, int caplen,
+ const u_char *esrc, const u_char *edst)
+{
+ struct llc llc;
+ register u_short et;
+ register int ret;
+
+ if (caplen < 3) {
+ (void)printf("[|llc]");
+ default_print((u_char *)p, caplen);
+ return(0);
+ }
+
+ /* Watch out for possible alignment problems */
+ bcopy((char *)p, (char *)&llc, min(caplen, sizeof(llc)));
+
+ if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
+ ipx_print(p, length);
+ return (1);
+ }
+#ifdef notyet
+ else if (p[0] == 0xf0 && p[1] == 0xf0)
+ netbios_print(p, length);
+#endif
+ if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
+ && llc.llcui == LLC_UI) {
+ isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
+ return (1);
+ }
+
+ if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
+ && llc.llcui == LLC_UI) {
+ if (caplen < sizeof(llc)) {
+ (void)printf("[|llc-snap]");
+ default_print((u_char *)p, caplen);
+ return (0);
+ }
+ if (vflag)
+ (void)printf("snap %s ", protoid_string(llc.llcpi));
+
+ caplen -= sizeof(llc);
+ length -= sizeof(llc);
+ p += sizeof(llc);
+
+ /* This is an encapsulated Ethernet packet */
+ et = EXTRACT_SHORT(&llc.ethertype[0]);
+ ret = ether_encap_print(et, p, length, caplen);
+ if (ret)
+ return (ret);
+ }
+
+ if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
+ if (eflag)
+ (void)printf("%s ", llcsap_string(llc.dsap));
+ else
+ (void)printf("%s > %s %s ",
+ etheraddr_string(esrc),
+ etheraddr_string(edst),
+ llcsap_string(llc.dsap));
+ } else {
+ if (eflag)
+ (void)printf("%s > %s ",
+ llcsap_string(llc.ssap & ~LLC_GSAP),
+ llcsap_string(llc.dsap));
+ else
+ (void)printf("%s %s > %s %s ",
+ etheraddr_string(esrc),
+ llcsap_string(llc.ssap & ~LLC_GSAP),
+ etheraddr_string(edst),
+ llcsap_string(llc.dsap));
+ }
+
+ if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
+ const char *m;
+ char f;
+ m = tok2str(cmd2str, "%02x", LLC_U_CMD(llc.llcu));
+ switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
+ case 0: f = 'C'; break;
+ case LLC_GSAP: f = 'R'; break;
+ case LLC_U_POLL: f = 'P'; break;
+ case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
+ default: f = '?'; break;
+ }
+
+ printf("%s/%c", m, f);
+
+ p += 3;
+ length -= 3;
+ caplen -= 3;
+
+ if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
+ if (*p == LLC_XID_FI) {
+ printf(": %02x %02x", p[1], p[2]);
+ p += 3;
+ length -= 3;
+ caplen -= 3;
+ }
+ }
+ } else {
+ char f;
+ llc.llcis = ntohs(llc.llcis);
+ switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
+ case 0: f = 'C'; break;
+ case LLC_GSAP: f = 'R'; break;
+ case LLC_U_POLL: f = 'P'; break;
+ case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
+ default: f = '?'; break;
+ }
+
+ if ((llc.llcu & LLC_S_FMT) == LLC_S_FMT) {
+ static char *llc_s[] = { "rr", "rej", "rnr", "03" };
+ (void)printf("%s (r=%d,%c)",
+ llc_s[LLC_S_CMD(llc.llcis)],
+ LLC_IS_NR(llc.llcis),
+ f);
+ } else {
+ (void)printf("I (s=%d,r=%d,%c)",
+ LLC_I_NS(llc.llcis),
+ LLC_IS_NR(llc.llcis),
+ f);
+ }
+ p += 4;
+ length -= 4;
+ caplen -= 4;
+ }
+ (void)printf(" len=%d", length);
+ if (caplen > 0) {
+ default_print_unaligned(p, caplen);
+ }
+ return(1);
+}
diff --git a/usr.sbin/tcpdump/print-nfs.c b/usr.sbin/tcpdump/print-nfs.c
new file mode 100644
index 00000000000..5ba11d9e989
--- /dev/null
+++ b/usr.sbin/tcpdump/print-nfs.c
@@ -0,0 +1,856 @@
+/* $NetBSD: print-nfs.c,v 1.4 1995/04/24 13:27:45 cgd Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-nfs.c,v 1.41 94/06/12 14:35:15 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#ifdef SOLARIS
+#include <tiuser.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "extract.h" /* must come after interface.h */
+
+#include "nfsv2.h"
+#include "nfsfh.h"
+
+static void nfs_printfh(const u_int32 *);
+static void xid_map_enter(const struct rpc_msg *, const struct ip *);
+static int32 xid_map_find(const struct rpc_msg *, const struct ip *);
+static void interp_reply(const struct rpc_msg *, u_int32, int);
+
+void
+nfsreply_print(register const u_char *bp, int length,
+ register const u_char *bp2)
+{
+ register const struct rpc_msg *rp;
+ register const struct ip *ip;
+ int32 proc;
+
+ rp = (const struct rpc_msg *)bp;
+ ip = (const struct ip *)bp2;
+
+ if (!nflag)
+ (void)printf("%s.nfs > %s.%x: reply %s %d",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst),
+ ntohl(rp->rm_xid),
+ ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
+ "ok":"ERR",
+ length);
+ else
+ (void)printf("%s.%x > %s.%x: reply %s %d",
+ ipaddr_string(&ip->ip_src),
+ NFS_PORT,
+ ipaddr_string(&ip->ip_dst),
+ ntohl(rp->rm_xid),
+ ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
+ "ok":"ERR",
+ length);
+
+ proc = xid_map_find(rp, ip);
+ if (proc >= 0)
+ interp_reply(rp, (u_int32)proc, length);
+}
+
+/*
+ * Return a pointer to the first file handle in the packet.
+ * If the packet was truncated, return 0.
+ */
+static const u_int32 *
+parsereq(register const struct rpc_msg *rp, register int length)
+{
+ register const u_int32 *dp = (u_int32 *)&rp->rm_call.cb_cred;
+ register const u_int32 *ep = (u_int32 *)snapend;
+ register u_int len;
+
+ if (&dp[2] >= ep)
+ return (0);
+ /*
+ * find the start of the req data (if we captured it)
+ */
+ len = ntohl(dp[1]);
+ if (dp < ep && len < length) {
+ dp += (len + (2 * sizeof(u_int32) + 3)) / sizeof(u_int32);
+ len = ntohl(dp[1]);
+ if ((dp < ep) && (len < length)) {
+ dp += (len + (2 * sizeof(u_int32) + 3)) /
+ sizeof(u_int32);
+ if (dp < ep)
+ return (dp);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Print out an NFS file handle and return a pointer to following word.
+ * If packet was truncated, return 0.
+ */
+static const u_int32 *
+parsefh(register const u_int32 *dp)
+{
+ if (dp + 8 <= (u_int32 *)snapend) {
+ nfs_printfh(dp);
+ return (dp + 8);
+ }
+ return (0);
+}
+
+/*
+ * Print out a file name and return pointer to 32-bit word past it.
+ * If packet was truncated, return 0.
+ */
+static const u_int32 *
+parsefn(register const u_int32 *dp)
+{
+ register u_int32 len;
+ register const u_char *cp;
+
+ /* Bail if we don't have the string length */
+ if ((u_char *)dp > snapend - sizeof(*dp))
+ return(0);
+
+ /* Fetch string length; convert to host order */
+ len = *dp++;
+ NTOHL(len);
+
+ cp = (u_char *)dp;
+ /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
+ dp += ((len + 3) & ~3) / sizeof(*dp);
+ if ((u_char *)dp > snapend)
+ return (0);
+ /* XXX seems like we should be checking the length */
+ (void) fn_printn(cp, len, NULL);
+
+ return (dp);
+}
+
+/*
+ * Print out file handle and file name.
+ * Return pointer to 32-bit word past file name.
+ * If packet was truncated (or there was some other error), return 0.
+ */
+static const u_int32 *
+parsefhn(register const u_int32 *dp)
+{
+ dp = parsefh(dp);
+ if (dp == 0)
+ return (0);
+ putchar(' ');
+ return (parsefn(dp));
+}
+
+void
+nfsreq_print(register const u_char *bp, int length, register const u_char *bp2)
+{
+ register const struct rpc_msg *rp;
+ register const struct ip *ip;
+ register const u_int32 *dp;
+ register const u_char *ep;
+
+#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
+
+ rp = (const struct rpc_msg *)bp;
+ ip = (const struct ip *)bp2;
+ ep = snapend;
+ if (!nflag)
+ (void)printf("%s.%x > %s.nfs: %d",
+ ipaddr_string(&ip->ip_src),
+ ntohl(rp->rm_xid),
+ ipaddr_string(&ip->ip_dst),
+ length);
+ else
+ (void)printf("%s.%x > %s.%x: %d",
+ ipaddr_string(&ip->ip_src),
+ ntohl(rp->rm_xid),
+ ipaddr_string(&ip->ip_dst),
+ NFS_PORT,
+ length);
+
+ xid_map_enter(rp, ip); /* record proc number for later on */
+
+ switch (ntohl(rp->rm_call.cb_proc)) {
+#ifdef NFSPROC_NOOP
+ case NFSPROC_NOOP:
+ printf(" nop");
+ return;
+#else
+#define NFSPROC_NOOP -1
+#endif
+ case NFSPROC_NULL:
+ printf(" null");
+ return;
+
+ case NFSPROC_GETATTR:
+ printf(" getattr");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_SETATTR:
+ printf(" setattr");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+#if NFSPROC_ROOT != NFSPROC_NOOP
+ case NFSPROC_ROOT:
+ printf(" root");
+ break;
+#endif
+ case NFSPROC_LOOKUP:
+ printf(" lookup");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READLINK:
+ printf(" readlink");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READ:
+ printf(" read");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 3 * sizeof(*dp));
+ printf(" %lu bytes @ %lu",
+ ntohl(dp[1]), ntohl(dp[0]));
+ return;
+ }
+ break;
+
+#if NFSPROC_WRITECACHE != NFSPROC_NOOP
+ case NFSPROC_WRITECACHE:
+ printf(" writecache");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 4 * sizeof(*dp));
+ printf(" %lu (%lu) bytes @ %lu (%lu)",
+ ntohl(dp[3]), ntohl(dp[2]),
+ ntohl(dp[1]), ntohl(dp[0]));
+ return;
+ }
+ break;
+#endif
+ case NFSPROC_WRITE:
+ printf(" write");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 4 * sizeof(*dp));
+ printf(" %lu (%lu) bytes @ %lu (%lu)",
+ ntohl(dp[3]), ntohl(dp[2]),
+ ntohl(dp[1]), ntohl(dp[0]));
+ return;
+ }
+ break;
+
+ case NFSPROC_CREATE:
+ printf(" create");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_REMOVE:
+ printf(" remove");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_RENAME:
+ printf(" rename");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefhn(dp)) != 0) {
+ fputs(" ->", stdout);
+ if (parsefhn(dp) != 0)
+ return;
+ }
+ break;
+
+ case NFSPROC_LINK:
+ printf(" link");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ fputs(" ->", stdout);
+ if (parsefhn(dp) != 0)
+ return;
+ }
+ break;
+
+ case NFSPROC_SYMLINK:
+ printf(" symlink");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefhn(dp)) != 0) {
+ fputs(" -> ", stdout);
+ if (parsefn(dp) != 0)
+ return;
+ }
+ break;
+
+ case NFSPROC_MKDIR:
+ printf(" mkdir");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_RMDIR:
+ printf(" rmdir");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READDIR:
+ printf(" readdir");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 2 * sizeof(*dp));
+ /*
+ * Print the offset as signed, since -1 is common,
+ * but offsets > 2^31 aren't.
+ */
+ printf(" %lu bytes @ %ld", ntohl(dp[1]), ntohl(dp[0]));
+ return;
+ }
+ break;
+
+ case NFSPROC_STATFS:
+ printf(" statfs");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ default:
+ printf(" proc-%lu", ntohl(rp->rm_call.cb_proc));
+ return;
+ }
+ fputs(" [|nfs]", stdout);
+#undef TCHECK
+}
+
+/*
+ * Print out an NFS file handle.
+ * We assume packet was not truncated before the end of the
+ * file handle pointed to by dp.
+ *
+ * Note: new version (using portable file-handle parser) doesn't produce
+ * generation number. It probably could be made to do that, with some
+ * additional hacking on the parser code.
+ */
+static void
+nfs_printfh(register const u_int32 *dp)
+{
+ my_fsid fsid;
+ ino_t ino;
+ char *sfsname = NULL;
+
+ Parse_fh((caddr_t*)dp, &fsid, &ino, NULL, &sfsname, 0);
+
+ if (sfsname) {
+ /* file system ID is ASCII, not numeric, for this server OS */
+ static char temp[NFS_FHSIZE+1];
+
+ /* Make sure string is null-terminated */
+ strncpy(temp, sfsname, NFS_FHSIZE);
+ /* Remove trailing spaces */
+ sfsname = strchr(temp, ' ');
+ if (sfsname)
+ *sfsname = 0;
+
+ (void)printf(" fh %s/%ld", temp, ino);
+ }
+ else {
+ (void)printf(" fh %d,%d/%ld",
+ fsid.fsid_dev.Major, fsid.fsid_dev.Minor,
+ ino);
+ }
+}
+
+/*
+ * Maintain a small cache of recent client.XID.server/proc pairs, to allow
+ * us to match up replies with requests and thus to know how to parse
+ * the reply.
+ */
+
+struct xid_map_entry {
+ u_int32 xid; /* transaction ID (net order) */
+ struct in_addr client; /* client IP address (net order) */
+ struct in_addr server; /* server IP address (net order) */
+ u_int32 proc; /* call proc number (host order) */
+};
+
+/*
+ * Map entries are kept in an array that we manage as a ring;
+ * new entries are always added at the tail of the ring. Initially,
+ * all the entries are zero and hence don't match anything.
+ */
+
+#define XIDMAPSIZE 64
+
+struct xid_map_entry xid_map[XIDMAPSIZE];
+
+int xid_map_next = 0;
+int xid_map_hint = 0;
+
+static void
+xid_map_enter(const struct rpc_msg *rp, const struct ip *ip)
+{
+ struct xid_map_entry *xmep;
+
+ xmep = &xid_map[xid_map_next];
+
+ if (++xid_map_next >= XIDMAPSIZE)
+ xid_map_next = 0;
+
+ xmep->xid = rp->rm_xid;
+ xmep->client = ip->ip_src;
+ xmep->server = ip->ip_dst;
+ xmep->proc = ntohl(rp->rm_call.cb_proc);
+}
+
+/* Returns NFSPROC_xxx or -1 on failure */
+static int32
+xid_map_find(const struct rpc_msg *rp, const struct ip *ip)
+{
+ int i;
+ struct xid_map_entry *xmep;
+ u_int32 xid = rp->rm_xid;
+ u_int32 clip = ip->ip_dst.s_addr;
+ u_int32 sip = ip->ip_src.s_addr;
+
+ /* Start searching from where we last left off */
+ i = xid_map_hint;
+ do {
+ xmep = &xid_map[i];
+ if (xmep->xid == xid && xmep->client.s_addr == clip &&
+ xmep->server.s_addr == sip) {
+ /* match */
+ xid_map_hint = i;
+ return ((int32)xmep->proc);
+ }
+ if (++i >= XIDMAPSIZE)
+ i = 0;
+ } while (i != xid_map_hint);
+
+ /* search failed */
+ return(-1);
+}
+
+/*
+ * Routines for parsing reply packets
+ */
+
+/*
+ * Return a pointer to the beginning of the actual results.
+ * If the packet was truncated, return 0.
+ */
+static const u_int32 *
+parserep(register const struct rpc_msg *rp, register int length)
+{
+ register const u_int32 *dp;
+ register const u_int32 *ep = (const u_int32 *)snapend;
+ int len;
+ enum accept_stat astat;
+
+ /*
+ * Portability note:
+ * Here we find the address of the ar_verf credentials.
+ * Originally, this calculation was
+ * dp = (u_int32 *)&rp->rm_reply.rp_acpt.ar_verf
+ * On the wire, the rp_acpt field starts immediately after
+ * the (32 bit) rp_stat field. However, rp_acpt (which is a
+ * "struct accepted_reply") contains a "struct opaque_auth",
+ * whose internal representation contains a pointer, so on a
+ * 64-bit machine the compiler inserts 32 bits of padding
+ * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
+ * the internal representation to parse the on-the-wire
+ * representation. Instead, we skip past the rp_stat field,
+ * which is an "enum" and so occupies one 32-bit word.
+ */
+ dp = ((const u_int32 *)&rp->rm_reply) + 1;
+ if (&dp[1] >= ep)
+ return(0);
+ len = ntohl(dp[1]);
+ if (len >= length)
+ return(0);
+ /*
+ * skip past the ar_verf credentials.
+ */
+ dp += (len + (2*sizeof(u_int32) + 3)) / sizeof(u_int32);
+ if (dp >= ep)
+ return(0);
+
+ /*
+ * now we can check the ar_stat field
+ */
+ astat = ntohl(*(enum accept_stat *)dp);
+ switch (astat) {
+
+ case SUCCESS:
+ break;
+
+ case PROG_UNAVAIL:
+ printf(" PROG_UNAVAIL");
+ return(0);
+
+ case PROG_MISMATCH:
+ printf(" PROG_MISMATCH");
+ return(0);
+
+ case PROC_UNAVAIL:
+ printf(" PROC_UNAVAIL");
+ return(0);
+
+ case GARBAGE_ARGS:
+ printf(" GARBAGE_ARGS");
+ return(0);
+
+ case SYSTEM_ERR:
+ printf(" SYSTEM_ERR");
+ return(0);
+
+ default:
+ printf(" ar_stat %d", astat);
+ return(0);
+ }
+ /* successful return */
+ if ((sizeof(astat) + ((char *)dp)) < (char *)ep)
+ return((u_int32 *) (sizeof(astat) + ((char *)dp)));
+
+ return (0);
+}
+
+#define T2CHECK(p, l) if ((u_char *)(p) > ((u_char *)snapend) - l) return(0)
+
+/*
+ * Not all systems have strerror().
+ */
+static char *
+strerr(int errno)
+{
+
+ return (strerror(errno));
+}
+
+static const u_int32 *
+parsestatus(const u_int32 *dp)
+{
+ int errno;
+ T2CHECK(dp, 4);
+
+ errno = ntohl(dp[0]);
+ if (errno != 0) {
+ char *errmsg;
+
+ if (qflag)
+ return(0);
+
+ errmsg = strerr(errno);
+ if (errmsg)
+ printf(" ERROR: %s", errmsg);
+ else
+ printf(" ERROR: %d", errno);
+ return(0);
+ }
+ return (dp + 1);
+}
+
+static struct token type2str[] = {
+ { NFNON, "NON" },
+ { NFREG, "REG" },
+ { NFDIR, "DIR" },
+ { NFBLK, "BLK" },
+ { NFCHR, "CHR" },
+ { NFLNK, "LNK" },
+ { 0, NULL }
+};
+
+static const u_int32 *
+parsefattr(const u_int32 *dp, int verbose)
+{
+ const struct nfsv2_fattr *fap;
+
+ T2CHECK(dp, 4);
+
+ fap = (const struct nfsv2_fattr *)dp;
+ if (verbose)
+ printf(" %s %o ids %d/%d sz %d ",
+ tok2str(type2str, "unk-ft %d ", ntohl(fap->fa_type)),
+ ntohl(fap->fa_mode), ntohl(fap->fa_uid),
+ ntohl(fap->fa_gid), ntohl(fap->fa_nfssize));
+ /* print lots more stuff */
+ if (verbose > 1) {
+ printf("nlink %d rdev %x fsid %x nodeid %x a/m/ctime ",
+ ntohl(fap->fa_nlink), ntohl(fap->fa_nfsrdev),
+ ntohl(fap->fa_nfsfsid), ntohl(fap->fa_nfsfileid));
+ printf("%d.%06d ",
+ ntohl(fap->fa_nfsatime.nfs_sec),
+ ntohl(fap->fa_nfsatime.nfs_usec));
+ printf("%d.%06d ",
+ ntohl(fap->fa_nfsmtime.nfs_sec),
+ ntohl(fap->fa_nfsmtime.nfs_usec));
+ printf("%d.%06d ",
+ ntohl(fap->fa_nfsctime.nfs_sec),
+ ntohl(fap->fa_nfsctime.nfs_usec));
+ }
+ return ((const u_int32 *)&fap[1]);
+}
+
+static int
+parseattrstat(const u_int32 *dp, int verbose)
+{
+ dp = parsestatus(dp);
+ if (dp == NULL)
+ return (0);
+
+ return ((long)parsefattr(dp, verbose));
+}
+
+static int
+parsediropres(const u_int32 *dp)
+{
+ dp = parsestatus(dp);
+ if (dp == NULL)
+ return (0);
+
+ dp = parsefh(dp);
+ if (dp == NULL)
+ return (0);
+
+ return (parsefattr(dp, vflag) != NULL);
+}
+
+static int
+parselinkres(const u_int32 *dp)
+{
+ dp = parsestatus(dp);
+ if (dp == NULL)
+ return(0);
+
+ putchar(' ');
+ return (parsefn(dp) != NULL);
+}
+
+static int
+parsestatfs(const u_int32 *dp)
+{
+ const struct nfsv2_statfs *sfsp;
+
+ dp = parsestatus(dp);
+ if (dp == NULL)
+ return(0);
+
+ if (qflag)
+ return(1);
+
+ T2CHECK(dp, 20);
+
+ sfsp = (const struct nfsv2_statfs *)dp;
+ printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
+ ntohl(sfsp->sf_tsize), ntohl(sfsp->sf_bsize),
+ ntohl(sfsp->sf_blocks), ntohl(sfsp->sf_bfree),
+ ntohl(sfsp->sf_bavail));
+
+ return (1);
+}
+
+static int
+parserddires(const u_int32 *dp)
+{
+ dp = parsestatus(dp);
+ if (dp == 0)
+ return (0);
+ if (qflag)
+ return (1);
+
+ T2CHECK(dp, 12);
+ printf(" offset %x size %d ", ntohl(dp[0]), ntohl(dp[1]));
+ if (dp[2] != 0)
+ printf("eof");
+
+ return (1);
+}
+
+static void
+interp_reply(const struct rpc_msg *rp, u_int32 proc, int length)
+{
+ register const u_int32 *dp;
+
+ switch (proc) {
+
+#ifdef NFSPROC_NOOP
+ case NFSPROC_NOOP:
+ printf(" nop");
+ return;
+#else
+#define NFSPROC_NOOP -1
+#endif
+ case NFSPROC_NULL:
+ printf(" null");
+ return;
+
+ case NFSPROC_GETATTR:
+ printf(" getattr");
+ dp = parserep(rp, length);
+ if (dp != 0 && parseattrstat(dp, !qflag) != 0)
+ return;
+ break;
+
+ case NFSPROC_SETATTR:
+ printf(" setattr");
+ dp = parserep(rp, length);
+ if (dp != 0 && parseattrstat(dp, !qflag) != 0)
+ return;
+ break;
+
+#if NFSPROC_ROOT != NFSPROC_NOOP
+ case NFSPROC_ROOT:
+ printf(" root");
+ break;
+#endif
+ case NFSPROC_LOOKUP:
+ printf(" lookup");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsediropres(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READLINK:
+ printf(" readlink");
+ dp = parserep(rp, length);
+ if (dp != 0 && parselinkres(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READ:
+ printf(" read");
+ dp = parserep(rp, length);
+ if (dp != 0 && parseattrstat(dp, vflag) != 0)
+ return;
+ break;
+
+#if NFSPROC_WRITECACHE != NFSPROC_NOOP
+ case NFSPROC_WRITECACHE:
+ printf(" writecache");
+ break;
+#endif
+ case NFSPROC_WRITE:
+ printf(" write");
+ dp = parserep(rp, length);
+ if (dp != 0 && parseattrstat(dp, vflag) != 0)
+ return;
+ break;
+
+ case NFSPROC_CREATE:
+ printf(" create");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsediropres(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_REMOVE:
+ printf(" remove");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatus(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_RENAME:
+ printf(" rename");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatus(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_LINK:
+ printf(" link");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatus(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_SYMLINK:
+ printf(" symlink");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatus(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_MKDIR:
+ printf(" mkdir");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsediropres(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_RMDIR:
+ printf(" rmdir");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatus(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_READDIR:
+ printf(" readdir");
+ dp = parserep(rp, length);
+ if (dp != 0 && parserddires(dp) != 0)
+ return;
+ break;
+
+ case NFSPROC_STATFS:
+ printf(" statfs");
+ dp = parserep(rp, length);
+ if (dp != 0 && parsestatfs(dp) != 0)
+ return;
+ break;
+
+ default:
+ printf(" proc-%lu", proc);
+ return;
+ }
+ fputs(" [|nfs]", stdout);
+}
diff --git a/usr.sbin/tcpdump/print-ntp.c b/usr.sbin/tcpdump/print-ntp.c
new file mode 100644
index 00000000000..ed92f695224
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ntp.c
@@ -0,0 +1,287 @@
+/* $NetBSD: print-ntp.c,v 1.2 1995/03/06 19:11:22 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print ntp packets.
+ * By Jeffrey Mogul/DECWRL
+ * loosely based on print-bootp.c
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-ntp.c,v 1.14 94/06/14 20:18:46 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#undef MODEMASK /* Solaris sucks */
+#include "ntp.h"
+
+static void p_sfix(const struct s_fixedpt *);
+static void p_ntp_time(const struct l_fixedpt *);
+static void p_ntp_delta(const struct l_fixedpt *, const struct l_fixedpt *);
+
+/*
+ * Print ntp requests
+ */
+void
+ntp_print(register const u_char *cp, int length)
+{
+ register const struct ntpdata *bp;
+ register const u_char *ep;
+ int mode, version, leapind;
+ static char rclock[5];
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ bp = (struct ntpdata *)cp;
+ /* Note funny sized packets */
+ if (length != sizeof(struct ntpdata))
+ (void)printf(" [len=%d]", length);
+
+ /* 'ep' points to the end of avaible data. */
+ ep = snapend;
+
+ TCHECK(bp->status, sizeof(bp->status));
+
+ version = (bp->status & VERSIONMASK) >> 3;
+ printf(" v%d", version);
+
+ leapind = bp->status & LEAPMASK;
+ switch (leapind) {
+
+ case NO_WARNING:
+ break;
+
+ case PLUS_SEC:
+ fputs(" +1s", stdout);
+ break;
+
+ case MINUS_SEC:
+ fputs(" -1s", stdout);
+ break;
+ }
+
+ mode = bp->status & MODEMASK;
+ switch (mode) {
+
+ case MODE_UNSPEC: /* unspecified */
+ fputs(" unspec", stdout);
+ break;
+
+ case MODE_SYM_ACT: /* symmetric active */
+ fputs(" sym_act", stdout);
+ break;
+
+ case MODE_SYM_PAS: /* symmetric passive */
+ fputs(" sym_pas", stdout);
+ break;
+
+ case MODE_CLIENT: /* client */
+ fputs(" client", stdout);
+ break;
+
+ case MODE_SERVER: /* server */
+ fputs(" server", stdout);
+ break;
+
+ case MODE_BROADCAST: /* broadcast */
+ fputs(" bcast", stdout);
+ break;
+
+ case MODE_RES1: /* reserved */
+ fputs(" res1", stdout);
+ break;
+
+ case MODE_RES2: /* reserved */
+ fputs(" res2", stdout);
+ break;
+
+ }
+
+ TCHECK(bp->stratum, sizeof(bp->stratum));
+ printf(" strat %d", bp->stratum);
+
+ TCHECK(bp->ppoll, sizeof(bp->ppoll));
+ printf(" poll %d", bp->ppoll);
+
+ /* Can't TCHECK bp->precision bitfield so bp->distance + 0 instead */
+ TCHECK(bp->distance, 0);
+ printf(" prec %d", bp->precision);
+
+ if (!vflag)
+ return;
+
+ TCHECK(bp->distance, sizeof(bp->distance));
+ fputs(" dist ", stdout);
+ p_sfix(&bp->distance);
+
+ TCHECK(bp->dispersion, sizeof(bp->dispersion));
+ fputs(" disp ", stdout);
+ p_sfix(&bp->dispersion);
+
+ TCHECK(bp->refid, sizeof(bp->refid));
+ fputs(" ref ", stdout);
+ /* Interpretation depends on stratum */
+ switch (bp->stratum) {
+
+ case UNSPECIFIED:
+ case PRIM_REF:
+ strncpy(rclock, (char *)&(bp->refid), 4);
+ rclock[4] = '\0';
+ fputs(rclock, stdout);
+ break;
+
+ case INFO_QUERY:
+ printf("%s INFO_QUERY", ipaddr_string(&(bp->refid)));
+ /* this doesn't have more content */
+ return;
+
+ case INFO_REPLY:
+ printf("%s INFO_REPLY", ipaddr_string(&(bp->refid)));
+ /* this is too complex to be worth printing */
+ return;
+
+ default:
+ printf("%s", ipaddr_string(&(bp->refid)));
+ break;
+ }
+
+ TCHECK(bp->reftime, sizeof(bp->reftime));
+ putchar('@');
+ p_ntp_time(&(bp->reftime));
+
+ TCHECK(bp->org, sizeof(bp->org));
+ fputs(" orig ", stdout);
+ p_ntp_time(&(bp->org));
+
+ TCHECK(bp->rec, sizeof(bp->rec));
+ fputs(" rec ", stdout);
+ p_ntp_delta(&(bp->org), &(bp->rec));
+
+ TCHECK(bp->xmt, sizeof(bp->xmt));
+ fputs(" xmt ", stdout);
+ p_ntp_delta(&(bp->org), &(bp->xmt));
+
+ return;
+
+trunc:
+ fputs(" [|ntp]", stdout);
+#undef TCHECK
+}
+
+static void
+p_sfix(register const struct s_fixedpt *sfp)
+{
+ register int i;
+ register int f;
+ register float ff;
+
+ i = ntohs(sfp->int_part);
+ f = ntohs(sfp->fraction);
+ ff = f / 65536.0; /* shift radix point by 16 bits */
+ f = ff * 1000000.0; /* Treat fraction as parts per million */
+ printf("%d.%06d", i, f);
+}
+
+#define FMAXINT (4294967296.0) /* floating point rep. of MAXINT */
+
+static void
+p_ntp_time(register const struct l_fixedpt *lfp)
+{
+ register int32 i;
+ register u_int32 uf;
+ register u_int32 f;
+ register float ff;
+
+ i = ntohl(lfp->int_part);
+ uf = ntohl(lfp->fraction);
+ ff = uf;
+ if (ff < 0.0) /* some compilers are buggy */
+ ff += FMAXINT;
+ ff = ff / FMAXINT; /* shift radix point by 32 bits */
+ f = ff * 1000000000.0; /* treat fraction as parts per billion */
+ printf("%lu.%09d", i, f);
+}
+
+/* Prints time difference between *lfp and *olfp */
+static void
+p_ntp_delta(register const struct l_fixedpt *olfp,
+ register const struct l_fixedpt *lfp)
+{
+ register int32 i;
+ register u_int32 uf;
+ register u_int32 ouf;
+ register u_int32 f;
+ register float ff;
+ int signbit;
+
+ i = ntohl(lfp->int_part) - ntohl(olfp->int_part);
+
+ uf = ntohl(lfp->fraction);
+ ouf = ntohl(olfp->fraction);
+
+ if (i > 0) { /* new is definitely greater than old */
+ signbit = 0;
+ f = uf - ouf;
+ if (ouf > uf) /* must borrow from high-order bits */
+ i -= 1;
+ } else if (i < 0) { /* new is definitely less than old */
+ signbit = 1;
+ f = ouf - uf;
+ if (uf > ouf) /* must carry into the high-order bits */
+ i += 1;
+ i = -i;
+ } else { /* int_part is zero */
+ if (uf > ouf) {
+ signbit = 0;
+ f = uf - ouf;
+ } else {
+ signbit = 1;
+ f = ouf - uf;
+ }
+ }
+
+ ff = f;
+ if (ff < 0.0) /* some compilers are buggy */
+ ff += FMAXINT;
+ ff = ff / FMAXINT; /* shift radix point by 32 bits */
+ f = ff * 1000000000.0; /* treat fraction as parts per billion */
+ if (signbit)
+ putchar('-');
+ else
+ putchar('+');
+ printf("%d.%09d", i, f);
+}
diff --git a/usr.sbin/tcpdump/print-null.c b/usr.sbin/tcpdump/print-null.c
new file mode 100644
index 00000000000..69a34566897
--- /dev/null
+++ b/usr.sbin/tcpdump/print-null.c
@@ -0,0 +1,113 @@
+/* $NetBSD: print-null.c,v 1.3 1995/03/06 19:11:24 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-null.c,v 1.14 94/06/10 17:01:35 mccanne Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "pcap.h"
+
+#define NULL_HDRLEN 4
+
+static void
+null_print(const u_char *p, const struct ip *ip, int length)
+{
+ u_int family;
+
+ bcopy(p, &family, sizeof(family));
+
+ if (nflag) {
+ /* XXX just dump the header */
+ return;
+ }
+ switch (family) {
+
+ case AF_INET:
+ printf("ip: ");
+ break;
+
+ case AF_NS:
+ printf("ns: ");
+ break;
+
+ default:
+ printf("AF %d: ", family);
+ break;
+ }
+}
+
+void
+null_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ int length = h->len;
+ int caplen = h->caplen;
+ const struct ip *ip;
+
+ ts_print(&h->ts);
+
+ /*
+ * Some printers want to get back at the link level addresses,
+ * and/or check that they're not walking off the end of the packet.
+ * Rather than pass them all the way down, we set these globals.
+ */
+ packetp = p;
+ snapend = p + caplen;
+
+ length -= NULL_HDRLEN;
+
+ ip = (struct ip *)(p + NULL_HDRLEN);
+
+ if (eflag)
+ null_print(p, ip, length);
+
+ ip_print((const u_char *)ip, length);
+
+ if (xflag)
+ default_print((const u_char *)ip, caplen - NULL_HDRLEN);
+ putchar('\n');
+}
+
diff --git a/usr.sbin/tcpdump/print-ospf.c b/usr.sbin/tcpdump/print-ospf.c
new file mode 100644
index 00000000000..90ffecf9dd7
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ospf.c
@@ -0,0 +1,580 @@
+/* $NetBSD: print-ospf.c,v 1.3 1995/03/06 19:11:25 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-ospf.c,v 1.12 94/06/14 20:18:46 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#include "ospf.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+struct bits {
+ u_int32 bit;
+ const char *str;
+};
+
+static const struct bits ospf_option_bits[] = {
+ { OSPF_OPTION_T, "T" },
+ { OSPF_OPTION_E, "E" },
+ { OSPF_OPTION_MC, "MC" },
+ { 0, NULL }
+};
+
+static const struct bits ospf_rla_flag_bits[] = {
+ { RLA_FLAG_B, "B" },
+ { RLA_FLAG_E, "E" },
+ { RLA_FLAG_W1, "W1" },
+ { RLA_FLAG_W2, "W2" },
+ { 0, NULL }
+};
+
+static const char *ospf_types[OSPF_TYPE_MAX] = {
+ (char *) 0,
+ "hello",
+ "dd",
+ "ls_req",
+ "ls_upd",
+ "ls_ack"
+};
+
+static inline void
+ospf_print_seqage(register u_int32 seq, register time_t us)
+{
+ register time_t sec = us % 60;
+ register time_t mins = (us / 60) % 60;
+ register time_t hour = us/3600;
+
+ printf(" S %X age ",
+ seq);
+ if (hour) {
+ printf("%d:%02d:%02d",
+ hour,
+ mins,
+ sec);
+ } else if (mins) {
+ printf("%d:%02d",
+ mins,
+ sec);
+ } else {
+ printf("%d",
+ sec);
+ }
+}
+
+
+static inline void
+ospf_print_bits(register const struct bits *bp, register u_char options)
+{
+ char sep = ' ';
+
+ do {
+ if (options & bp->bit) {
+ printf("%c%s",
+ sep,
+ bp->str);
+ sep = '/';
+ }
+ } while ((++bp)->bit) ;
+}
+
+
+#define LS_PRINT(lsp, type) switch (type) { \
+ case LS_TYPE_ROUTER: \
+ printf(" rtr %s ", ipaddr_string(&lsp->ls_router)); break; \
+ case LS_TYPE_NETWORK: \
+ printf(" net dr %s if %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \
+ case LS_TYPE_SUM_IP: \
+ printf(" sum %s abr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+ case LS_TYPE_SUM_ABR: \
+ printf(" abr %s rtr %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \
+ case LS_TYPE_ASE: \
+ printf(" ase %s asbr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+ case LS_TYPE_GROUP: \
+ printf(" group %s rtr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+ }
+
+static int
+ospf_print_lshdr(register const struct lsa_hdr *lshp, const caddr_t end)
+{
+ if ((caddr_t) (lshp + 1) > end) {
+ return 1;
+ }
+
+ printf(" {"); /* } (ctags) */
+
+ if (!lshp->ls_type || lshp->ls_type >= LS_TYPE_MAX) {
+ printf(" ??LS type %d?? }", /* { (ctags) */
+ lshp->ls_type);
+ return 1;
+ }
+
+ ospf_print_bits(ospf_option_bits, lshp->ls_options);
+ ospf_print_seqage(ntohl(lshp->ls_seq),
+ ntohs(lshp->ls_age));
+
+ LS_PRINT(lshp, lshp->ls_type);
+
+ return 0;
+}
+
+
+/*
+ * Print a single link state advertisement. If truncated return 1, else 0.
+ */
+
+static int
+ospf_print_lsa(register const struct lsa *lsap, const caddr_t end)
+{
+ register const char *ls_end;
+ const struct rlalink *rlp;
+ const struct tos_metric *tosp;
+ const struct in_addr *ap;
+ const struct aslametric *almp;
+ const struct mcla *mcp;
+ const u_int32 *lp;
+ int j, k;
+
+ if (ospf_print_lshdr(&lsap->ls_hdr, end)) {
+ return 1;
+ }
+
+ ls_end = (caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length);
+
+ if (ls_end > end) {
+ printf(" }"); /* { (ctags) */
+ return 1;
+ }
+
+ switch (lsap->ls_hdr.ls_type) {
+ case LS_TYPE_ROUTER:
+ ospf_print_bits(ospf_rla_flag_bits, lsap->lsa_un.un_rla.rla_flags);
+
+ j = ntohs(lsap->lsa_un.un_rla.rla_count);
+ rlp = lsap->lsa_un.un_rla.rla_link;
+ while (j--) {
+ struct rlalink *rln = (struct rlalink *) ((caddr_t) (rlp + 1) + ((rlp->link_toscount) * sizeof (struct tos_metric)));
+
+ if ((caddr_t) rln > ls_end) {
+ break;
+ }
+ printf(" {"); /* } (ctags) */
+
+ switch (rlp->link_type) {
+ case RLA_TYPE_VIRTUAL:
+ printf(" virt");
+ /* Fall through */
+
+ case RLA_TYPE_ROUTER:
+ printf(" nbrid %s if %s",
+ ipaddr_string(&rlp->link_id),
+ ipaddr_string(&rlp->link_data));
+ break;
+
+ case RLA_TYPE_TRANSIT:
+ printf(" dr %s if %s",
+ ipaddr_string(&rlp->link_id),
+ ipaddr_string(&rlp->link_data));
+ break;
+
+ case RLA_TYPE_STUB:
+ printf(" net %s mask %s",
+ ipaddr_string(&rlp->link_id),
+ ipaddr_string(&rlp->link_data));
+ break;
+
+ default:
+ printf(" ??RouterLinksType %d?? }", /* { (ctags) */
+ rlp->link_type);
+ return 0;
+ }
+ printf(" tos 0 metric %d",
+ ntohs(rlp->link_tos0metric));
+ tosp = (struct tos_metric *) ((sizeof rlp->link_tos0metric) + (caddr_t) rlp);
+ for (k = 0; k < rlp->link_toscount; k++, tosp++) {
+ printf(" tos %d metric %d",
+ ntohs(tosp->tos_type),
+ ntohs(tosp->tos_metric));
+ }
+ printf(" }"); /* { (ctags) */
+ rlp = rln;
+ }
+ break;
+
+ case LS_TYPE_NETWORK:
+ printf(" mask %s rtrs",
+ ipaddr_string(&lsap->lsa_un.un_nla.nla_mask));
+ for (ap = lsap->lsa_un.un_nla.nla_router;
+ (caddr_t) (ap + 1) <= ls_end;
+ ap++) {
+ printf(" %s",
+ ipaddr_string(ap));
+ }
+ break;
+
+ case LS_TYPE_SUM_IP:
+ printf(" mask %s",
+ ipaddr_string(&lsap->lsa_un.un_sla.sla_mask));
+ /* Fall through */
+
+ case LS_TYPE_SUM_ABR:
+
+ for (lp = lsap->lsa_un.un_sla.sla_tosmetric;
+ (caddr_t) (lp + 1) <= ls_end;
+ lp++) {
+ u_int32 ul = ntohl(*lp);
+
+ printf(" tos %d metric %d",
+ (ul & SLA_MASK_TOS) >> SLA_SHIFT_TOS,
+ ul & SLA_MASK_METRIC);
+ }
+ break;
+
+ case LS_TYPE_ASE:
+ printf(" mask %s",
+ ipaddr_string(&lsap->lsa_un.un_asla.asla_mask));
+
+ for (almp = lsap->lsa_un.un_asla.asla_metric;
+ (caddr_t) (almp + 1) <= ls_end;
+ almp++) {
+ u_int32 ul = ntohl(almp->asla_tosmetric);
+
+ printf(" type %d tos %d metric %d",
+ (ul & ASLA_FLAG_EXTERNAL) ? 2 : 1,
+ (ul & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS,
+ (ul & ASLA_MASK_METRIC));
+ if (almp->asla_forward.s_addr) {
+ printf(" forward %s",
+ ipaddr_string(&almp->asla_forward));
+ }
+ if (almp->asla_tag.s_addr) {
+ printf(" tag %s",
+ ipaddr_string(&almp->asla_tag));
+ }
+ }
+ break;
+
+ case LS_TYPE_GROUP:
+ /* Multicast extensions as of 23 July 1991 */
+ for (mcp = lsap->lsa_un.un_mcla;
+ (caddr_t) (mcp + 1) <= ls_end;
+ mcp++) {
+ switch (ntohl(mcp->mcla_vtype)) {
+ case MCLA_VERTEX_ROUTER:
+ printf(" rtr rtrid %s",
+ ipaddr_string(&mcp->mcla_vid));
+ break;
+
+ case MCLA_VERTEX_NETWORK:
+ printf(" net dr %s",
+ ipaddr_string(&mcp->mcla_vid));
+ break;
+
+ default:
+ printf(" ??VertexType %d??",
+ ntohl(mcp->mcla_vtype));
+ break;
+ }
+ }
+ }
+
+ printf(" }"); /* { (ctags) */
+ return 0;
+}
+
+
+void
+ospf_print(register const u_char *bp, register int length,
+ register const u_char *bp2)
+{
+ register const struct ospfhdr *op;
+ register const struct ip *ip;
+ register const caddr_t end = (caddr_t)snapend;
+ register const struct lsa *lsap;
+ register const struct lsa_hdr *lshp;
+ char sep;
+ int i, j;
+ const struct in_addr *ap;
+ const struct lsr *lsrp;
+
+ op = (struct ospfhdr *)bp;
+ ip = (struct ip *)bp2;
+ /* Print the source and destination address */
+ (void) printf("%s > %s:",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+
+ if ((caddr_t) (&op->ospf_len + 1) > end) {
+ goto trunc_test;
+ }
+
+ /* If the type is valid translate it, or just print the type */
+ /* value. If it's not valid, say so and return */
+ if (op->ospf_type || op->ospf_type < OSPF_TYPE_MAX) {
+ printf(" OSPFv%d-%s %d:",
+ op->ospf_version,
+ ospf_types[op->ospf_type],
+ length);
+ } else {
+ printf(" ospf-v%d-??type %d?? %d:",
+ op->ospf_version,
+ op->ospf_type,
+ length);
+ return;
+ }
+
+ if (length != ntohs(op->ospf_len)) {
+ printf(" ??len %d??",
+ ntohs(op->ospf_len));
+ goto trunc_test;
+ }
+
+ if ((caddr_t) (&op->ospf_routerid + 1) > end) {
+ goto trunc_test;
+ }
+
+ /* Print the routerid if it is not the same as the source */
+ if (ip->ip_src.s_addr != op->ospf_routerid.s_addr) {
+ printf(" rtrid %s",
+ ipaddr_string(&op->ospf_routerid));
+ }
+
+ if ((caddr_t) (&op->ospf_areaid + 1) > end) {
+ goto trunc_test;
+ }
+
+ if (op->ospf_areaid.s_addr) {
+ printf(" area %s",
+ ipaddr_string(&op->ospf_areaid));
+ } else {
+ printf(" backbone");
+ }
+
+ if ((caddr_t) (op->ospf_authdata + OSPF_AUTH_SIZE) > end) {
+ goto trunc_test;
+ }
+
+ if (vflag) {
+ /* Print authentication data (should we really do this?) */
+ switch (ntohs(op->ospf_authtype)) {
+ case OSPF_AUTH_NONE:
+ break;
+
+ case OSPF_AUTH_SIMPLE:
+ printf(" auth ");
+ j = 0;
+ for (i = 0; i < sizeof (op->ospf_authdata); i++) {
+ if (!isprint(op->ospf_authdata[i])) {
+ j = 1;
+ break;
+ }
+ }
+ if (j) {
+ /* Print the auth-data as a string of octets */
+ printf("%s.%s",
+ ipaddr_string((struct in_addr *) op->ospf_authdata),
+ ipaddr_string((struct in_addr *) &op->ospf_authdata[sizeof (struct in_addr)]));
+ } else {
+ /* Print the auth-data as a text string */
+ printf("'%.8s'",
+ op->ospf_authdata);
+ }
+ break;
+
+ default:
+ printf(" ??authtype-%d??",
+ ntohs(op->ospf_authtype));
+ return;
+ }
+ }
+
+
+ /* Do rest according to version. */
+ switch (op->ospf_version) {
+ case 2:
+ /* ospf version 2 */
+ switch (op->ospf_type) {
+ case OSPF_TYPE_UMD: /* Rob Coltun's special monitoring packets; do nothing */
+ break;
+
+ case OSPF_TYPE_HELLO:
+ if ((caddr_t) (&op->ospf_hello.hello_deadint + 1) > end) {
+ break;
+ }
+ if (vflag) {
+ ospf_print_bits(ospf_option_bits, op->ospf_hello.hello_options);
+ printf(" mask %s int %d pri %d dead %d",
+ ipaddr_string(&op->ospf_hello.hello_mask),
+ ntohs(op->ospf_hello.hello_helloint),
+ op->ospf_hello.hello_priority,
+ ntohl(op->ospf_hello.hello_deadint));
+ }
+
+ if ((caddr_t) (&op->ospf_hello.hello_dr + 1) > end) {
+ break;
+ }
+ if (op->ospf_hello.hello_dr.s_addr) {
+ printf(" dr %s",
+ ipaddr_string(&op->ospf_hello.hello_dr));
+ }
+
+ if ((caddr_t) (&op->ospf_hello.hello_bdr + 1) > end) {
+ break;
+ }
+ if (op->ospf_hello.hello_bdr.s_addr) {
+ printf(" bdr %s",
+ ipaddr_string(&op->ospf_hello.hello_bdr));
+ }
+
+ if (vflag) {
+ if ((caddr_t) (op->ospf_hello.hello_neighbor + 1) > end) {
+ break;
+ }
+ printf(" nbrs");
+ for (ap = op->ospf_hello.hello_neighbor;
+ (caddr_t) (ap + 1) <= end;
+ ap++) {
+ printf(" %s",
+ ipaddr_string(ap));
+ }
+ }
+ break; /* HELLO */
+
+ case OSPF_TYPE_DB:
+ if ((caddr_t) (&op->ospf_db.db_seq + 1) > end) {
+ break;
+ }
+ ospf_print_bits(ospf_option_bits, op->ospf_db.db_options);
+ sep = ' ';
+ if (op->ospf_db.db_flags & OSPF_DB_INIT) {
+ printf("%cI",
+ sep);
+ sep = '/';
+ }
+ if (op->ospf_db.db_flags & OSPF_DB_MORE) {
+ printf("%cM",
+ sep);
+ sep = '/';
+ }
+ if (op->ospf_db.db_flags & OSPF_DB_MASTER) {
+ printf("%cMS",
+ sep);
+ sep = '/';
+ }
+ printf(" S %X",
+ ntohl(op->ospf_db.db_seq));
+
+ if (vflag) {
+ /* Print all the LS adv's */
+ lshp = op->ospf_db.db_lshdr;
+
+ while (!ospf_print_lshdr(lshp, end)) {
+ printf(" }"); /* { (ctags) */
+ lshp++;
+ }
+ }
+ break;
+
+ case OSPF_TYPE_LSR:
+ if (vflag) {
+ for (lsrp = op->ospf_lsr; (caddr_t) (lsrp+1) <= end; lsrp++) {
+ int32 type;
+
+ if ((caddr_t) (lsrp + 1) > end) {
+ break;
+ }
+
+ printf(" {"); /* } (ctags) */
+ if (!(type = lsrp->ls_type) || type >= LS_TYPE_MAX) {
+ printf(" ??LinkStateType %d }", /* { (ctags) */
+ type);
+ printf(" }"); /* { (ctags) */
+ break;
+ }
+
+ LS_PRINT(lsrp, type);
+ printf(" }"); /* { (ctags) */
+ }
+ }
+ break;
+
+ case OSPF_TYPE_LSU:
+ if (vflag) {
+ lsap = op->ospf_lsu.lsu_lsa;
+ i = ntohl(op->ospf_lsu.lsu_count);
+
+ while (i-- &&
+ !ospf_print_lsa(lsap, end)) {
+ lsap = (struct lsa *) ((caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length));
+ }
+ }
+ break;
+
+
+ case OSPF_TYPE_LSA:
+ if (vflag) {
+ lshp = op->ospf_lsa.lsa_lshdr;
+
+ while (!ospf_print_lshdr(lshp, end)) {
+ printf(" }"); /* { (ctags) */
+ lshp++;
+ }
+ break;
+ }
+ } /* end switch on v2 packet type */
+ break;
+
+ default:
+ printf(" ospf [version %d]",
+ op->ospf_version);
+ break;
+ } /* end switch on version */
+
+ trunc_test:
+ if ((snapend - bp) < length) {
+ printf(" [|]");
+ }
+
+ return; /* from ospf_print */
+}
diff --git a/usr.sbin/tcpdump/print-ppp.c b/usr.sbin/tcpdump/print-ppp.c
new file mode 100644
index 00000000000..966e9f58782
--- /dev/null
+++ b/usr.sbin/tcpdump/print-ppp.c
@@ -0,0 +1,104 @@
+/* $NetBSD: print-ppp.c,v 1.3 1995/03/06 19:11:27 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-ppp.c,v 1.18 94/06/10 17:01:37 mccanne Exp (LBL)";
+#endif
+
+#ifdef PPP
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/* XXX This goes somewhere else. */
+#define PPP_HDRLEN 4
+
+void
+ppp_if_print(u_char *user, const struct pcap_pkthdr *h,
+ register const u_char *p)
+{
+ register int length = h->len;
+ register int caplen = h->caplen;
+ const struct ip *ip;
+
+ ts_print(&h->ts);
+
+ if (caplen < PPP_HDRLEN) {
+ printf("[|ppp]");
+ goto out;
+ }
+
+ /*
+ * Some printers want to get back at the link level addresses,
+ * and/or check that they're not walking off the end of the packet.
+ * Rather than pass them all the way down, we set these globals.
+ */
+ packetp = p;
+ snapend = p + caplen;
+
+ if (eflag)
+ printf("%c %4d %02x %04x: ", p[0] ? 'O' : 'I', length,
+ p[1], ntohs(*(u_short *)&p[2]));
+
+ length -= PPP_HDRLEN;
+ ip = (struct ip *)(p + PPP_HDRLEN);
+ ip_print((const u_char *)ip, length);
+
+ if (xflag)
+ default_print((const u_char *)ip, caplen - PPP_HDRLEN);
+out:
+ putchar('\n');
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+void
+ppp_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ error("not configured for ppp");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/print-rip.c b/usr.sbin/tcpdump/print-rip.c
new file mode 100644
index 00000000000..1be9c9dae12
--- /dev/null
+++ b/usr.sbin/tcpdump/print-rip.c
@@ -0,0 +1,117 @@
+/* $NetBSD: print-rip.c,v 1.4 1995/06/20 23:38:49 christos Exp $ */
+
+/*
+ * Copyright (c) 1989, 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-rip.c,v 1.20 94/06/14 20:18:47 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <protocols/routed.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static void
+rip_entry_print(register const struct netinfo *ni)
+{
+ if (ntohs(ni->rip_family) != AF_INET) {
+ register int i;
+
+ printf(" [family %d:", ntohs(ni->rip_family));
+ printf(" %04x", ni->rip_dst);
+ printf("]");
+ } else {
+ struct sockaddr_in sin;
+ sin.sin_addr.s_addr = ni->rip_dst;
+ printf(" %s", ipaddr_string(&sin.sin_addr));
+ if (ni->rip_tag)
+ printf(" [port %d]", ni->rip_tag);
+ }
+ printf("(%d)", ntohl(ni->rip_metric));
+}
+
+void
+rip_print(const u_char *dat, int length)
+{
+ register const struct rip *rp = (struct rip *)dat;
+ register const struct netinfo *ni;
+ register int amt = snapend - dat;
+ register int i = min(length, amt) -
+ (sizeof(struct rip) - sizeof(struct netinfo));
+ int j;
+ int trunc;
+
+ if (i < 0)
+ return;
+
+ switch (rp->rip_cmd) {
+
+ case RIPCMD_REQUEST:
+ printf(" rip-req %d", length);
+ break;
+ case RIPCMD_RESPONSE:
+ j = length / sizeof(*ni);
+ if (j * sizeof(*ni) != length - 4)
+ printf(" rip-resp %d[%d]:", j, length);
+ else
+ printf(" rip-resp %d:", j);
+ trunc = ((i / sizeof(*ni)) * sizeof(*ni) != i);
+ for (ni = rp->rip_nets; (i -= sizeof(*ni)) >= 0; ++ni)
+ rip_entry_print(ni);
+ if (trunc)
+ printf("[|rip]");
+ break;
+ case RIPCMD_TRACEON:
+ printf(" rip-traceon %d: \"%s\"", length, rp->rip_tracefile);
+ break;
+ case RIPCMD_TRACEOFF:
+ printf(" rip-traceoff %d", length);
+ break;
+ case RIPCMD_POLL:
+ printf(" rip-poll %d", length);
+ break;
+ case RIPCMD_POLLENTRY:
+ printf(" rip-pollentry %d", length);
+ break;
+ default:
+ printf(" rip-%d ?? %d", rp->rip_cmd, length);
+ break;
+ }
+ if (rp->rip_vers != RIP_VERSION_1)
+ printf(" [vers %d]", rp->rip_vers);
+}
diff --git a/usr.sbin/tcpdump/print-sl.c b/usr.sbin/tcpdump/print-sl.c
new file mode 100644
index 00000000000..582e9037021
--- /dev/null
+++ b/usr.sbin/tcpdump/print-sl.c
@@ -0,0 +1,245 @@
+/* $NetBSD: print-sl.c,v 1.5 1995/03/06 19:11:29 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1989, 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#)Header: print-sl.c,v 1.28 94/06/10 17:01:38 mccanne Exp (LBL)";
+#endif
+
+#ifdef CSLIP
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <net/slcompress.h>
+#include <net/slip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static int lastlen[2][256];
+static int lastconn = 255;
+
+static void sliplink_print(const u_char *, const struct ip *, int);
+static void compressed_sl_print(const u_char *, const struct ip *, int, int);
+
+void
+sl_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ register int caplen = h->caplen;
+ register int length = h->len;
+ register const struct ip *ip;
+
+ ts_print(&h->ts);
+
+ if (caplen < SLIP_HDRLEN) {
+ printf("[|slip]");
+ goto out;
+ }
+ /*
+ * Some printers want to get back at the link level addresses,
+ * and/or check that they're not walking off the end of the packet.
+ * Rather than pass them all the way down, we set these globals.
+ */
+ packetp = p;
+ snapend = p + caplen;
+
+ length -= SLIP_HDRLEN;
+
+ ip = (struct ip *)(p + SLIP_HDRLEN);
+
+ if (eflag)
+ sliplink_print(p, ip, length);
+
+ ip_print((u_char *)ip, length);
+
+ if (xflag)
+ default_print((u_char *)ip, caplen - SLIP_HDRLEN);
+ out:
+ putchar('\n');
+}
+
+static void
+sliplink_print(register const u_char *p, register const struct ip *ip,
+ register int length)
+{
+ int dir;
+ int hlen;
+
+ dir = p[SLX_DIR];
+ putchar(dir == SLIPDIR_IN ? 'I' : 'O');
+ putchar(' ');
+
+ if (nflag) {
+ /* XXX just dump the header */
+ int i;
+
+ for (i = 0; i < 15; ++i)
+ printf("%02x.", p[SLX_CHDR + i]);
+ printf("%02x: ", p[SLX_CHDR + 15]);
+ return;
+ }
+ switch (p[SLX_CHDR] & 0xf0) {
+
+ case TYPE_IP:
+ printf("ip %d: ", length + SLIP_HDRLEN);
+ break;
+
+ case TYPE_UNCOMPRESSED_TCP:
+ /*
+ * The connection id is stode in the IP protcol field.
+ */
+ lastconn = ip->ip_p;
+ hlen = ip->ip_hl;
+ hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
+ lastlen[dir][lastconn] = length - (hlen << 2);
+ printf("utcp %d: ", lastconn);
+ break;
+
+ default:
+ if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
+ compressed_sl_print(&p[SLX_CHDR], ip,
+ length, dir);
+ printf(": ");
+ } else
+ printf("slip-%d!: ", p[SLX_CHDR]);
+ }
+}
+
+static const u_char *
+print_sl_change(const char *str, register const u_char *cp)
+{
+ register u_int i;
+
+ if ((i = *cp++) == 0) {
+ i = (cp[0] << 8) | cp[1];
+ cp += 2;
+ }
+ printf(" %s%d", str, i);
+ return (cp);
+}
+
+static const u_char *
+print_sl_winchange(register const u_char *cp)
+{
+ register short i;
+
+ if ((i = *cp++) == 0) {
+ i = (cp[0] << 8) | cp[1];
+ cp += 2;
+ }
+ if (i >= 0)
+ printf(" W+%d", i);
+ else
+ printf(" W%d", i);
+ return (cp);
+}
+
+static void
+compressed_sl_print(const u_char *chdr, const struct ip *ip,
+ int length, int dir)
+{
+ register const u_char *cp = chdr;
+ register u_int flags;
+ int hlen;
+
+ flags = *cp++;
+ if (flags & NEW_C) {
+ lastconn = *cp++;
+ printf("ctcp %d", lastconn);
+ } else
+ printf("ctcp *");
+
+ /* skip tcp checksum */
+ cp += 2;
+
+ switch (flags & SPECIALS_MASK) {
+ case SPECIAL_I:
+ printf(" *SA+%d", lastlen[dir][lastconn]);
+ break;
+
+ case SPECIAL_D:
+ printf(" *S+%d", lastlen[dir][lastconn]);
+ break;
+
+ default:
+ if (flags & NEW_U)
+ cp = print_sl_change("U=", cp);
+ if (flags & NEW_W)
+ cp = print_sl_winchange(cp);
+ if (flags & NEW_A)
+ cp = print_sl_change("A+", cp);
+ if (flags & NEW_S)
+ cp = print_sl_change("S+", cp);
+ break;
+ }
+ if (flags & NEW_I)
+ cp = print_sl_change("I+", cp);
+
+ /*
+ * 'hlen' is the length of the uncompressed TCP/IP header (in words).
+ * 'cp - chdr' is the length of the compressed header.
+ * 'length - hlen' is the amount of data in the packet.
+ */
+ hlen = ip->ip_hl;
+ hlen += ((struct tcphdr *)&((int32 *)ip)[hlen])->th_off;
+ lastlen[dir][lastconn] = length - (hlen << 2);
+ printf(" %d (%d)", lastlen[dir][lastconn], cp - chdr);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+void
+sl_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+
+ error("not configured for slip");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/print-snmp.c b/usr.sbin/tcpdump/print-snmp.c
new file mode 100644
index 00000000000..87bda376ab3
--- /dev/null
+++ b/usr.sbin/tcpdump/print-snmp.c
@@ -0,0 +1,1034 @@
+/* $NetBSD: print-snmp.c,v 1.3 1995/03/06 19:11:30 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * John Robert LoVerso. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by John Robert LoVerso.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This implementation has been influenced by the CMU SNMP release,
+ * by Steve Waldbusser. However, this shares no code with that system.
+ * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
+ * Earlier forms of this implementation were derived and/or inspired by an
+ * awk script originally written by C. Philip Wood of LANL (but later
+ * heavily modified by John Robert LoVerso). The copyright notice for
+ * that work is preserved below, even though it may not rightly apply
+ * to this file.
+ *
+ * This started out as a very simple program, but the incremental decoding
+ * (into the BE structure) complicated things.
+ *
+ # Los Alamos National Laboratory
+ #
+ # Copyright, 1990. The Regents of the University of California.
+ # This software was produced under a U.S. Government contract
+ # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
+ # operated by the University of California for the U.S. Department
+ # of Energy. The U.S. Government is licensed to use, reproduce,
+ # and distribute this software. Permission is granted to the
+ # public to copy and use this software without charge, provided
+ # that this Notice and any statement of authorship are reproduced
+ # on all copies. Neither the Government nor the University makes
+ # any warranty, express or implied, or assumes any liability or
+ # responsibility for the use of this software.
+ # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso (jlv)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/*
+ * Universal ASN.1 types
+ * (we only care about the tag values for those allowed in the Internet SMI)
+ */
+char *Universal[] = {
+ "U-0",
+ "Boolean",
+ "Integer",
+#define INTEGER 2
+ "Bitstring",
+ "String",
+#define STRING 4
+ "Null",
+#define ASN_NULL 5
+ "ObjID",
+#define OBJECTID 6
+ "ObjectDes",
+ "U-8","U-9","U-10","U-11", /* 8-11 */
+ "U-12","U-13","U-14","U-15", /* 12-15 */
+ "Sequence",
+#define SEQUENCE 16
+ "Set"
+};
+
+/*
+ * Application-wide ASN.1 types from the Internet SMI and their tags
+ */
+char *Application[] = {
+ "IpAddress",
+#define IPADDR 0
+ "Counter",
+#define COUNTER 1
+ "Gauge",
+#define GAUGE 2
+ "TimeTicks",
+#define TIMETICKS 3
+ "Opaque"
+};
+
+/*
+ * Context-specific ASN.1 types for the SNMP PDUs and their tags
+ */
+char *Context[] = {
+ "GetRequest",
+#define GETREQ 0
+ "GetNextRequest",
+#define GETNEXTREQ 1
+ "GetResponse",
+#define GETRESP 2
+ "SetRequest",
+#define SETREQ 3
+ "Trap"
+#define TRAP 4
+};
+
+/*
+ * Private ASN.1 types
+ * The Internet SMI does not specify any
+ */
+char *Private[] = {
+ "P-0"
+};
+
+/*
+ * error-status values for any SNMP PDU
+ */
+char *ErrorStatus[] = {
+ "noError",
+ "tooBig",
+ "noSuchName",
+ "badValue",
+ "readOnly",
+ "genErr"
+};
+#define DECODE_ErrorStatus(e) \
+ ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
+ ? ErrorStatus[e] : (sprintf(errbuf, "err=%d", e), errbuf))
+
+/*
+ * generic-trap values in the SNMP Trap-PDU
+ */
+char *GenericTrap[] = {
+ "coldStart",
+ "warmStart",
+ "linkDown",
+ "linkUp",
+ "authenticationFailure",
+ "egpNeighborLoss",
+ "enterpriseSpecific"
+#define GT_ENTERPRISE 7
+};
+#define DECODE_GenericTrap(t) \
+ ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
+ ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
+
+/*
+ * ASN.1 type class table
+ * Ties together the preceding Universal, Application, Context, and Private
+ * type definitions.
+ */
+#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
+struct {
+ char *name;
+ char **Id;
+ int numIDs;
+} Class[] = {
+ defineCLASS(Universal),
+#define UNIVERSAL 0
+ defineCLASS(Application),
+#define APPLICATION 1
+ defineCLASS(Context),
+#define CONTEXT 2
+ defineCLASS(Private),
+#define PRIVATE 3
+};
+
+/*
+ * defined forms for ASN.1 types
+ */
+char *Form[] = {
+ "Primitive",
+#define PRIMITIVE 0
+ "Constructed",
+#define CONSTRUCTED 1
+};
+
+/*
+ * A structure for the OID tree for the compiled-in MIB.
+ * This is stored as a general-order tree.
+ */
+struct obj {
+ char *desc; /* name of object */
+ u_char oid; /* sub-id following parent */
+ u_char type; /* object type (unused) */
+ struct obj *child, *next; /* child and next sibling pointers */
+} *objp = NULL;
+
+/*
+ * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
+ * RFC-1156 format files into "makemib". "mib.h" MUST define at least
+ * a value for `mibroot'.
+ *
+ * In particular, this is gross, as this is including initialized structures,
+ * and by right shouldn't be an "include" file.
+ */
+#include "mib.h"
+
+/*
+ * This defines a list of OIDs which will be abbreviated on output.
+ * Currently, this includes the prefixes for the Internet MIB, the
+ * private enterprises tree, and the experimental tree.
+ */
+struct obj_abrev {
+ char *prefix; /* prefix for this abrev */
+ struct obj *node; /* pointer into object table */
+ char *oid; /* ASN.1 encoded OID */
+} obj_abrev_list[] = {
+#ifndef NO_ABREV_MIB
+ /* .iso.org.dod.internet.mgmt.mib */
+ { "", &_mib_obj, "\53\6\1\2\1" },
+#endif
+#ifndef NO_ABREV_ENTER
+ /* .iso.org.dod.internet.private.enterprises */
+ { "E:", &_enterprises_obj, "\53\6\1\4\1" },
+#endif
+#ifndef NO_ABREV_EXPERI
+ /* .iso.org.dod.internet.experimental */
+ { "X:", &_experimental_obj, "\53\6\1\3" },
+#endif
+ { 0,0,0 }
+};
+
+/*
+ * This is used in the OID print routine to walk down the object tree
+ * rooted at `mibroot'.
+ */
+#define OBJ_PRINT(o, suppressdot) \
+{ \
+ if (objp) { \
+ do { \
+ if ((o) == objp->oid) \
+ break; \
+ } while ((objp = objp->next) != NULL); \
+ } \
+ if (objp) { \
+ printf(suppressdot?"%s":".%s", objp->desc); \
+ objp = objp->child; \
+ } else \
+ printf(suppressdot?"%u":".%u", (o)); \
+}
+
+/*
+ * This is the definition for the Any-Data-Type storage used purely for
+ * temporary internal representation while decoding an ASN.1 data stream.
+ */
+struct be {
+ u_long asnlen;
+ union {
+ caddr_t raw;
+ long integer;
+ u_long uns;
+ const u_char *str;
+ } data;
+ u_char form, class, id; /* tag info */
+ u_char type;
+#define BE_ANY 255
+#define BE_NONE 0
+#define BE_NULL 1
+#define BE_OCTET 2
+#define BE_OID 3
+#define BE_INT 4
+#define BE_UNS 5
+#define BE_STR 6
+#define BE_SEQ 7
+#define BE_INETADDR 8
+#define BE_PDU 9
+};
+
+/*
+ * Defaults for SNMP PDU components
+ */
+#define DEF_COMMUNITY "public"
+#define DEF_VERSION 0
+
+/*
+ * constants for ASN.1 decoding
+ */
+#define OIDMUX 40
+#define ASNLEN_INETADDR 4
+#define ASN_SHIFT7 7
+#define ASN_SHIFT8 8
+#define ASN_BIT8 0x80
+#define ASN_LONGLEN 0x80
+
+#define ASN_ID_BITS 0x1f
+#define ASN_FORM_BITS 0x20
+#define ASN_FORM_SHIFT 5
+#define ASN_CLASS_BITS 0xc0
+#define ASN_CLASS_SHIFT 6
+
+#define ASN_ID_EXT 0x1f /* extension ID in tag field */
+
+/*
+ * truncated==1 means the packet was complete, but we don't have all of
+ * it to decode.
+ */
+static int truncated;
+#define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
+
+/*
+ * This decodes the next ASN.1 object in the stream pointed to by "p"
+ * (and of real-length "len") and stores the intermediate data in the
+ * provided BE object.
+ *
+ * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
+ * O/w, this returns the number of bytes parsed from "p".
+ */
+static int
+asn1_parse(register const u_char *p, int len, struct be *elem)
+{
+ u_char form, class, id;
+ int i, hdr;
+
+ elem->asnlen = 0;
+ elem->type = BE_ANY;
+ if (len < 1) {
+ ifNotTruncated puts("[nothing to parse], stdout");
+ return -1;
+ }
+
+ /*
+ * it would be nice to use a bit field, but you can't depend on them.
+ * +---+---+---+---+---+---+---+---+
+ * + class |frm| id |
+ * +---+---+---+---+---+---+---+---+
+ * 7 6 5 4 3 2 1 0
+ */
+ id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
+#ifdef notdef
+ form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
+ class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
+ form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
+#else
+ form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
+ class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
+#endif
+ elem->form = form;
+ elem->class = class;
+ elem->id = id;
+ if (vflag)
+ printf("|%.2x", *p);
+ p++; len--; hdr = 1;
+ /* extended tag field */
+ if (id == ASN_ID_EXT) {
+ for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
+ if (vflag)
+ printf("|%.2x", *p);
+ id += *p & ~ASN_BIT8;
+ }
+ if (len == 0 && *p & ASN_BIT8) {
+ ifNotTruncated fputs("[Xtagfield?]", stdout);
+ return -1;
+ }
+ }
+ if (len < 1) {
+ ifNotTruncated fputs("[no asnlen]", stdout);
+ return -1;
+ }
+ elem->asnlen = *p;
+ if (vflag)
+ printf("|%.2x", *p);
+ p++; len--; hdr++;
+ if (elem->asnlen & ASN_BIT8) {
+ int noct = elem->asnlen % ASN_BIT8;
+ elem->asnlen = 0;
+ if (len < noct) {
+ ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
+ return -1;
+ }
+ for (; noct-- > 0; len--, hdr++) {
+ if (vflag)
+ printf("|%.2x", *p);
+ elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
+ }
+ }
+ if (len < elem->asnlen) {
+ if (!truncated) {
+ printf("[len%d<asnlen%u]", len, elem->asnlen);
+ return -1;
+ }
+ /* maybe should check at least 4? */
+ elem->asnlen = len;
+ }
+ if (form >= sizeof(Form)/sizeof(Form[0])) {
+ ifNotTruncated printf("[form?%d]", form);
+ return -1;
+ }
+ if (class >= sizeof(Class)/sizeof(Class[0])) {
+ ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
+ return -1;
+ }
+ if (id >= Class[class].numIDs) {
+ ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
+ Class[class].name, id);
+ return -1;
+ }
+
+ switch (form) {
+ case PRIMITIVE:
+ switch (class) {
+ case UNIVERSAL:
+ switch (id) {
+ case STRING:
+ elem->type = BE_STR;
+ elem->data.str = p;
+ break;
+
+ case INTEGER: {
+ register long data;
+ elem->type = BE_INT;
+ data = 0;
+
+ if (*p & ASN_BIT8) /* negative */
+ data = -1;
+ for (i = elem->asnlen; i-- > 0; p++)
+ data = (data << ASN_SHIFT8) | *p;
+ elem->data.integer = data;
+ break;
+ }
+
+ case OBJECTID:
+ elem->type = BE_OID;
+ elem->data.raw = (caddr_t)p;
+ break;
+
+ case ASN_NULL:
+ elem->type = BE_NULL;
+ elem->data.raw = NULL;
+ break;
+
+ default:
+ elem->type = BE_OCTET;
+ elem->data.raw = (caddr_t)p;
+ printf("[P/U/%s]",
+ Class[class].Id[id]);
+ break;
+ }
+ break;
+
+ case APPLICATION:
+ switch (id) {
+ case IPADDR:
+ elem->type = BE_INETADDR;
+ elem->data.raw = (caddr_t)p;
+ break;
+
+ case COUNTER:
+ case GAUGE:
+ case TIMETICKS: {
+ register u_long data;
+ elem->type = BE_UNS;
+ data = 0;
+ for (i = elem->asnlen; i-- > 0; p++)
+ data = (data << 8) + *p;
+ elem->data.uns = data;
+ break;
+ }
+
+ default:
+ elem->type = BE_OCTET;
+ elem->data.raw = (caddr_t)p;
+ printf("[P/A/%s]",
+ Class[class].Id[id]);
+ break;
+ }
+ break;
+
+ default:
+ elem->type = BE_OCTET;
+ elem->data.raw = (caddr_t)p;
+ printf("[P/%s/%s]",
+ Class[class].name, Class[class].Id[id]);
+ break;
+ }
+ break;
+
+ case CONSTRUCTED:
+ switch (class) {
+ case UNIVERSAL:
+ switch (id) {
+ case SEQUENCE:
+ elem->type = BE_SEQ;
+ elem->data.raw = (caddr_t)p;
+ break;
+
+ default:
+ elem->type = BE_OCTET;
+ elem->data.raw = (caddr_t)p;
+ printf("C/U/%s", Class[class].Id[id]);
+ break;
+ }
+ break;
+
+ case CONTEXT:
+ elem->type = BE_PDU;
+ elem->data.raw = (caddr_t)p;
+ break;
+
+ default:
+ elem->type = BE_OCTET;
+ elem->data.raw = (caddr_t)p;
+ printf("C/%s/%s",
+ Class[class].name, Class[class].Id[id]);
+ break;
+ }
+ break;
+ }
+ p += elem->asnlen;
+ len -= elem->asnlen;
+ return elem->asnlen + hdr;
+}
+
+/*
+ * Display the ASN.1 object represented by the BE object.
+ * This used to be an integral part of asn1_parse() before the intermediate
+ * BE form was added.
+ */
+static void
+asn1_print(struct be *elem)
+{
+ u_char *p = (u_char *)elem->data.raw;
+ u_long asnlen = elem->asnlen;
+ int i;
+
+ switch (elem->type) {
+
+ case BE_OCTET:
+ for (i = asnlen; i-- > 0; p++);
+ printf("_%.2x", *p);
+ break;
+
+ case BE_NULL:
+ break;
+
+ case BE_OID: {
+ int o = 0, first = -1, i = asnlen;
+
+ if (!nflag && asnlen > 2) {
+ struct obj_abrev *a = &obj_abrev_list[0];
+ for (; a->node; a++) {
+ if (!bcmp(a->oid, (char *)p, strlen(a->oid))) {
+ objp = a->node->child;
+ i -= strlen(a->oid);
+ p += strlen(a->oid);
+ fputs(a->prefix, stdout);
+ first = 1;
+ break;
+ }
+ }
+ }
+ for (; i-- > 0; p++) {
+ o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
+ if (*p & ASN_LONGLEN)
+ continue;
+
+ /*
+ * first subitem encodes two items with 1st*OIDMUX+2nd
+ */
+ if (first < 0) {
+ if (!nflag)
+ objp = mibroot;
+ first = 0;
+ OBJ_PRINT(o/OIDMUX, first);
+ o %= OIDMUX;
+ }
+ OBJ_PRINT(o, first);
+ if (--first < 0)
+ first = 0;
+ o = 0;
+ }
+ break;
+ }
+
+ case BE_INT:
+ printf("%ld", elem->data.integer);
+ break;
+
+ case BE_UNS:
+ printf("%ld", elem->data.uns);
+ break;
+
+ case BE_STR: {
+ register int printable = 1, first = 1;
+ const u_char *p = elem->data.str;
+ for (i = asnlen; printable && i-- > 0; p++)
+ printable = isprint(*p) || isspace(*p);
+ p = elem->data.str;
+ if (printable)
+ (void)fn_print(p, p + asnlen);
+ else
+ for (i = asnlen; i-- > 0; p++) {
+ printf(first ? "%.2x" : "_%.2x", *p);
+ first = 0;
+ }
+ break;
+ }
+
+ case BE_SEQ:
+ printf("Seq(%d)", elem->asnlen);
+ break;
+
+ case BE_INETADDR: {
+ char sep;
+ if (asnlen != ASNLEN_INETADDR)
+ printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
+ sep='[';
+ for (i = asnlen; i-- > 0; p++) {
+ printf("%c%u", sep, *p);
+ sep='.';
+ }
+ putchar(']');
+ break;
+ }
+
+ case BE_PDU:
+ printf("%s(%d)",
+ Class[CONTEXT].Id[elem->id], elem->asnlen);
+ break;
+
+ case BE_ANY:
+ fputs("[BE_ANY!?]", stdout);
+ break;
+
+ default:
+ fputs("[be!?]", stdout);
+ break;
+ }
+}
+
+#ifdef notdef
+/*
+ * This is a brute force ASN.1 printer: recurses to dump an entire structure.
+ * This will work for any ASN.1 stream, not just an SNMP PDU.
+ *
+ * By adding newlines and spaces at the correct places, this would print in
+ * Rose-Normal-Form.
+ *
+ * This is not currently used.
+ */
+static void
+asn1_decode(u_char *p, int length)
+{
+ struct be elem;
+ int i = 0;
+
+ while (i >= 0 && length > 0) {
+ i = asn1_parse(p, length, &elem);
+ if (i >= 0) {
+ fputs(" ", stdout);
+ asn1_print(&elem);
+ if (elem.type == BE_SEQ || elem.type == BE_PDU) {
+ fputs(" {", stdout);
+ asn1_decode(elem.data.raw, elem.asnlen);
+ fputs(" }", stdout);
+ }
+ length -= i;
+ p += i;
+ }
+ }
+}
+#endif
+
+/*
+ * General SNMP header
+ * SEQUENCE {
+ * version INTEGER {version-1(0)},
+ * community OCTET STRING,
+ * data ANY -- PDUs
+ * }
+ * PDUs for all but Trap: (see rfc1157 from page 15 on)
+ * SEQUENCE {
+ * request-id INTEGER,
+ * error-status INTEGER,
+ * error-index INTEGER,
+ * varbindlist SEQUENCE OF
+ * SEQUENCE {
+ * name ObjectName,
+ * value ObjectValue
+ * }
+ * }
+ * PDU for Trap:
+ * SEQUENCE {
+ * enterprise OBJECT IDENTIFIER,
+ * agent-addr NetworkAddress,
+ * generic-trap INTEGER,
+ * specific-trap INTEGER,
+ * time-stamp TimeTicks,
+ * varbindlist SEQUENCE OF
+ * SEQUENCE {
+ * name ObjectName,
+ * value ObjectValue
+ * }
+ * }
+ */
+
+/*
+ * Decode SNMP varBind
+ */
+static void
+varbind_print(u_char pduid, const u_char *np, int length, int error)
+{
+ struct be elem;
+ int count = 0, ind;
+
+ /* Sequence of varBind */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_SEQ) {
+ fputs("[!SEQ of varbind]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ if (count < length)
+ printf("[%d extra after SEQ of varbind]", length - count);
+ /* descend */
+ length = elem.asnlen;
+ np = (u_char *)elem.data.raw;
+
+ for (ind = 1; length > 0; ind++) {
+ const u_char *vbend;
+ int vblength;
+
+ if (!error || ind == error)
+ fputs(" ", stdout);
+
+ /* Sequence */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_SEQ) {
+ fputs("[!varbind]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ vbend = np + count;
+ vblength = length - count;
+ /* descend */
+ length = elem.asnlen;
+ np = (u_char *)elem.data.raw;
+
+ /* objName (OID) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_OID) {
+ fputs("[objName!=OID]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ if (!error || ind == error)
+ asn1_print(&elem);
+ length -= count;
+ np += count;
+
+ if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
+ fputs("=", stdout);
+
+ /* objVal (ANY) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (pduid == GETREQ || pduid == GETNEXTREQ) {
+ if (elem.type != BE_NULL) {
+ fputs("[objVal!=NULL]", stdout);
+ asn1_print(&elem);
+ }
+ } else
+ if (error && ind == error && elem.type != BE_NULL)
+ fputs("[err objVal!=NULL]", stdout);
+ if (!error || ind == error)
+ asn1_print(&elem);
+
+ length = vblength;
+ np = vbend;
+ }
+}
+
+/*
+ * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
+ */
+static void
+snmppdu_print(u_char pduid, const u_char *np, int length)
+{
+ struct be elem;
+ int count = 0, error;
+
+ /* reqId (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[reqId!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ /* ignore the reqId */
+ length -= count;
+ np += count;
+
+ /* errorStatus (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[errorStatus!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ error = 0;
+ if ((pduid == GETREQ || pduid == GETNEXTREQ)
+ && elem.data.integer != 0) {
+ char errbuf[10];
+ printf("[errorStatus(%s)!=0]",
+ DECODE_ErrorStatus(elem.data.integer));
+ } else if (elem.data.integer != 0) {
+ char errbuf[10];
+ printf(" %s", DECODE_ErrorStatus(elem.data.integer));
+ error = elem.data.integer;
+ }
+ length -= count;
+ np += count;
+
+ /* errorIndex (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[errorIndex!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ if ((pduid == GETREQ || pduid == GETNEXTREQ)
+ && elem.data.integer != 0)
+ printf("[errorIndex(%d)!=0]", elem.data.integer);
+ else if (elem.data.integer != 0) {
+ if (!error)
+ printf("[errorIndex(%d) w/o errorStatus]",
+ elem.data.integer);
+ else {
+ printf("@%d", elem.data.integer);
+ error = elem.data.integer;
+ }
+ } else if (error) {
+ fputs("[errorIndex==0]", stdout);
+ error = 0;
+ }
+ length -= count;
+ np += count;
+
+ varbind_print(pduid, np, length, error);
+ return;
+}
+
+/*
+ * Decode SNMP Trap PDU
+ */
+static void
+trap_print(const u_char *np, int length)
+{
+ struct be elem;
+ int count = 0, generic;
+
+ putchar(' ');
+
+ /* enterprise (oid) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_OID) {
+ fputs("[enterprise!=OID]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ asn1_print(&elem);
+ length -= count;
+ np += count;
+
+ putchar(' ');
+
+ /* agent-addr (inetaddr) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INETADDR) {
+ fputs("[agent-addr!=INETADDR]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ asn1_print(&elem);
+ length -= count;
+ np += count;
+
+ /* generic-trap (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[generic-trap!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ generic = elem.data.integer;
+ {
+ char buf[10];
+ printf(" %s", DECODE_GenericTrap(generic));
+ }
+ length -= count;
+ np += count;
+
+ /* specific-trap (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[specific-trap!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ if (generic != GT_ENTERPRISE) {
+ if (elem.data.integer != 0)
+ printf("[specific-trap(%d)!=0]", elem.data.integer);
+ } else
+ printf(" s=%d", elem.data.integer);
+ length -= count;
+ np += count;
+
+ putchar(' ');
+
+ /* time-stamp (TimeTicks) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_UNS) { /* XXX */
+ fputs("[time-stamp!=TIMETICKS]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ asn1_print(&elem);
+ length -= count;
+ np += count;
+
+ varbind_print (TRAP, np, length, 0);
+ return;
+}
+
+/*
+ * Decode SNMP header and pass on to PDU printing routines
+ */
+void
+snmp_print(const u_char *np, int length)
+{
+ struct be elem, pdu;
+ int count = 0;
+
+ truncated = 0;
+
+ /* truncated packet? */
+ if (np + length > snapend) {
+ truncated = 1;
+ length = snapend - np;
+ }
+
+ putchar(' ');
+
+ /* initial Sequence */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_SEQ) {
+ fputs("[!init SEQ]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ if (count < length)
+ printf("[%d extra after iSEQ]", length - count);
+ /* descend */
+ length = elem.asnlen;
+ np = (u_char *)elem.data.raw;
+ /* Version (Integer) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_INT) {
+ fputs("[version!=INT]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ /* only handle version==0 */
+ if (elem.data.integer != DEF_VERSION) {
+ printf("[version(%d)!=0]", elem.data.integer);
+ return;
+ }
+ length -= count;
+ np += count;
+
+ /* Community (String) */
+ if ((count = asn1_parse(np, length, &elem)) < 0)
+ return;
+ if (elem.type != BE_STR) {
+ fputs("[comm!=STR]", stdout);
+ asn1_print(&elem);
+ return;
+ }
+ /* default community */
+ if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
+ sizeof(DEF_COMMUNITY) - 1))
+ /* ! "public" */
+ printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
+ length -= count;
+ np += count;
+
+ /* PDU (Context) */
+ if ((count = asn1_parse(np, length, &pdu)) < 0)
+ return;
+ if (pdu.type != BE_PDU) {
+ fputs("[no PDU]", stdout);
+ return;
+ }
+ if (count < length)
+ printf("[%d extra after PDU]", length - count);
+ asn1_print(&pdu);
+ /* descend into PDU */
+ length = pdu.asnlen;
+ np = (u_char *)pdu.data.raw;
+
+ switch (pdu.id) {
+ case TRAP:
+ trap_print(np, length);
+ break;
+ case GETREQ:
+ case GETNEXTREQ:
+ case GETRESP:
+ case SETREQ:
+ snmppdu_print(pdu.id, np, length);
+ break;
+ }
+ return;
+}
diff --git a/usr.sbin/tcpdump/print-sunrpc.c b/usr.sbin/tcpdump/print-sunrpc.c
new file mode 100644
index 00000000000..d3e23a334c6
--- /dev/null
+++ b/usr.sbin/tcpdump/print-sunrpc.c
@@ -0,0 +1,114 @@
+/* $NetBSD: print-sunrpc.c,v 1.3 1995/03/06 19:11:32 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-sunrpc.c,v 1.12 94/06/14 20:18:48 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#ifdef SOLARIS
+#include <tiuser.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "extract.h" /* must come after interface.h */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+static void bswap(u_int32 *, u_int);
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Byte swap an array of n 32-bit words.
+ * Assume input is word-aligned.
+ * Check that buffer is bounded by "snapend".
+ */
+static void
+bswap(register u_int32 *bp, register u_int n)
+{
+ register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp);
+
+ if (nwords > n)
+ nwords = n;
+ for (; --nwords >= 0; ++bp)
+ *bp = ntohl(*bp);
+}
+#endif
+
+static struct token proc2str[] = {
+ { PMAPPROC_NULL, "null" },
+ { PMAPPROC_SET, "set" },
+ { PMAPPROC_UNSET, "unset" },
+ { PMAPPROC_GETPORT, "getport" },
+ { PMAPPROC_DUMP, "dump" },
+ { PMAPPROC_CALLIT, "call" },
+ { 0, NULL }
+};
+
+void
+sunrpcrequest_print(register const u_char *bp, register int length,
+ register const u_char *bp2)
+{
+ register const struct rpc_msg *rp;
+ register const struct ip *ip;
+
+ rp = (struct rpc_msg *)bp;
+ ip = (struct ip *)bp2;
+
+ if (!nflag)
+ (void)printf("%s.%x > %s.sunrpc: %d",
+ ipaddr_string(&ip->ip_src),
+ ntohl(rp->rm_xid),
+ ipaddr_string(&ip->ip_dst),
+ length);
+ else
+ (void)printf("%s.%x > %s.%x: %d",
+ ipaddr_string(&ip->ip_src),
+ ntohl(rp->rm_xid),
+ ipaddr_string(&ip->ip_dst),
+ PMAPPORT,
+ length);
+ printf(" %s", tok2str(proc2str, " proc #%d",
+ ntohl(rp->rm_call.cb_proc)));
+}
+
diff --git a/usr.sbin/tcpdump/print-tcp.c b/usr.sbin/tcpdump/print-tcp.c
new file mode 100644
index 00000000000..50545d19867
--- /dev/null
+++ b/usr.sbin/tcpdump/print-tcp.c
@@ -0,0 +1,278 @@
+/* $NetBSD: print-tcp.c,v 1.5 1995/03/06 19:11:33 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-tcp.c,v 1.28 94/06/16 01:26:40 mccanne Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#ifndef TCPOPT_WSCALE
+#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */
+#endif
+#ifndef TCPOPT_SACKOK
+#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */
+#endif
+#ifndef TCPOPT_SACK
+#define TCPOPT_SACK 5 /* selective ack (rfc1072) */
+#endif
+#ifndef TCPOPT_ECHO
+#define TCPOPT_ECHO 6 /* echo (rfc1072) */
+#endif
+#ifndef TCPOPT_ECHOREPLY
+#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */
+#endif
+#ifndef TCPOPT_TIMESTAMP
+#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */
+#endif
+
+struct tha {
+ struct in_addr src;
+ struct in_addr dst;
+ u_int port;
+};
+
+struct tcp_seq_hash {
+ struct tcp_seq_hash *nxt;
+ struct tha addr;
+ tcp_seq seq;
+ tcp_seq ack;
+};
+
+#define TSEQ_HASHSIZE 919
+
+static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
+
+
+void
+tcp_print(register const u_char *bp, register int length,
+ register const u_char *bp2)
+{
+ register const struct tcphdr *tp;
+ register const struct ip *ip;
+ register u_char flags;
+ register int hlen;
+ u_short sport, dport, win, urp;
+ tcp_seq seq, ack;
+
+ tp = (struct tcphdr *)bp;
+ ip = (struct ip *)bp2;
+ if ((const u_char *)(tp + 1) > snapend) {
+ printf("[|tcp]");
+ return;
+ }
+ if (length < sizeof(struct tcphdr)) {
+ (void)printf("truncated-tcp %d", length);
+ return;
+ }
+
+ sport = ntohs(tp->th_sport);
+ dport = ntohs(tp->th_dport);
+ seq = ntohl(tp->th_seq);
+ ack = ntohl(tp->th_ack);
+ win = ntohs(tp->th_win);
+ urp = ntohs(tp->th_urp);
+
+ (void)printf("%s.%s > %s.%s: ",
+ ipaddr_string(&ip->ip_src), tcpport_string(sport),
+ ipaddr_string(&ip->ip_dst), tcpport_string(dport));
+
+ if (qflag) {
+ (void)printf("tcp %d", length - tp->th_off * 4);
+ return;
+ }
+ if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
+ if (flags & TH_SYN)
+ putchar('S');
+ if (flags & TH_FIN)
+ putchar('F');
+ if (flags & TH_RST)
+ putchar('R');
+ if (flags & TH_PUSH)
+ putchar('P');
+ } else
+ putchar('.');
+
+ if (!Sflag && (flags & TH_ACK)) {
+ register struct tcp_seq_hash *th;
+ register int rev;
+ struct tha tha;
+ /*
+ * Find (or record) the initial sequence numbers for
+ * this conversation. (we pick an arbitrary
+ * collating order so there's only one entry for
+ * both directions).
+ */
+ if (sport < dport ||
+ (sport == dport &&
+ ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
+ tha.src = ip->ip_src, tha.dst = ip->ip_dst;
+ tha.port = sport << 16 | dport;
+ rev = 0;
+ } else {
+ tha.src = ip->ip_dst, tha.dst = ip->ip_src;
+ tha.port = dport << 16 | sport;
+ rev = 1;
+ }
+
+ for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
+ th->nxt; th = th->nxt)
+ if (!bcmp((char *)&tha, (char *)&th->addr,
+ sizeof(th->addr)))
+ break;
+
+ if (!th->nxt || flags & TH_SYN) {
+ /* didn't find it or new conversation */
+ if (!th->nxt)
+ th->nxt = (struct tcp_seq_hash *)
+ calloc(1, sizeof (*th));
+ th->addr = tha;
+ if (rev)
+ th->ack = seq, th->seq = ack - 1;
+ else
+ th->seq = seq, th->ack = ack - 1;
+ } else {
+ if (rev)
+ seq -= th->ack, ack -= th->seq;
+ else
+ seq -= th->seq, ack -= th->ack;
+ }
+ }
+ hlen = tp->th_off * 4;
+ length -= hlen;
+ if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
+ (void)printf(" %lu:%lu(%d)", seq, seq + length, length);
+ if (flags & TH_ACK)
+ (void)printf(" ack %u", ack);
+
+ (void)printf(" win %d", win);
+
+ if (flags & TH_URG)
+ (void)printf(" urg %d", urp);
+ /*
+ * Handle any options.
+ */
+ if ((hlen -= sizeof(struct tcphdr)) > 0) {
+ register const u_char *cp = (const u_char *)tp + sizeof(*tp);
+ int i;
+ char ch = '<';
+
+ putchar(' ');
+ while (--hlen >= 0) {
+ putchar(ch);
+ switch (*cp++) {
+ case TCPOPT_MAXSEG:
+ {
+ (void)printf("mss %d", cp[1] << 8 | cp[2]);
+ if (*cp != 4)
+ (void)printf("[len %d]", *cp);
+ cp += 3;
+ hlen -= 3;
+ break;
+ }
+ case TCPOPT_EOL:
+ (void)printf("eol");
+ break;
+ case TCPOPT_NOP:
+ (void)printf("nop");
+ break;
+ case TCPOPT_WSCALE:
+ (void)printf("wscale %d", cp[1]);
+ if (*cp != 3)
+ (void)printf("[len %d]", *cp);
+ cp += 2;
+ hlen -= 2;
+ break;
+ case TCPOPT_SACKOK:
+ (void)printf("sackOK");
+ if (*cp != 2)
+ (void)printf("[len %d]", *cp);
+ cp += 1;
+ hlen -= 1;
+ break;
+ case TCPOPT_ECHO:
+ {
+ (void)printf("echo %u",
+ cp[1] << 24 | cp[2] << 16 |
+ cp[3] << 8 | cp[4]);
+ if (*cp != 6)
+ (void)printf("[len %d]", *cp);
+ cp += 5;
+ hlen -= 5;
+ break;
+ }
+ case TCPOPT_ECHOREPLY:
+ {
+ (void)printf("echoreply %u",
+ cp[1] << 24 | cp[2] << 16 |
+ cp[3] << 8 | cp[4]);
+ if (*cp != 6)
+ (void)printf("[len %d]", *cp);
+ cp += 5;
+ hlen -= 5;
+ break;
+ }
+ case TCPOPT_TIMESTAMP:
+ {
+ (void)printf("timestamp %lu %lu",
+ cp[1] << 24 | cp[2] << 16 |
+ cp[3] << 8 | cp[4],
+ cp[5] << 24 | cp[6] << 16 |
+ cp[7] << 8 | cp[8]);
+ if (*cp != 10)
+ (void)printf("[len %d]", *cp);
+ cp += 9;
+ hlen -= 9;
+ break;
+ }
+ default:
+ (void)printf("opt-%d:", cp[-1]);
+ for (i = *cp++ - 2, hlen -= i + 1; i > 0; --i)
+ (void)printf("%02x", *cp++);
+ break;
+ }
+ ch = ',';
+ }
+ putchar('>');
+ }
+}
+
diff --git a/usr.sbin/tcpdump/print-tftp.c b/usr.sbin/tcpdump/print-tftp.c
new file mode 100644
index 00000000000..a1938321728
--- /dev/null
+++ b/usr.sbin/tcpdump/print-tftp.c
@@ -0,0 +1,147 @@
+/* $NetBSD: print-tftp.c,v 1.2 1995/03/06 19:11:35 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print trivial file transfer protocol packets.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-tftp.c,v 1.20 94/06/14 20:18:49 leres Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <arpa/tftp.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/* op code to string mapping */
+static struct token op2str[] = {
+ { RRQ, "RRQ" }, /* read request */
+ { WRQ, "WRQ" }, /* write request */
+ { DATA, "DATA" }, /* data packet */
+ { ACK, "ACK" }, /* acknowledgement */
+ { ERROR, "ERROR" }, /* error code */
+ { 0, NULL }
+};
+
+/* error code to string mapping */
+static struct token err2str[] = {
+ { EUNDEF, "EUNDEF" }, /* not defined */
+ { ENOTFOUND, "ENOTFOUND" }, /* file not found */
+ { EACCESS, "EACCESS" }, /* access violation */
+ { ENOSPACE, "ENOSPACE" }, /* disk full or allocation exceeded */
+ { EBADOP, "EBADOP" }, /* illegal TFTP operation */
+ { EBADID, "EBADID" }, /* unknown transfer ID */
+ { EEXISTS, "EEXISTS" }, /* file already exists */
+ { ENOUSER, "ENOUSER" }, /* no such user */
+ { 0, NULL }
+};
+
+/*
+ * Print trivial file transfer program requests
+ */
+void
+tftp_print(register const u_char *bp, int length)
+{
+ register const struct tftphdr *tp;
+ register const char *cp;
+ register const u_char *ep, *p;
+ register int opcode;
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+ static char tstr[] = " [|tftp]";
+
+ tp = (const struct tftphdr *)bp;
+ /* 'ep' points to the end of avaible data. */
+ ep = snapend;
+
+ /* Print length */
+ printf(" %d", length);
+
+ /* Print tftp request type */
+ TCHECK(tp->th_opcode, sizeof(tp->th_opcode));
+ opcode = ntohs(tp->th_opcode);
+ cp = tok2str(op2str, "tftp-#%d", opcode);
+ printf(" %s", cp);
+ /* Bail if bogus opcode */
+ if (*cp == 't')
+ return;
+
+ switch (opcode) {
+
+ case RRQ:
+ case WRQ:
+ putchar(' ');
+ /*
+ * XXX Not all arpa/tftp.h's specify th_stuff as any
+ * array; use address of th_block instead
+ */
+#ifdef notdef
+ p = (u_char *)tp->th_stuff;
+#else
+ p = (u_char *)&tp->th_block;
+#endif
+ if (fn_print(p, ep)) {
+ fputs(&tstr[1], stdout);
+ return;
+ }
+ break;
+
+ case DATA:
+ TCHECK(tp->th_block, sizeof(tp->th_block));
+ printf(" block %d", ntohs(tp->th_block));
+ break;
+
+ case ACK:
+ break;
+
+ case ERROR:
+ /* Print error code string */
+ TCHECK(tp->th_code, sizeof(tp->th_code));
+ printf(" %s ", tok2str(err2str, "tftp-err-#%d",
+ ntohs(tp->th_code)));
+ /* Print error message string */
+ if (fn_print((const u_char *)tp->th_data, ep)) {
+ fputs(&tstr[1], stdout);
+ return;
+ }
+ break;
+
+ default:
+ /* We shouldn't get here */
+ printf("(unknown #%d)", opcode);
+ break;
+ }
+ return;
+trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
diff --git a/usr.sbin/tcpdump/print-udp.c b/usr.sbin/tcpdump/print-udp.c
new file mode 100644
index 00000000000..4758c9da601
--- /dev/null
+++ b/usr.sbin/tcpdump/print-udp.c
@@ -0,0 +1,259 @@
+/* $NetBSD: print-udp.c,v 1.3 1995/03/06 19:11:36 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-udp.c,v 1.37 94/06/10 17:01:42 mccanne Exp (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#undef NOERROR /* Solaris sucks */
+#include <arpa/nameser.h>
+#include <arpa/tftp.h>
+
+#ifdef SOLARIS
+#include <tiuser.h>
+#endif
+#include <rpc/rpc.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "appletalk.h"
+
+#include "nfsv2.h"
+#include "bootp.h"
+
+extern int packettype;
+
+static void
+vat_print(const void *hdr, int len, register const struct udphdr *up)
+{
+ /* vat/vt audio */
+ u_int ts = *(u_short *)hdr;
+ if ((ts & 0xf060) != 0) {
+ /* probably vt */
+ (void)printf(" udp/vt %d %d / %d",
+ ntohs(up->uh_ulen) - sizeof(*up),
+ ts & 0x3ff, ts >> 10);
+ } else {
+ /* probably vat */
+ u_int i0 = ((u_int *)hdr)[0];
+ u_int i1 = ((u_int *)hdr)[1];
+ printf(" udp/vat %d c%d %u%s",
+ ntohs(up->uh_ulen) - sizeof(*up) - 8,
+ i0 & 0xffff,
+ i1, i0 & 0x800000? "*" : "");
+ /* audio format */
+ if (i0 & 0x1f0000)
+ printf(" f%d", (i0 >> 16) & 0x1f);
+ if (i0 & 0x3f000000)
+ printf(" s%d", (i0 >> 24) & 0x3f);
+ }
+}
+
+static void
+rtp_print(const void *hdr, int len, register const struct udphdr *up)
+{
+ /* rtp v1 video */
+ u_int *ip = (u_int *)hdr;
+ u_int i0 = ((u_int *)hdr)[0];
+ u_int i1 = ((u_int *)hdr)[1];
+ u_int hasopt = i0 & 0x800000;
+ u_int contype = (i0 >> 16) & 0x3f;
+ printf(" udp/rtp %d c%d %s%s %d",
+ ntohs(up->uh_ulen) - sizeof(*up) - 8,
+ contype,
+ hasopt? "+" : "",
+ i0 & 0x400000? "*" : "",
+ i0 & 0xffff);
+ if (contype == 31) {
+ ip += 2;
+ len >>= 2;
+ len -= 2;
+ if (hasopt) {
+ u_int i2, optlen;
+ do {
+ i2 = ip[0];
+ optlen = (i2 >> 16) & 0xff;
+ if (optlen == 0 || optlen > len) {
+ printf(" !opt");
+ return;
+ }
+ ip += optlen;
+ } while ((int)i2 >= 0);
+ }
+ printf(" 0x%04x", ip[0] >> 16);
+ }
+ if (vflag)
+ printf(" %u", i1);
+}
+
+/* XXX probably should use getservbyname() and cache answers */
+#define TFTP_PORT 69 /*XXX*/
+#define SUNRPC_PORT 111 /*XXX*/
+#define SNMP_PORT 161 /*XXX*/
+#define NTP_PORT 123 /*XXX*/
+#define SNMPTRAP_PORT 162 /*XXX*/
+#define RIP_PORT 520 /*XXX*/
+
+void
+udp_print(register const u_char *bp, int length, register const u_char *bp2)
+{
+ register const struct udphdr *up;
+ register const struct ip *ip;
+ register const u_char *cp;
+ u_short sport, dport, ulen;
+
+ up = (struct udphdr *)bp;
+ ip = (struct ip *)bp2;
+ cp = (u_char *)(up + 1);
+ if (cp > snapend) {
+ printf("[|udp]");
+ return;
+ }
+ if (length < sizeof(struct udphdr)) {
+ (void)printf(" truncated-udp %d", length);
+ return;
+ }
+ length -= sizeof(struct udphdr);
+
+ sport = ntohs(up->uh_sport);
+ dport = ntohs(up->uh_dport);
+ ulen = ntohs(up->uh_ulen);
+ if (packettype) {
+ register struct rpc_msg *rp;
+ enum msg_type direction;
+
+ switch (packettype) {
+ case 1:
+ (void)printf("%s.%s > %s.%s:",
+ ipaddr_string(&ip->ip_src),
+ udpport_string(sport),
+ ipaddr_string(&ip->ip_dst),
+ udpport_string(dport));
+ vat_print((void *)(up + 1), length, up);
+ break;
+ case 2:
+ (void)printf("%s.%s > %s.%s:",
+ ipaddr_string(&ip->ip_src),
+ udpport_string(sport),
+ ipaddr_string(&ip->ip_dst),
+ udpport_string(dport));
+ wb_print((void *)(up + 1), length);
+ break;
+ case 3:
+ rp = (struct rpc_msg *)(up + 1);
+ direction = (enum msg_type)ntohl(rp->rm_direction);
+ if (direction == CALL)
+ sunrpcrequest_print((u_char *)rp, length,
+ (u_char *)ip);
+ else
+ nfsreply_print((u_char *)rp, length,
+ (u_char *)ip); /*XXX*/
+ break;
+ case 4:
+ (void)printf("%s.%s > %s.%s:",
+ ipaddr_string(&ip->ip_src),
+ udpport_string(sport),
+ ipaddr_string(&ip->ip_dst),
+ udpport_string(dport));
+ rtp_print((void *)(up + 1), length, up);
+ break;
+ }
+ return;
+ }
+
+ if (! qflag) {
+ register struct rpc_msg *rp;
+ enum msg_type direction;
+
+ rp = (struct rpc_msg *)(up + 1);
+ direction = (enum msg_type)ntohl(rp->rm_direction);
+ if (dport == NFS_PORT && direction == CALL) {
+ nfsreq_print((u_char *)rp, length, (u_char *)ip);
+ return;
+ }
+ else if (sport == NFS_PORT && direction == REPLY) {
+ nfsreply_print((u_char *)rp, length, (u_char *)ip);
+ return;
+ }
+#ifdef notdef
+ else if (dport == SUNRPC_PORT && direction == CALL) {
+ sunrpcrequest_print((u_char *)rp, length, (u_char *)ip);
+ return;
+ }
+#endif
+ else if (((struct LAP *)cp)->type == lapDDP &&
+ (atalk_port(sport) || atalk_port(dport))) {
+ if (vflag)
+ fputs("kip ", stdout);
+ atalk_print(cp, length);
+ return;
+ }
+ }
+ (void)printf("%s.%s > %s.%s:",
+ ipaddr_string(&ip->ip_src), udpport_string(sport),
+ ipaddr_string(&ip->ip_dst), udpport_string(dport));
+
+ if (!qflag) {
+#define ISPORT(p) (dport == (p) || sport == (p))
+ if (ISPORT(NAMESERVER_PORT))
+ ns_print((const u_char *)(up + 1), length);
+ else if (ISPORT(TFTP_PORT))
+ tftp_print((const u_char *)(up + 1), length);
+ else if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS))
+ bootp_print((const u_char *)(up + 1), length,
+ sport, dport);
+ else if (dport == RIP_PORT)
+ rip_print((const u_char *)(up + 1), length);
+ else if (ISPORT(SNMP_PORT) || ISPORT(SNMPTRAP_PORT))
+ snmp_print((const u_char *)(up + 1), length);
+ else if (ISPORT(NTP_PORT))
+ ntp_print((const u_char *)(up + 1), length);
+ else if (dport == 3456)
+ vat_print((const void *)(up + 1), length, up);
+ /*
+ * Kludge in test for whiteboard packets.
+ */
+ else if (dport == 4567)
+ wb_print((const void *)(up + 1), length);
+ else
+ (void)printf(" udp %d", ulen - sizeof(*up));
+#undef ISPORT
+ } else
+ (void)printf(" udp %d", ulen - sizeof(*up));
+}
diff --git a/usr.sbin/tcpdump/print-wb.c b/usr.sbin/tcpdump/print-wb.c
new file mode 100644
index 00000000000..ac7d6823e1d
--- /dev/null
+++ b/usr.sbin/tcpdump/print-wb.c
@@ -0,0 +1,447 @@
+/* $NetBSD: print-wb.c,v 1.2 1995/03/06 19:11:37 mycroft Exp $ */
+
+/*
+ * Copyright (c) 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: print-wb.c,v 1.14 94/06/14 20:18:50 leres Exp (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/* XXX need to add byte-swapping macros! */
+
+/*
+ * Largest packet size. Everything should fit within this space.
+ * For instance, multiline objects are sent piecewise.
+ */
+#define MAXFRAMESIZE 1024
+
+/*
+ * Multiple drawing ops can be sent in one packet. Each one starts on a
+ * an even multiple of DOP_ALIGN bytes, which must be a power of two.
+ */
+#define DOP_ALIGN 4
+#define DOP_ROUNDUP(x) ((((int)(x)) + (DOP_ALIGN - 1)) & ~(DOP_ALIGN - 1))
+#define DOP_NEXT(d)\
+ ((struct dophdr*)((u_char *)(d) + \
+ DOP_ROUNDUP(ntohs((d)->dh_len) + sizeof(*(d)))))
+
+/*
+ * Format of the whiteboard packet header.
+ * The transport level header.
+ */
+struct pkt_hdr {
+ u_int32 ph_src; /* site id of source */
+ u_int32 ph_ts; /* time stamp (for skew computation) */
+ u_short ph_version; /* version number */
+ u_char ph_type; /* message type */
+ u_char ph_flags; /* message flags */
+};
+
+/* Packet types */
+#define PT_DRAWOP 0 /* drawing operation */
+#define PT_ID 1 /* announcement packet */
+#define PT_RREQ 2 /* repair request */
+#define PT_RREP 3 /* repair reply */
+#define PT_KILL 4 /* terminate participation */
+#define PT_PREQ 5 /* page vector request */
+#define PT_PREP 7 /* page vector reply */
+
+/* flags */
+#define PF_USER 0x01 /* hint that packet has interactive data */
+#define PF_VIS 0x02 /* only visible ops wanted */
+
+struct PageID {
+ u_int32 p_sid; /* session id of initiator */
+ u_int32 p_uid; /* page number */
+};
+
+struct dophdr {
+ u_int32 dh_ts; /* sender's timestamp */
+ u_short dh_len; /* body length */
+ u_char dh_flags;
+ u_char dh_type; /* body type */
+ /* body follows */
+};
+/*
+ * Drawing op sub-types.
+ */
+#define DT_RECT 2
+#define DT_LINE 3
+#define DT_ML 4
+#define DT_DEL 5
+#define DT_XFORM 6
+#define DT_ELL 7
+#define DT_CHAR 8
+#define DT_STR 9
+#define DT_NOP 10
+#define DT_PSCODE 11
+#define DT_PSCOMP 12
+#define DT_REF 13
+#define DT_SKIP 14
+#define DT_HOLE 15
+#define DT_MAXTYPE 15
+
+/*
+ * A drawing operation.
+ */
+struct pkt_dop {
+ struct PageID pd_page; /* page that operations apply to */
+ u_int32 pd_sseq; /* start sequence number */
+ u_int32 pd_eseq; /* end sequence number */
+ /* drawing ops follow */
+};
+
+/*
+ * A repair request.
+ */
+struct pkt_rreq {
+ u_int32 pr_id; /* source id of drawops to be repaired */
+ struct PageID pr_page; /* page of drawops */
+ u_int32 pr_sseq; /* start seqno */
+ u_int32 pr_eseq; /* end seqno*/
+};
+
+/*
+ * A repair reply.
+ */
+struct pkt_rrep {
+ u_int32 pr_id; /* original site id of ops */
+ struct pkt_dop pr_dop;
+ /* drawing ops follow */
+};
+
+struct id_off {
+ u_int32 id;
+ u_int32 off;
+};
+
+struct pgstate {
+ u_int32 slot;
+ struct PageID page;
+ u_short nid;
+ u_short rsvd;
+ /* seqptr's */
+};
+
+/*
+ * An announcement packet.
+ */
+struct pkt_id {
+ u_int32 pi_mslot;
+ struct PageID pi_mpage; /* current page */
+ struct pgstate pi_ps;
+ /* seqptr's */
+ /* null-terminated site name */
+};
+
+struct pkt_preq {
+ struct PageID pp_page;
+ u_int32 pp_low;
+ u_int32 pp_high;
+};
+
+struct pkt_prep {
+ u_int32 pp_n; /* size of pageid array */
+ /* pgstate's follow */
+};
+
+static int
+wb_id(const struct pkt_id *id, int len)
+{
+ int i;
+ const char *cp;
+ const struct id_off *io;
+ char c;
+ int nid;
+
+ len -= sizeof(*id);
+ if (len < 0) {
+ printf(" truncated-wb-id!");
+ return (0);
+ }
+ if ((u_char *)(id + 1) > snapend)
+ return (-1);
+ nid = ntohs(id->pi_ps.nid);
+ len -= sizeof(*io) * nid;
+ if (len < 0) {
+ printf(" truncated-wb-id!");
+ return (0);
+ }
+ io = (struct id_off *)(id + 1);
+ cp = (char *)(io + nid);
+ if ((u_char *)cp + len > snapend)
+ return (-1);
+
+ printf(" wb-id: %d/%s:%d (max %d/%s:%d) ",
+ ntohl(id->pi_ps.slot),
+ ipaddr_string(&id->pi_ps.page.p_sid),
+ ntohl(id->pi_ps.page.p_uid),
+ ntohl(id->pi_mslot),
+ ipaddr_string(&id->pi_mpage.p_sid),
+ ntohl(id->pi_mpage.p_uid));
+
+ if (cp[len - 1] != '\0')
+ printf("(unterm!) ");
+
+ fn_print((u_char *)cp, (u_char *)cp + len);
+
+ c = '<';
+ for (i = 0; i < nid; ++io, ++i) {
+ printf("%c%s:%d", c, ipaddr_string(&io->id), ntohl(io->off));
+ c = ',';
+ }
+ printf(">");
+ return (0);
+}
+
+static int
+wb_rreq(const struct pkt_rreq *rreq, int len)
+{
+ if (len < sizeof(*rreq)) {
+ printf(" truncated-wb-rreq!");
+ return (0);
+ }
+ if ((u_char *)(rreq + 1) > snapend)
+ return (-1);
+
+ printf(" wb-rreq: please repair %s %s:%ld<%ld:%ld>",
+ ipaddr_string(&rreq->pr_id),
+ ipaddr_string(&rreq->pr_page.p_sid), ntohl(rreq->pr_page.p_uid),
+ ntohl(rreq->pr_sseq), ntohl(rreq->pr_eseq));
+ return (0);
+}
+
+static int
+wb_preq(const struct pkt_preq *preq, int len)
+{
+ if (len < sizeof(*preq)) {
+ printf(" truncated-wb-preq!");
+ return (0);
+ }
+ if ((u_char *)(preq + 1) > snapend)
+ return (-1);
+
+ printf(" wb-preq: need %d/%s:%ld",
+ ntohl(preq->pp_low),
+ ipaddr_string(&preq->pp_page.p_sid),
+ ntohl(preq->pp_page.p_uid));
+ return (0);
+}
+
+static int
+wb_prep(const struct pkt_prep *prep, int len)
+{
+ int n;
+ const struct pgstate* ps;
+ const u_char* ep = snapend;
+
+ if (len < sizeof(*prep)) {
+ printf(" truncated-wb-prep!");
+ return (0);
+ }
+ printf(" wb-prep:");
+ n = ntohl(prep->pp_n);
+ ps = (const struct pgstate*)(prep + 1);
+ while (--n >= 0 && (u_char*)ps < ep) {
+ const struct id_off *io, *ie;
+ char c = '<';
+
+ printf(" %lu/%s:%lu", ntohl(ps->slot),
+ ipaddr_string(&ps->page.p_sid),
+ ntohl(ps->page.p_uid));
+ io = (struct id_off*)(ps + 1);
+ for (ie = io + ps->nid; io < ie && (u_char*)io < ep; ++io) {
+ printf("%c%s:%lu", c, ipaddr_string(&io->id),
+ ntohl(io->off));
+ c = ',';
+ }
+ printf(">");
+ ps = (struct pgstate*)io;
+ }
+ return ((u_char*)ps <= ep? 0 : -1);
+}
+
+
+char *dopstr[] = {
+ "dop-0!",
+ "dop-1!",
+ "RECT",
+ "LINE",
+ "ML",
+ "DEL",
+ "XFORM",
+ "ELL",
+ "CHAR",
+ "STR",
+ "NOP",
+ "PSCODE",
+ "PSCOMP",
+ "REF",
+ "SKIP",
+ "HOLE",
+};
+
+static int
+wb_dops(const struct dophdr *dh, u_int32 ss, u_int32 es)
+{
+ printf(" <");
+ for ( ; ss <= es; ++ss) {
+ register int t = dh->dh_type;
+
+ if (t > DT_MAXTYPE)
+ printf(" dop-%d!", t);
+ else {
+ printf(" %s", dopstr[t]);
+ if (t == DT_SKIP || t == DT_HOLE) {
+ int ts = ntohl(dh->dh_ts);
+ printf("%d", ts - ss + 1);
+ if (ss > ts || ts > es) {
+ printf("[|]");
+ if (ts < ss)
+ return (0);
+ }
+ ss = ts;
+ }
+ }
+ dh = DOP_NEXT(dh);
+ if ((u_char*)dh >= snapend) {
+ printf("[|wb]");
+ break;
+ }
+ }
+ printf(" >");
+ return (0);
+}
+
+static int
+wb_rrep(const struct pkt_rrep *rrep, int len)
+{
+ const struct pkt_dop *dop = &rrep->pr_dop;
+
+ len -= sizeof(*rrep);
+ if (len < 0) {
+ printf(" truncated-wb-rrep!");
+ return (0);
+ }
+ if ((u_char *)(rrep + 1) > snapend)
+ return (-1);
+
+ printf(" wb-rrep: for %s %s:%d<%ld:%ld>",
+ ipaddr_string(&rrep->pr_id),
+ ipaddr_string(&dop->pd_page.p_sid), ntohl(dop->pd_page.p_uid),
+ ntohl(dop->pd_sseq), ntohl(dop->pd_eseq));
+
+ return (wb_dops((const struct dophdr*)(dop + 1),
+ ntohl(dop->pd_sseq), ntohl(dop->pd_eseq)));
+}
+
+static int
+wb_drawop(const struct pkt_dop *dop, int len)
+{
+ len -= sizeof(*dop);
+ if (len < 0) {
+ printf(" truncated-wb-dop!");
+ return (0);
+ }
+ if ((u_char *)(dop + 1) > snapend)
+ return (-1);
+
+ printf(" wb-dop: %s:%d<%ld:%ld>",
+ ipaddr_string(&dop->pd_page.p_sid), ntohl(dop->pd_page.p_uid),
+ ntohl(dop->pd_sseq), ntohl(dop->pd_eseq));
+
+ return (wb_dops((const struct dophdr*)(dop + 1),
+ ntohl(dop->pd_sseq), ntohl(dop->pd_eseq)));
+}
+
+/*
+ * Print whiteboard multicast packets.
+ */
+void
+wb_print(register const void *hdr, register int len)
+{
+ register const struct pkt_hdr* ph;
+
+ ph = (const struct pkt_hdr*)hdr;
+ len -= sizeof(*ph);
+ if (len < 0) {
+ printf(" truncated-wb!");
+ return;
+ }
+ if ((u_char *)(ph + 1) > snapend) {
+ trunc:
+ printf("[|wb]");
+ return;
+ }
+ if (ph->ph_flags)
+ printf("*");
+ switch (ph->ph_type) {
+
+ case PT_KILL:
+ printf(" wb-kill");
+ break;
+
+ case PT_ID:
+ if (wb_id((struct pkt_id *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ case PT_RREQ:
+ if (wb_rreq((struct pkt_rreq *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ case PT_RREP:
+ if (wb_rrep((struct pkt_rrep *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ case PT_DRAWOP:
+ if (wb_drawop((struct pkt_dop *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ case PT_PREQ:
+ if (wb_preq((struct pkt_preq *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ case PT_PREP:
+ if (wb_prep((struct pkt_prep *)(ph + 1), len) < 0)
+ goto trunc;
+ break;
+
+ default:
+ printf(" wb-%d!", ph->ph_type);
+ return;
+ }
+}
diff --git a/usr.sbin/tcpdump/send-ack.awk b/usr.sbin/tcpdump/send-ack.awk
new file mode 100644
index 00000000000..1f98e50322e
--- /dev/null
+++ b/usr.sbin/tcpdump/send-ack.awk
@@ -0,0 +1,70 @@
+# $NetBSD: send-ack.awk,v 1.2 1995/03/06 19:11:42 mycroft Exp $
+
+BEGIN {
+ # we need the number of bytes in a packet to do the output
+ # in packet numbers rather than byte numbers.
+ if (packetsize <= 0)
+ packetsize = 512
+ expectNext = 1
+ lastwin = -1
+ }
+ {
+ # convert tcp trace to send/ack form.
+ n = split ($1,t,":")
+ tim = t[1]*3600 + t[2]*60 + t[3]
+ if (NR <= 1) {
+ tzero = tim
+ ltim = tim
+ OFS = "\t"
+ }
+ if ($6 != "ack") {
+ # we have a data packet record:
+ # ignore guys with syn, fin or reset 'cause we
+ # can't handle their sequence numbers. Try to
+ # detect and add a flag character for 'anomalies':
+ # * -> re-sent packet
+ # - -> packet after hole (missing packet(s))
+ # # -> odd size packet
+ if ($5 !~ /[SFR]/) {
+ i = index($6,":")
+ j = index($6,"(")
+ strtSeq = substr($6,1,i-1)
+ endSeq = substr($6,i+1,j-i-1)
+ len = endSeq - strtSeq
+ id = endSeq
+ if (! timeOf[id])
+ timeOf[id] = tim
+ if (endSeq - expectNext < 0)
+ flag = "*"
+ else {
+ if (strtSeq - expectNext > 0)
+ flag = "-"
+ else if (len != packetsize)
+ flag = "#"
+ else
+ flag = " "
+ expectNext = endSeq
+ }
+ printf "%7.2f\t%7.2f\t%s send %s %d", tim-tzero, tim-ltim,\
+ flag, $5, strtSeq
+ if (++timesSent[id] > 1)
+ printf " (%.2f) [%d]", tim - timeOf[id], timesSent[id]
+ if (len != packetsize)
+ printf " <%d>", len
+ }
+ } else {
+ id = $7
+
+ printf "%7.2f\t%7.2f\t%s ack %s %d", tim-tzero, tim-ltim,\
+ flag, $5, id
+ if ($9 != lastwin) {
+ printf " win %d", $9
+ lastwin = $9
+ }
+ printf " (%.2f)", tim - timeOf[id]
+ if (++timesAcked[id] > 1)
+ printf " [%d]", timesAcked[id]
+ }
+ printf "\n"
+ ltim = tim
+ }
diff --git a/usr.sbin/tcpdump/stime.awk b/usr.sbin/tcpdump/stime.awk
new file mode 100644
index 00000000000..d57968ed932
--- /dev/null
+++ b/usr.sbin/tcpdump/stime.awk
@@ -0,0 +1,21 @@
+# $NetBSD: stime.awk,v 1.2 1995/03/06 19:11:43 mycroft Exp $
+
+$6 !~ /^ack/ && $5 !~ /[SFR]/ {
+ # given a tcpdump ftp trace, output one line for each send
+ # in the form
+ # <send time> <seq no>
+ # where <send time> is the time packet was sent (in seconds with
+ # zero at time of first packet) and <seq no> is the tcp sequence
+ # number of the packet divided by 1024 (i.e., Kbytes sent).
+ #
+ # convert time to seconds
+ n = split ($1,t,":")
+ tim = t[1]*3600 + t[2]*60 + t[3]
+ if (! tzero) {
+ tzero = tim
+ OFS = "\t"
+ }
+ # get packet sequence number
+ i = index($6,":")
+ printf "%7.2f\t%g\n", tim-tzero, substr($6,1,i-1)/1024
+ }
diff --git a/usr.sbin/tcpdump/tcpdump.8 b/usr.sbin/tcpdump/tcpdump.8
new file mode 100644
index 00000000000..01879d3b2ce
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump.8
@@ -0,0 +1,1173 @@
+.\" $NetBSD: tcpdump.8,v 1.3 1995/03/06 19:11:46 mycroft Exp $
+.\"
+.\" @(#) Header: tcpdump.1,v 1.45 94/06/20 18:54:27 leres Exp (LBL)
+.\"
+.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH TCPDUMP 1 "20 Jun 1994"
+.SH NAME
+tcpdump \- dump traffic on a network
+.SH SYNOPSIS
+.na
+.B tcpdump
+[
+.B \-deflnNOpqStvx
+] [
+.B \-c
+.I count
+] [
+.B \-F
+.I file
+]
+.br
+.ti +8
+[
+.B \-i
+.I interface
+] [
+.B \-r
+.I file
+]
+[
+.B \-s
+.I snaplen
+]
+.br
+.ti +8
+[
+.B \-w
+.I file
+]
+.I expression
+.br
+.ad
+.SH DESCRIPTION
+.LP
+\fITcpdump\fP prints out the headers of packets on a network interface
+that match the boolean \fIexpression\fP.
+.B Under SunOS:
+You must be root to invoke \fItcpdump\fP or it must be installed
+setuid to root.
+.B Under Ultrix:
+Any user can invoke \fItcpdump\fP once the super-user has enabled
+promiscuous-mode operation using
+.IR pfconfig (8).
+.B Under BSD:
+Access is controlled by the permissions on
+.I /dev/bpf0,
+etc.
+.SH OPTIONS
+.TP
+.B \-c
+Exit after receiving \fIcount\fP packets.
+.TP
+.B \-d
+Dump the compiled packet-matching code to standard output and stop.
+.TP
+.B \-e
+Print the link-level header on each dump line.
+.TP
+.B \-f
+Print `foreign' internet addresses numerically rather than symbolically
+(this option is intended to get around serious brain damage in
+Sun's yp server \(em usually it hangs forever translating non-local
+internet numbers).
+.TP
+.B \-F
+Use \fIfile\fP as input for the filter expression.
+An additional expression given on the command line is ignored.
+.TP
+.B \-i
+Listen on \fIinterface\fP.
+If unspecified, \fItcpdump\fP searches the system interface list for the
+lowest numbered, configured up interface (excluding loopback).
+Ties are broken by choosing the earliest match.
+.TP
+.B \-l
+Make stdout line buffered. Useful if you want to see the data
+while capturing it. E.g.,
+.br
+``tcpdump\ \ \-l\ \ |\ \ tee dat'' or
+``tcpdump\ \ \-l \ \ > dat\ \ &\ \ tail\ \ \-f\ \ dat''.
+.TP
+.B \-n
+Don't convert addresses (i.e., host addresses, port numbers, etc.) to names.
+.TP
+.B \-N
+Don't print domain name qualification of host names. E.g.,
+if you give this flag then \fItcpdump\fP will print ``nic''
+instead of ``nic.ddn.mil''.
+.TP
+.B \-O
+Do not run the packet-matching code optimizer. This is useful only
+if you suspect a bug in the optimizer.
+.TP
+.B \-p
+\fIDon't\fP put the interface
+into promiscuous mode. Note that the interface might be in promiscuous
+for some other reason; hence, `-p' cannot be used as an abbreviation for
+`ether host {localhost} or broadcast'.
+.TP
+.B \-q
+Quick (quiet?) output. Print less protocol information so output
+lines are shorter.
+.TP
+.B \-r
+Read packets from \fIfile\fR (which was created with the -w option).
+Standard input is used if \fIfile\fR is ``-''.
+.TP
+.B \-s
+Snarf \fIsnaplen\fP bytes of data from each packet rather than the
+default of 68 (with NIT, the minimum is actually 96).
+68 bytes is adequate for IP, ICMP, TCP
+and UDP but may truncate protocol information from name server and NFS
+packets (see below). Packets truncated because of a limited snapshot
+are indicated in the output with ``[|\fIproto\fP]'', where \fIproto\fP
+is the name of the protocol level at which the truncation has occurred.
+Note that taking larger snapshots both increases
+the amount of time it takes to process packets and, effectively,
+decreases the amount of packet buffering. This may cause packets to be
+lost. You should limit \fIsnaplen\fP to the smallest number that will
+capture the protocol information you're interested in.
+.TP
+.B \-S
+Print absolute, rather than relative, TCP sequence numbers.
+.TP
+.B \-t
+\fIDon't\fP print a timestamp on each dump line.
+.TP
+.B \-tt
+Print an unformatted timestamp on each dump line.
+.TP
+.B \-v
+(Slightly more) verbose output. For example, the time to live
+and type of service information in an IP packet is printed.
+.TP
+.B \-vv
+Even more verbose output. For example, additional fields are
+printed from NFS reply packets.
+.TP
+.B \-w
+Write the raw packets to \fIfile\fR rather than parsing and printing
+them out. They can later be printed with the \-r option.
+Standard output is used if \fIfile\fR is ``-''.
+.TP
+.B \-x
+Print each packet (minus its link level header) in hex.
+The smaller of the entire packet or
+.I snaplen
+bytes will be printed.
+.IP "\fI expression\fP"
+.RS
+selects which packets will be dumped. If no \fIexpression\fP
+is given, all packets on the net will be dumped. Otherwise,
+only packets for which \fIexpression\fP is `true' will be dumped.
+.LP
+The \fIexpression\fP consists of one or more
+.I primitives.
+Primitives usually consist of an
+.I id
+(name or number) preceded by one or more qualifiers. There are three
+different kinds of qualifier:
+.IP \fItype\fP
+qualifiers say what kind of thing the id name or number refers to.
+Possible types are
+.BR host ,
+.B net
+and
+.BR port .
+E.g., `host foo', `net 128.3', `port 20'. If there is no type
+qualifier,
+.B host
+is assumed.
+.IP \fIdir\fP
+qualifiers specify a particular tranfer direction to and/or from
+.I id.
+Possible directions are
+.BR src ,
+.BR dst ,
+.B "src or dst"
+and
+.B "src and"
+.BR dst .
+E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'. If
+there is no dir qualifier,
+.B "src or dst"
+is assumed.
+.IP \fIproto\fP
+qualifiers restrict the match to a particular protocol. Possible
+protos are:
+.BR ether ,
+.BR fddi ,
+.BR ip ,
+.BR arp ,
+.BR rarp ,
+.BR decnet ,
+.BR lat ,
+.BR moprc ,
+.BR mopdl ,
+.B tcp
+and
+.BR udp .
+E.g., `ether src foo', `arp net 128.3', `tcp port 21'. If there is
+no proto qualifier, all protocols consistent with the type are
+assumed. E.g., `src foo' means `(ip or arp or rarp) src foo'
+(except the latter is not legal syntax), `net bar' means `(ip or
+arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'.
+.LP
+[`fddi' is actually an alias for `ether'; the parser treats them
+identically as meaning ``the data link level used on the specified
+network interface.'' FDDI headers contain Ethernet-like source
+and destination addresses, and often contain Ethernet-like packet
+types, so you can filter on these FDDI fields just as with the
+analogous Ethernet fields. FDDI headers also contain other fields,
+but you cannot name them explicitly in a filter expression.]
+.LP
+In addition to the above, there are some special `primitive' keywords
+that don't follow the pattern:
+.BR gateway ,
+.BR broadcast ,
+.BR less ,
+.B greater
+and arithmetic expressions. All of these are described below.
+.LP
+More complex filter expressions are built up by using the words
+.BR and ,
+.B or
+and
+.B not
+to combine primitives. E.g., `host foo and not port ftp and not port ftp-data'.
+To save typing, identical qualifier lists can be omitted. E.g.,
+`tcp dst port ftp or ftp-data or domain' is exactly the same as
+`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.
+.LP
+Allowable primitives are:
+.IP "\fBdst host \fIhost\fR"
+True if the IP destination field of the packet is \fIhost\fP,
+which may be either an address or a name.
+.IP "\fBsrc host \fIhost\fR"
+True if the IP source field of the packet is \fIhost\fP.
+.IP "\fBhost \fIhost\fP
+True if either the IP source or destination of the packet is \fIhost\fP.
+Any of the above host expressions can be prepended with the keywords,
+\fBip\fP, \fBarp\fP, or \fBrarp\fP as in:
+.in +.5i
+.nf
+\fBip host \fIhost\fR
+.fi
+.in -.5i
+which is equivalent to:
+.in +.5i
+.nf
+\fBether proto \fI\\ip\fB and host \fIhost\fR
+.fi
+.in -.5i
+If \fIhost\fR is a name with multiple IP addresses, each address will
+be checked for a match.
+.IP "\fBether dst \fIehost\fP
+True if the ethernet destination address is \fIehost\fP. \fIEhost\fP
+may be either a name from /etc/ethers or a number (see
+.IR ethers (3N)
+for numeric format).
+.IP "\fBether src \fIehost\fP
+True if the ethernet source address is \fIehost\fP.
+.IP "\fBether host \fIehost\fP
+True if either the ethernet source or destination address is \fIehost\fP.
+.IP "\fBgateway\fP \fIhost\fP
+True if the packet used \fIhost\fP as a gateway. I.e., the ethernet
+source or destination address was \fIhost\fP but neither the IP source
+nor the IP destination was \fIhost\fP. \fIHost\fP must be a name and
+must be found in both /etc/hosts and /etc/ethers. (An equivalent
+expression is
+.in +.5i
+.nf
+\fBether host \fIehost \fBand not host \fIhost\fR
+.fi
+.in -.5i
+which can be used with either names or numbers for \fIhost / ehost\fP.)
+.IP "\fBdst net \fInet\fR"
+True if the IP destination address of the packet has a network
+number of \fInet\fP, which may be either an address or a name.
+.IP "\fBsrc net \fInet\fR"
+True if the IP source address of the packet has a network
+number of \fInet\fP.
+.IP "\fBnet \fInet\fR"
+True if either the IP source or destination address of the packet has a network
+number of \fInet\fP.
+.IP "\fBdst port \fIport\fR"
+True if the packet is ip/tcp or ip/udp and has a
+destination port value of \fIport\fP.
+The \fIport\fP can be a number or a name used in /etc/services (see
+.IR tcp (4P)
+and
+.IR udp (4P)).
+If a name is used, both the port
+number and protocol are checked. If a number or ambiguous name is used,
+only the port number is checked (e.g., \fBdst port 513\fR will print both
+tcp/login traffic and udp/who traffic, and \fBport domain\fR will print
+both tcp/domain and udp/domain traffic).
+.IP "\fBsrc port \fIport\fR"
+True if the packet has a source port value of \fIport\fP.
+.IP "\fBport \fIport\fR"
+True if either the source or destination port of the packet is \fIport\fP.
+Any of the above port expressions can be prepended with the keywords,
+\fBtcp\fP or \fBudp\fP, as in:
+.in +.5i
+.nf
+\fBtcp src port \fIport\fR
+.fi
+.in -.5i
+which matches only tcp packets.
+.IP "\fBless \fIlength\fR"
+True if the packet has a length less than or equal to \fIlength\fP.
+This is equivalent to:
+.in +.5i
+.nf
+\fBlen <= \fIlength\fP.
+.fi
+.in -.5i
+.IP "\fBgreater \fIlength\fR"
+True if the packet has a length greater than or equal to \fIlength\fP.
+This is equivalent to:
+.in +.5i
+.nf
+\fBlen >= \fIlength\fP.
+.fi
+.in -.5i
+.IP "\fBip proto \fIprotocol\fR"
+True if the packet is an ip packet (see
+.IR ip (4P))
+of protocol type \fIprotocol\fP.
+\fIProtocol\fP can be a number or one of the names
+\fIicmp\fP, \fIudp\fP, \fInd\fP, or \fItcp\fP.
+Note that the identifiers \fItcp\fP, \fIudp\fP, and \fIicmp\fP are also
+keywords and must be escaped via backslash (\\), which is \\\\ in the C-shell.
+.IP "\fBether broadcast\fR"
+True if the packet is an ethernet broadcast packet. The \fIether\fP
+keyword is optional.
+.IP "\fBip broadcast\fR"
+True if the packet is an IP broadcast packet. It checks for both
+the all-zeroes and all-ones broadcast conventions, and looks up
+the local subnet mask.
+.IP "\fBether multicast\fR"
+True if the packet is an ethernet multicast packet. The \fIether\fP
+keyword is optional.
+This is shorthand for `\fBether[0] & 1 != 0\fP'.
+.IP "\fBip multicast\fR"
+True if the packet is an IP multicast packet.
+.IP "\fBether proto \fIprotocol\fR"
+True if the packet is of ether type \fIprotocol\fR.
+\fIProtocol\fP can be a number or a name like
+\fIip\fP, \fIarp\fP, or \fIrarp\fP.
+Note these identifiers are also keywords
+and must be escaped via backslash (\\).
+[In the case of FDDI (e.g., `\fBfddi protocol arp\fR'), the
+protocol identification comes from the 802.2 Logical Link Control
+(LLC) header, which is usually layered on top of the FDDI header.
+\fItcpdump\fP assumes, when filtering on the protocol identifier,
+that all FDDI packets include an LLC header, and that the LLC header
+is in so-called SNAP format.]
+.IP "\fBdecnet src \fIhost\fR"
+True if the DECNET source address is
+.IR host ,
+which may be an address of the form ``10.123'', or a DECNET host
+name. [DECNET host name support is only available on Ultrix systems
+that are configured to run DECNET.]
+.IP "\fBdecnet dst \fIhost\fR"
+True if the DECNET destination address is
+.IR host .
+.IP "\fBdecnet host \fIhost\fR"
+True if either the DECNET source or destination address is
+.IR host .
+.IP "\fBip\fR, \fBarp\fR, \fBrarp\fR, \fBdecnet\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBether proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above protocols.
+.IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBether proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above protocols.
+Note that
+\fItcpdump\fP does not currently know how to parse these protocols.
+.IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBip proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above protocols.
+.IP "\fIexpr relop expr\fR"
+True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=,
+and \fIexpr\fR is an arithmetic expression composed of integer constants
+(expressed in standard C syntax), the normal binary operators
+[+, -, *, /, &, |], a length operator, and special packet data accessors.
+To access
+data inside the packet, use the following syntax:
+.in +.5i
+.nf
+\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR
+.fi
+.in -.5i
+\fIProto\fR is one of \fBether, fddi,
+ip, arp, rarp, tcp, udp, \fRor \fBicmp\fR, and
+indicates the protocol layer for the index operation.
+The byte offset, relative to the indicated protocol layer, is
+given by \fIexpr\fR.
+\fISize\fR is optional and indicates the number of bytes in the
+field of interest; it can be either one, two, or four, and defaults to one.
+The length operator, indicated by the keyword \fBlen\fP, gives the
+length of the packet.
+
+For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic.
+The expression `\fBip[0] & 0xf != 5\fP'
+catches all IP packets with options. The expression
+`\fBip[6:2] & 0x1fff = 0\fP'
+catches only unfragmented datagrams and frag zero of fragmented datagrams.
+This check is implicitly applied to the \fBtcp\fP and \fBudp\fP
+index operations.
+For instance, \fBtcp[0]\fP always means the first
+byte of the TCP \fIheader\fP, and never means the first byte of an
+intervening fragment.
+.LP
+Primitives may be combined using:
+.IP
+A parenthesized group of primitives and operators
+(parentheses are special to the Shell and must be escaped).
+.IP
+Negation (`\fB!\fP' or `\fBnot\fP').
+.IP
+Concatenation (`\fB&&\fP' or `\fBand\fP').
+.IP
+Alternation (`\fB||\fP' or `\fBor\fP').
+.LP
+Negation has highest precedence.
+Alternation and concatenation have equal precedence and associate
+left to right. Note that explicit \fBand\fR tokens, not juxtaposition,
+are now required for concatenation.
+.LP
+If an identifier is given without a keyword, the most recent keyword
+is assumed.
+For example,
+.in +.5i
+.nf
+\fBnot host vs and ace\fR
+.fi
+.in -.5i
+is short for
+.in +.5i
+.nf
+\fBnot host vs and host ace\fR
+.fi
+.in -.5i
+which should not be confused with
+.in +.5i
+.nf
+\fBnot ( host vs or ace )\fR
+.fi
+.in -.5i
+.LP
+Expression arguments can be passed to tcpdump as either a single argument
+or as multiple arguments, whichever is more convenient.
+Generally, if the expression contains Shell metacharacters, it is
+easier to pass it as a single, quoted argument.
+Multiple arguments are concatenated with spaces before being parsed.
+.SH EXAMPLES
+.LP
+To print all packets arriving at or departing from \fIsundown\fP:
+.RS
+.nf
+\fBtcpdump host sundown\fP
+.fi
+.RE
+.LP
+To print traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR:
+.RS
+.nf
+\fBtcpdump host helios and \\( hot or ace \\)\fP
+.fi
+.RE
+.LP
+To print all IP packets between \fIace\fR and any host except \fIhelios\fR:
+.RS
+.nf
+\fBtcpdump ip host ace and not helios\fP
+.fi
+.RE
+.LP
+To print all traffic between local hosts and hosts at Berkeley:
+.RS
+.nf
+.B
+tcpdump net ucb-ether
+.fi
+.RE
+.LP
+To print all ftp traffic through internet gateway \fIsnup\fP:
+(note that the expression is quoted to prevent the shell from
+(mis-)interpreting the parentheses):
+.RS
+.nf
+.B
+tcpdump 'gateway snup and (port ftp or ftp-data)'
+.fi
+.RE
+.LP
+To print traffic neither sourced from nor destined for local hosts
+(if you gateway to one other net, this stuff should never make it
+onto your local net).
+.RS
+.nf
+.B
+tcpdump ip and not net \fIlocalnet\fP
+.fi
+.RE
+.LP
+To print the start and end packets (the SYN and FIN packets) of each
+TCP conversation that involves a non-local host.
+.RS
+.nf
+.B
+tcpdump 'tcp[13] & 3 != 0 and not src and dst net \fIlocalnet\fP'
+.fi
+.RE
+.LP
+To print IP packets longer than 576 bytes sent through gateway \fIsnup\fP:
+.RS
+.nf
+.B
+tcpdump 'gateway snup and ip[2:2] > 576'
+.fi
+.RE
+.LP
+To print IP broadcast or multicast packets that were
+.I not
+sent via ethernet broadcast or multicast:
+.RS
+.nf
+.B
+tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
+.fi
+.RE
+.LP
+To print all ICMP packets that are not echo requests/replies (i.e., not
+ping packets):
+.RS
+.nf
+.B
+tcpdump 'icmp[0] != 8 and icmp[0] != 0"
+.fi
+.RE
+.SH OUTPUT FORMAT
+.LP
+The output of \fItcpdump\fP is protocol dependent. The following
+gives a brief description and examples of most of the formats.
+.de HD
+.sp 1.5
+.B
+..
+.HD
+Link Level Headers
+.LP
+If the '-e' option is given, the link level header is printed out.
+On ethernets, the source and destination addresses, protocol,
+and packet length are printed.
+.LP
+On FDDI networks, the '-e' option causes \fItcpdump\fP to print
+the `frame control' field, the source and destination addresses,
+and the packet length. (The `frame control' field governs the
+interpretation of the rest of the packet. Normal packets (such
+as those containing IP datagrams) are `async' packets, with a priority
+value between 0 and 7; for example, `\fBasync4\fR'. Such packets
+are assumed to contain an 802.2 Logical Link Control (LLC) packet;
+the LLC header is printed if it is \fInot\fR an ISO datagram or a
+so-called SNAP packet.
+.LP
+\fI(N.B.: The following description assumes familiarity with
+the SLIP compression algorithm described in RFC-1144.)\fP
+.LP
+On SLIP links, a direction indicator (``I'' for inbound, ``O'' for outbound),
+packet type, and compression information are printed out.
+The packet type is printed first.
+The three types are \fIip\fP, \fIutcp\fP, and \fIctcp\fP.
+No further link information is printed for \fIip\fR packets.
+For TCP packets, the connection identifier is printed following the type.
+If the packet is compressed, its encoded header is printed out.
+The special cases are printed out as
+\fB*S+\fIn\fR and \fB*SA+\fIn\fR, where \fIn\fR is the amount by which
+the sequence number (or sequence number and ack) has changed.
+If it is not a special case,
+zero or more changes are printed.
+A change is indicated by U (urgent pointer), W (window), A (ack),
+S (sequence number), and I (packet ID), followed by a delta (+n or -n),
+or a new value (=n).
+Finally, the amount of data in the packet and compressed header length
+are printed.
+.LP
+For example, the following line shows an outbound compressed TCP packet,
+with an implicit connection identifier; the ack has changed by 6,
+the sequence number by 49, and the packet ID by 6; there are 3 bytes of
+data and 6 bytes of compressed header:
+.RS
+.nf
+\fBO ctcp * A+6 S+49 I+6 3 (6)\fP
+.fi
+.RE
+.HD
+ARP/RARP Packets
+.LP
+Arp/rarp output shows the type of request and its arguments. The
+format is intended to be self explanatory.
+Here is a short sample taken from the start of an `rlogin' from
+host \fIrtsg\fP to host \fIcsam\fP:
+.RS
+.nf
+.sp .5
+\f(CWarp who-has csam tell rtsg
+arp reply csam is-at CSAM\fP
+.sp .5
+.fi
+.RE
+The first line says that rtsg sent an arp packet asking
+for the ethernet address of internet host csam. Csam
+replies with its ethernet address (in this example, ethernet addresses
+are in caps and internet addresses in lower case).
+.LP
+This would look less redundant if we had done \fBtcpdump \-n\fP:
+.RS
+.nf
+.sp .5
+\f(CWarp who-has 128.3.254.6 tell 128.3.254.68
+arp reply 128.3.254.6 is-at 02:07:01:00:01:c4\fP
+.fi
+.RE
+.LP
+If we had done \fBtcpdump \-e\fP, the fact that the first packet is
+broadcast and the second is point-to-point would be visible:
+.RS
+.nf
+.sp .5
+\f(CWRTSG Broadcast 0806 64: arp who-has csam tell rtsg
+CSAM RTSG 0806 64: arp reply csam is-at CSAM\fP
+.sp .5
+.fi
+.RE
+For the first packet this says the ethernet source address is RTSG, the
+destination is the broadcast address, the type field
+contained hex 0806 (type ETHER_ARP) and the total length was 64 bytes.
+.HD
+TCP Packets
+.LP
+\fI(N.B.:The following description assumes familiarity with
+the TCP protocol described in RFC-793. If you are not familiar
+with the protocol, neither this description nor tcpdump will
+be of much use to you.)\fP
+.LP
+The general format of a tcp protocol line is:
+.RS
+.nf
+.sp .5
+\fIsrc > dst: flags data-seqno ack window urgent options\fP
+.sp .5
+.fi
+.RE
+\fISrc\fP and \fIdst\fP are the source and destination IP
+addresses and ports. \fIFlags\fP are some combination of S (SYN),
+F (FIN), P (PUSH) or R (RST) or a single `.' (no flags).
+\fIData-seqno\fP describes the portion of sequence space covered
+by the data in this packet (see example below).
+\fIAck\fP is sequence number of the next data expected the other
+direction on this connection.
+\fIWindow\fP is the number of bytes of receive buffer space available
+the other direction on this connection.
+\fIUrg\fP indicates there is `urgent' data in the packet.
+\fIOptions\fP are tcp options enclosed in angle brackets (e.g., <mss 1024>).
+.LP
+\fISrc, dst\fP and \fIflags\fP are always present. The other fields
+depend on the contents of the packet's tcp protocol header and
+are output only if appropriate.
+.LP
+Here is the opening portion of an rlogin from host \fIrtsg\fP to
+host \fIcsam\fP.
+.RS
+.nf
+.sp .5
+\s-2\f(CWrtsg.1023 > csam.login: S 768512:768512(0) win 4096 <mss 1024>
+csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 <mss 1024>
+rtsg.1023 > csam.login: . ack 1 win 4096
+rtsg.1023 > csam.login: P 1:2(1) ack 1 win 4096
+csam.login > rtsg.1023: . ack 2 win 4096
+rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096
+csam.login > rtsg.1023: P 1:2(1) ack 21 win 4077
+csam.login > rtsg.1023: P 2:3(1) ack 21 win 4077 urg 1
+csam.login > rtsg.1023: P 3:4(1) ack 21 win 4077 urg 1\fP\s+2
+.sp .5
+.fi
+.RE
+The first line says that tcp port 1023 on rtsg sent a packet
+to port \fIlogin\fP
+on csam. The \fBS\fP indicates that the \fISYN\fP flag was set.
+The packet sequence number was 768512 and it contained no data.
+(The notation is `first:last(nbytes)' which means `sequence
+numbers \fIfirst\fP
+up to but not including \fIlast\fP which is \fInbytes\fP bytes of user data'.)
+There was no piggy-backed ack, the available receive window was 4096
+bytes and there was a max-segment-size option requesting an mss of
+1024 bytes.
+.LP
+Csam replies with a similar packet except it includes a piggy-backed
+ack for rtsg's SYN. Rtsg then acks csam's SYN. The `.' means no
+flags were set.
+The packet contained no data so there is no data sequence number.
+Note that the ack sequence
+number is a small integer (1). The first time \fBtcpdump\fP sees a
+tcp `conversation', it prints the sequence number from the packet.
+On subsequent packets of the conversation, the difference between
+the current packet's sequence number and this initial sequence number
+is printed. This means that sequence numbers after the
+first can be interpreted
+as relative byte positions in the conversation's data stream (with the
+first data byte each direction being `1'). `-S' will override this
+feature, causing the original sequence numbers to be output.
+.LP
+On the 6th line, rtsg sends csam 19 bytes of data (bytes 2 through 20
+in the rtsg \(-> csam side of the conversation).
+The PUSH flag is set in the packet.
+On the 7th line, csam says it's received data sent by rtsg up to
+but not including byte 21. Most of this data is apparently sitting in the
+socket buffer since csam's receive window has gotten 19 bytes smaller.
+Csam also sends one byte of data to rtsg in this packet.
+On the 8th and 9th lines,
+csam sends two bytes of urgent, pushed data to rtsg.
+.HD
+.B
+UDP Packets
+.LP
+UDP format is illustrated by this rwho packet:
+.RS
+.nf
+.sp .5
+\f(CWactinide.who > broadcast.who: udp 84\fP
+.sp .5
+.fi
+.RE
+This says that port \fIwho\fP on host \fIactinide\fP sent a udp
+datagram to port \fIwho\fP on host \fIbroadcast\fP, the Internet
+broadcast address. The packet contained 84 bytes of user data.
+.LP
+Some UDP services are recognized (from the source or destination
+port number) and the higher level protocol information printed.
+In particular, Domain Name service requests (RFC-1034/1035) and Sun
+RPC calls (RFC-1050) to NFS.
+.HD
+UDP Name Server Requests
+.LP
+\fI(N.B.:The following description assumes familiarity with
+the Domain Service protocol described in RFC-1035. If you are not familiar
+with the protocol, the following description will appear to be written
+in greek.)\fP
+.LP
+Name server requests are formatted as
+.RS
+.nf
+.sp .5
+\fIsrc > dst: id op? flags qtype qclass name (len)\fP
+.sp .5
+\f(CWh2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)\fP
+.sp .5
+.fi
+.RE
+Host \fIh2opolo\fP asked the domain server on \fIhelios\fP for an
+address record (qtype=A) associated with the name \fIucbvax.berkeley.edu.\fP
+The query id was `3'. The `+' indicates the \fIrecursion desired\fP flag
+was set. The query length was 37 bytes, not including the UDP and
+IP protocol headers. The query operation was the normal one, \fIQuery\fP,
+so the op field was omitted. If the op had been anything else, it would
+have been printed between the `3' and the `+'.
+Similarly, the qclass was the normal one,
+\fIC_IN\fP, and omitted. Any other qclass would have been printed
+immediately after the `A'.
+.LP
+A few anomalies are checked and may result in extra fields enclosed in
+square brackets: If a query contains an answer, name server or
+authority section,
+.IR ancount ,
+.IR nscount ,
+or
+.I arcount
+are printed as `[\fIn\fPa]', `[\fIn\fPn]' or `[\fIn\fPau]' where \fIn\fP
+is the appropriate count.
+If any of the response bits are set (AA, RA or rcode) or any of the
+`must be zero' bits are set in bytes two and three, `[b2&3=\fIx\fP]'
+is printed, where \fIx\fP is the hex value of header bytes two and three.
+.HD
+UDP Name Server Responses
+.LP
+Name server responses are formatted as
+.RS
+.nf
+.sp .5
+\fIsrc > dst: id op rcode flags a/n/au type class data (len)\fP
+.sp .5
+\f(CWhelios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273)
+helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)\fP
+.sp .5
+.fi
+.RE
+In the first example, \fIhelios\fP responds to query id 3 from \fIh2opolo\fP
+with 3 answer records, 3 name server records and 7 authority records.
+The first answer record is type A (address) and its data is internet
+address 128.32.137.3. The total size of the response was 273 bytes,
+excluding UDP and IP headers. The op (Query) and response code
+(NoError) were omitted, as was the class (C_IN) of the A record.
+.LP
+In the second example, \fIhelios\fP responds to query 2 with a
+response code of non-existent domain (NXDomain) with no answers,
+one name server and no authority records. The `*' indicates that
+the \fIauthoritative answer\fP bit was set. Since there were no
+answers, no type, class or data were printed.
+.LP
+Other flag characters that might appear are `\-' (recursion available,
+RA, \fInot\fP set) and `|' (truncated message, TC, set). If the
+`question' section doesn't contain exactly one entry, `[\fIn\fPq]'
+is printed.
+.LP
+Note that name server requests and responses tend to be large and the
+default \fIsnaplen\fP of 96 bytes may not capture enough of the packet
+to print. Use the \fB\-s\fP flag to increase the snaplen if you
+need to seriously investigate name server traffic. `\fB\-s 128\fP'
+has worked well for me.
+
+.HD
+NFS Requests and Replies
+.LP
+Sun NFS (Network File System) requests and replies are printed as:
+.RS
+.nf
+.sp .5
+\fIsrc.xid > dst.nfs: len op args\fP
+\fIsrc.nfs > dst.xid: reply stat len op results\fP
+.sp .5
+\f(CW
+sushi.6709 > wrl.nfs: 112 readlink fh 21,24/10.73165
+wrl.nfs > sushi.6709: reply ok 40 readlink "../var"
+sushi.201b > wrl.nfs:
+ 144 lookup fh 9,74/4096.6878 "xcolors"
+wrl.nfs > sushi.201b:
+ reply ok 128 lookup fh 9,74/4134.3150
+\fP
+.sp .5
+.fi
+.RE
+In the first line, host \fIsushi\fP sends a transaction with id \fI6709\fP
+to \fIwrl\fP (note that the number following the src host is a
+transaction id, \fInot\fP the source port). The request was 112 bytes,
+excluding the UDP and IP headers. The operation was a \fIreadlink\fP
+(read symbolic link) on file handle (\fIfh\fP) 21,24/10.731657119.
+(If one is lucky, as in this case, the file handle can be interpreted
+as a major,minor device number pair, followed by the inode number and
+generation number.)
+\fIWrl\fP replies `ok' with the contents of the link.
+.LP
+In the third line, \fIsushi\fP asks \fIwrl\fP to lookup the name
+`\fIxcolors\fP' in directory file 9,74/4096.6878. Note that the data printed
+depends on the operation type. The format is intended to be self
+explanatory if read in conjunction with
+an NFS protocol spec.
+.LP
+If the \-v (verbose) flag is given, additional information is printed.
+For example:
+.RS
+.nf
+.sp .5
+\f(CW
+sushi.1372a > wrl.nfs:
+ 148 read fh 21,11/12.195 8192 bytes @ 24576
+wrl.nfs > sushi.1372a:
+ reply ok 1472 read REG 100664 ids 417/0 sz 29388
+\fP
+.sp .5
+.fi
+.RE
+(\-v also prints the IP header TTL, ID, and fragmentation fields,
+which have been omitted from this example.) In the first line,
+\fIsushi\fP asks \fIwrl\fP to read 8192 bytes from file 21,11/12.195,
+at byte offset 24576. \fIWrl\fP replies `ok'; the packet shown on the
+second line is the first fragment of the reply, and hence is only 1472
+bytes long (the other bytes will follow in subsequent fragments, but
+these fragments do not have NFS or even UDP headers and so might not be
+printed, depending on the filter expression used). Because the \-v flag
+is given, some of the file attributes (which are returned in addition
+to the file data) are printed: the file type (``REG'', for regular file),
+the file mode (in octal), the uid and gid, and the file size.
+.LP
+If the \-v flag is given more than once, even more details are printed.
+.LP
+Note that NFS requests are very large and much of the detail won't be printed
+unless \fIsnaplen\fP is increased. Try using `\fB\-s 192\fP' to watch
+NFS traffic.
+.LP
+NFS reply packets do not explicitly identify the RPC operation. Instead,
+\fItcpdump\fP keeps track of ``recent'' requests, and matches them to the
+replies using the transaction ID. If a reply does not closely follow the
+corresponding request, it might not be parseble.
+.HD
+KIP Appletalk (DDP in UDP)
+.LP
+Appletalk DDP packets encapsulated in UDP datagrams are de-encapsulated
+and dumped as DDP packets (i.e., all the UDP header information is
+discarded). The file
+.I /etc/atalk.names
+is used to translate appletalk net and node numbers to names.
+Lines in this file have the form
+.RS
+.nf
+.sp .5
+\fInumber name\fP
+
+\f(CW1.254 ether
+16.1 icsd-net
+1.254.110 ace\fP
+.sp .5
+.fi
+.RE
+The first two lines give the names of appletalk networks. The third
+line gives the name of a particular host (a host is distinguished
+from a net by the 3rd octet in the number \-
+a net number \fImust\fP have two octets and a host number \fImust\fP
+have three octets.) The number and name should be separated by
+whitespace (blanks or tabs).
+The
+.I /etc/atalk.names
+file may contain blank lines or comment lines (lines starting with
+a `#').
+.LP
+Appletalk addresses are printed in the form
+.RS
+.nf
+.sp .5
+\fInet.host.port\fP
+
+\f(CW144.1.209.2 > icsd-net.112.220
+office.2 > icsd-net.112.220
+jssmag.149.235 > icsd-net.2\fP
+.sp .5
+.fi
+.RE
+(If the
+.I /etc/atalk.names
+doesn't exist or doesn't contain an entry for some appletalk
+host/net number, addresses are printed in numeric form.)
+In the first example, NBP (DDP port 2) on net 144.1 node 209
+is sending to whatever is listening on port 220 of net icsd node 112.
+The second line is the same except the full name of the source node
+is known (`office'). The third line is a send from port 235 on
+net jssmag node 149 to broadcast on the icsd-net NBP port (note that
+the broadcast address (255) is indicated by a net name with no host
+number \- for this reason it's a good idea to keep node names and
+net names distinct in /etc/atalk.names).
+.LP
+NBP (name binding protocol) and ATP (Appletalk transaction protocol)
+packets have their contents interpreted. Other protocols just dump
+the protocol name (or number if no name is registered for the
+protocol) and packet size.
+
+\fBNBP packets\fP are formatted like the following examples:
+.RS
+.nf
+.sp .5
+\s-2\f(CWicsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*"
+jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250
+techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186\fP\s+2
+.sp .5
+.fi
+.RE
+The first line is a name lookup request for laserwriters sent by net icsd host
+112 and broadcast on net jssmag. The nbp id for the lookup is 190.
+The second line shows a reply for this request (note that it has the
+same id) from host jssmag.209 saying that it has a laserwriter
+resource named "RM1140" registered on port 250. The third line is
+another reply to the same request saying host techpit has laserwriter
+"techpit" registered on port 186.
+
+\fBATP packet\fP formatting is demonstrated by the following example:
+.RS
+.nf
+.sp .5
+\s-2\f(CWjssmag.209.165 > helios.132: atp-req 12266<0-7> 0xae030001
+helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000
+jssmag.209.165 > helios.132: atp-req 12266<3,5> 0xae030001
+helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
+jssmag.209.165 > helios.132: atp-rel 12266<0-7> 0xae030001
+jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002\fP\s+2
+.sp .5
+.fi
+.RE
+Jssmag.209 initiates transaction id 12266 with host helios by requesting
+up to 8 packets (the `<0-7>'). The hex number at the end of the line
+is the value of the `userdata' field in the request.
+.LP
+Helios responds with 8 512-byte packets. The `:digit' following the
+transaction id gives the packet sequence number in the transaction
+and the number in parens is the amount of data in the packet,
+excluding the atp header. The `*' on packet 7 indicates that the
+EOM bit was set.
+.LP
+Jssmag.209 then requests that packets 3 & 5 be retransmitted. Helios
+resends them then jssmag.209 releases the transaction. Finally,
+jssmag.209 initiates the next request. The `*' on the request
+indicates that XO (`exactly once') was \fInot\fP set.
+
+.HD
+IP Fragmentation
+.LP
+Fragmented Internet datagrams are printed as
+.RS
+.nf
+.sp .5
+\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB+)\fR
+\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB)\fR
+.sp .5
+.fi
+.RE
+(The first form indicates there are more fragments. The second
+indicates this is the last fragment.)
+.LP
+\fIId\fP is the fragment id. \fISize\fP is the fragment
+size (in bytes) excluding the IP header. \fIOffset\fP is this
+fragment's offset (in bytes) in the original datagram.
+.LP
+The fragment information is output for each fragment. The first
+fragment contains the higher level protocol header and the frag
+info is printed after the protocol info. Fragments
+after the first contain no higher level protocol header and the
+frag info is printed after the source and destination addresses.
+For example, here is part of an ftp from arizona.edu to lbl-rtsg.arpa
+over a CSNET connection that doesn't appear to handle 576 byte datagrams:
+.RS
+.nf
+.sp .5
+\s-2\f(CWarizona.ftp-data > rtsg.1170: . 1024:1332(308) ack 1 win 4096 (frag 595a:328@0+)
+arizona > rtsg: (frag 595a:204@328)
+rtsg.1170 > arizona.ftp-data: . ack 1536 win 2560\fP\s+2
+.sp .5
+.fi
+.RE
+There are a couple of things to note here: First, addresses in the
+2nd line don't include port numbers. This is because the TCP
+protocol information is all in the first fragment and we have no idea
+what the port or sequence numbers are when we print the later fragments.
+Second, the tcp sequence information in the first line is printed as if there
+were 308 bytes of user data when, in fact, there are 512 bytes (308 in
+the first frag and 204 in the second). If you are looking for holes
+in the sequence space or trying to match up acks
+with packets, this can fool you.
+.LP
+A packet with the IP \fIdon't fragment\fP flag is marked with a
+trailing \fB(DF)\fP.
+.HD
+Timestamps
+.LP
+By default, all output lines are preceded by a timestamp. The timestamp
+is the current clock time in the form
+.RS
+.nf
+\fIhh:mm:ss.frac\fP
+.fi
+.RE
+and is as accurate as the kernel's clock (e.g., \(+-10ms on a Sun-3).
+The timestamp reflects the time the kernel first saw the packet. No attempt
+is made to account for the time lag between when the
+ethernet interface removed the packet from the wire and when the kernel
+serviced the `new packet' interrupt (of course,
+with Sun's lousy clock resolution this time lag is negligible.)
+.SH "SEE ALSO"
+traffic(1C), nit(4P), bpf(4)
+.SH AUTHORS
+Van Jacobson (van@helios.ee.lbl.gov),
+Craig Leres (leres@helios.ee.lbl.gov) and
+Steven McCanne (mccanne@helios.ee.lbl.gov), all of
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
+.SH BUGS
+The clock resolution on most Suns is pathetic (20ms).
+If you want to use the timestamp to generate some of the important
+performance distributions (like packet interarrival time) it's best
+to watch something that generates packets slowly (like an Arpanet
+gateway or a MicroVax running VMS).
+.LP
+NIT doesn't let you watch your own outbound traffic, BPF will.
+We recommend that you use the latter.
+.LP
+\fItcpdump\fP for Ultrix requires Ultrix version 4.0 or later; the kernel
+has to have been built with the \fIpacketfilter\fP pseudo-device driver
+(see
+.IR packetfilter (4)).
+In order to watch either your own outbound or inbound traffic,
+you will need to use Ultrix version 4.2 or later, and you will have
+to have used the
+.IR pfconfig (8)
+command to enable ``copyall'' mode.
+.LP
+Under SunOS 4.1, the packet capture code (or Streams NIT) is not what
+you'd call efficient. Don't plan on doing much with your Sun while
+you're monitoring a busy network.
+.LP
+On Sun systems prior to release 3.2, NIT is very buggy.
+If run on an old system, tcpdump may crash the machine.
+.LP
+Some attempt should be made to reassemble IP fragments or, at least
+to compute the right length for the higher level protocol.
+.LP
+Name server inverse queries are not dumped correctly: The (empty)
+question section is printed rather than real query in the answer
+section. Some believe that inverse queries are themselves a bug and
+prefer to fix the program generating them rather than tcpdump.
+.LP
+Apple Ethertalk DDP packets could be dumped as easily as KIP DDP
+packets but aren't.
+Even if we were inclined to do anything to promote the use of
+Ethertalk (we aren't), LBL doesn't allow Ethertalk on any of its
+networks so we'd would have no way of testing this code.
+.LP
+A packet trace that crosses a daylight savings time change will give
+skewed time stamps (the time change is ignored).
+.LP
+Filters expressions that manipulate FDDI headers assume that all FDDI
+packets are encapsulated Ethernet packets. This is true for IP, ARP,
+and DECNET Phase IV, but is not true for protocols such as ISO CLNS.
+Therefore, the filter may inadvertently accept certain packets that
+do not properly match the filter expression.
diff --git a/usr.sbin/tcpdump/tcpdump.c b/usr.sbin/tcpdump/tcpdump.c
new file mode 100644
index 00000000000..fc6b153c80a
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump.c
@@ -0,0 +1,413 @@
+/* $NetBSD: tcpdump.c,v 1.3 1995/04/24 13:27:48 cgd Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+char copyright[] =
+ "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994\nThe Regents of the University of California. All rights reserved.\n";
+static char rcsid[] =
+ "@(#)Header: tcpdump.c,v 1.93 94/06/10 17:01:44 mccanne Exp (LBL)";
+#endif
+
+/*
+ * tcpdump - monitor tcp/ip traffic on an ethernet.
+ *
+ * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
+ * Mercilessly hacked and occasionally improved since then via the
+ * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <pcap.h>
+#include <signal.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+int fflag; /* don't translate "foreign" IP address */
+int nflag; /* leave addresses as numbers */
+int Nflag; /* remove domains from printed host names */
+int pflag; /* don't go promiscuous */
+int qflag; /* quick (shorter) output */
+int tflag = 1; /* print packet arrival time */
+int eflag; /* print ethernet header */
+int vflag; /* verbose */
+int xflag; /* print packet in hex */
+int Oflag = 1; /* run filter code optimizer */
+int Sflag; /* print raw TCP sequence numbers */
+int packettype;
+
+int dflag; /* print filter code */
+
+char *program_name;
+
+int thiszone;
+
+SIGRET cleanup(int);
+extern void bpf_dump(struct bpf_program *, int);
+
+/* Length of saved portion of packet. */
+int snaplen = DEFAULT_SNAPLEN;
+
+struct printer {
+ pcap_handler f;
+ int type;
+};
+
+static struct printer printers[] = {
+ { ether_if_print, DLT_EN10MB },
+ { sl_if_print, DLT_SLIP },
+ { ppp_if_print, DLT_PPP },
+ { fddi_if_print, DLT_FDDI },
+ { null_if_print, DLT_NULL },
+ { NULL, 0 },
+};
+
+static pcap_handler
+lookup_printer(int type)
+{
+ struct printer *p;
+
+ for (p = printers; p->f; ++p)
+ if (type == p->type)
+ return p->f;
+
+ error("unknown data link type 0x%x", type);
+ /* NOTREACHED */
+}
+
+static pcap_t *pd;
+
+#ifdef __osf__
+#include <sys/sysinfo.h>
+#include <sys/proc.h>
+void
+abort_on_misalignment()
+{
+ int buf[2];
+
+ buf[0] = SSIN_UACPROC;
+ buf[1] = UAC_SIGBUS;
+ if (setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0) < 0) {
+ perror("setsysinfo");
+ exit(1);
+ }
+}
+
+#endif
+
+int
+main(int argc, char **argv)
+{
+ register int cnt, op;
+ u_long localnet, netmask;
+ register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
+ pcap_handler printer;
+ struct bpf_program fcode;
+ u_char *pcap_userdata;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ extern char *optarg;
+ extern int optind, opterr;
+
+#ifdef __osf__
+ abort_on_misalignment();
+#endif
+
+ cnt = -1;
+ device = NULL;
+ infile = NULL;
+ RFileName = NULL;
+ WFileName = NULL;
+ if ((cp = strrchr(argv[0], '/')) != NULL)
+ program_name = cp + 1;
+ else
+ program_name = argv[0];
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "c:defF:i:lnNOpqr:s:StT:vw:xY")) != EOF)
+ switch (op) {
+ case 'c':
+ cnt = atoi(optarg);
+ break;
+
+ case 'd':
+ ++dflag;
+ break;
+
+ case 'e':
+ ++eflag;
+ break;
+
+ case 'f':
+ ++fflag;
+ break;
+
+ case 'F':
+ infile = optarg;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 'l':
+ setlinebuf(stdout);
+ break;
+
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'N':
+ ++Nflag;
+ break;
+
+ case 'O':
+ Oflag = 0;
+ break;
+
+ case 'p':
+ ++pflag;
+ break;
+
+ case 'q':
+ ++qflag;
+ break;
+
+ case 'r':
+ RFileName = optarg;
+ break;
+
+ case 's':
+ snaplen = atoi(optarg);
+ break;
+
+ case 'S':
+ ++Sflag;
+ break;
+
+ case 't':
+ --tflag;
+ break;
+
+ case 'T':
+ if (strcasecmp(optarg, "vat") == 0)
+ packettype = 1;
+ else if (strcasecmp(optarg, "wb") == 0)
+ packettype = 2;
+ else if (strcasecmp(optarg, "rpc") == 0)
+ packettype = 3;
+ else if (strcasecmp(optarg, "rtp") == 0)
+ packettype = 4;
+ else
+ error("unknown packet type `%s'", optarg);
+ break;
+
+ case 'v':
+ ++vflag;
+ break;
+
+ case 'w':
+ WFileName = optarg;
+ break;
+#ifdef YYDEBUG
+ case 'Y':
+ {
+ extern int yydebug;
+ yydebug = 1;
+ }
+ break;
+#endif
+ case 'x':
+ ++xflag;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (tflag > 0)
+ thiszone = gmt2local();
+
+ if (RFileName != NULL) {
+ /*
+ * We don't need network access, so set it back to the user id.
+ * Also, this prevents the user from reading anyone's
+ * trace file.
+ */
+ setuid(getuid());
+
+ pd = pcap_open_offline(RFileName, errbuf);
+ if (pd == NULL)
+ error(errbuf);
+ localnet = 0;
+ netmask = 0;
+ if (fflag != 0)
+ error("-f and -r options are incompatible");
+ } else {
+ if (device == NULL) {
+ device = pcap_lookupdev(errbuf);
+ if (device == NULL)
+ error(errbuf);
+ }
+ pd = pcap_open_live(device, snaplen, !pflag, 1000, errbuf);
+ if (pd == NULL)
+ error(errbuf);
+ if (pcap_lookupnet(device, &localnet, &netmask, errbuf) < 0)
+ error(errbuf);
+ /*
+ * Let user own process after socket has been opened.
+ */
+ setuid(getuid());
+ }
+ if (infile)
+ cmdbuf = read_infile(infile);
+ else
+ cmdbuf = copy_argv(&argv[optind]);
+
+ if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+ error(pcap_geterr(pd));
+ if (dflag) {
+ bpf_dump(&fcode, dflag);
+ exit(0);
+ }
+ init_addrtoname(fflag, localnet, netmask);
+
+ (void)signal(SIGTERM, cleanup);
+ (void)signal(SIGINT, cleanup);
+ (void)signal(SIGHUP, cleanup);
+
+ if (pcap_setfilter(pd, &fcode) < 0)
+ error(pcap_geterr(pd));
+ if (WFileName) {
+ pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
+ if (p == NULL)
+ error(pcap_geterr(pd));
+ printer = pcap_dump;
+ pcap_userdata = (u_char *)p;
+ } else {
+ printer = lookup_printer(pcap_datalink(pd));
+ pcap_userdata = 0;
+ }
+ if (RFileName == NULL) {
+ fprintf(stderr, "%s: listening on %s\n", program_name, device);
+ fflush(stderr);
+ }
+ pcap_loop(pd, cnt, printer, pcap_userdata);
+ pcap_close(pd);
+ exit(0);
+}
+
+/* make a clean exit on interrupts */
+SIGRET
+cleanup(int signo)
+{
+ struct pcap_stat stat;
+
+ /* Can't print the summary if reading from a savefile */
+ if (pd != NULL && pcap_file(pd) == NULL) {
+ (void)fflush(stdout);
+ putc('\n', stderr);
+ if (pcap_stats(pd, &stat) < 0)
+ (void)fprintf(stderr, "pcap_stats: %s\n",
+ pcap_geterr(pd));
+ else {
+ (void)fprintf(stderr, "%d packets received by filter\n",
+ stat.ps_recv);
+ (void)fprintf(stderr, "%d packets dropped by kernel\n",
+ stat.ps_drop);
+ }
+ }
+ exit(0);
+}
+
+/* Like default_print() but data need not be aligned */
+void
+default_print_unaligned(register const u_char *cp, register int length)
+{
+ register u_int i, s;
+ register int nshorts;
+
+ nshorts = (u_int) length / sizeof(u_short);
+ i = 0;
+ while (--nshorts >= 0) {
+ if ((i++ % 8) == 0)
+ (void)printf("\n\t\t\t");
+ s = *cp++;
+ (void)printf(" %02x%02x", s, *cp++);
+ }
+ if (length & 1) {
+ if ((i % 8) == 0)
+ (void)printf("\n\t\t\t");
+ (void)printf(" %02x", *cp);
+ }
+}
+
+void
+default_print(register const u_char *bp, register int length)
+{
+ register const u_short *sp;
+ register u_int i;
+ register int nshorts;
+
+ if ((long)bp & 1) {
+ default_print_unaligned(bp, length);
+ return;
+ }
+ sp = (u_short *)bp;
+ nshorts = (u_int) length / sizeof(u_short);
+ i = 0;
+ while (--nshorts >= 0) {
+ if ((i++ % 8) == 0)
+ (void)printf("\n\t\t\t");
+ (void)printf(" %04x", ntohs(*sp++));
+ }
+ if (length & 1) {
+ if ((i % 8) == 0)
+ (void)printf("\n\t\t\t");
+ (void)printf(" %02x", *(u_char *)sp);
+ }
+}
+
+void
+usage()
+{
+ extern char version[];
+
+ (void)fprintf(stderr, "Version %s\n", version);
+ (void)fprintf(stderr,
+"Usage: tcpdump [-deflnOpqtvx] [-c count] [-i interface]\n");
+ (void)fprintf(stderr,
+"\t\t[-r filename] [-w filename] [expr]\n");
+ exit(-1);
+}
diff --git a/usr.sbin/tcpdump/util.c b/usr.sbin/tcpdump/util.c
new file mode 100644
index 00000000000..2c456a85e27
--- /dev/null
+++ b/usr.sbin/tcpdump/util.c
@@ -0,0 +1,337 @@
+/* $NetBSD: util.c,v 1.3 1995/03/06 19:11:53 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) Header: util.c,v 1.28 94/06/12 14:30:31 leres Exp (LBL)";
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#ifdef SOLARIS
+#include <fcntl.h>
+#endif
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+
+#include "interface.h"
+
+/*
+ * Print out a filename (or other ascii string).
+ * If ep is NULL, assume no truncation check is needed.
+ * Return true if truncated.
+ */
+int
+fn_print(register const u_char *s, register const u_char *ep)
+{
+ register int ret;
+ register u_char c;
+
+ ret = 1; /* assume truncated */
+ putchar('"');
+ while (ep == NULL || s < ep) {
+ c = *s++;
+ if (c == '\0') {
+ ret = 0;
+ break;
+ }
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+ return(ret);
+}
+
+/*
+ * Print out a counted filename (or other ascii string).
+ * If ep is NULL, assume no truncation check is needed.
+ * Return true if truncated.
+ */
+int
+fn_printn(register const u_char *s, register u_int n,
+ register const u_char *ep)
+{
+ register int ret;
+ register u_char c;
+
+ ret = 1; /* assume truncated */
+ putchar('"');
+ while (ep == NULL || s < ep) {
+ if (n-- <= 0) {
+ ret = 0;
+ break;
+ }
+ c = *s++;
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+ return(ret);
+}
+
+/*
+ * Print the timestamp
+ */
+void
+ts_print(register const struct timeval *tvp)
+{
+ register int s;
+ extern int32 thiszone;
+
+ if (tflag > 0) {
+ /* Default */
+ s = (tvp->tv_sec + thiszone) % 86400;
+ (void)printf("%02d:%02d:%02d.%06d ",
+ s / 3600, (s % 3600) / 60, s % 60, tvp->tv_usec);
+ } else if (tflag < 0) {
+ /* Unix timeval style */
+ (void)printf("%d.%06d ", tvp->tv_sec, tvp->tv_usec);
+ }
+}
+
+/*
+ * Convert a token value to a string; use "fmt" if not found.
+ */
+const char *
+tok2str(register const struct token *lp, register const char *fmt,
+ register int v)
+{
+ static char buf[128];
+
+ while (lp->s != NULL) {
+ if (lp->v == v)
+ return (lp->s);
+ ++lp;
+ }
+ if (fmt == NULL)
+ fmt = "#%d";
+ (void)sprintf(buf, fmt, v);
+ return (buf);
+}
+
+/* A replacement for strdup() that cuts down on malloc() overhead */
+char *
+savestr(register const char *str)
+{
+ register u_int size;
+ register char *p;
+ static char *strptr = NULL;
+ static u_int strsize = 0;
+
+ size = strlen(str) + 1;
+ if (size > strsize) {
+ strsize = 1024;
+ if (strsize < size)
+ strsize = size;
+ strptr = malloc(strsize);
+ if (strptr == NULL)
+ error("savestr: malloc");
+ }
+ (void)strcpy(strptr, str);
+ p = strptr;
+ strptr += size;
+ strsize -= size;
+ return (p);
+}
+
+#ifdef NOVFPRINTF
+/*
+ * Stock 4.3 doesn't have vfprintf.
+ * This routine is due to Chris Torek.
+ */
+vfprintf(f, fmt, args)
+ FILE *f;
+ char *fmt;
+ va_list args;
+{
+ int ret;
+
+ if ((f->_flag & _IOWRT) == 0) {
+ if (f->_flag & _IORW)
+ f->_flag |= _IOWRT;
+ else
+ return EOF;
+ }
+ ret = _doprnt(fmt, args, f);
+ return ferror(f) ? EOF : ret;
+}
+#endif
+
+/* VARARGS */
+__dead void
+#if __STDC__ || defined(SOLARIS)
+error(char *fmt, ...)
+#else
+error(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: ", program_name);
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+ exit(1);
+ /* NOTREACHED */
+}
+
+/* VARARGS */
+void
+#if __STDC__ || defined(SOLARIS)
+warning(char *fmt, ...)
+#else
+warning(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: warning: ", program_name);
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+}
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+char *
+copy_argv(register char **argv)
+{
+ register char **p;
+ register int len = 0;
+ char *buf;
+ char *src, *dst;
+
+ p = argv;
+ if (*p == 0)
+ return 0;
+
+ while (*p)
+ len += strlen(*p++) + 1;
+
+ buf = malloc(len);
+
+ p = argv;
+ dst = buf;
+ while ((src = *p++) != NULL) {
+ while ((*dst++ = *src++) != '\0')
+ ;
+ dst[-1] = ' ';
+ }
+ dst[-1] = '\0';
+
+ return buf;
+}
+
+char *
+read_infile(char *fname)
+{
+ struct stat buf;
+ int fd;
+ char *p;
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0)
+ error("can't open '%s'", fname);
+
+ if (fstat(fd, &buf) < 0)
+ error("can't state '%s'", fname);
+
+ p = malloc((u_int)buf.st_size);
+ if (read(fd, p, (int)buf.st_size) != buf.st_size)
+ error("problem reading '%s'", fname);
+
+ return p;
+}
+
+int
+gmt2local()
+{
+#ifndef SOLARIS
+ struct timeval now;
+ struct timezone tz;
+ long t;
+
+ if (gettimeofday(&now, &tz) < 0)
+ error("gettimeofday");
+ t = tz.tz_minuteswest * -60;
+ if (localtime((time_t *)&now.tv_sec)->tm_isdst)
+ t += 3600;
+ return (t);
+#else
+ tzset();
+ return (-altzone);
+#endif
+}
diff --git a/usr.sbin/tcpdump/version.c b/usr.sbin/tcpdump/version.c
new file mode 100644
index 00000000000..33cc7ff833a
--- /dev/null
+++ b/usr.sbin/tcpdump/version.c
@@ -0,0 +1,3 @@
+/* $NetBSD: version.c,v 1.2 1995/03/06 19:11:56 mycroft Exp $ */
+
+char version[] = "3.0";
diff --git a/usr.sbin/timed/CHANGES b/usr.sbin/timed/CHANGES
new file mode 100644
index 00000000000..773f4774905
--- /dev/null
+++ b/usr.sbin/timed/CHANGES
@@ -0,0 +1,144 @@
+# @(#)CHANGES 5.1 (Berkeley) 5/11/93
+
+This new version is almost identical to the timed and timedc code
+that has been shipped for years by a workstation vendor.
+
+Among the many changes:
+
+improve `timedc msite` to accept a list of hostnames.
+
+change slave-masters to answer the packets generated by `timedc msite`
+ with the name of the real master, not their own. This makes it
+ possible to "chase the chain" of slave servers to the ultimate
+ master.
+
+much improve the log caused by `timedc trace on`:
+ -made `timed -t` work.
+ -suppression of repeated entries, which both slowed down the daemon
+ (sometimes catastrophically) and tended to make disks fill up
+ even more quickly.
+ -better time stamps on log entries
+ -more messages
+ -dump information about slaves, master, and so on each time
+ a message asking the log be turned on is received, and
+ when the log is turned off.
+ -fewer CPU cycles
+
+use a hash table to keep track of slaves, instead of the stupid linear
+ list. This becomes handy with hundreds of slaves, instead of
+ the original design limit of "a room with a few VAX's."
+
+separate the main protocol timer from that used to look for other networks
+ to master.
+
+time stamp packets received by the daemon, so that time corrections
+ are not made (even more) inaccurate by waiting in the internal,
+ timed queue while the daemon is processing other messages.
+
+made -n and -i work with subnets not named in /etc/networks
+
+compute the median of the measured clocks, instead of the average
+ of "good" times.
+
+vastly improve the accuracy of the clock difference measure by
+ `timedc clockdiff`.
+
+use adjtime() when possible, and directly set the clock only when
+ necessary.
+
+when the requested adjustment is small, perform only part of it, to
+ damp oscillations and improve the long term accuracy of the
+ adjustments.
+
+fix uncounted core-dumps on machines that do not allow dereferencing 0
+ in both the daemon and timedc.
+
+fix "master loop detection".
+
+fix several cases in which multi-homed masters could get into shouting
+ matches, consuming all available network bandwidth and CPU cycles
+ (which ever runs out first), and convincing all bystanders to stop
+ advancing their own clocks.
+
+refuse to behave badly when other machines do. Instead of arguing forever,
+ go off and sulk when other machines refuse to play by the rules.
+
+increase the maximum number of clients.
+
+add "-F host,host2,..." to "freerun" or "trust" only some hosts. This
+ is handy both when only some machines should be trusted to let
+ root use the `date` command to change time in the network.
+
+ It is also handy when one machine has some other way of adjusting
+ its clock, whether NTP or a direct radio or atomic connection.
+ "-F localhost" causes `timed` to "trust" only itself.
+
+ It is also handy to build a hierarchy of timed masters crossing
+ networks. The TSP protocol has no provision of "goodness of clock",
+ no natural way to completely heal network paritions. Judicious
+ use of -F or -G can cause each gateway to trust only itself and
+ machines closer to a central machine with a radio or atomic clock.
+
+add #ifdef code that supports NIS "netgroups" of trusted hosts, which
+ can be easier to administer than -F.
+
+add #ifdef code to compute an aged total adjustment. This can be used
+ in systems that can make long term changes in their system clock
+ frequency, e.g. "timetrim" in the Silicon Graphics kernel.
+
+
+Problems observed by others that are unresolved include:
+
+Practically any users can send to the master TSP messages and this
+ way corrupt the reliability of the system. Authentication
+ of messages should be provided. Unfortunately, that would
+ require changing the protocol with all of the implied
+ compatiblity problems. Fortunately, the new -F and -G args
+ can be used to cause the daemon to ignore time changes from
+ untrusted machines.
+
+MAN. The limit of 1013 on the number of slaves hosts should be doc'ed.
+
+ It should be dynamically allocated with no limit. On a
+ large network, one host could possibly master over many
+ more than 30 hosts. Given the timers in the code and
+ effectively in the protocol, and the time required by each
+ master to talk to each slave, it is not practical to have
+ more than 200-300 slaves. The master cannot keep up because
+ the slave-chatting is single-threaded. when the master
+ gets behind, slaves start demanding elections. To
+ significantly increase the number of slaves would require
+ multi-treading things, and given that a network with more
+ than 300 directly addressable machines has worse problems
+ than keep the time of day right, not worth worrying about.
+
+UGLY,CODE. timedc/cmds.c has a lots of repeated code in it.
+
+**** The first thing is that each command is set up as if it
+ were an individual program taking argc and argv. A more
+ conventional calling style should be used. I don't think
+ any of the routines take more than a couple arguments.
+
+UGLY. fxn definition syntax does't follow convention:
+ has type on same line.
+
+**** It needs to be fixed at least enough that tags
+ will work on it. An entire cleanup might be nice later, but
+ is noncritical.
+
+LOBBY(mildly),CODE: Would be very convenient if date(1) took a
+ +-<number> argument to set the time relatively. With
+ the advent of timed it is now reasonable to synchronize
+ with WWV, which is nearly impossible to do "by hand"
+ with just an absolute date, and scripts are too slow.
+ format could be +-nn...nn.ss, where the '.' is required
+ to remove ambiguity.
+
+**** If you want to do it go ahead. It sounds useful. As far as
+ syntax goes, the normal format for the date should work just
+ fine for this. If the date is preceeded by a plus or minus,
+ the change is relative, otherwise it is absolute.
+
+
+Vernon Schryver.
+vjs@sgi.com
diff --git a/usr.sbin/timed/Makefile b/usr.sbin/timed/Makefile
new file mode 100644
index 00000000000..1870dee25dd
--- /dev/null
+++ b/usr.sbin/timed/Makefile
@@ -0,0 +1,6 @@
+# from: @(#)Makefile 5.1 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:27 deraadt Exp $
+
+SUBDIR= timed timedc
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/timed/timed/Makefile b/usr.sbin/timed/timed/Makefile
new file mode 100644
index 00000000000..45b8a673cca
--- /dev/null
+++ b/usr.sbin/timed/timed/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 5.12 (Berkeley) 5/7/93
+#
+# optional flags are: MEASURE TESTING DEBUG
+
+PROG= timed
+SRCS= acksend.c candidate.c correct.c master.c networkdelta.c readmsg.c \
+ slave.c timed.c byteorder.c measure.c cksum.c
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+MAN= timed.8
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/timed/timed/acksend.c b/usr.sbin/timed/timed/acksend.c
new file mode 100644
index 00000000000..c1a94fa7241
--- /dev/null
+++ b/usr.sbin/timed/timed/acksend.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)acksend.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+
+
+struct tsp *answer;
+
+extern u_short sequence;
+
+void
+xmit(int type,
+ u_short seq,
+ struct sockaddr_in *addr)
+{
+ static struct tsp msg;
+
+ msg.tsp_type = type;
+ msg.tsp_seq = seq;
+ msg.tsp_vers = TSPVERSION;
+ (void)strcpy(msg.tsp_name, hostname);
+ bytenetorder(&msg);
+ if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(addr->sin_addr);
+ }
+}
+
+
+/*
+ * Acksend implements reliable datagram transmission by using sequence
+ * numbers and retransmission when necessary.
+ * If `name' is ANYADDR, this routine implements reliable broadcast.
+ *
+ * Because this function calls readmsg(), none of its args may be in
+ * a message provided by readmsg().
+ */
+struct tsp *
+acksend(struct tsp *message, /* this message */
+ struct sockaddr_in *addr, char *name, /* to here */
+ int ack, /* look for this ack */
+ struct netinfo *net, /* receive from this network */
+ int bad) /* 1=losing patience */
+{
+ struct timeval twait;
+ int count;
+ long msec;
+
+ message->tsp_vers = TSPVERSION;
+ message->tsp_seq = sequence;
+ if (trace) {
+ fprintf(fd, "acksend: to %s: ",
+ (name == ANYADDR ? "broadcast" : name));
+ print(message, addr);
+ }
+ bytenetorder(message);
+
+ msec = 200;
+ count = bad ? 1 : 5; /* 5 packets in 6.4 seconds */
+ answer = 0;
+ do {
+ if (!answer) {
+ /* do not go crazy transmitting just because the
+ * other guy cannot keep our sequence numbers
+ * straight.
+ */
+ if (sendto(sock, (char *)message, sizeof(struct tsp),
+ 0, (struct sockaddr*)addr,
+ sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(addr->sin_addr);
+ break;
+ }
+ }
+
+ mstotvround(&twait, msec);
+ answer = readmsg(ack, name, &twait, net);
+ if (answer != 0) {
+ if (answer->tsp_seq != sequence) {
+ if (trace)
+ fprintf(fd,"acksend: seq # %u!=%u\n",
+ answer->tsp_seq, sequence);
+ continue;
+ }
+ break;
+ }
+
+ msec *= 2;
+ } while (--count > 0);
+ sequence++;
+
+ return(answer);
+}
diff --git a/usr.sbin/timed/timed/byteorder.c b/usr.sbin/timed/timed/byteorder.c
new file mode 100644
index 00000000000..9c82f88926c
--- /dev/null
+++ b/usr.sbin/timed/timed/byteorder.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)byteorder.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+
+/*
+ * Two routines to do the necessary byte swapping for timed protocol
+ * messages. Protocol is defined in /usr/include/protocols/timed.h
+ */
+void
+bytenetorder(struct tsp *ptr)
+{
+ ptr->tsp_seq = htons((u_short)ptr->tsp_seq);
+ switch (ptr->tsp_type) {
+
+ case TSP_SETTIME:
+ case TSP_ADJTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec);
+ ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec);
+ break;
+
+ default:
+ break; /* nothing more needed */
+ }
+}
+
+void
+bytehostorder(struct tsp *ptr)
+{
+ ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq);
+ switch (ptr->tsp_type) {
+
+ case TSP_SETTIME:
+ case TSP_ADJTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec);
+ ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec);
+ break;
+
+ default:
+ break; /* nothing more needed */
+ }
+}
diff --git a/usr.sbin/timed/timed/candidate.c b/usr.sbin/timed/timed/candidate.c
new file mode 100644
index 00000000000..176de79e0fb
--- /dev/null
+++ b/usr.sbin/timed/timed/candidate.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)candidate.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+
+/*
+ * `election' candidates a host as master: it is called by a slave
+ * which runs with the -M option set when its election timeout expires.
+ * Note the conservative approach: if a new timed comes up, or another
+ * candidate sends an election request, the candidature is withdrawn.
+ */
+int
+election(net)
+ struct netinfo *net;
+{
+ struct tsp *resp, msg;
+ struct timeval then, wait;
+ struct tsp *answer;
+ struct hosttbl *htp;
+ char loop_lim = 0;
+
+/* This code can get totally confused if it gets slightly behind. For
+ * example, if readmsg() has some QUIT messages waiting from the last
+ * round, we would send an ELECTION message, get the stale QUIT,
+ * and give up. This results in network storms when several machines
+ * do it at once.
+ */
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "election: discarded stale REFUSE\n");
+ }
+ while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "election: discarded stale QUIT\n");
+ }
+
+again:
+ syslog(LOG_INFO, "This machine is a candidate time master");
+ if (trace)
+ fprintf(fd, "This machine is a candidate time master\n");
+ msg.tsp_type = TSP_ELECTION;
+ msg.tsp_vers = TSPVERSION;
+ (void)strcpy(msg.tsp_name, hostname);
+ bytenetorder(&msg);
+ if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&net->dest_addr,
+ sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(net->dest_addr.sin_addr);
+ return(SLAVE);
+ }
+
+ (void)gettimeofday(&then, 0);
+ then.tv_sec += 3;
+ for (;;) {
+ (void)gettimeofday(&wait, 0);
+ timersub(&then, &wait, &wait);
+ resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
+ if (!resp)
+ return(MASTER);
+
+ switch (resp->tsp_type) {
+
+ case TSP_ACCEPT:
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ break;
+
+ case TSP_MASTERUP:
+ case TSP_MASTERREQ:
+ /*
+ * If another timedaemon is coming up at the same
+ * time, give up, and let it be the master.
+ */
+ if (++loop_lim < 5
+ && !good_host_name(resp->tsp_name)) {
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ suppress(&from, resp->tsp_name, net);
+ goto again;
+ }
+ rmnetmachs(net);
+ return(SLAVE);
+
+ case TSP_QUIT:
+ case TSP_REFUSE:
+ /*
+ * Collision: change value of election timer
+ * using exponential backoff.
+ *
+ * Fooey.
+ * An exponential backoff on a delay starting at
+ * 6 to 15 minutes for a process that takes
+ * milliseconds is silly. It is particularly
+ * strange that the original code would increase
+ * the backoff without bound.
+ */
+ rmnetmachs(net);
+ return(SLAVE);
+
+ case TSP_ELECTION:
+ /* no master for another round */
+ htp = addmach(resp->tsp_name,&from,fromnet);
+ msg.tsp_type = TSP_REFUSE;
+ (void)strcpy(msg.tsp_name, hostname);
+ answer = acksend(&msg, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (!answer) {
+ syslog(LOG_ERR, "error in election from %s",
+ htp->name);
+ }
+ break;
+
+ case TSP_SLAVEUP:
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ break;
+
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "candidate: ");
+ print(resp, &from);
+ }
+ break;
+ }
+ }
+}
diff --git a/usr.sbin/timed/timed/cksum.c b/usr.sbin/timed/timed/cksum.c
new file mode 100644
index 00000000000..50e41285513
--- /dev/null
+++ b/usr.sbin/timed/timed/cksum.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)cksum.c 5.2 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include <sys/types.h>
+
+/*
+ * I N _ C K S U M
+ *
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ * There is no profit in a specialized version of the checksum
+ * function for any machine where int's are 32 bits and shorts are 16.
+ *
+ * All timed packets are smaller than 32K shorts, so there is no need to
+ * worry about carries except at the end.
+ */
+int
+in_cksum(u_short *addr, int len)
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while( nleft > 1 ) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if( nleft == 1 )
+ sum += (*(u_char *)w) << 8;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
diff --git a/usr.sbin/timed/timed/correct.c b/usr.sbin/timed/timed/correct.c
new file mode 100644
index 00000000000..ec00df17889
--- /dev/null
+++ b/usr.sbin/timed/timed/correct.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)correct.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+#include <math.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#ifdef sgi
+#include <sys/syssgi.h>
+#endif /* sgi */
+
+static void adjclock(struct timeval*);
+
+/*
+ * sends to the slaves the corrections for their clocks after fixing our
+ * own
+ */
+void
+correct(long avdelta)
+{
+ struct hosttbl *htp;
+ int corr;
+ struct timeval adjlocal;
+ struct tsp to;
+ struct tsp *answer;
+
+ mstotvround(&adjlocal, avdelta);
+
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->delta != HOSTDOWN) {
+ corr = avdelta - htp->delta;
+/* If the other machine is off in the weeds, set its time directly.
+ * If a slave gets the wrong day, the original code would simply
+ * fix the minutes. If you fix a network partition, you can get
+ * into such situations.
+ */
+ if (htp->need_set
+ || corr >= MAXADJ*1000
+ || corr <= -MAXADJ*1000) {
+ htp->need_set = 0;
+ (void)gettimeofday(&to.tsp_time,0);
+ timeradd(&to.tsp_time, &adjlocal, &to.tsp_time);
+ to.tsp_type = TSP_SETTIME;
+ } else {
+ mstotvround(&to.tsp_time, corr);
+ to.tsp_type = TSP_ADJTIME;
+ }
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, 0);
+ if (!answer) {
+ htp->delta = HOSTDOWN;
+ syslog(LOG_WARNING,
+ "no reply to time correction from %s",
+ htp->name);
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering\n",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ }
+ }
+ }
+
+ /*
+ * adjust our own clock now that we are not sending it out
+ */
+ adjclock(&adjlocal);
+}
+
+
+static void
+adjclock(struct timeval *corr)
+{
+ static int passes = 0;
+ static int smoother = 0;
+ long delta; /* adjustment in usec */
+ long ndelta;
+ struct timeval now;
+ struct timeval adj;
+
+ if (!timerisset(corr))
+ return;
+
+ adj = *corr;
+ if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
+ delta = adj.tv_sec*1000000 + adj.tv_usec;
+ /* If the correction is less than the minimum round
+ * trip time for an ICMP packet, and thus
+ * less than the likely error in the measurement,
+ * do not do the entire correction. Do half
+ * or a quarter of it.
+ */
+
+ if (delta > -MIN_ROUND*1000
+ && delta < MIN_ROUND*1000) {
+ if (smoother <= 4)
+ smoother++;
+ ndelta = delta >> smoother;
+ if (trace)
+ fprintf(fd,
+ "trimming delta %ld usec to %ld\n",
+ delta, ndelta);
+ adj.tv_usec = ndelta;
+ adj.tv_sec = 0;
+ } else if (smoother > 0) {
+ smoother--;
+ }
+ if (0 > adjtime(corr, 0)) {
+ syslog(LOG_ERR, "adjtime: %m");
+ }
+ if (passes > 1
+ && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
+ smoother = 0;
+ passes = 0;
+ syslog(LOG_WARNING,
+ "large time adjustment of %+.3f sec",
+ delta/1000000.0);
+ }
+ } else {
+ syslog(LOG_WARNING,
+ "clock correction %d sec too large to adjust",
+ adj.tv_sec);
+ (void) gettimeofday(&now, 0);
+ timeradd(&now, corr, &now);
+ if (settimeofday(&now, 0) < 0)
+ syslog(LOG_ERR, "settimeofday: %m");
+ }
+
+#ifdef sgi
+ /* Accumulate the total change, and use it to adjust the basic
+ * clock rate.
+ */
+ if (++passes > 2) {
+#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */
+#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0)
+
+ extern char *timetrim_fn;
+ extern char *timetrim_wpat;
+ extern long timetrim;
+ extern double tot_adj, hr_adj; /* totals in nsec */
+ extern double tot_ticks, hr_ticks;
+
+ static double nag_tick;
+ double cur_ticks, hr_delta_ticks, tot_delta_ticks;
+ double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
+ double tot_trim, hr_trim; /* nsec/sec */
+ struct tms tm;
+ FILE *timetrim_st;
+
+ cur_ticks = times(&tm);
+ tot_adj += delta*1000.0;
+ hr_adj += delta*1000.0;
+
+ tot_delta_ticks = cur_ticks-tot_ticks;
+ if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
+ tot_adj -= rint(tot_adj/16);
+ tot_ticks += rint(tot_delta_ticks/16);
+ tot_delta_ticks = cur_ticks-tot_ticks;
+ }
+ hr_delta_ticks = cur_ticks-hr_ticks;
+
+ tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
+ tru_tot_adj = (tot_adj
+ + timetrim*rint(tot_delta_ticks/CLK_TCK));
+
+ if (hr_delta_ticks >= SECDAY*CLK_TCK
+ || (tot_delta_ticks < 4*SECDAY*CLK_TCK
+ && hr_delta_ticks >= SECHR*CLK_TCK)
+ || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
+
+ tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
+ hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
+
+ if (trace
+ || (abs(timetrim - hr_trim) > 100000.0
+ && 0 == timetrim_fn
+ && ((cur_ticks - nag_tick)
+ >= 24*SECDAY*CLK_TCK))) {
+ nag_tick = cur_ticks;
+ syslog(LOG_NOTICE,
+ "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
+ tru_tot_adj/F_NSEC_PER_SEC,
+ tot_delta_ticks/(SECHR*CLK_TCK*1.0),
+ tru_hr_adj/F_NSEC_PER_SEC,
+ hr_delta_ticks/(SECHR*CLK_TCK*1.0),
+ tot_trim,
+ hr_trim);
+ }
+
+ if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
+ tot_ticks = hr_ticks;
+ tot_adj = hr_adj;
+ } else if (0 > syssgi(SGI_SETTIMETRIM,
+ (long)tot_trim)) {
+ syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
+ (long)tot_trim);
+ } else {
+ if (0 != timetrim_fn) {
+ timetrim_st = fopen(timetrim_fn, "w");
+ if (0 == timetrim_st) {
+ syslog(LOG_ERR, "fopen(%s): %m",
+ timetrim_fn);
+ } else {
+ if (0 > fprintf(timetrim_st,
+ timetrim_wpat,
+ (long)tot_trim,
+ tru_tot_adj,
+ tot_delta_ticks)) {
+ syslog(LOG_ERR,
+ "fprintf(%s): %m",
+ timetrim_fn);
+ }
+ (void)fclose(timetrim_st);
+ }
+ }
+
+ tot_adj -= ((tot_trim - timetrim)
+ * rint(tot_delta_ticks/CLK_TCK));
+ timetrim = tot_trim;
+ }
+
+ hr_ticks = cur_ticks;
+ hr_adj = 0;
+ }
+ }
+#endif /* sgi */
+}
+
+
+/* adjust the time in a message by the time it
+ * spent in the queue
+ */
+void
+adj_msg_time(struct tsp *msg, struct timeval *now)
+{
+ struct timeval diff;
+
+ timersub(now, &from_when, &diff);
+ timeradd(&msg->tsp_time, &diff, &msg->tsp_time);
+}
diff --git a/usr.sbin/timed/timed/globals.h b/usr.sbin/timed/timed/globals.h
new file mode 100644
index 00000000000..6d255a8e3c8
--- /dev/null
+++ b/usr.sbin/timed/timed/globals.h
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 1985 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.
+ *
+ * @(#)globals.h 5.1 (Berkeley) 5/11/93
+ */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <protocols/timed.h>
+#ifdef sgi
+#include <bstring.h>
+#include <sys/clock.h>
+/* use the constant HZ instead of the function CLK_TCK */
+#undef CLK_TCK
+#define CLK_TCK HZ
+#else
+#define SECHR (60*60)
+#define SECDAY (24*SECHR)
+#endif /* sgi */
+
+extern int errno;
+extern int sock;
+
+/* Best expected round trip for a measurement.
+ * This is essentially the number of milliseconds per CPU tick (CLK_TCK?).
+ * All delays shorter than this are usually reported as 0.
+ */
+#define MIN_ROUND ((1000-1)/CLK_TCK)
+
+
+#define SAMPLEINTVL 240 /* synch() freq for master in sec */
+#define MAXADJ 20 /* max adjtime() correction in sec */
+
+#define MAX_TRIM 3000000 /* max drift in nsec/sec, 0.3% */
+#define BIG_ADJ (MAX_TRIM/1000*SAMPLEINTVL*2) /* max good adj */
+
+#define MINTOUT 360 /* election delays, 6-15 minutes */
+#define MAXTOUT 900
+
+#define BAD_STATUS (-1)
+#define GOOD 1
+#define UNREACHABLE 2
+#define NONSTDTIME 3
+#define HOSTDOWN 0x7fffffff
+
+#define OFF 0
+#define ON 1
+
+#define MAX_HOPCNT 10 /* max value for tsp_hpcnt */
+
+#define LOSTHOST 3 /* forget after this many failures */
+
+#define VALID_RANGE (MAXADJ*1000) /* good times in milliseconds */
+#define GOOD_RANGE (MIN_ROUND*2)
+#define VGOOD_RANGE (MIN_ROUND-1)
+
+
+/*
+ * Global and per-network states.
+ */
+#define NOMASTER 0 /* no good master */
+#define SLAVE 1
+#define MASTER 2
+#define IGNORE 4
+#define ALL (SLAVE|MASTER|IGNORE)
+#define SUBMASTER (SLAVE|MASTER)
+
+#define NHOSTS 1013 /* max of hosts controlled by timed
+ * This must be a prime number.
+ */
+struct hosttbl {
+ struct hosttbl *h_bak; /* hash chain */
+ struct hosttbl *h_fwd;
+ struct hosttbl *l_bak; /* "sequential" list */
+ struct hosttbl *l_fwd;
+ struct netinfo *ntp;
+ struct sockaddr_in addr;
+ char name[MAXHOSTNAMELEN+1];
+ u_char head; /* 1=head of hash chain */
+ u_char good; /* 0=trusted host, for averaging */
+ u_char noanswer; /* count of failures to answer */
+ u_char need_set; /* need a SETTIME */
+ u_short seq;
+ long delta;
+};
+
+/* closed hash table with internal chaining */
+extern struct hosttbl hosttbl[NHOSTS+1];
+#define self hosttbl[0]
+#define hostname (self.name)
+
+
+struct netinfo {
+ struct netinfo *next;
+ struct in_addr net;
+ u_long mask;
+ struct in_addr my_addr;
+ struct sockaddr_in dest_addr; /* broadcast addr or point-point */
+ long status;
+ struct timeval slvwait; /* delay before sending our time */
+ int quit_count; /* recent QUITs */
+};
+
+#include "timed-extern.h"
+
+#define tvtomsround(tv) ((tv).tv_sec*1000 + ((tv).tv_usec + 500)/1000)
+
+extern struct netinfo *nettab;
+extern int status;
+extern int trace;
+extern int sock;
+extern struct sockaddr_in from;
+extern struct timeval from_when; /* when the last msg arrived */
+extern u_short sequence; /* TSP message sequence number */
+extern struct netinfo *fromnet, *slavenet;
+extern FILE *fd;
+extern long delay1, delay2;
+extern int nslavenets; /* nets were I could be a slave */
+extern int nmasternets; /* nets were I could be a master */
+extern int nignorednets; /* ignored nets */
+extern int nnets; /* nets I am connected to */
+
+
+#define trace_msg(msg) {if (trace) fprintf(fd, msg);}
+
+#define trace_sendto_err(addr) { \
+ int st_errno = errno; \
+ syslog(LOG_ERR, "%s %d: sendto %s: %m", \
+ __FILE__, __LINE__, inet_ntoa(addr)); \
+ if (trace) \
+ fprintf(fd, "%s %d: sendto %s: %d", __FILE__, __LINE__, \
+ inet_ntoa(addr), st_errno); \
+}
+
+
+# define max(a,b) (a<b ? b : a)
+# define min(a,b) (a>b ? b : a)
+# define abs(x) (x>=0 ? x : -(x))
diff --git a/usr.sbin/timed/timed/master.c b/usr.sbin/timed/timed/master.c
new file mode 100644
index 00000000000..a77e6edbf44
--- /dev/null
+++ b/usr.sbin/timed/timed/master.c
@@ -0,0 +1,913 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)master.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <setjmp.h>
+#ifdef sgi
+#include <sys/schedctl.h>
+#include <utmpx.h> /* includes utmp.h */
+#else
+#include <utmp.h>
+#endif /* sgi */
+
+#include "pathnames.h"
+
+extern int measure_delta;
+extern jmp_buf jmpenv;
+extern int Mflag;
+extern int justquit;
+
+static int dictate;
+static int slvcount; /* slaves listening to our clock */
+
+static void mchgdate(struct tsp*);
+
+#ifdef sgi
+extern void getutmpx(const struct utmp *, struct utmpx *);
+extern void logwtmp(struct timeval*, struct timeval*);
+#endif /* sgi */
+
+
+/*
+ * The main function of `master' is to periodically compute the differences
+ * (deltas) between its clock and the clocks of the slaves, to compute the
+ * network average delta, and to send to the slaves the differences between
+ * their individual deltas and the network delta.
+ * While waiting, it receives messages from the slaves (i.e. requests for
+ * master's name, remote requests to set the network time, ...), and
+ * takes the appropriate action.
+ */
+int
+master()
+{
+ struct hosttbl *htp;
+ long pollingtime;
+#define POLLRATE 4
+ int polls;
+ struct timeval wait, ntime;
+ time_t tmpt;
+ struct tsp *msg, *answer, to;
+ char newdate[32];
+ struct sockaddr_in taddr;
+ char tname[MAXHOSTNAMELEN];
+ struct netinfo *ntp;
+ int i;
+
+ syslog(LOG_NOTICE, "This machine is master");
+ if (trace)
+ fprintf(fd, "This machine is master\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ masterup(ntp);
+ }
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec+3;
+ if (justquit)
+ polls = 0;
+ else
+ polls = POLLRATE-1;
+
+/* Process all outstanding messages before spending the long time necessary
+ * to update all timers.
+ */
+loop:
+ (void)gettimeofday(&ntime, 0);
+ wait.tv_sec = pollingtime - ntime.tv_sec;
+ if (wait.tv_sec < 0)
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
+ if (!msg) {
+ (void)gettimeofday(&ntime, 0);
+ if (ntime.tv_sec >= pollingtime) {
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ get_goodgroup(0);
+
+/* If a bogus master told us to quit, we can have decided to ignore a
+ * network. Therefore, periodically try to take over everything.
+ */
+ polls = (polls + 1) % POLLRATE;
+ if (0 == polls && nignorednets > 0) {
+ trace_msg("Looking for nets to re-master\n");
+ for (ntp = nettab; ntp; ntp = ntp->next) {
+ if (ntp->status == IGNORE
+ || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (ntp->status == MASTER) {
+ masterup(ntp);
+ polls = POLLRATE-1;
+ }
+ }
+ if (ntp->status == MASTER
+ && --ntp->quit_count < 0)
+ ntp->quit_count = 0;
+ }
+ if (polls != 0)
+ setstatus();
+ }
+
+ synch(0L);
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ to.tsp_type = TSP_LOOP;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = sequence++;
+ to.tsp_hopcnt = MAX_HOPCNT;
+ (void)strcpy(to.tsp_name, hostname);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)) < 0) {
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ }
+
+
+ } else {
+ switch (msg->tsp_type) {
+
+ case TSP_MASTERREQ:
+ break;
+
+ case TSP_SLAVEUP:
+ newslave(msg);
+ break;
+
+ case TSP_SETDATE:
+ /*
+ * XXX check to see it is from ourself
+ */
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ tmpt = msg->tsp_time.tv_sec;
+ (void)strcpy(newdate, ctime(&tmpt));
+#endif /* sgi */
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted date change by %s to %s",
+ msg->tsp_name, newdate);
+ spreadtime();
+ break;
+ }
+
+ mchgdate(msg);
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_SETDATEREQ:
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ tmpt = msg->tsp_time.tv_sec;
+ (void)strcpy(newdate, ctime(&tmpt));
+#endif /* sgi */
+ htp = findhost(msg->tsp_name);
+ if (htp == 0) {
+ syslog(LOG_ERR,
+ "attempted SET DATEREQ by uncontrolled %s to %s",
+ msg->tsp_name, newdate);
+ break;
+ }
+ if (htp->seq == msg->tsp_seq)
+ break;
+ htp->seq = msg->tsp_seq;
+ if (!htp->good) {
+ syslog(LOG_NOTICE,
+ "attempted SET DATEREQ by untrusted %s to %s",
+ msg->tsp_name, newdate);
+ spreadtime();
+ break;
+ }
+
+ mchgdate(msg);
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_MSITE:
+ xmit(TSP_ACK, msg->tsp_seq, &from);
+ break;
+
+ case TSP_MSITEREQ:
+ break;
+
+ case TSP_TRACEON:
+ traceon();
+ break;
+
+ case TSP_TRACEOFF:
+ traceoff("Tracing ended at %s\n");
+ break;
+
+ case TSP_ELECTION:
+ if (!fromnet)
+ break;
+ if (fromnet->status == MASTER) {
+ pollingtime = 0;
+ (void)addmach(msg->tsp_name, &from,fromnet);
+ }
+ taddr = from;
+ (void)strcpy(tname, msg->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 1);
+ if (answer == NULL) {
+ syslog(LOG_ERR, "election error by %s",
+ tname);
+ }
+ break;
+
+ case TSP_CONFLICT:
+ /*
+ * After a network partition, there can be
+ * more than one master: the first slave to
+ * come up will notify here the situation.
+ */
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+ (void)strcpy(to.tsp_name, hostname);
+
+ /* The other master often gets into the same state,
+ * with boring results if we stay at it forever.
+ */
+ ntp = fromnet; /* (acksend() can leave fromnet=0 */
+ for (i = 0; i < 3; i++) {
+ to.tsp_type = TSP_RESOLVE;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp, 0);
+ if (!answer)
+ break;
+ htp = addmach(answer->tsp_name,&from,ntp);
+ to.tsp_type = TSP_QUIT;
+ msg = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (msg == NULL) {
+ syslog(LOG_ERR,
+ "no response from %s to CONFLICT-QUIT",
+ htp->name);
+ }
+ }
+ masterup(ntp);
+ pollingtime = 0;
+ break;
+
+ case TSP_RESOLVE:
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+ /*
+ * do not want to call synch() while waiting
+ * to be killed!
+ */
+ (void)gettimeofday(&ntime, (struct timezone *)0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_QUIT:
+ doquit(msg); /* become a slave */
+ break;
+
+ case TSP_LOOP:
+ if (!fromnet || fromnet->status != MASTER
+ || !strcmp(msg->tsp_name, hostname))
+ break;
+ /*
+ * We should not have received this from a net
+ * we are master on. There must be two masters.
+ */
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, 1);
+ if (!answer) {
+ syslog(LOG_WARNING,
+ "loop breakage: no reply from %s=%s to QUIT",
+ htp->name, inet_ntoa(htp->addr.sin_addr));
+ (void)remmach(htp);
+ }
+
+ case TSP_TEST:
+ if (trace) {
+ fprintf(fd,
+ "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
+ nnets, nmasternets, nslavenets, nignorednets);
+ setstatus();
+ }
+ pollingtime = 0;
+ polls = POLLRATE-1;
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "garbage message: ");
+ print(msg, &from);
+ }
+ break;
+ }
+ }
+ goto loop;
+}
+
+
+/*
+ * change the system date on the master
+ */
+static void
+mchgdate(struct tsp *msg)
+{
+ char tname[MAXHOSTNAMELEN];
+ char olddate[32];
+ struct timeval otime, ntime;
+
+ (void)strcpy(tname, msg->tsp_name);
+
+ xmit(TSP_DATEACK, msg->tsp_seq, &from);
+
+ (void)strcpy(olddate, date());
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg,&otime);
+
+ timersub(&msg->tsp_time, &otime, &ntime);
+ if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
+ /*
+ * do not change the clock if we can adjust it
+ */
+ dictate = 3;
+ synch(tvtomsround(ntime));
+ } else {
+#ifdef sgi
+ if (0 > settimeofday(&msg->tsp_time, 0)) {
+ syslog(LOG_ERR, "settimeofday(): %m");
+ }
+ logwtmp(&otime, &msg->tsp_time);
+#else
+ logwtmp("|", "date", "");
+ (void)settimeofday(&msg->tsp_time, 0);
+ logwtmp("}", "date", "");
+#endif /* sgi */
+ spreadtime();
+ }
+
+ syslog(LOG_NOTICE, "date changed by %s from %s",
+ tname, olddate);
+}
+
+
+/*
+ * synchronize all of the slaves
+ */
+void
+synch(long mydelta)
+{
+ struct hosttbl *htp;
+ int measure_status;
+ struct timeval check, stop, wait;
+#ifdef sgi
+ int pri;
+#endif /* sgi */
+
+ if (slvcount > 0) {
+ if (trace)
+ fprintf(fd, "measurements starting at %s\n", date());
+ (void)gettimeofday(&check, 0);
+#ifdef sgi
+ /* run fast to get good time */
+ pri = schedctl(NDPRI,0,NDPHIMIN);
+ if (pri < 0)
+ syslog(LOG_ERR, "schedctl(): %m");
+#endif /* sgi */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->noanswer != 0) {
+ measure_status = measure(500, 100,
+ htp->name,
+ &htp->addr,0);
+ } else {
+ measure_status = measure(3000, 100,
+ htp->name,
+ &htp->addr,0);
+ }
+ if (measure_status != GOOD) {
+ /* The slave did not respond. We have
+ * just wasted lots of time on it.
+ */
+ htp->delta = HOSTDOWN;
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering ICMP\n",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ } else {
+ htp->delta = measure_delta;
+ }
+ (void)gettimeofday(&stop, 0);
+ timersub(&stop, &check, &stop);
+ if (stop.tv_sec >= 1) {
+ if (trace)
+ (void)fflush(fd);
+ /*
+ * ack messages periodically
+ */
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ if (0 != readmsg(TSP_TRACEON,ANYADDR,
+ &wait,0))
+ traceon();
+ (void)gettimeofday(&check, 0);
+ }
+ }
+#ifdef sgi
+ if (pri >= 0)
+ (void)schedctl(NDPRI,0,pri);
+#endif /* sgi */
+ if (trace)
+ fprintf(fd, "measurements finished at %s\n", date());
+ }
+ if (!(status & SLAVE)) {
+ if (!dictate) {
+ mydelta = networkdelta();
+ } else {
+ dictate--;
+ }
+ }
+ if (trace && (mydelta != 0 || (status & SLAVE)))
+ fprintf(fd,"local correction of %ld ms.\n", mydelta);
+ correct(mydelta);
+}
+
+/*
+ * sends the time to each slave after the master
+ * has received the command to set the network time
+ */
+void
+spreadtime()
+{
+ struct hosttbl *htp;
+ struct tsp to;
+ struct tsp *answer;
+
+/* Do not listen to the consensus after forcing the time. This is because
+ * the consensus takes a while to reach the time we are dictating.
+ */
+ dictate = 2;
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ to.tsp_type = TSP_SETTIME;
+ (void)strcpy(to.tsp_name, hostname);
+ (void)gettimeofday(&to.tsp_time, 0);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (answer == 0) {
+ /* We client does not respond, then we have
+ * just wasted lots of time on it.
+ */
+ syslog(LOG_WARNING,
+ "no reply to SETTIME from %s", htp->name);
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ }
+ }
+}
+
+
+void
+prthp(clock_t delta)
+{
+ static time_t next_time;
+ time_t this_time;
+ struct tms tm;
+ struct hosttbl *htp;
+ int length, l;
+ int i;
+
+ if (!fd) /* quit if tracing already off */
+ return;
+
+ this_time = times(&tm);
+ if (this_time + delta < next_time)
+ return;
+ next_time = this_time + CLK_TCK;
+
+ fprintf(fd, "host table: %d entries at %s\n", slvcount, date());
+ htp = self.l_fwd;
+ length = 1;
+ for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) {
+ l = strlen(htp->name) + 1;
+ if (length+l >= 80) {
+ fprintf(fd, "\n");
+ length = 0;
+ }
+ length += l;
+ fprintf(fd, " %s", htp->name);
+ }
+ fprintf(fd, "\n");
+}
+
+
+static struct hosttbl *newhost_hash;
+static struct hosttbl *lasthfree = &hosttbl[0];
+
+
+struct hosttbl * /* answer or 0 */
+findhost(char *name)
+{
+ int i, j;
+ struct hosttbl *htp;
+ char *p;
+
+ j= 0;
+ for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++)
+ j = (j << 2) ^ *p;
+ newhost_hash = &hosttbl[j % NHOSTS];
+
+ htp = newhost_hash;
+ if (htp->name[0] == '\0')
+ return(0);
+ do {
+ if (!strcmp(name, htp->name))
+ return(htp);
+ htp = htp->h_fwd;
+ } while (htp != newhost_hash);
+ return(0);
+}
+
+/*
+ * add a host to the list of controlled machines if not already there
+ */
+struct hosttbl *
+addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp)
+{
+ struct hosttbl *ret, *p, *b, *f;
+
+ ret = findhost(name);
+ if (ret == 0) {
+ if (slvcount >= NHOSTS) {
+ if (trace) {
+ fprintf(fd, "no more slots in host table\n");
+ prthp(CLK_TCK);
+ }
+ syslog(LOG_ERR, "no more slots in host table");
+ Mflag = 0;
+ longjmp(jmpenv, 2); /* give up and be a slave */
+ }
+
+ /* if our home hash slot is occupied, find a free entry
+ * in the hash table
+ */
+ if (newhost_hash->name[0] != '\0') {
+ do {
+ ret = lasthfree;
+ if (++lasthfree > &hosttbl[NHOSTS])
+ lasthfree = &hosttbl[1];
+ } while (ret->name[0] != '\0');
+
+ if (!newhost_hash->head) {
+ /* Move an interloper using our home. Use
+ * scratch pointers in case the new head is
+ * pointing to itself.
+ */
+ f = newhost_hash->h_fwd;
+ b = newhost_hash->h_bak;
+ f->h_bak = ret;
+ b->h_fwd = ret;
+ f = newhost_hash->l_fwd;
+ b = newhost_hash->l_bak;
+ f->l_bak = ret;
+ b->l_fwd = ret;
+ bcopy(newhost_hash,ret,sizeof(*ret));
+ ret = newhost_hash;
+ ret->head = 1;
+ ret->h_fwd = ret;
+ ret->h_bak = ret;
+ } else {
+ /* link to an existing chain in our home
+ */
+ ret->head = 0;
+ p = newhost_hash->h_bak;
+ ret->h_fwd = newhost_hash;
+ ret->h_bak = p;
+ p->h_fwd = ret;
+ newhost_hash->h_bak = ret;
+ }
+ } else {
+ ret = newhost_hash;
+ ret->head = 1;
+ ret->h_fwd = ret;
+ ret->h_bak = ret;
+ }
+ ret->addr = *addr;
+ ret->ntp = ntp;
+ (void)strncpy(ret->name, name, sizeof(ret->name));
+ ret->good = good_host_name(name);
+ ret->l_fwd = &self;
+ ret->l_bak = self.l_bak;
+ self.l_bak->l_fwd = ret;
+ self.l_bak = ret;
+ slvcount++;
+
+ ret->noanswer = 0;
+ ret->need_set = 1;
+
+ } else {
+ ret->noanswer = (ret->noanswer != 0);
+ }
+
+ /* need to clear sequence number anyhow */
+ ret->seq = 0;
+ return(ret);
+}
+
+/*
+ * remove the machine with the given index in the host table.
+ */
+struct hosttbl *
+remmach(struct hosttbl *htp)
+{
+ struct hosttbl *lprv, *hnxt, *f, *b;
+
+ if (trace)
+ fprintf(fd, "remove %s\n", htp->name);
+
+ /* get out of the lists */
+ htp->l_fwd->l_bak = lprv = htp->l_bak;
+ htp->l_bak->l_fwd = htp->l_fwd;
+ htp->h_fwd->h_bak = htp->h_bak;
+ htp->h_bak->h_fwd = hnxt = htp->h_fwd;
+
+ /* If we are in the home slot, pull up the chain */
+ if (htp->head && hnxt != htp) {
+ if (lprv == hnxt)
+ lprv = htp;
+
+ /* Use scratch pointers in case the new head is pointing to
+ * itself.
+ */
+ f = hnxt->h_fwd;
+ b = hnxt->h_bak;
+ f->h_bak = htp;
+ b->h_fwd = htp;
+ f = hnxt->l_fwd;
+ b = hnxt->l_bak;
+ f->l_bak = htp;
+ b->l_fwd = htp;
+ hnxt->head = 1;
+ bcopy(hnxt, htp, sizeof(*htp));
+ lasthfree = hnxt;
+ } else {
+ lasthfree = htp;
+ }
+
+ lasthfree->name[0] = '\0';
+ lasthfree->h_fwd = 0;
+ lasthfree->l_fwd = 0;
+ slvcount--;
+
+ return lprv;
+}
+
+
+/*
+ * Remove all the machines from the host table that exist on the given
+ * network. This is called when a master transitions to a slave on a
+ * given network.
+ */
+void
+rmnetmachs(struct netinfo *ntp)
+{
+ struct hosttbl *htp;
+
+ if (trace)
+ prthp(CLK_TCK);
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (ntp == htp->ntp)
+ htp = remmach(htp);
+ }
+ if (trace)
+ prthp(CLK_TCK);
+}
+
+
+void
+masterup(struct netinfo *net)
+{
+ xmit(TSP_MASTERUP, 0, &net->dest_addr);
+
+ /*
+ * Do not tell new slaves our time for a while. This ensures
+ * we do not tell them to start using our time, before we have
+ * found a good master.
+ */
+ (void)gettimeofday(&net->slvwait, 0);
+}
+
+void
+newslave(struct tsp *msg)
+{
+ struct hosttbl *htp;
+ struct tsp *answer, to;
+ struct timeval now;
+
+ if (!fromnet || fromnet->status != MASTER)
+ return;
+
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ htp->seq = msg->tsp_seq;
+ if (trace)
+ prthp(0);
+
+ /*
+ * If we are stable, send our time to the slave.
+ * Do not go crazy if the date has been changed.
+ */
+ (void)gettimeofday(&now, 0);
+ if (now.tv_sec >= fromnet->slvwait.tv_sec+3
+ || now.tv_sec < fromnet->slvwait.tv_sec) {
+ to.tsp_type = TSP_SETTIME;
+ (void)strcpy(to.tsp_name, hostname);
+ (void)gettimeofday(&to.tsp_time, 0);
+ answer = acksend(&to, &htp->addr,
+ htp->name, TSP_ACK,
+ 0, htp->noanswer);
+ if (answer) {
+ htp->need_set = 0;
+ } else {
+ syslog(LOG_WARNING,
+ "no reply to initial SETTIME from %s",
+ htp->name);
+ htp->noanswer = LOSTHOST;
+ }
+ }
+}
+
+
+/*
+ * react to a TSP_QUIT:
+ */
+void
+doquit(struct tsp *msg)
+{
+ if (fromnet->status == MASTER) {
+ if (!good_host_name(msg->tsp_name)) {
+ if (fromnet->quit_count <= 0) {
+ syslog(LOG_NOTICE,"untrusted %s told us QUIT",
+ msg->tsp_name);
+ suppress(&from, msg->tsp_name, fromnet);
+ fromnet->quit_count = 1;
+ return;
+ }
+ syslog(LOG_NOTICE, "untrusted %s told us QUIT twice",
+ msg->tsp_name);
+ fromnet->quit_count = 2;
+ fromnet->status = NOMASTER;
+ } else {
+ fromnet->status = SLAVE;
+ }
+ rmnetmachs(fromnet);
+ longjmp(jmpenv, 2); /* give up and be a slave */
+
+ } else {
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE, "untrusted %s told us QUIT",
+ msg->tsp_name);
+ fromnet->quit_count = 2;
+ }
+ }
+}
+
+void
+traceon(void)
+{
+ if (!fd) {
+ fd = fopen(_PATH_TIMEDLOG, "w");
+ if (!fd) {
+ trace = 0;
+ return;
+ }
+ fprintf(fd,"Tracing started at %s\n", date());
+ }
+ trace = 1;
+ get_goodgroup(1);
+ setstatus();
+ prthp(CLK_TCK);
+}
+
+
+void
+traceoff(char *msg)
+{
+ get_goodgroup(1);
+ setstatus();
+ prthp(CLK_TCK);
+ if (trace) {
+ fprintf(fd, msg, date());
+ (void)fclose(fd);
+ fd = 0;
+ }
+#ifdef GPROF
+ moncontrol(0);
+ _mcleanup();
+ moncontrol(1);
+#endif
+ trace = OFF;
+}
+
+
+#ifdef sgi
+void
+logwtmp(struct timeval *otime, struct timeval *ntime)
+{
+ static struct utmp wtmp[2] = {
+ {"","",OTIME_MSG,0,OLD_TIME,0,0,0},
+ {"","",NTIME_MSG,0,NEW_TIME,0,0,0}
+ };
+ static char *wtmpfile = WTMP_FILE;
+ static struct utmpx wtmpx[2];
+ int f;
+
+ wtmp[0].ut_time = otime->tv_sec + (otime->tv_usec + 500000) / 1000000;
+ wtmp[1].ut_time = ntime->tv_sec + (ntime->tv_usec + 500000) / 1000000;
+ if (wtmp[0].ut_time == wtmp[1].ut_time)
+ return;
+
+ setutent();
+ (void)pututline(&wtmp[0]);
+ (void)pututline(&wtmp[1]);
+ endutent();
+ if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) {
+ (void)write(f, (char *)wtmp, sizeof(wtmp));
+ (void)close(f);
+ }
+
+ /*
+ * convert the wtmp entries into utmpx format in wtmpx[0..1]
+ * and append to /var/adm/wtmpx to keep wtmp and wtmpx in sync.
+ */
+ getutmpx(&wtmp[0], &wtmpx[0]);
+ getutmpx(&wtmp[1], &wtmpx[1]);
+ if ((f = open(WTMPX_FILE, O_WRONLY|O_APPEND)) >= 0) {
+ (void)write(f, (char *)wtmpx, sizeof(wtmpx));
+ (void)close(f);
+ }
+}
+#endif /* sgi */
diff --git a/usr.sbin/timed/timed/measure.c b/usr.sbin/timed/timed/measure.c
new file mode 100644
index 00000000000..1e707c78da2
--- /dev/null
+++ b/usr.sbin/timed/timed/measure.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)measure.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#define MSEC_DAY (SECDAY*1000)
+
+#define PACKET_IN 1024
+
+#define MSGS 5 /* timestamps to average */
+#define TRIALS 10 /* max # of timestamps sent */
+
+extern int sock_raw;
+
+int measure_delta;
+
+extern int in_cksum(u_short*, int);
+
+static n_short seqno = 0;
+
+/*
+ * Measures the differences between machines' clocks using
+ * ICMP timestamp messages.
+ */
+int /* status val defined in globals.h */
+measure(u_long maxmsec, /* wait this many msec at most */
+ u_long wmsec, /* msec to wait for an answer */
+ char *hname,
+ struct sockaddr_in *addr,
+ int print) /* print complaints on stderr */
+{
+ int length;
+ int measure_status;
+ int rcvcount, trials;
+ int cc, count;
+ fd_set ready;
+ long sendtime, recvtime, histime1, histime2;
+ long idelta, odelta, total;
+ long min_idelta, min_odelta;
+ struct timeval tdone, tcur, ttrans, twait, tout;
+ u_char packet[PACKET_IN], opacket[64];
+ register struct icmp *icp = (struct icmp *) packet;
+ register struct icmp *oicp = (struct icmp *) opacket;
+ struct ip *ip = (struct ip *) packet;
+
+ min_idelta = min_odelta = 0x7fffffff;
+ measure_status = HOSTDOWN;
+ measure_delta = HOSTDOWN;
+ errno = 0;
+
+ /* open raw socket used to measure time differences */
+ if (sock_raw < 0) {
+ sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (sock_raw < 0) {
+ syslog(LOG_ERR, "opening raw socket: %m");
+ goto quit;
+ }
+ }
+
+
+ /*
+ * empty the icmp input queue
+ */
+ FD_ZERO(&ready);
+ for (;;) {
+ tout.tv_sec = tout.tv_usec = 0;
+ FD_SET(sock_raw, &ready);
+ if (select(sock_raw+1, &ready, 0,0, &tout)) {
+ length = sizeof(struct sockaddr_in);
+ cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+ 0,&length);
+ if (cc < 0)
+ goto quit;
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Choose the smallest transmission time in each of the two
+ * directions. Use these two latter quantities to compute the delta
+ * between the two clocks.
+ */
+
+ oicp->icmp_type = ICMP_TSTAMP;
+ oicp->icmp_code = 0;
+ oicp->icmp_id = getpid();
+ oicp->icmp_rtime = 0;
+ oicp->icmp_ttime = 0;
+ oicp->icmp_seq = seqno;
+
+ FD_ZERO(&ready);
+
+#ifdef sgi
+ sginap(1); /* start at a clock tick */
+#endif /* sgi */
+
+ (void)gettimeofday(&tdone, 0);
+ mstotvround(&tout, maxmsec);
+ timeradd(&tdone, &tout, &tdone); /* when we give up */
+
+ mstotvround(&twait, wmsec);
+
+ rcvcount = 0;
+ trials = 0;
+ while (rcvcount < MSGS) {
+ (void)gettimeofday(&tcur, 0);
+
+ /*
+ * keep sending until we have sent the max
+ */
+ if (trials < TRIALS) {
+ trials++;
+ oicp->icmp_otime = htonl((tcur.tv_sec % SECDAY) * 1000
+ + tcur.tv_usec / 1000);
+ oicp->icmp_cksum = 0;
+ oicp->icmp_cksum = in_cksum((u_short*)oicp,
+ sizeof(*oicp));
+
+ count = sendto(sock_raw, opacket, sizeof(*oicp), 0,
+ (struct sockaddr*)addr,
+ sizeof(struct sockaddr));
+ if (count < 0) {
+ if (measure_status == HOSTDOWN)
+ measure_status = UNREACHABLE;
+ goto quit;
+ }
+ ++oicp->icmp_seq;
+
+ timeradd(&tcur, &twait, &ttrans);
+ } else {
+ ttrans = tdone;
+ }
+
+ while (rcvcount < trials) {
+ timersub(&ttrans, &tcur, &tout);
+ if (tout.tv_sec < 0)
+ tout.tv_sec = 0;
+
+ FD_SET(sock_raw, &ready);
+ count = select(sock_raw+1, &ready, (fd_set *)0,
+ (fd_set *)0, &tout);
+ (void)gettimeofday(&tcur, (struct timezone *)0);
+ if (count <= 0)
+ break;
+
+ length = sizeof(struct sockaddr_in);
+ cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+ 0,&length);
+ if (cc < 0)
+ goto quit;
+
+ /*
+ * got something. See if it is ours
+ */
+ icp = (struct icmp *)(packet + (ip->ip_hl << 2));
+ if (cc < sizeof(*ip)
+ || icp->icmp_type != ICMP_TSTAMPREPLY
+ || icp->icmp_id != oicp->icmp_id
+ || icp->icmp_seq < seqno
+ || icp->icmp_seq >= oicp->icmp_seq)
+ continue;
+
+
+ sendtime = ntohl(icp->icmp_otime);
+ recvtime = ((tcur.tv_sec % SECDAY) * 1000 +
+ tcur.tv_usec / 1000);
+
+ total = recvtime-sendtime;
+ if (total < 0) /* do not hassle midnight */
+ continue;
+
+ rcvcount++;
+ histime1 = ntohl(icp->icmp_rtime);
+ histime2 = ntohl(icp->icmp_ttime);
+ /*
+ * a host using a time format different from
+ * msec. since midnight UT (as per RFC792) should
+ * set the high order bit of the 32-bit time
+ * value it transmits.
+ */
+ if ((histime1 & 0x80000000) != 0) {
+ measure_status = NONSTDTIME;
+ goto quit;
+ }
+ measure_status = GOOD;
+
+ idelta = recvtime-histime2;
+ odelta = histime1-sendtime;
+
+ /* do not be confused by midnight */
+ if (idelta < -MSEC_DAY/2) idelta += MSEC_DAY;
+ else if (idelta > MSEC_DAY/2) idelta -= MSEC_DAY;
+
+ if (odelta < -MSEC_DAY/2) odelta += MSEC_DAY;
+ else if (odelta > MSEC_DAY/2) odelta -= MSEC_DAY;
+
+ /* save the quantization error so that we can get a
+ * measurement finer than our system clock.
+ */
+ if (total < MIN_ROUND) {
+ measure_delta = (odelta - idelta)/2;
+ goto quit;
+ }
+
+ if (idelta < min_idelta)
+ min_idelta = idelta;
+ if (odelta < min_odelta)
+ min_odelta = odelta;
+
+ measure_delta = (min_odelta - min_idelta)/2;
+ }
+
+ if (tcur.tv_sec > tdone.tv_sec
+ || (tcur.tv_sec == tdone.tv_sec
+ && tcur.tv_usec >= tdone.tv_usec))
+ break;
+ }
+
+quit:
+ seqno += TRIALS; /* allocate our sequence numbers */
+
+ /*
+ * If no answer is received for TRIALS consecutive times,
+ * the machine is assumed to be down
+ */
+ if (measure_status == GOOD) {
+ if (trace) {
+ fprintf(fd,
+ "measured delta %4d, %d trials to %-15s %s\n",
+ measure_delta, trials,
+ inet_ntoa(addr->sin_addr), hname);
+ }
+ } else if (print) {
+ if (errno != 0)
+ fprintf(stderr, "measure %s: %s\n", hname,
+ strerror(errno));
+ } else {
+ if (errno != 0) {
+ syslog(LOG_ERR, "measure %s: %m", hname);
+ } else {
+ syslog(LOG_ERR, "measure: %s did not respond", hname);
+ }
+ if (trace) {
+ fprintf(fd,
+ "measure: %s failed after %d trials\n",
+ hname, trials);
+ (void)fflush(fd);
+ }
+ }
+
+ return(measure_status);
+}
+
+
+
+
+
+/*
+ * round a number of milliseconds into a struct timeval
+ */
+void
+mstotvround(struct timeval *res, long x)
+{
+#ifndef sgi
+ if (x < 0)
+ x = -((-x + 3)/5);
+ else
+ x = (x+3)/5;
+ x *= 5;
+#endif /* sgi */
+ res->tv_sec = x/1000;
+ res->tv_usec = (x-res->tv_sec*1000)*1000;
+ if (res->tv_usec < 0) {
+ res->tv_usec += 1000000;
+ res->tv_sec--;
+ }
+}
diff --git a/usr.sbin/timed/timed/networkdelta.c b/usr.sbin/timed/timed/networkdelta.c
new file mode 100644
index 00000000000..0e58580126a
--- /dev/null
+++ b/usr.sbin/timed/timed/networkdelta.c
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)networkdelta.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+
+static long median(float, float*, long*, long*, unsigned int);
+
+/*
+ * Compute a corrected date.
+ * Compute the median of the reasonable differences. First compute
+ * the median of all authorized differences, and then compute the
+ * median of all differences that are reasonably close to the first
+ * median.
+ *
+ * This differs from the original BSD implementation, which looked for
+ * the largest group of machines with essentially the same date.
+ * That assumed that machines with bad clocks would be uniformly
+ * distributed. Unfortunately, in real life networks, the distribution
+ * of machines is not uniform among models of machines, and the
+ * distribution of errors in clocks tends to be quite consistent
+ * for a given model. In other words, all model VI Supre Servres
+ * from GoFast Inc. tend to have about the same error.
+ * The original BSD implementation would chose the clock of the
+ * most common model, and discard all others.
+ *
+ * Therefore, get best we can do is to try to average over all
+ * of the machines in the network, while discarding "obviously"
+ * bad values.
+ */
+long
+networkdelta()
+{
+ struct hosttbl *htp;
+ long med;
+ long lodelta, hidelta;
+ long logood, higood;
+ long x[NHOSTS];
+ long *xp;
+ int numdelta;
+ float eps;
+
+ /*
+ * compute the median of the good values
+ */
+ med = 0;
+ numdelta = 1;
+ xp = &x[0];
+ *xp = 0; /* account for ourself */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->good
+ && htp->noanswer == 0
+ && htp->delta != HOSTDOWN) {
+ med += htp->delta;
+ numdelta++;
+ *++xp = htp->delta;
+ }
+ }
+
+ /*
+ * If we are the only trusted time keeper, then do not change our
+ * clock. There may be another time keeping service active.
+ */
+ if (numdelta == 1)
+ return 0;
+
+ med /= numdelta;
+ eps = med - x[0];
+ if (trace)
+ fprintf(fd, "median of %d values starting at %ld is about ",
+ numdelta, med);
+ med = median(med, &eps, &x[0], xp+1, VALID_RANGE);
+
+ /*
+ * compute the median of all values near the good median
+ */
+ hidelta = med + GOOD_RANGE;
+ lodelta = med - GOOD_RANGE;
+ higood = med + VGOOD_RANGE;
+ logood = med - VGOOD_RANGE;
+ xp = &x[0];
+ htp = &self;
+ do {
+ if (htp->noanswer == 0
+ && htp->delta >= lodelta
+ && htp->delta <= hidelta
+ && (htp->good
+ || (htp->delta >= logood
+ && htp->delta <= higood))) {
+ *xp++ = htp->delta;
+ }
+ } while (&self != (htp = htp->l_fwd));
+
+ if (xp == &x[0]) {
+ if (trace)
+ fprintf(fd, "nothing close to median %ld\n", med);
+ return med;
+ }
+
+ if (xp == &x[1]) {
+ if (trace)
+ fprintf(fd, "only value near median is %ld\n", x[0]);
+ return x[0];
+ }
+
+ if (trace)
+ fprintf(fd, "median of %d values starting at %ld is ",
+ xp-&x[0], med);
+ return median(med, &eps, &x[0], xp, 1);
+}
+
+
+/*
+ * compute the median of an array of signed integers, using the idea
+ * in <<Numerical Recipes>>.
+ */
+static long
+median(float a, /* initial guess for the median */
+ float *eps_ptr, /* spacing near the median */
+ long *x, long *xlim, /* the data */
+ unsigned int gnuf) /* good enough estimate */
+{
+ long *xptr;
+ float ap = LONG_MAX; /* bounds on the median */
+ float am = -LONG_MAX;
+ float aa;
+ int npts; /* # of points above & below guess */
+ float xp; /* closet point above the guess */
+ float xm; /* closet point below the guess */
+ float eps;
+ float dum, sum, sumx;
+ int pass;
+#define AMP 1.5 /* smoothing constants */
+#define AFAC 1.5
+
+ eps = *eps_ptr;
+ if (eps < 1.0) {
+ eps = -eps;
+ if (eps < 1.0)
+ eps = 1.0;
+ }
+
+ for (pass = 1; ; pass++) { /* loop over the data */
+ sum = 0.0;
+ sumx = 0.0;
+ npts = 0;
+ xp = LONG_MAX;
+ xm = -LONG_MAX;
+
+ for (xptr = x; xptr != xlim; xptr++) {
+ float xx = *xptr;
+
+ dum = xx - a;
+ if (dum != 0.0) { /* avoid dividing by 0 */
+ if (dum > 0.0) {
+ npts++;
+ if (xx < xp)
+ xp = xx;
+ } else {
+ npts--;
+ if (xx > xm)
+ xm = xx;
+ dum = -dum;
+ }
+ dum = 1.0/(eps + dum);
+ sum += dum;
+ sumx += xx * dum;
+ }
+ }
+
+ if (ap-am < gnuf || sum == 0) {
+ if (trace)
+ fprintf(fd,
+ "%ld in %d passes; early out balance=%d\n",
+ (long)a, pass, npts);
+ return a; /* guess was good enough */
+ }
+
+ aa = (sumx/sum-a)*AMP;
+ if (npts >= 2) { /* guess was too low */
+ am = a;
+ aa = xp + max(0.0, aa);;
+ if (aa > ap)
+ aa = (a + ap)/2;
+
+ } else if (npts <= -2) { /* guess was two high */
+ ap = a;
+ aa = xm + min(0.0, aa);;
+ if (aa < am)
+ aa = (a + am)/2;
+
+ } else {
+ break; /* got it */
+ }
+
+ if (a == aa) {
+ if (trace)
+ fprintf(fd,
+ "%ld in %d passes; force out balance=%d\n",
+ (long)a, pass, npts);
+ return a;
+ }
+ eps = AFAC*abs(aa - a);
+ *eps_ptr = eps;
+ a = aa;
+ }
+
+ if (((x - xlim) % 2) != 0) { /* even number of points? */
+ if (npts == 0) /* yes, return an average */
+ a = (xp+xm)/2;
+ else if (npts > 0)
+ a = (a+xp)/2;
+ else
+ a = (xm+a)/2;
+
+ } else if (npts != 0) { /* odd number of points */
+ if (npts > 0)
+ a = xp;
+ else
+ a = xm;
+ }
+
+ if (trace)
+ fprintf(fd, "%ld in %d passes\n", (long)a, pass);
+ return a;
+}
diff --git a/usr.sbin/timed/timed/pathnames.h b/usr.sbin/timed/timed/pathnames.h
new file mode 100644
index 00000000000..370f5d82bfc
--- /dev/null
+++ b/usr.sbin/timed/timed/pathnames.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1985 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.
+ *
+ * @(#)pathnames.h 5.6 (Berkeley) 5/11/93
+ */
+
+#include <paths.h>
+
+#ifdef sgi
+#define _PATH_MASTERLOG "/var/adm/timed.masterlog"
+#define _PATH_TIMEDLOG "/var/adm/timed.log"
+#else
+#define _PATH_MASTERLOG "/var/log/timed.masterlog"
+#define _PATH_TIMEDLOG "/var/log/timed.log"
+#endif
diff --git a/usr.sbin/timed/timed/readmsg.c b/usr.sbin/timed/timed/readmsg.c
new file mode 100644
index 00000000000..7a113f8edcb
--- /dev/null
+++ b/usr.sbin/timed/timed/readmsg.c
@@ -0,0 +1,488 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)readmsg.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+
+extern char *tsptype[];
+
+/*
+ * LOOKAT checks if the message is of the requested type and comes from
+ * the right machine, returning 1 in case of affirmative answer
+ */
+#define LOOKAT(msg, mtype, mfrom, netp, froms) \
+ (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \
+ ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \
+ ((netp) == 0 || \
+ ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
+
+struct timeval rtime, rwait, rtout;
+struct tsp msgin;
+static struct tsplist {
+ struct tsp info;
+ struct timeval when;
+ struct sockaddr_in addr;
+ struct tsplist *p;
+} msgslist;
+struct sockaddr_in from;
+struct netinfo *fromnet;
+struct timeval from_when;
+
+/*
+ * `readmsg' returns message `type' sent by `machfrom' if it finds it
+ * either in the receive queue, or in a linked list of previously received
+ * messages that it maintains.
+ * Otherwise it waits to see if the appropriate message arrives within
+ * `intvl' seconds. If not, it returns NULL.
+ */
+
+struct tsp *
+readmsg(int type, char *machfrom, struct timeval *intvl,
+ struct netinfo *netfrom)
+{
+ int length;
+ fd_set ready;
+ static struct tsplist *head = &msgslist;
+ static struct tsplist *tail = &msgslist;
+ static int msgcnt = 0;
+ struct tsplist *prev;
+ register struct netinfo *ntp;
+ register struct tsplist *ptr;
+
+ if (trace) {
+ fprintf(fd, "readmsg: looking for %s from %s, %s\n",
+ tsptype[type], machfrom == NULL ? "ANY" : machfrom,
+ netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
+ if (head->p != 0) {
+ length = 1;
+ for (ptr = head->p; ptr != 0; ptr = ptr->p) {
+ /* do not repeat the hundreds of messages */
+ if (++length > 3) {
+ if (ptr == tail) {
+ fprintf(fd,"\t ...%d skipped\n",
+ length);
+ } else {
+ continue;
+ }
+ }
+ fprintf(fd, length > 1 ? "\t" : "queue:\t");
+ print(&ptr->info, &ptr->addr);
+ }
+ }
+ }
+
+ ptr = head->p;
+ prev = head;
+
+ /*
+ * Look for the requested message scanning through the
+ * linked list. If found, return it and free the space
+ */
+
+ while (ptr != NULL) {
+ if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
+again:
+ msgin = ptr->info;
+ from = ptr->addr;
+ from_when = ptr->when;
+ prev->p = ptr->p;
+ if (ptr == tail)
+ tail = prev;
+ free((char *)ptr);
+ fromnet = NULL;
+ if (netfrom == NULL)
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if ((ntp->mask & from.sin_addr.s_addr) ==
+ ntp->net.s_addr) {
+ fromnet = ntp;
+ break;
+ }
+ }
+ else
+ fromnet = netfrom;
+ if (trace) {
+ fprintf(fd, "readmsg: found ");
+ print(&msgin, &from);
+ }
+
+/* The protocol can get far behind. When it does, it gets
+ * hopelessly confused. So delete duplicate messages.
+ */
+ for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
+ if (ptr->addr.sin_addr.s_addr
+ == from.sin_addr.s_addr
+ && ptr->info.tsp_type == msgin.tsp_type) {
+ if (trace)
+ fprintf(fd, "\tdup ");
+ goto again;
+ }
+ }
+ msgcnt--;
+ return(&msgin);
+ } else {
+ prev = ptr;
+ ptr = ptr->p;
+ }
+ }
+
+ /*
+ * If the message was not in the linked list, it may still be
+ * coming from the network. Set the timer and wait
+ * on a select to read the next incoming message: if it is the
+ * right one, return it, otherwise insert it in the linked list.
+ */
+
+ (void)gettimeofday(&rtout, 0);
+ timeradd(&rtout, intvl, &rtout);
+ FD_ZERO(&ready);
+ for (;;) {
+ (void)gettimeofday(&rtime, 0);
+ timersub(&rtout, &rtime, &rwait);
+ if (rwait.tv_sec < 0)
+ rwait.tv_sec = rwait.tv_usec = 0;
+ else if (rwait.tv_sec == 0
+ && rwait.tv_usec < 1000000/CLK_TCK)
+ rwait.tv_usec = 1000000/CLK_TCK;
+
+ if (trace) {
+ fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
+ rwait.tv_sec, rwait.tv_usec, date());
+ /* Notice a full disk, as we flush trace info.
+ * It is better to flush periodically than at
+ * every line because the tracing consists of bursts
+ * of many lines. Without care, tracing slows
+ * down the code enough to break the protocol.
+ */
+ if (rwait.tv_sec != 0
+ && EOF == fflush(fd))
+ traceoff("Tracing ended for cause at %s\n");
+ }
+
+ FD_SET(sock, &ready);
+ if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
+ &rwait)) {
+ if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
+ return(0);
+ continue;
+ }
+ length = sizeof(from);
+ if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
+ (struct sockaddr*)&from, &length) < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ (void)gettimeofday(&from_when, (struct timezone *)0);
+ bytehostorder(&msgin);
+
+ if (msgin.tsp_vers > TSPVERSION) {
+ if (trace) {
+ fprintf(fd,"readmsg: version mismatch\n");
+ /* should do a dump of the packet */
+ }
+ continue;
+ }
+
+ fromnet = NULL;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if ((ntp->mask & from.sin_addr.s_addr) ==
+ ntp->net.s_addr) {
+ fromnet = ntp;
+ break;
+ }
+
+ /*
+ * drop packets from nets we are ignoring permanently
+ */
+ if (fromnet == NULL) {
+ /*
+ * The following messages may originate on
+ * this host with an ignored network address
+ */
+ if (msgin.tsp_type != TSP_TRACEON &&
+ msgin.tsp_type != TSP_SETDATE &&
+ msgin.tsp_type != TSP_MSITE &&
+ msgin.tsp_type != TSP_TEST &&
+ msgin.tsp_type != TSP_TRACEOFF) {
+ if (trace) {
+ fprintf(fd,"readmsg: discard null net ");
+ print(&msgin, &from);
+ }
+ continue;
+ }
+ }
+
+ /*
+ * Throw away messages coming from this machine,
+ * unless they are of some particular type.
+ * This gets rid of broadcast messages and reduces
+ * master processing time.
+ */
+ if (!strcmp(msgin.tsp_name, hostname)
+ && msgin.tsp_type != TSP_SETDATE
+ && msgin.tsp_type != TSP_TEST
+ && msgin.tsp_type != TSP_MSITE
+ && msgin.tsp_type != TSP_TRACEON
+ && msgin.tsp_type != TSP_TRACEOFF
+ && msgin.tsp_type != TSP_LOOP) {
+ if (trace) {
+ fprintf(fd, "readmsg: discard own ");
+ print(&msgin, &from);
+ }
+ continue;
+ }
+
+ /*
+ * Send acknowledgements here; this is faster and
+ * avoids deadlocks that would occur if acks were
+ * sent from a higher level routine. Different
+ * acknowledgements are necessary, depending on
+ * status.
+ */
+ if (fromnet == NULL) /* do not de-reference 0 */
+ ignoreack();
+ else if (fromnet->status == MASTER)
+ masterack();
+ else if (fromnet->status == SLAVE)
+ slaveack();
+ else
+ ignoreack();
+
+ if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
+ if (trace) {
+ fprintf(fd, "readmsg: ");
+ print(&msgin, &from);
+ }
+ return(&msgin);
+ } else if (++msgcnt > NHOSTS*3) {
+
+/* The protocol gets hopelessly confused if it gets too far
+* behind. However, it seems able to recover from all cases of lost
+* packets. Therefore, if we are swamped, throw everything away.
+*/
+ if (trace)
+ fprintf(fd,
+ "readmsg: discarding %d msgs\n",
+ msgcnt);
+ msgcnt = 0;
+ while ((ptr=head->p) != NULL) {
+ head->p = ptr->p;
+ free((char *)ptr);
+ }
+ tail = head;
+ } else {
+ tail->p = (struct tsplist *)
+ malloc(sizeof(struct tsplist));
+ tail = tail->p;
+ tail->p = NULL;
+ tail->info = msgin;
+ tail->addr = from;
+ /* timestamp msgs so SETTIMEs are correct */
+ tail->when = from_when;
+ }
+ }
+}
+
+/*
+ * Send the necessary acknowledgements:
+ * only the type ACK is to be sent by a slave
+ */
+void
+slaveack()
+{
+ switch(msgin.tsp_type) {
+
+ case TSP_ADJTIME:
+ case TSP_SETTIME:
+ case TSP_ACCEPT:
+ case TSP_REFUSE:
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_QUIT:
+ if (trace) {
+ fprintf(fd, "Slaveack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "Slaveack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * Certain packets may arrive from this machine on ignored networks.
+ * These packets should be acknowledged.
+ */
+void
+ignoreack()
+{
+ switch(msgin.tsp_type) {
+
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_QUIT:
+ if (trace) {
+ fprintf(fd, "Ignoreack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "Ignoreack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * `masterack' sends the necessary acknowledgments
+ * to the messages received by a master
+ */
+void
+masterack()
+{
+ struct tsp resp;
+
+ resp = msgin;
+ resp.tsp_vers = TSPVERSION;
+ (void)strcpy(resp.tsp_name, hostname);
+
+ switch(msgin.tsp_type) {
+
+ case TSP_QUIT:
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_MSITEREQ:
+ if (trace) {
+ fprintf(fd, "Masterack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ case TSP_RESOLVE:
+ case TSP_MASTERREQ:
+ if (trace) {
+ fprintf(fd, "Masterack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd,"Masterack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * Print a TSP message
+ */
+void
+print(msg, addr)
+struct tsp *msg;
+struct sockaddr_in *addr;
+{
+ char tm[26];
+ time_t msgtime;
+
+ switch (msg->tsp_type) {
+
+ case TSP_LOOP:
+ fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ msg->tsp_hopcnt,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ case TSP_SETTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+#ifdef sgi
+ (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ msgtime = msg->tsp_time.tv_sec;
+ strncpy(tm, ctime(&msgtime)+3+1, sizeof(tm));
+ tm[15] = '\0'; /* ugh */
+#endif /* sgi */
+ fprintf(fd, "%s %d %-6u %s %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ tm,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ case TSP_ADJTIME:
+ fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ msg->tsp_time.tv_sec,
+ msg->tsp_time.tv_usec,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ default:
+ fprintf(fd, "%s %d %-6u %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+ }
+}
diff --git a/usr.sbin/timed/timed/slave.c b/usr.sbin/timed/timed/slave.c
new file mode 100644
index 00000000000..c60491c5169
--- /dev/null
+++ b/usr.sbin/timed/timed/slave.c
@@ -0,0 +1,716 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)slave.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "globals.h"
+#include <setjmp.h>
+#include "pathnames.h"
+
+extern jmp_buf jmpenv;
+extern int Mflag;
+extern int justquit;
+
+extern u_short sequence;
+
+static char master_name[MAXHOSTNAMELEN+1];
+static struct netinfo *old_slavenet;
+static int old_status;
+
+static void schgdate(struct tsp *, char *);
+static void setmaster(struct tsp *);
+static void answerdelay(void);
+
+#ifdef sgi
+extern void logwtmp(struct timeval *, struct timeval *);
+#else
+extern void logwtmp(char *, char *, char *);
+#endif /* sgi */
+
+int
+slave()
+{
+ int tries;
+ long electiontime, refusetime, looktime, looptime, adjtime;
+ u_short seq;
+ long fastelection;
+#define FASTTOUT 3
+ struct in_addr cadr;
+ struct timeval otime;
+ struct sockaddr_in taddr;
+ char tname[MAXHOSTNAMELEN];
+ struct tsp *msg, to;
+ struct timeval ntime, wait;
+ time_t tmpt;
+ struct tsp *answer;
+ int timeout();
+ char olddate[32];
+ char newdate[32];
+ struct netinfo *ntp;
+ struct hosttbl *htp;
+
+
+ old_slavenet = 0;
+ seq = 0;
+ refusetime = 0;
+ adjtime = 0;
+
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ if (justquit)
+ looktime = electiontime;
+ else
+ looktime = fastelection;
+ looptime = fastelection;
+
+ if (slavenet)
+ xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
+ if (status & MASTER) {
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ masterup(ntp);
+ }
+ }
+
+loop:
+ get_goodgroup(0);
+ (void)gettimeofday(&ntime, (struct timezone *)0);
+ if (ntime.tv_sec > electiontime) {
+ if (trace)
+ fprintf(fd, "election timer expired\n");
+ longjmp(jmpenv, 1);
+ }
+
+ if (ntime.tv_sec >= looktime) {
+ if (trace)
+ fprintf(fd, "Looking for nets to master\n");
+
+ if (Mflag && nignorednets > 0) {
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == IGNORE
+ || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (ntp->status == MASTER) {
+ masterup(ntp);
+ } else if (ntp->status == MASTER) {
+ ntp->status = NOMASTER;
+ }
+ }
+ if (ntp->status == MASTER
+ && --ntp->quit_count < 0)
+ ntp->quit_count = 0;
+ }
+ makeslave(slavenet); /* prune extras */
+ setstatus();
+ }
+ (void)gettimeofday(&ntime, 0);
+ looktime = ntime.tv_sec + delay2;
+ }
+ if (ntime.tv_sec >= looptime) {
+ if (trace)
+ fprintf(fd, "Looking for loops\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER) {
+ to.tsp_type = TSP_LOOP;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = sequence++;
+ to.tsp_hopcnt = MAX_HOPCNT;
+ (void)strcpy(to.tsp_name, hostname);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)) < 0) {
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + delay2;
+ }
+
+ wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
+ if (wait.tv_sec < 0)
+ wait.tv_sec = 0;
+ wait.tv_sec += FASTTOUT;
+ wait.tv_usec = 0;
+ msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
+
+ if (msg != NULL) {
+ /*
+ * filter stuff not for us
+ */
+ switch (msg->tsp_type) {
+ case TSP_SETDATE:
+ case TSP_TRACEOFF:
+ case TSP_TRACEON:
+ /*
+ * XXX check to see they are from ourself
+ */
+ break;
+
+ case TSP_TEST:
+ case TSP_MSITE:
+ break;
+
+ case TSP_MASTERUP:
+ if (!fromnet) {
+ if (trace) {
+ fprintf(fd, "slave ignored: ");
+ print(msg, &from);
+ }
+ goto loop;
+ }
+ break;
+
+ default:
+ if (!fromnet
+ || fromnet->status == IGNORE
+ || fromnet->status == NOMASTER) {
+ if (trace) {
+ fprintf(fd, "slave ignored: ");
+ print(msg, &from);
+ }
+ goto loop;
+ }
+ break;
+ }
+
+
+ /*
+ * now process the message
+ */
+ switch (msg->tsp_type) {
+
+ case TSP_ADJTIME:
+ if (fromnet != slavenet)
+ break;
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted time adjustment by %s",
+ msg->tsp_name);
+ suppress(&from, msg->tsp_name, fromnet);
+ break;
+ }
+ /*
+ * Speed up loop detection in case we have a loop.
+ * Otherwise the clocks can race until the loop
+ * is found.
+ */
+ (void)gettimeofday(&otime, 0);
+ if (adjtime < otime.tv_sec)
+ looptime -= (looptime-otime.tv_sec)/2 + 1;
+
+ setmaster(msg);
+ if (seq != msg->tsp_seq) {
+ seq = msg->tsp_seq;
+ synch(tvtomsround(msg->tsp_time));
+ }
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ adjtime = ntime.tv_sec + SAMPLEINTVL*2;
+ break;
+
+ case TSP_SETTIME:
+ if (fromnet != slavenet)
+ break;
+ if (seq == msg->tsp_seq)
+ break;
+ seq = msg->tsp_seq;
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg,&otime);
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+ (void)cftime(olddate, "%D %T", &otime.tv_sec);
+#else
+ /*
+ * the following line is necessary due to syslog
+ * calling ctime() which clobbers the static buffer
+ */
+ (void)strcpy(olddate, date());
+ tmpt = msg->tsp_time.tv_sec;
+ (void)strcpy(newdate, ctime(&tmpt));
+#endif /* sgi */
+
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted time setting by untrusted %s to %s",
+ msg->tsp_name, newdate);
+ suppress(&from, msg->tsp_name, fromnet);
+ break;
+ }
+
+ setmaster(msg);
+ timersub(&msg->tsp_time, &otime, &ntime);
+ if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
+ /*
+ * do not change the clock if we can adjust it
+ */
+ synch(tvtomsround(ntime));
+ } else {
+#ifdef sgi
+ if (0 > settimeofday(&msg->tsp_time, 0)) {
+ syslog(LOG_ERR,"settimeofdate(): %m");
+ break;
+ }
+ logwtmp(&otime, &msg->tsp_time);
+#else
+ logwtmp("|", "date", "");
+ (void)settimeofday(&msg->tsp_time, 0);
+ logwtmp("}", "date", "");
+#endif /* sgi */
+ syslog(LOG_NOTICE,
+ "date changed by %s from %s",
+ msg->tsp_name, olddate);
+ if (status & MASTER)
+ spreadtime();
+ }
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+
+/* This patches a bad protocol bug. Imagine a system with several networks,
+ * where there are a pair of redundant gateways between a pair of networks,
+ * each running timed. Assume that we start with a third machine mastering
+ * one of the networks, and one of the gateways mastering the other.
+ * Imagine that the third machine goes away and the non-master gateway
+ * decides to replace it. If things are timed just 'right,' we will have
+ * each gateway mastering one network for a little while. If a SETTIME
+ * message gets into the network at that time, perhaps from the newly
+ * masterful gateway as it was taking control, the SETTIME will loop
+ * forever. Each time a gateway receives it on its slave side, it will
+ * call spreadtime to forward it on its mastered network. We are now in
+ * a permanent loop, since the SETTIME msgs will keep any clock
+ * in the network from advancing. Normally, the 'LOOP' stuff will detect
+ * and correct the situation. However, with the clocks stopped, the
+ * 'looptime' timer cannot expire. While they are in this state, the
+ * masters will try to saturate the network with SETTIME packets.
+ */
+ looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
+ break;
+
+ case TSP_MASTERUP:
+ if (slavenet && fromnet != slavenet)
+ break;
+ if (!good_host_name(msg->tsp_name)) {
+ suppress(&from, msg->tsp_name, fromnet);
+ if (electiontime > fastelection)
+ electiontime = fastelection;
+ break;
+ }
+ makeslave(fromnet);
+ setmaster(msg);
+ setstatus();
+ answerdelay();
+ xmit(TSP_SLAVEUP, 0, &from);
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ refusetime = 0;
+ break;
+
+ case TSP_MASTERREQ:
+ if (fromnet->status != SLAVE)
+ break;
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ break;
+
+ case TSP_SETDATE:
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ tmpt = msg->tsp_time.tv_sec;
+ (void)strcpy(newdate, ctime(&tmpt));
+#endif /* sgi */
+ schgdate(msg, newdate);
+ break;
+
+ case TSP_SETDATEREQ:
+ if (fromnet->status != MASTER)
+ break;
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ tmpt = msg->tsp_time.tv_sec;
+ (void)strcpy(newdate, ctime(&tmpt));
+#endif /* sgi */
+ htp = findhost(msg->tsp_name);
+ if (0 == htp) {
+ syslog(LOG_WARNING,
+ "DATEREQ from uncontrolled machine");
+ break;
+ }
+ if (!htp->good) {
+ syslog(LOG_WARNING,
+ "attempted date change by untrusted %s to %s",
+ htp->name, newdate);
+ spreadtime();
+ break;
+ }
+ schgdate(msg, newdate);
+ break;
+
+ case TSP_TRACEON:
+ traceon();
+ break;
+
+ case TSP_TRACEOFF:
+ traceoff("Tracing ended at %s\n");
+ break;
+
+ case TSP_SLAVEUP:
+ newslave(msg);
+ break;
+
+ case TSP_ELECTION:
+ if (fromnet->status == SLAVE) {
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ seq = 0;
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "suppress election of %s",
+ msg->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ electiontime = fastelection;
+ } else if (cadr.s_addr != from.sin_addr.s_addr
+ && ntime.tv_sec < refusetime) {
+/* if the candidate has to repeat itself, the old code would refuse it
+ * the second time. That would prevent elections.
+ */
+ to.tsp_type = TSP_REFUSE;
+ } else {
+ cadr.s_addr = from.sin_addr.s_addr;
+ to.tsp_type = TSP_ACCEPT;
+ refusetime = ntime.tv_sec + 30;
+ }
+ taddr = from;
+ (void)strcpy(tname, msg->tsp_name);
+ (void)strcpy(to.tsp_name, hostname);
+ answerdelay();
+ if (!acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 0))
+ syslog(LOG_WARNING,
+ "no answer from candidate %s\n",
+ tname);
+
+ } else { /* fromnet->status == MASTER */
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer)) {
+ syslog(LOG_ERR,
+ "no reply from %s to ELECTION-QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ break;
+
+ case TSP_CONFLICT:
+ if (fromnet->status != MASTER)
+ break;
+ /*
+ * After a network partition, there can be
+ * more than one master: the first slave to
+ * come up will notify here the situation.
+ */
+ (void)strcpy(to.tsp_name, hostname);
+
+ /* The other master often gets into the same state,
+ * with boring results.
+ */
+ ntp = fromnet; /* (acksend() can leave fromnet=0 */
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp, 0);
+ if (answer == NULL)
+ break;
+ htp = addmach(answer->tsp_name,&from,ntp);
+ to.tsp_type = TSP_QUIT;
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (!answer) {
+ syslog(LOG_WARNING,
+ "conflict error: no reply from %s to QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ masterup(ntp);
+ break;
+
+ case TSP_MSITE:
+ if (!slavenet)
+ break;
+ taddr = from;
+ to.tsp_type = TSP_MSITEREQ;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = 0;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &slavenet->dest_addr,
+ ANYADDR, TSP_ACK,
+ slavenet, 0);
+ if (answer != NULL
+ && good_host_name(answer->tsp_name)) {
+ setmaster(answer);
+ to.tsp_type = TSP_ACK;
+ (void)strcpy(to.tsp_name, answer->tsp_name);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&taddr, sizeof(taddr)) < 0) {
+ trace_sendto_err(taddr.sin_addr);
+ }
+ }
+ break;
+
+ case TSP_MSITEREQ:
+ break;
+
+ case TSP_ACCEPT:
+ case TSP_REFUSE:
+ case TSP_RESOLVE:
+ break;
+
+ case TSP_QUIT:
+ doquit(msg); /* become a slave */
+ break;
+
+ case TSP_TEST:
+ electiontime = 0;
+ break;
+
+ case TSP_LOOP:
+ /* looking for loops of masters */
+ if (!(status & MASTER))
+ break;
+ if (fromnet->status == SLAVE) {
+ if (!strcmp(msg->tsp_name, hostname)) {
+ /*
+ * Someone forwarded our message back to
+ * us. There must be a loop. Tell the
+ * master of this network to quit.
+ *
+ * The other master often gets into
+ * the same state, with boring results.
+ */
+ ntp = fromnet;
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp,0);
+ if (answer == NULL)
+ break;
+ taddr = from;
+ (void)strcpy(tname, answer->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 1)) {
+ syslog(LOG_ERR,
+ "no reply from %s to slave LOOP-QUIT",
+ tname);
+ } else {
+ electiontime = 0;
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + FASTTOUT;
+ } else {
+ if (msg->tsp_hopcnt-- < 1)
+ break;
+ bytenetorder(msg);
+ for (ntp = nettab; ntp != 0; ntp = ntp->next) {
+ if (ntp->status == MASTER
+ && 0 > sendto(sock, (char *)msg,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)))
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ } else { /* fromnet->status == MASTER */
+ /*
+ * We should not have received this from a net
+ * we are master on. There must be two masters,
+ * unless the packet was really from us.
+ */
+ if (from.sin_addr.s_addr
+ == fromnet->my_addr.s_addr) {
+ if (trace)
+ fprintf(fd,"discarding forwarded LOOP\n");
+ break;
+ }
+
+ /*
+ * The other master often gets into the same
+ * state, with boring results.
+ */
+ ntp = fromnet;
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp,0);
+ if (!answer)
+ break;
+ htp = addmach(answer->tsp_name,
+ &from,ntp);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to,&htp->addr,htp->name,
+ TSP_ACK, 0, htp->noanswer)) {
+ syslog(LOG_ERR,
+ "no reply from %s to master LOOP-QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + FASTTOUT;
+ }
+ break;
+ default:
+ if (trace) {
+ fprintf(fd, "garbage message: ");
+ print(msg, &from);
+ }
+ break;
+ }
+ }
+ goto loop;
+}
+
+
+/*
+ * tell the world who our master is
+ */
+static void
+setmaster(struct tsp *msg)
+{
+ if (slavenet
+ && (slavenet != old_slavenet
+ || strcmp(msg->tsp_name, master_name)
+ || old_status != status)) {
+ (void)strcpy(master_name, msg->tsp_name);
+ old_slavenet = slavenet;
+ old_status = status;
+
+ if (status & MASTER) {
+ syslog(LOG_NOTICE, "submaster to %s", master_name);
+ if (trace)
+ fprintf(fd, "submaster to %s\n", master_name);
+
+ } else {
+ syslog(LOG_NOTICE, "slave to %s", master_name);
+ if (trace)
+ fprintf(fd, "slave to %s\n", master_name);
+ }
+ }
+}
+
+
+
+/*
+ * handle date change request on a slave
+ */
+static void
+schgdate(struct tsp *msg, char *newdate)
+{
+ struct tsp to;
+ u_short seq;
+ struct sockaddr_in taddr;
+ struct timeval otime;
+
+ if (!slavenet)
+ return; /* no where to forward */
+
+ taddr = from;
+ seq = msg->tsp_seq;
+
+ syslog(LOG_INFO,
+ "forwarding date change by %s to %s",
+ msg->tsp_name, newdate);
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg, &otime);
+
+ to.tsp_type = TSP_SETDATEREQ;
+ to.tsp_time = msg->tsp_time;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &slavenet->dest_addr,
+ ANYADDR, TSP_DATEACK,
+ slavenet, 0))
+ return; /* no answer */
+
+ xmit(TSP_DATEACK, seq, &taddr);
+}
+
+
+/*
+ * Used before answering a broadcast message to avoid network
+ * contention and likely collisions.
+ */
+static void
+answerdelay(void)
+{
+#ifdef sgi
+ sginap(delay1);
+#else
+ struct timeval timeout;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = delay1;
+
+ (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
+ &timeout);
+ return;
+#endif /* sgi */
+}
diff --git a/usr.sbin/timed/timed/timed-extern.h b/usr.sbin/timed/timed/timed-extern.h
new file mode 100644
index 00000000000..a8ba26c77d6
--- /dev/null
+++ b/usr.sbin/timed/timed/timed-extern.h
@@ -0,0 +1,86 @@
+/*-
+ * 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.
+ *
+ * @(#)extern.h 5.1 (Berkeley) 5/11/93
+ */
+
+struct hosttbl;
+struct netinfo;
+struct sockaddr_in;
+struct timeval;
+struct tsp;
+
+struct hosttbl *addmach(char *, struct sockaddr_in *, struct netinfo *);
+struct hosttbl *findhost(char *);
+struct hosttbl *remmach(struct hosttbl *);
+
+struct tsp *readmsg(int, char *, struct timeval *, struct netinfo *);
+struct tsp *acksend(struct tsp *,
+ struct sockaddr_in *, char *, int, struct netinfo *, int);
+
+void addnetname(char *);
+void adj_msg_time(struct tsp *, struct timeval *);
+void bytehostorder(struct tsp *);
+void bytenetorder(struct tsp *);
+void byteorder(struct tsp *);
+long casual(long, long);
+int cksum(u_short *, int);
+void correct(long);
+char *date(void);
+void doquit(struct tsp *);
+int election(struct netinfo *);
+void get_goodgroup(int);
+int good_host_name(char *);
+void ignoreack(void);
+int in_cksum(u_short *, int);
+void lookformaster(struct netinfo *);
+void makeslave(struct netinfo *);
+int master(void);
+void masterack(void);
+void masterup(struct netinfo *);
+int measure(u_long, u_long, char *, struct sockaddr_in *, int);
+void msterup(struct netinfo *);
+void mstotvround(struct timeval *, long);
+long networkdelta(void);
+void newslave(struct tsp *);
+void print(struct tsp *, struct sockaddr_in *);
+void prthp(clock_t);
+void rmnetmachs(struct netinfo *);
+void setstatus(void);
+int slave(void);
+void slaveack(void);
+void spreadtime(void);
+void suppress(struct sockaddr_in *, char *, struct netinfo *);
+void synch(long);
+void traceoff(char *);
+void traceon(void);
+void xmit(int, u_short, struct sockaddr_in *);
diff --git a/usr.sbin/timed/timed/timed.8 b/usr.sbin/timed/timed/timed.8
new file mode 100644
index 00000000000..70fc7036627
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.8
@@ -0,0 +1,221 @@
+.\" Copyright (c) 1980, 1991 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.
+.\"
+.\" @(#)timed.8 6.7 (Berkeley) 5/11/93
+.\"
+.Dd May 11, 1993
+.Dt TIMED 8
+.Os BSD 4.3
+.Sh NAME
+.Nm timed
+.Nd time server daemon
+.Sh SYNOPSIS
+.Nm timed
+.Op Fl M
+.Op Fl t
+.Op Fl d
+.Op Fl i Ar network
+.Op Fl n Ar network
+.Op Fl F Ar host1 host2 ...
+.Sh DESCRIPTION
+This
+is a time server daemon and is normally invoked
+at boot time from the
+.Xr rc 8
+file.
+It synchronizes the host's time with the time of other
+machines in a local area network running
+.Nm timed .
+These time servers will slow down the clocks of some machines
+and speed up the clocks of others to bring them to the average network time.
+The average network time is computed from measurements of clock differences
+using the
+.Tn ICMP
+timestamp request message.
+.Pp
+The service provided by
+.Nm timed
+is based on a master-slave
+scheme.
+When
+.Nm timed
+is started on a machine, it asks the master for the network time
+and sets the host's clock to that time.
+After that, it accepts synchronization messages periodically sent by
+the master and calls
+.Xr adjtime 2
+to perform the needed corrections on the host's clock.
+.Pp
+It also communicates with
+.Xr date 1
+in order to set the date globally,
+and with
+.Xr timedc 8 ,
+a timed control program.
+If the machine running the master crashes, then the slaves will elect
+a new master from among slaves running with the
+.Fl M
+flag.
+A
+.Nm timed
+running without the
+.Fl M
+or
+.Fl F
+flags will remain a slave.
+The
+.Fl t
+flag enables
+.Nm timed
+to trace the messages it receives in the
+file
+.Pa /var/log/timed.log .
+Tracing can be turned on or off by the program
+.Xr timedc 8 .
+The
+.Fl d
+flag is for debugging the daemon.
+It causes the program to not put itself into the background.
+Normally
+.Nm timed
+checks for a master time server on each network to which
+it is connected, except as modified by the options described below.
+It will request synchronization service from the first master server
+located.
+If permitted by the
+.Fl M
+flag, it will provide synchronization service on any attached networks
+on which no current master server was detected.
+Such a server propagates the time computed by the top-level master.
+The
+.Fl n
+flag, followed by the name of a network which the host is connected to
+(see
+.Xr networks 5 ) ,
+overrides the default choice of the
+network addresses made by the program.
+Each time the
+.Fl n
+flag appears, that network name is added to a list of valid networks.
+All other networks are ignored.
+The
+.Fl i
+flag, followed by the name of a network to which the host is connected
+(see
+.Xr networks 5 ) ,
+overrides the default choice of the network addresses made by the program.
+Each time the
+.Fl i
+flag appears, that network name is added to a list of networks to ignore.
+All other networks are used by the time daemon.
+The
+.Fl n
+and
+.Fl i
+flags are meaningless if used together.
+.Pp
+.Nm Timed
+checks for a master time server on each network to which
+it is connected, except as modified by the
+.Fl n
+and
+.Fl i
+options described above.
+If it finds masters on more than one network, it chooses one network
+on which to be a "slave," and then periodically checks the other
+networks to see if the masters there have disappeared.
+.Pp
+One way to synchronize a group of machines is to use an NTP daemon to
+synchronize the clock of one machine to a distant standard or a radio
+receiver and
+.Fl F Ar hostname
+to tell its timed daemon to trust only itself.
+.Pp
+Messages printed by the kernel on the system console occur with
+interrupts disabled.
+This means that the clock stops while they are printing.
+A machine with many disk or network hardware problems and consequent
+messages cannot keep good time by itself. Each message typically causes
+the clock to lose a dozen milliseconds. A time daemon can
+correct the result.
+.Pp
+Messages in the system log about machines that failed to respond
+usually indicate machines that crashed or were turned off.
+Complaints about machines that failed to respond to initial time
+settings are often associated with
+.Dq multi-homed
+machines that looked for time masters on more than one network and eventually
+chose to become a slave on the other network.
+.Sh WARNINGS
+If two or more time daemons, whether
+.Nm timed ,
+.Xr NTP ,
+try to adjust the same clock, temporal chaos will result.
+If both
+.Nm
+and another time daemon are run on the same machine,
+ensure that the
+.Fl F
+flag is used, so that
+.Nm timed
+never attempts to adjust the local clock.
+.Pp
+The protocol is based on UDP/IP broadcasts. All machines within
+the range of a broadcast that are using the TSP protocol must cooperate.
+There cannot be more than a single administrative domain using the
+.Fl F
+flag among all machines reached by a broadcast packet.
+Failure to follow this rule is usually indicated by complaints concerning
+.Dq untrusted
+machines in the system log.
+.Sh FILES
+.Bl -tag -width /var/log/timed.masterlog -compact
+.It Pa /var/log/timed.log
+tracing file for timed
+.It Pa /var/log/timed.masterlog
+log file for master timed
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr gettimeofday 2 ,
+.Xr icmp 4 ,
+.Xr timedc 8
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/timed/timed/timed.c b/usr.sbin/timed/timed/timed.c
new file mode 100644
index 00000000000..7a200909467
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.c
@@ -0,0 +1,975 @@
+/*-
+ * Copyright (c) 1985, 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
+char copyright[] =
+"@(#) Copyright (c) 1985, 1993 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timed.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif /* sgi */
+
+#define TSPTYPES
+#include "globals.h"
+#include <net/if.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <setjmp.h>
+#include "pathnames.h"
+#include <math.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#ifdef sgi
+#include <unistd.h>
+#include <sys/syssgi.h>
+#include <sys/schedctl.h>
+#endif /* sgi */
+
+int trace = 0;
+int sock, sock_raw = -1;
+int status = 0;
+u_short sequence; /* sequence number */
+long delay1;
+long delay2;
+
+int nslavenets; /* nets were I could be a slave */
+int nmasternets; /* nets were I could be a master */
+int nignorednets; /* ignored nets */
+int nnets; /* nets I am connected to */
+
+FILE *fd; /* trace file FD */
+
+jmp_buf jmpenv;
+
+struct netinfo *nettab = 0;
+struct netinfo *slavenet;
+int Mflag;
+int justquit = 0;
+int debug;
+
+static struct nets {
+ char *name;
+ long net;
+ struct nets *next;
+} *nets = 0;
+
+struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
+
+static struct goodhost { /* hosts that we trust */
+ char name[MAXHOSTNAMELEN+1];
+ struct goodhost *next;
+ char perm;
+} *goodhosts;
+
+static char *goodgroup; /* net group of trusted hosts */
+static void checkignorednets(void);
+static void pickslavenet(struct netinfo *);
+static void add_good_host(char*,char);
+
+#ifdef sgi
+char *timetrim_fn;
+char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n";
+char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;";
+long timetrim;
+double tot_adj, hr_adj; /* totals in nsec */
+double tot_ticks, hr_ticks;
+
+int bufspace = 60*1024;
+#endif
+
+
+/*
+ * The timedaemons synchronize the clocks of hosts in a local area network.
+ * One daemon runs as master, all the others as slaves. The master
+ * performs the task of computing clock differences and sends correction
+ * values to the slaves.
+ * Slaves start an election to choose a new master when the latter disappears
+ * because of a machine crash, network partition, or when killed.
+ * A resolution protocol is used to kill all but one of the masters
+ * that happen to exist in segments of a partitioned network when the
+ * network partition is fixed.
+ *
+ * Authors: Riccardo Gusella & Stefano Zatti
+ *
+ * overhauled at Silicon Graphics
+ */
+int
+main(int argc, char **argv)
+{
+ int on;
+ int ret;
+ int nflag, iflag;
+ struct timeval ntime;
+ struct servent *srvp;
+ char buf[BUFSIZ], *cp, *cplim;
+ struct ifconf ifc;
+ struct ifreq ifreq, ifreqf, *ifr;
+ register struct netinfo *ntp;
+ struct netinfo *ntip;
+ struct netinfo *savefromnet;
+ struct netent *nentp;
+ struct nets *nt;
+ struct sockaddr_in server;
+ u_short port;
+ char c;
+ extern char *optarg;
+ extern int optind, opterr;
+#ifdef sgi
+ FILE *timetrim_st;
+#endif
+
+#define IN_MSG "timed: -i and -n make no sense together\n"
+#ifdef sgi
+ struct tms tms;
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n"
+#else
+#ifdef HAVENIS
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"
+#else
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"
+#endif /* HAVENIS */
+#endif /* sgi */
+
+#ifdef lint
+ ntip = NULL;
+#endif
+
+ on = 1;
+ nflag = OFF;
+ iflag = OFF;
+
+#ifdef sgi
+ if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) {
+ perror("timed: syssgi(GETTIMETRIM)");
+ timetrim = 0;
+ }
+ tot_ticks = hr_ticks = times(&tms);
+#endif /* sgi */
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != EOF) {
+ switch (c) {
+ case 'M':
+ Mflag = 1;
+ break;
+
+ case 't':
+ trace = 1;
+ break;
+
+ case 'n':
+ if (iflag) {
+ fprintf(stderr, IN_MSG);
+ exit(1);
+ } else {
+ nflag = ON;
+ addnetname(optarg);
+ }
+ break;
+
+ case 'i':
+ if (nflag) {
+ fprintf(stderr, IN_MSG);
+ exit(1);
+ } else {
+ iflag = ON;
+ addnetname(optarg);
+ }
+ break;
+
+ case 'F':
+ add_good_host(optarg,1);
+ while (optind < argc && argv[optind][0] != '-')
+ add_good_host(argv[optind++], 1);
+ break;
+
+ case 'd':
+ debug = 1;
+ break;
+ case 'G':
+ if (goodgroup != 0) {
+ fprintf(stderr,"timed: only one net group\n");
+ exit(1);
+ }
+ goodgroup = optarg;
+ break;
+#ifdef sgi
+ case 'P':
+ timetrim_fn = optarg;
+ break;
+#endif /* sgi */
+
+ default:
+ fprintf(stderr, USAGE);
+ exit(1);
+ break;
+ }
+ }
+ if (optind < argc) {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+#ifdef sgi
+ if (timetrim_fn == 0) {
+ ;
+ } else if (0 == (timetrim_st = fopen(timetrim_fn, "r+"))) {
+ if (errno != ENOENT) {
+ (void)fprintf(stderr,"timed: ");
+ perror(timetrim_fn);
+ timetrim_fn = 0;
+ }
+ } else {
+ int i;
+ long trim;
+ double adj, ticks;
+
+ i = fscanf(timetrim_st, timetrim_rpat,
+ &trim, &adj, &ticks);
+ if (i < 1
+ || trim > MAX_TRIM
+ || trim < -MAX_TRIM
+ || i == 2
+ || (i == 3
+ && trim != rint(adj*CLK_TCK/ticks))) {
+ if (trace && i != EOF)
+ (void)fprintf(stderr,
+ "timed: unrecognized contents in %s\n",
+ timetrim_fn);
+ } else {
+ if (0 > syssgi(SGI_SETTIMETRIM,
+ trim)) {
+ perror("timed: syssgi(SETTIMETRIM)");
+ } else {
+ timetrim = trim;
+ }
+ if (i == 3)
+ tot_ticks -= ticks;
+ }
+ (void)fclose(timetrim_st);
+ }
+#endif /* sgi */
+
+ /* If we care about which machine is the master, then we must
+ * be willing to be a master
+ */
+ if (0 != goodgroup || 0 != goodhosts)
+ Mflag = 1;
+
+ if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
+ perror("gethostname");
+ exit(1);
+ }
+ self.l_bak = &self;
+ self.l_fwd = &self;
+ self.h_bak = &self;
+ self.h_fwd = &self;
+ self.head = 1;
+ self.good = 1;
+
+ if (goodhosts != 0) /* trust ourself */
+ add_good_host(hostname,1);
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "unknown service 'timed/udp'\n");
+ exit(1);
+ }
+ port = srvp->s_port;
+ bzero(&server, sizeof(server));
+ server.sin_port = srvp->s_port;
+ server.sin_family = AF_INET;
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ exit(1);
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
+ sizeof(on)) < 0) {
+ perror("setsockopt");
+ exit(1);
+ }
+ if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
+ if (errno == EADDRINUSE)
+ fprintf(stderr,"timed: time daemon already running\n");
+ else
+ perror("bind");
+ exit(1);
+ }
+#ifdef sgi
+ /*
+ * handle many slaves with our buffer
+ */
+ if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace,
+ sizeof(bufspace))) {
+ perror("setsockopt");
+ exit(1);
+ }
+#endif /* sgi */
+
+ /* choose a unique seed for random number generation */
+ (void)gettimeofday(&ntime, 0);
+ srandom(ntime.tv_sec + ntime.tv_usec);
+
+ sequence = random(); /* initial seq number */
+
+#ifndef sgi
+ /* rounds kernel variable time to multiple of 5 ms. */
+ ntime.tv_sec = 0;
+ ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
+ (void)adjtime(&ntime, (struct timeval *)0);
+#endif /* sgi */
+
+ for (nt = nets; nt; nt = nt->next) {
+ nentp = getnetbyname(nt->name);
+ if (nentp == 0) {
+ nt->net = inet_network(nt->name);
+ if (nt->net != INADDR_NONE)
+ nentp = getnetbyaddr(nt->net, AF_INET);
+ }
+ if (nentp != 0) {
+ nt->net = nentp->n_net;
+ } else if (nt->net == INADDR_NONE) {
+ fprintf(stderr, "timed: unknown net %s\n", nt->name);
+ exit(1);
+ } else if (nt->net == INADDR_ANY) {
+ fprintf(stderr, "timed: bad net %s\n", nt->name);
+ exit(1);
+ } else {
+ fprintf(stderr,
+ "timed: warning: %s unknown in /etc/networks\n",
+ nt->name);
+ }
+
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ }
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+ perror("timed: get interface configuration");
+ exit(1);
+ }
+ ntp = NULL;
+#ifdef sgi
+#define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */
+#else
+#define size(p) max((p).sa_len, sizeof(p))
+#endif
+ cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+ for (cp = buf; cp < cplim;
+ cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+ ifr = (struct ifreq *)cp;
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ if (!ntp)
+ ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
+ bzero(ntp,sizeof(*ntp));
+ ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+ ntp->status = NOMASTER;
+ ifreq = *ifr;
+ ifreqf = *ifr;
+
+ if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
+ perror("get interface flags");
+ continue;
+ }
+ if ((ifreqf.ifr_flags & IFF_UP) == 0)
+ continue;
+ if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
+ (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
+ continue;
+ }
+
+
+ if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ perror("get netmask");
+ continue;
+ }
+ ntp->mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+
+ if (ifreqf.ifr_flags & IFF_BROADCAST) {
+ if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+ perror("get broadaddr");
+ continue;
+ }
+ ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
+ /* What if the broadcast address is all ones?
+ * So we cannot just mask ntp->dest_addr. */
+ ntp->net = ntp->my_addr;
+ ntp->net.s_addr &= ntp->mask;
+ } else {
+ if (ioctl(sock, SIOCGIFDSTADDR,
+ (char *)&ifreq) < 0) {
+ perror("get destaddr");
+ continue;
+ }
+ ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
+ ntp->net = ntp->dest_addr.sin_addr;
+ }
+
+ ntp->dest_addr.sin_port = port;
+
+ for (nt = nets; nt; nt = nt->next) {
+ if (ntp->net.s_addr == nt->net)
+ break;
+ }
+ if (nflag && !nt || iflag && nt)
+ continue;
+
+ ntp->next = NULL;
+ if (nettab == NULL) {
+ nettab = ntp;
+ } else {
+ ntip->next = ntp;
+ }
+ ntip = ntp;
+ ntp = NULL;
+ }
+ if (ntp)
+ (void) free((char *)ntp);
+ if (nettab == NULL) {
+ fprintf(stderr, "timed: no network usable\n");
+ exit(1);
+ }
+
+
+#ifdef sgi
+ (void)schedctl(RENICE,0,10); /* run fast to get good time */
+
+ /* ticks to delay before responding to a broadcast */
+ delay1 = casual(0, CLK_TCK/10);
+#else
+
+ /* microseconds to delay before responding to a broadcast */
+ delay1 = casual(1, 100*1000);
+#endif /* sgi */
+
+ /* election timer delay in secs. */
+ delay2 = casual(MINTOUT, MAXTOUT);
+
+
+#ifdef sgi
+ (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1);
+#else
+ if (!debug)
+ daemon(debug, 0);
+#endif /* sgi */
+
+ if (trace)
+ traceon();
+ openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ /*
+ * keep returning here
+ */
+ ret = setjmp(jmpenv);
+ savefromnet = fromnet;
+ setstatus();
+
+ if (Mflag) {
+ switch (ret) {
+
+ case 0:
+ checkignorednets();
+ pickslavenet(0);
+ break;
+ case 1:
+ /* Just lost our master */
+ if (slavenet != 0)
+ slavenet->status = election(slavenet);
+ if (!slavenet || slavenet->status == MASTER) {
+ checkignorednets();
+ pickslavenet(0);
+ } else {
+ makeslave(slavenet); /* prune extras */
+ }
+ break;
+
+ case 2:
+ /* Just been told to quit */
+ justquit = 1;
+ pickslavenet(savefromnet);
+ break;
+ }
+
+ setstatus();
+ if (!(status & MASTER) && sock_raw != -1) {
+ /* sock_raw is not being used now */
+ (void)close(sock_raw);
+ sock_raw = -1;
+ }
+
+ if (status == MASTER)
+ master();
+ else
+ slave();
+
+ } else {
+ if (sock_raw != -1) {
+ (void)close(sock_raw);
+ sock_raw = -1;
+ }
+
+ if (ret) {
+ /* we just lost our master or were told to quit */
+ justquit = 1;
+ }
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ rmnetmachs(ntp);
+ ntp->status = NOMASTER;
+ }
+ checkignorednets();
+ pickslavenet(0);
+ setstatus();
+
+ slave();
+ }
+ /* NOTREACHED */
+#ifdef lint
+ return(0);
+#endif
+}
+
+
+/* suppress an upstart, untrustworthy, self-appointed master
+ */
+void
+suppress(struct sockaddr_in *addr,
+ char *name,
+ struct netinfo *net)
+{
+ struct sockaddr_in tgt;
+ char tname[MAXHOSTNAMELEN];
+ struct tsp msg;
+ static struct timeval wait;
+
+ if (trace)
+ fprintf(fd, "suppress: %s\n", name);
+ tgt = *addr;
+ (void)strcpy(tname, name);
+
+ while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "suppress:\tdiscarded packet from %s\n",
+ name);
+ }
+
+ syslog(LOG_NOTICE, "suppressing false master %s", tname);
+ msg.tsp_type = TSP_QUIT;
+ (void)strcpy(msg.tsp_name, hostname);
+ (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
+}
+
+void
+lookformaster(struct netinfo *ntp)
+{
+ struct tsp resp, conflict, *answer;
+ struct timeval ntime;
+ char mastername[MAXHOSTNAMELEN];
+ struct sockaddr_in masteraddr;
+
+ get_goodgroup(0);
+ ntp->status = SLAVE;
+
+ /* look for master */
+ resp.tsp_type = TSP_MASTERREQ;
+ (void)strcpy(resp.tsp_name, hostname);
+ answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
+ TSP_MASTERACK, ntp, 0);
+ if (answer != 0 && !good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ answer = 0;
+ }
+ if (answer == 0) {
+ /*
+ * Various conditions can cause conflict: races between
+ * two just started timedaemons when no master is
+ * present, or timedaemons started during an election.
+ * A conservative approach is taken. Give up and became a
+ * slave, postponing election of a master until first
+ * timer expires.
+ */
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ if (Mflag)
+ ntp->status = MASTER;
+ else
+ ntp->status = NOMASTER;
+ return;
+ }
+
+ ntp->status = SLAVE;
+ (void)strcpy(mastername, answer->tsp_name);
+ masteraddr = from;
+
+ /*
+ * If network has been partitioned, there might be other
+ * masters; tell the one we have just acknowledged that
+ * it has to gain control over the others.
+ */
+ ntime.tv_sec = 0;
+ ntime.tv_usec = 300000;
+ answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
+ /*
+ * checking also not to send CONFLICT to ack'ed master
+ * due to duplicated MASTERACKs
+ */
+ if (answer != NULL &&
+ strcmp(answer->tsp_name, mastername) != 0) {
+ conflict.tsp_type = TSP_CONFLICT;
+ (void)strcpy(conflict.tsp_name, hostname);
+ if (!acksend(&conflict, &masteraddr, mastername,
+ TSP_ACK, 0, 0)) {
+ syslog(LOG_ERR,
+ "error on sending TSP_CONFLICT");
+ }
+ }
+}
+
+/*
+ * based on the current network configuration, set the status, and count
+ * networks;
+ */
+void
+setstatus()
+{
+ struct netinfo *ntp;
+
+ status = 0;
+ nmasternets = nslavenets = nnets = nignorednets = 0;
+ if (trace)
+ fprintf(fd, "Net status:\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ switch ((int)ntp->status) {
+ case MASTER:
+ nmasternets++;
+ break;
+ case SLAVE:
+ nslavenets++;
+ break;
+ case NOMASTER:
+ case IGNORE:
+ nignorednets++;
+ break;
+ }
+ if (trace) {
+ fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
+ switch ((int)ntp->status) {
+ case NOMASTER:
+ fprintf(fd, "NOMASTER\n");
+ break;
+ case MASTER:
+ fprintf(fd, "MASTER\n");
+ break;
+ case SLAVE:
+ fprintf(fd, "SLAVE\n");
+ break;
+ case IGNORE:
+ fprintf(fd, "IGNORE\n");
+ break;
+ default:
+ fprintf(fd, "invalid state %d\n",
+ (int)ntp->status);
+ break;
+ }
+ }
+ nnets++;
+ status |= ntp->status;
+ }
+ status &= ~IGNORE;
+ if (trace)
+ fprintf(fd,
+ "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n",
+ nnets, nmasternets, nslavenets, nignorednets, delay2);
+}
+
+void
+makeslave(struct netinfo *net)
+{
+ register struct netinfo *ntp;
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == SLAVE && ntp != net)
+ ntp->status = IGNORE;
+ }
+ slavenet = net;
+}
+
+/*
+ * Try to become master over ignored nets..
+ */
+static void
+checkignorednets(void)
+{
+ register struct netinfo *ntp;
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (!Mflag && ntp->status == SLAVE)
+ break;
+
+ if (ntp->status == IGNORE || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (!Mflag && ntp->status == SLAVE)
+ break;
+ }
+ }
+}
+
+/*
+ * choose a good network on which to be a slave
+ * The ignored networks must have already been checked.
+ * Take a hint about for a good network.
+ */
+static void
+pickslavenet(struct netinfo *ntp)
+{
+ if (slavenet != 0 && slavenet->status == SLAVE) {
+ makeslave(slavenet); /* prune extras */
+ return;
+ }
+
+ if (ntp == 0 || ntp->status != SLAVE) {
+ for (ntp = nettab; ntp != 0; ntp = ntp->next) {
+ if (ntp->status == SLAVE)
+ break;
+ }
+ }
+ makeslave(ntp);
+}
+
+/*
+ * returns a random number in the range [inf, sup]
+ */
+long
+casual(long inf, long sup)
+{
+ double value;
+
+ value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
+ return(inf + (sup - inf)*value);
+}
+
+char *
+date()
+{
+#ifdef sgi
+ struct timeval tv;
+ static char tm[32];
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ (void)cftime(tm, "%D %T", &tv.tv_sec);
+ return (tm);
+#else
+ struct timeval tv;
+ time_t t;
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ t = tv.tv_sec;
+ return (ctime(&t));
+#endif /* sgi */
+}
+
+void
+addnetname(char *name)
+{
+ register struct nets **netlist = &nets;
+
+ while (*netlist)
+ netlist = &((*netlist)->next);
+ *netlist = (struct nets *)malloc(sizeof **netlist);
+ if (*netlist == 0) {
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ bzero((char *)*netlist, sizeof(**netlist));
+ (*netlist)->name = name;
+}
+
+/* note a host as trustworthy */
+static void
+add_good_host(char* name,
+ char perm) /* 1=not part of the netgroup */
+{
+ register struct goodhost *ghp;
+ register struct hostent *hentp;
+
+ ghp = (struct goodhost*)malloc(sizeof(*ghp));
+ if (!ghp) {
+ syslog(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+
+ bzero((char*)ghp, sizeof(*ghp));
+ (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
+ ghp->next = goodhosts;
+ ghp->perm = perm;
+ goodhosts = ghp;
+
+ hentp = gethostbyname(name);
+ if (0 == hentp && perm)
+ (void)fprintf(stderr, "unknown host %s\n", name);
+}
+
+
+/* update our image of the net-group of trustworthy hosts
+ */
+void
+get_goodgroup(int force)
+{
+# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
+ static unsigned long last_update = -NG_DELAY;
+ unsigned long new_update;
+ struct hosttbl *htp;
+ struct goodhost *ghp, **ghpp;
+ char *mach, *usr, *dom;
+ struct tms tm;
+
+
+ /* if no netgroup, then we are finished */
+ if (goodgroup == 0 || !Mflag)
+ return;
+
+ /* Do not chatter with the netgroup master too often.
+ */
+ new_update = times(&tm);
+ if (new_update < last_update + NG_DELAY
+ && !force)
+ return;
+ last_update = new_update;
+
+ /* forget the old temporary entries */
+ ghpp = &goodhosts;
+ while (0 != (ghp = *ghpp)) {
+ if (!ghp->perm) {
+ *ghpp = ghp->next;
+ free((char*)ghp);
+ } else {
+ ghpp = &ghp->next;
+ }
+ }
+
+#ifdef HAVENIS
+ /* quit now if we are not one of the trusted masters
+ */
+ if (!innetgr(goodgroup, &hostname[0], 0,0)) {
+ if (trace)
+ (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
+ &hostname[0], goodgroup);
+ return;
+ }
+ if (trace)
+ (void)fprintf(fd, "get_goodgroup: %s in %s\n",
+ &hostname[0], goodgroup);
+
+ /* mark the entire netgroup as trusted */
+ (void)setnetgrent(goodgroup);
+ while (getnetgrent(&mach,&usr,&dom)) {
+ if (0 != mach)
+ add_good_host(mach,0);
+ }
+ (void)endnetgrent();
+
+ /* update list of slaves */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ htp->good = good_host_name(&htp->name[0]);
+ }
+#endif /* HAVENIS */
+}
+
+
+/* see if a machine is trustworthy
+ */
+int /* 1=trust hp to change our date */
+good_host_name(name)
+ char *name;
+{
+ register struct goodhost *ghp = goodhosts;
+ register char c;
+
+ if (!ghp || !Mflag) /* trust everyone if no one named */
+ return 1;
+
+ c = *name;
+ do {
+ if (c == ghp->name[0]
+ && !strcasecmp(name, ghp->name))
+ return 1; /* found him, so say so */
+ } while (0 != (ghp = ghp->next));
+
+ if (!strcasecmp(name,hostname)) /* trust ourself */
+ return 1;
+
+ return 0; /* did not find him */
+}
diff --git a/usr.sbin/timed/timedc/Makefile b/usr.sbin/timed/timedc/Makefile
new file mode 100644
index 00000000000..ccc6f8fc36a
--- /dev/null
+++ b/usr.sbin/timed/timedc/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 5.4 (Berkeley) 5/11/93
+
+PROG= timedc
+SRCS= cmds.c cmdtab.c timedc.c byteorder.c measure.c cksum.c
+MAN= timedc.8
+BINOWN= root
+BINMODE=4555
+.PATH: ${.CURDIR}/../timed
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/timed/timedc/cmds.c b/usr.sbin/timed/timedc/cmds.c
new file mode 100644
index 00000000000..2858a4a1d4d
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmds.c
@@ -0,0 +1,519 @@
+/*-
+ * Copyright (c) 1985, 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 sccsid[] = "@(#)cmds.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "timedc.h"
+#include <sys/file.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#define TSPTYPES
+#include <protocols/timed.h>
+
+#ifdef sgi
+#include <bstring.h>
+#include <sys/clock.h>
+#else
+#define SECHR (60*60)
+#define SECDAY (24*SECHR)
+#endif /* sgi */
+
+# define DATE_PROTO "udp"
+# define DATE_PORT "time"
+
+
+int sock;
+int sock_raw;
+char myname[MAXHOSTNAMELEN];
+struct hostent *hp;
+struct sockaddr_in server;
+struct sockaddr_in dayaddr;
+extern int measure_delta;
+
+void bytenetorder(struct tsp *);
+void bytehostorder(struct tsp *);
+
+
+#define BU ((unsigned long)2208988800U) /* seconds before UNIX epoch */
+
+
+/* compute the difference between our date and another machine
+ */
+static int /* difference in days from our time */
+daydiff(char *hostname)
+{
+ int i;
+ int trials;
+ struct timeval tout, now;
+ fd_set ready;
+ struct sockaddr from;
+ int fromlen;
+ unsigned long sec;
+
+
+ /* wait 2 seconds between 10 tries */
+ tout.tv_sec = 2;
+ tout.tv_usec = 0;
+ for (trials = 0; trials < 10; trials++) {
+ /* ask for the time */
+ sec = 0;
+ if (sendto(sock, &sec, sizeof(sec), 0,
+ (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
+ perror("sendto(sock)");
+ return 0;
+ }
+
+ for (;;) {
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ i = select(sock+1, &ready, (fd_set *)0,
+ (fd_set *)0, &tout);
+ if (i < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("select(date read)");
+ return 0;
+ }
+ if (0 == i)
+ break;
+
+ fromlen = sizeof(from);
+ if (recvfrom(sock,&sec,sizeof(sec),0,
+ &from,&fromlen) < 0) {
+ perror("recvfrom(date read)");
+ return 0;
+ }
+
+ sec = ntohl(sec);
+ if (sec < BU) {
+ fprintf(stderr,
+ "%s says it is before 1970: %lu",
+ hostname, sec);
+ return 0;
+ }
+ sec -= BU;
+
+ (void)gettimeofday(&now, (struct timezone*)0);
+ return (sec - now.tv_sec);
+ }
+ }
+
+ /* if we get here, we tried too many times */
+ fprintf(stderr,"%s will not tell us the date\n", hostname);
+ return 0;
+}
+
+
+/*
+ * Clockdiff computes the difference between the time of the machine on
+ * which it is called and the time of the machines given as argument.
+ * The time differences measured by clockdiff are obtained using a sequence
+ * of ICMP TSTAMP messages which are returned to the sender by the IP module
+ * in the remote machine.
+ * In order to compare clocks of machines in different time zones, the time
+ * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
+ * If a hosts uses a different time format, it should set the high order
+ * bit of the 32-bit quantity it transmits.
+ * However, VMS apparently transmits the time in milliseconds since midnight
+ * local time (rather than GMT) without setting the high order bit.
+ * Furthermore, it does not understand daylight-saving time. This makes
+ * clockdiff behaving inconsistently with hosts running VMS.
+ *
+ * In order to reduce the sensitivity to the variance of message transmission
+ * time, clockdiff sends a sequence of messages. Yet, measures between
+ * two `distant' hosts can be affected by a small error. The error can,
+ * however, be reduced by increasing the number of messages sent in each
+ * measurement.
+ */
+void
+clockdiff(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int measure_status;
+ extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
+ register int avg_cnt;
+ register long avg;
+ struct servent *sp;
+
+ if (argc < 2) {
+ printf("Usage: clockdiff host ... \n");
+ return;
+ }
+
+ (void)gethostname(myname,sizeof(myname));
+
+ /* get the address for the date ready */
+ sp = getservbyname(DATE_PORT, DATE_PROTO);
+ if (!sp) {
+ (void)fprintf(stderr, "%s/%s is an unknown service\n",
+ DATE_PORT, DATE_PROTO);
+ dayaddr.sin_port = 0;
+ } else {
+ dayaddr.sin_port = sp->s_port;
+ }
+
+ while (argc > 1) {
+ argc--; argv++;
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "timedc: %s: ", *argv);
+ herror(0);
+ continue;
+ }
+
+ server.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
+ for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
+ measure_status = measure(10000,100, *argv, &server, 1);
+ if (measure_status != GOOD)
+ break;
+ avg += measure_delta;
+ }
+ if (measure_status == GOOD)
+ measure_delta = avg/avg_cnt;
+
+ switch (measure_status) {
+ case HOSTDOWN:
+ printf("%s is down\n", hp->h_name);
+ continue;
+ case NONSTDTIME:
+ printf("%s transmitts a non-standard time format\n",
+ hp->h_name);
+ continue;
+ case UNREACHABLE:
+ printf("%s is unreachable\n", hp->h_name);
+ continue;
+ }
+
+ /*
+ * Try to get the date only after using ICMP timestamps to
+ * get the time. This is because the date protocol
+ * is optional.
+ */
+ if (dayaddr.sin_port != 0) {
+ dayaddr.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
+ hp->h_length);
+ avg = daydiff(*argv);
+ if (avg > SECDAY) {
+ printf("time on %s is %ld days ahead %s\n",
+ hp->h_name, avg/SECDAY, myname);
+ continue;
+ } else if (avg < -SECDAY) {
+ printf("time on %s is %ld days behind %s\n",
+ hp->h_name, -avg/SECDAY, myname);
+ continue;
+ }
+ }
+
+ if (measure_delta > 0) {
+ printf("time on %s is %d ms. ahead of time on %s\n",
+ hp->h_name, measure_delta, myname);
+ } else if (measure_delta == 0) {
+ printf("%s and %s have the same time\n",
+ hp->h_name, myname);
+ } else {
+ printf("time on %s is %d ms. behind time on %s\n",
+ hp->h_name, -measure_delta, myname);
+ }
+ }
+ return;
+}
+
+
+/*
+ * finds location of master timedaemon
+ */
+void
+msite(int argc, char *argv[])
+{
+ int cc;
+ fd_set ready;
+ struct sockaddr_in dest;
+ int i, length;
+ struct sockaddr from;
+ struct timeval tout;
+ struct tsp msg;
+ struct servent *srvp;
+ char *tgtname;
+
+ if (argc < 1) {
+ printf("Usage: msite [hostname]\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+ dest.sin_port = srvp->s_port;
+ dest.sin_family = AF_INET;
+
+ (void)gethostname(myname, sizeof(myname));
+ i = 1;
+ do {
+ tgtname = (i >= argc) ? myname : argv[i];
+ hp = gethostbyname(tgtname);
+ if (hp == 0) {
+ fprintf(stderr, "timedc: %s: ", tgtname);
+ herror(0);
+ continue;
+ }
+ bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
+
+ (void)strcpy(msg.tsp_name, myname);
+ msg.tsp_type = TSP_MSITE;
+ msg.tsp_vers = TSPVERSION;
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&dest,
+ sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ continue;
+ }
+
+ tout.tv_sec = 15;
+ tout.tv_usec = 0;
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
+ &tout)) {
+ length = sizeof(struct sockaddr);
+ cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
+ &from, &length);
+ if (cc < 0) {
+ perror("recvfrom");
+ continue;
+ }
+ bytehostorder(&msg);
+ if (msg.tsp_type == TSP_ACK) {
+ printf("master timedaemon at %s is %s\n",
+ tgtname, msg.tsp_name);
+ } else {
+ printf("received wrong ack: %s\n",
+ tsptype[msg.tsp_type]);
+ }
+ } else {
+ printf("communication error with %s\n", tgtname);
+ }
+ } while (++i < argc);
+}
+
+/*
+ * quits timedc
+ */
+void
+quit()
+{
+ exit(0);
+}
+
+
+/*
+ * Causes the election timer to expire on the selected hosts
+ * It sends just one udp message per machine, relying on
+ * reliability of communication channel.
+ */
+void
+testing(int argc, char *argv[])
+{
+ struct servent *srvp;
+ struct sockaddr_in sin;
+ struct tsp msg;
+
+ if (argc < 2) {
+ printf("Usage: election host1 [host2 ...]\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+
+ while (argc > 1) {
+ argc--; argv++;
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "timedc: %s: ", *argv);
+ herror(0);
+ argc--; argv++;
+ continue;
+ }
+ sin.sin_port = srvp->s_port;
+ sin.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
+
+ msg.tsp_type = TSP_TEST;
+ msg.tsp_vers = TSPVERSION;
+ (void)gethostname(myname, sizeof(myname));
+ (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ }
+ }
+}
+
+
+/*
+ * Enables or disables tracing on local timedaemon
+ */
+void
+tracing(int argc, char *argv[])
+{
+ int onflag;
+ int length;
+ int cc;
+ fd_set ready;
+ struct sockaddr_in dest;
+ struct sockaddr from;
+ struct timeval tout;
+ struct tsp msg;
+ struct servent *srvp;
+
+ if (argc != 2) {
+ printf("Usage: tracing { on | off }\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+ dest.sin_port = srvp->s_port;
+ dest.sin_family = AF_INET;
+
+ (void)gethostname(myname,sizeof(myname));
+ hp = gethostbyname(myname);
+ bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
+
+ if (strcmp(argv[1], "on") == 0) {
+ msg.tsp_type = TSP_TRACEON;
+ onflag = ON;
+ } else {
+ msg.tsp_type = TSP_TRACEOFF;
+ onflag = OFF;
+ }
+
+ (void)strcpy(msg.tsp_name, myname);
+ msg.tsp_vers = TSPVERSION;
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ return;
+ }
+
+ tout.tv_sec = 5;
+ tout.tv_usec = 0;
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
+ length = sizeof(struct sockaddr);
+ cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
+ &from, &length);
+ if (cc < 0) {
+ perror("recvfrom");
+ return;
+ }
+ bytehostorder(&msg);
+ if (msg.tsp_type == TSP_ACK)
+ if (onflag)
+ printf("timed tracing enabled\n");
+ else
+ printf("timed tracing disabled\n");
+ else
+ printf("wrong ack received: %s\n",
+ tsptype[msg.tsp_type]);
+ } else
+ printf("communication error\n");
+}
+
+int
+priv_resources()
+{
+ int port;
+ struct sockaddr_in sin;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ perror("opening socket");
+ return(-1);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = 0;
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ sin.sin_port = htons((u_short)port);
+ if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
+ break;
+ if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
+ perror("bind");
+ (void) close(sock);
+ return(-1);
+ }
+ }
+ if (port == IPPORT_RESERVED / 2) {
+ fprintf(stderr, "all reserved ports in use\n");
+ (void) close(sock);
+ return(-1);
+ }
+
+ sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (sock_raw < 0) {
+ perror("opening raw socket");
+ (void) close(sock);
+ return(-1);
+ }
+ return(1);
+}
diff --git a/usr.sbin/timed/timedc/cmdtab.c b/usr.sbin/timed/timedc/cmdtab.c
new file mode 100644
index 00000000000..d89f4446ac3
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmdtab.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1983 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[] = "@(#)cmdtab.c 2.7 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#include "timedc.h"
+
+char clockdiffhelp[] = "measures clock differences between machines";
+char helphelp[] = "gets help on commands";
+char msitehelp[] = "finds location of master";
+char quithelp[] = "exits timedc";
+char testinghelp[] = "causes election timers to expire";
+char tracinghelp[] = "turns tracing on or off";
+
+struct cmd cmdtab[] = {
+ { "clockdiff", clockdiffhelp, clockdiff, 0 },
+ { "election", testinghelp, testing, 1 },
+ { "help", helphelp, help, 0 },
+ { "msite", msitehelp, msite, 0 },
+ { "quit", quithelp, quit, 0 },
+ { "trace", tracinghelp, tracing, 1 },
+ { "?", helphelp, help, 0 },
+};
+
+int NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
diff --git a/usr.sbin/timed/timedc/timedc-extern.h b/usr.sbin/timed/timedc/timedc-extern.h
new file mode 100644
index 00000000000..81a45c8ddac
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc-extern.h
@@ -0,0 +1,48 @@
+/*-
+ * 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.
+ *
+ * @(#)extern.h 5.1 (Berkeley) 5/11/93
+ */
+
+struct tsp;
+
+void bytehostorder(struct tsp *);
+void bytenetorder(struct tsp *);
+void clockdiff(int, char *[]);
+void help(int, char *[]);
+void intr(int);
+void makeargv(void);
+void msite(int, char *[]);
+int priv_resources(void);
+void quit(void);
+void testing(int, char *[]);
+void tracing(int, char *[]);
diff --git a/usr.sbin/timed/timedc/timedc.8 b/usr.sbin/timed/timedc/timedc.8
new file mode 100644
index 00000000000..c89a6f925f1
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.8
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1980, 1991 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.
+.\"
+.\" @(#)timedc.8 6.7 (Berkeley) 5/11/93
+.\"
+.Dd May 11, 1993
+.Dt TIMEDC 8
+.Os BSD 4.3
+.ad
+.Sh NAME
+.Nm timedc
+.Nd timed control program
+.Sh SYNOPSIS
+.Nm timedc
+.Oo Ar command\ \&
+.Op Ar argument ...
+.Oc
+.Sh DESCRIPTION
+.Nm Timedc
+is used to control the operation of the
+.Xr timed 8
+program.
+It may be used to:
+.Bl -bullet
+.It
+Measure the differences between machines' clocks,
+.It
+Find the location where the master time server is running,
+.It
+Enable or disable tracing of messages received by
+.Xr timed ,
+and
+.It
+Perform various debugging actions.
+.El
+.Pp
+Without any arguments,
+.Nm timedc
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm timedc
+interprets the first argument as a command and the remaining
+arguments as parameters to the command. The standard input
+may be redirected causing
+.Nm timedc
+to read commands from a file.
+Commands may be abbreviated;
+recognized commands are:
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic \&? Op Ar command ...
+.Pp
+.It Ic help Op Ar command ...
+Print a short description of each command specified in the argument list,
+or, if no arguments are given, a list of the recognized commands.
+.Pp
+.It Ic clockdiff Ar host ...
+Compute the differences between the clock of the host machine
+and the clocks of the machines given as arguments.
+.Pp
+.It Ic msite Op Ar host ...
+Show the master time server for specified host(s).
+.Pp
+.It Xo
+.Ic trace
+.Li \&{ Ar on Li \&|
+.Ar off \&}
+.Xc
+Enable or disable the tracing of incoming messages to
+.Xr timed
+in the file
+.Pa /var/log/timed.log.
+.Pp
+.It Ic election Ar host
+Asks the daemon
+on the target host to reset its
+.Dq election
+timers and to ensure that a time master has been elected.
+.Pp
+.It Ic quit
+Exit from timedc.
+.El
+.Pp
+Other commands may be included for use in testing and debugging
+.Xr timed ;
+the help command and
+the program source may be consulted for details.
+.Sh FILES
+.Bl -tag -width /var/log/timed.masterlog -compact
+.It Pa /var/log/timed.log
+tracing file for timed
+.It Pa /var/log/timed.masterlog
+log file for master timed
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr icmp 4 ,
+.Xr timed 8
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds -compact
+.It ?Ambiguous command
+abbreviation matches more than one command
+.It ?Invalid command
+no match found
+.It ?Privileged command
+command can be executed by root only
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/timed/timedc/timedc.c b/usr.sbin/timed/timedc/timedc.c
new file mode 100644
index 00000000000..5faf6c2a66f
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.c
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 1985, 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
+char copyright[] =
+"@(#) Copyright (c) 1985, 1993 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timedc.c 5.1 (Berkeley) 5/11/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.1.1.1 $"
+#endif
+
+#include "timedc.h"
+#include <strings.h>
+#include <signal.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+int trace = 0;
+FILE *fd = 0;
+int margc;
+int fromatty;
+char *margv[20];
+char cmdline[200];
+jmp_buf toplevel;
+static struct cmd *getcmd(char *);
+
+int
+main(int argc, char *argv[])
+{
+ register struct cmd *c;
+
+ openlog("timedc", LOG_ODELAY, LOG_AUTH);
+
+ /*
+ * security dictates!
+ */
+ if (priv_resources() < 0) {
+ fprintf(stderr, "Could not get privileged resources\n");
+ exit(1);
+ }
+ (void) setuid(getuid());
+
+ if (--argc > 0) {
+ c = getcmd(*++argv);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ exit(1);
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ exit(1);
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+
+ fromatty = isatty(fileno(stdin));
+ if (setjmp(toplevel))
+ putchar('\n');
+ (void) signal(SIGINT, intr);
+ for (;;) {
+ if (fromatty) {
+ printf("timedc> ");
+ (void) fflush(stdout);
+ }
+ if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
+ quit();
+ if (cmdline[0] == 0)
+ break;
+ makeargv();
+ if (margv[0] == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ }
+ return 0;
+}
+
+void
+intr(signo)
+ int signo;
+{
+ if (!fromatty)
+ exit(0);
+ longjmp(toplevel, 1);
+}
+
+
+static struct cmd *
+getcmd(char *name)
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+ extern struct cmd cmdtab[];
+ extern int NCMDS;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+ p = c->c_name;
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return(c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return((struct cmd *)-1);
+ return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+void
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+
+ margc = 0;
+ for (cp = cmdline; *cp;) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+ extern struct cmd cmdtab[];
+
+ if (argc == 1) {
+ register int i, j, w;
+ int columns, width = 0, lines;
+ extern int NCMDS;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ printf("%s", c->c_name);
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", (int)HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
diff --git a/usr.sbin/timed/timedc/timedc.h b/usr.sbin/timed/timedc/timedc.h
new file mode 100644
index 00000000000..971467f46da
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1985, 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.
+ *
+ * @(#)timedc.h 5.1 (Berkeley) 5/11/93
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef sgi
+#include <sys/uio.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+
+extern int errno;
+
+#define ON 1
+#define OFF 0
+
+#define GOOD 1
+#define UNREACHABLE 2
+#define NONSTDTIME 3
+#define HOSTDOWN 0x7fffffff
+
+struct cmd {
+ char *c_name; /* command name */
+ char *c_help; /* help message */
+ void (*c_handler)(); /* routine to do the work */
+ int c_priv; /* privileged command */
+};
+
+#include "timedc-extern.h"
diff --git a/usr.sbin/traceroute/Makefile b/usr.sbin/traceroute/Makefile
new file mode 100644
index 00000000000..b1bc49a16d1
--- /dev/null
+++ b/usr.sbin/traceroute/Makefile
@@ -0,0 +1,9 @@
+# $NetBSD: Makefile,v 1.5 1995/03/26 21:45:18 glass Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= traceroute
+MAN= traceroute.8
+BINOWN= root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/traceroute/mean.awk b/usr.sbin/traceroute/mean.awk
new file mode 100644
index 00000000000..d103264115f
--- /dev/null
+++ b/usr.sbin/traceroute/mean.awk
@@ -0,0 +1,51 @@
+#!/bin/awk -f
+# $NetBSD: mean.awk,v 1.4 1995/03/27 02:24:13 glass Exp $
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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.
+#
+# @(#)mean.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the average time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ tottime += $(f - 1)
+ ++n
+ }
+ }
+ if (n > 0)
+ print $1, tottime/n, median
+}
diff --git a/usr.sbin/traceroute/median.awk b/usr.sbin/traceroute/median.awk
new file mode 100644
index 00000000000..e2a6202b747
--- /dev/null
+++ b/usr.sbin/traceroute/median.awk
@@ -0,0 +1,68 @@
+#!/bin/awk -f
+# $NetBSD: median.awk,v 1.4 1995/03/27 02:24:16 glass Exp $
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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.
+#
+# @(#)median.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the median time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ ++n
+ time[n] = $(f - 1)
+ }
+ }
+ if (n > 0) {
+ # insertion sort the times to find the median
+ for (i = 2; i <= n; ++i) {
+ v = time[i]; j = i - 1;
+ while (time[j] > v) {
+ time[j+1] = time[j];
+ j = j - 1;
+ if (j < 0)
+ break;
+ }
+ time[j+1] = v;
+ }
+ if (n > 1 && (n % 2) == 0)
+ median = (time[n/2] + time[(n/2) + 1]) / 2
+ else
+ median = time[(n+1)/2]
+
+ print $1, median
+ }
+}
diff --git a/usr.sbin/traceroute/traceroute.8 b/usr.sbin/traceroute/traceroute.8
new file mode 100644
index 00000000000..81548d0365e
--- /dev/null
+++ b/usr.sbin/traceroute/traceroute.8
@@ -0,0 +1,362 @@
+.\" $NetBSD: traceroute.8,v 1.5 1995/03/26 21:45:22 glass Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Van Jacobson.
+.\"
+.\" 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.
+.\"
+.\" @(#)traceroute.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TRACEROUTE 8
+.Os BSD 4.3
+.Sh NAME
+.Nm traceroute
+.Nd print the route packets take to network host
+.Sh SYNOPSIS
+.Nm traceroute
+.Op Fl d
+.Op Fl D
+.Op Fl g Ar gateway_addr
+.Op Fl m Ar max_ttl
+.Op Fl n
+.Op Fl p Ar port
+.Op Fl q Ar nqueries
+.Op Fl r
+.Bk -words
+.Op Fl s Ar src_addr
+.Ek
+.Op Fl t Ar tos
+.Op Fl w Ar waittime
+.Ar host
+.Op Ar packetsize
+.Sh DESCRIPTION
+The Internet is a large and complex aggregation of
+network hardware, connected together by gateways.
+Tracking the route one's packets follow (or finding the miscreant
+gateway that's discarding your packets) can be difficult.
+.Nm Traceroute
+utilizes the IP protocol `time to live' field and attempts to elicit an
+.Tn ICMP
+.Dv TIME_EXCEEDED
+response from each gateway along the path to some
+host.
+.Pp
+The only mandatory parameter is the destination host name or IP number.
+The default probe datagram length is 38 bytes, but this may be increased
+by specifying a packet size (in bytes) after the destination host
+name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl d
+Turn on socket-level debugging.
+.It Fl D
+Dump the packet data to standard error before transmitting it.
+.It Fl g Ar gateway_addr
+Add
+.Ar gateway_addr
+to the list of addresses in the IP Loose Source Record Route (LSRR)
+option. If no gateways are specified, the LSRR option is omitted.
+.It Fl m Ar max_ttl
+Set the max time-to-live (max number of hops) used in outgoing probe
+packets. The default is 30 hops (the same default used for
+.Tn TCP
+connections).
+.It Fl n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each gateway found on the
+path).
+.It Fl p Ar port
+Set the base
+.Tn UDP
+.Ar port
+number used in probes (default is 33434).
+.Nm Traceroute
+hopes that nothing is listening on
+.Tn UDP
+ports
+.Em base
+to
+.Em base+nhops-1
+at the destination host (so an
+.Tn ICMP
+.Dv PORT_UNREACHABLE
+message will
+be returned to terminate the route tracing). If something is
+listening on a port in the default range, this option can be used
+to pick an unused port range.
+.It Fl q Ar nqueries
+Set the number of probes per ``ttl'' to
+.Ar nqueries
+(default is three probes).
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network,
+an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it (e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl s Ar src_addr
+Use the following IP address
+(which must be given as an IP number, not
+a hostname) as the source address in outgoing probe packets. On
+hosts with more than one IP address, this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on. If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent.
+.It Fl t Ar tos
+Set the
+.Em type-of-service
+in probe packets to the following value (default zero). The value must be
+a decimal integer in the range 0 to 255. This option can be used to
+see if different types-of-service result in different paths. (If you
+are not running a
+.Bx 4.3 tahoe
+or later system, this may be academic since the normal network
+services like telnet and ftp don't let you control the
+.Dv TOS ) .
+Not all values of
+.Dv TOS
+are legal or
+meaningful \- see the IP spec for definitions. Useful values are
+probably
+.Ql \-t 16
+(low delay) and
+.Ql \-t 8
+(high throughput).
+.It Fl v
+Verbose output. Received
+.Tn ICMP
+packets other than
+.Dv TIME_EXCEEDED
+and
+.Dv UNREACHABLE Ns s
+are listed.
+.It Fl w
+Set the time (in seconds) to wait for a response to a probe (default 3
+sec.).
+.El
+.Pp
+This program attempts to trace the route an IP packet would follow to some
+internet host by launching
+.Tn UDP
+probe
+packets with a small ttl (time to live) then listening for an
+.Tn ICMP
+"time exceeded" reply from a gateway. We start our probes
+with a ttl of one and increase by one until we get an
+.Tn ICMP
+"port unreachable"
+(which means we got to "host") or hit a max (which
+defaults to 30 hops & can be changed with the
+.Fl m
+flag). Three
+probes (changed with
+.Fl q
+flag) are sent at each ttl setting and a
+line is printed showing the ttl, address of the gateway and
+round trip time of each probe. If the probe answers come from
+different gateways, the address of each responding system will
+be printed. If there is no response within a 3 sec. timeout
+interval (changed with the
+.Fl w
+flag), a "*" is printed for that
+probe.
+.Pp
+We don't want the destination
+host to process the
+.Tn UDP
+probe packets so the destination port is set to an
+unlikely value (if some clod on the destination is using that
+value, it can be changed with the
+.Fl p
+flag).
+.Pp
+A sample use and output might be:
+.Bd -literal
+[yak 71]% traceroute nis.nsf.net.
+traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+
+.Ed
+Note that lines 2 & 3 are the same. This is due to a buggy
+kernel on the 2nd hop system \- lbl-csam.arpa \- that forwards
+packets with a zero ttl (a bug in the distributed version
+of 4.3
+.Tn BSD ) .
+Note that you have to guess what path
+the packets are taking cross-country since the
+.Tn NSFNet
+(129.140)
+doesn't supply address-to-name translations for its
+.Tn NSS Ns es .
+.Pp
+A more interesting example is:
+.Bd -literal
+[yak 72]% traceroute allspice.lcs.mit.edu.
+traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+12 * * *
+13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+14 * * *
+15 * * *
+16 * * *
+17 * * *
+18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+
+.Ed
+Note that the gateways 12, 14, 15, 16 & 17 hops away
+either don't send
+.Tn ICMP
+"time exceeded" messages or send them
+with a ttl too small to reach us. 14 \- 17 are running the
+.Tn MIT
+C Gateway code that doesn't send "time exceeded"s. God
+only knows what's going on with 12.
+.Pp
+The silent gateway 12 in the above may be the result of a bug in
+the 4.[23]
+.Tn BSD
+network code (and its derivatives): 4.x (x <= 3)
+sends an unreachable message using whatever ttl remains in the
+original datagram. Since, for gateways, the remaining ttl is
+zero, the
+.Tn ICMP
+"time exceeded" is guaranteed to not make it back
+to us. The behavior of this bug is slightly more interesting
+when it appears on the destination system:
+.Bd -literal
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+7 * * *
+8 * * *
+9 * * *
+10 * * *
+11 * * *
+12 * * *
+13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+
+.Ed
+Notice that there are 12 "gateways" (13 is the final
+destination) and exactly the last half of them are "missing".
+What's really happening is that rip (a Sun-3 running Sun OS3.5)
+is using the ttl from our arriving datagram as the ttl in its
+.Tn ICMP
+reply. So, the reply will time out on the return path
+(with no notice sent to anyone since
+.Tn ICMP's
+aren't sent for
+.Tn ICMP's )
+until we probe with a ttl that's at least twice the path
+length. I.e., rip is really only 7 hops away. A reply that
+returns with a ttl of 1 is a clue this problem exists.
+.Nm Traceroute
+prints a "!" after the time if the ttl is <= 1.
+Since vendors ship a lot of obsolete
+.Pf ( Tn DEC Ns \'s
+Ultrix, Sun 3.x) or
+non-standard
+.Pq Tn HPUX
+software, expect to see this problem
+frequently and/or take care picking the target host of your
+probes.
+Other possible annotations after the time are
+.Sy !H ,
+.Sy !N ,
+.Sy !P
+(got a host, network or protocol unreachable, respectively),
+.Sy !S
+or
+.Sy !F
+(source route failed or fragmentation needed \- neither of these should
+ever occur and the associated gateway is busted if you see one). If
+almost all the probes result in some kind of unreachable,
+.Nm traceroute
+will give up and exit.
+.Pp
+.Bd -literal
+traceroute \-g 10.3.0.5 128.182.0.0
+
+.Ed
+will show the path from the Cambridge Mailbridge to PSC, while
+.Bd -literal
+traceroute \-g 192.5.146.4 \-g 10.3.0.5 35.0.0.0
+
+.Ed
+will show the path from the Cambridge Mailbridge to Merit, using PSC to
+reach the Mailbridge.
+.Pp
+This program is intended for use in network testing, measurement
+and management.
+It should be used primarily for manual fault isolation.
+Because of the load it could impose on the network, it is unwise to use
+.Nm traceroute
+during normal operations or from automated scripts.
+.Sh AUTHOR
+Implemented by Van Jacobson from a suggestion by Steve Deering. Debugged
+by a cast of thousands with particularly cogent suggestions or fixes from
+C. Philip Wood, Tim Seaver and Ken Adelman.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ping 8
+.Sh HISTORY
+The
+.Nm
+command
+.Bt
diff --git a/usr.sbin/traceroute/traceroute.c b/usr.sbin/traceroute/traceroute.c
new file mode 100644
index 00000000000..11062e5a8be
--- /dev/null
+++ b/usr.sbin/traceroute/traceroute.c
@@ -0,0 +1,825 @@
+/* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ *
+ * 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) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93";*/
+#else
+static char rcsid[] = "$NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * traceroute host - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host. We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway. We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to 30 hops & can be changed with the -m flag). Three
+ * probes (change with -q flag) are sent at each ttl setting and a
+ * line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe. If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed. If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format. We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ * [yak 71]% traceroute nis.nsf.net.
+ * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+ * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+ * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+ * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+ *
+ * Note that lines 2 & 3 are the same. This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ * [yak 72]% traceroute allspice.lcs.mit.edu.
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+ * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+ * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+ * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+ * 12 * * *
+ * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+ * 14 * * *
+ * 15 * * *
+ * 16 * * *
+ * 17 * * *
+ * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us. 14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s. God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram. Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us. The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+ * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+ * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+ * 7 * * *
+ * 8 * * *
+ * 9 * * *
+ * 10 * * *
+ * 11 * * *
+ * 12 * * *
+ * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply. So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length. I.e., rip is really only 7 hops away. A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one). If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid. (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley: A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in a ip datagram). See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
+ * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram. 8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id). So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range). To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example. I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep. I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering. Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis. I don't know (or care) who came up with
+ * the idea first. I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself. Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless. Maybe one day...
+ *
+ * -- Van Jacobson (van@helios.ee.lbl.gov)
+ * Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define Fprintf (void)fprintf
+#define Sprintf (void)sprintf
+#define Printf (void)printf
+
+#define HEADERSIZE (sizeof(struct ip) + lsrrlen + sizeof(struct udphdr) + sizeof(struct packetdata))
+#define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4)
+
+/*
+ * Format of the data in a (udp) probe packet.
+ */
+struct packetdata {
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+};
+
+struct in_addr gateway[MAX_LSRR + 1];
+int lsrrlen = 0;
+
+u_char packet[512], *outpacket; /* last inbound (icmp) packet */
+
+int wait_for_reply __P((int, struct sockaddr_in *));
+void send_probe __P((int, int, struct sockaddr_in *));
+double deltaT __P((struct timeval *, struct timeval *));
+int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
+void print __P((u_char *, int, struct sockaddr_in *));
+char *inetname __P((struct in_addr));
+void usage __P((void));
+
+int s; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+struct timezone tz; /* leftover */
+
+int datalen; /* How much data */
+
+char *source = 0;
+char *hostname;
+
+int nprobes = 3;
+int max_ttl = 30;
+u_short ident;
+u_short port = 32768+666; /* start udp dest port # for probe packets */
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int dump;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct hostent *hp;
+ struct protoent *pe;
+ struct sockaddr_in from, to;
+ int ch, i, lsrr, on, probe, seq, tos, ttl;
+ struct ip *ip;
+
+ lsrr = 0;
+ on = 1;
+ seq = tos = 0;
+ while ((ch = getopt(argc, argv, "dDg:m:np:q:rs:t:w:v")) != -1)
+ switch (ch) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'D':
+ dump = 1;
+ break;
+ case 'g':
+ if (lsrr >= MAX_LSRR)
+ errx(1, "too many gateways; max %d", MAX_LSRR);
+ if (inet_aton(optarg, &gateway[lsrr]) == 0) {
+ hp = gethostbyname(optarg);
+ if (hp == 0)
+ errx(1, "unknown host %s", optarg);
+ memcpy(&gateway[lsrr], hp->h_addr, hp->h_length);
+ }
+ if (++lsrr == 1)
+ lsrrlen = 4;
+ lsrrlen += 4;
+ break;
+ case 'm':
+ max_ttl = atoi(optarg);
+ if (max_ttl < 1 || max_ttl > MAXTTL)
+ errx(1, "max ttl must be 1 to %d.", MAXTTL);
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ if (port < 1)
+ errx(1, "port must be >0.");
+ break;
+ case 'q':
+ nprobes = atoi(optarg);
+ if (nprobes < 1)
+ errx(1, "nprobes must be >0.");
+ break;
+ case 'r':
+ options |= SO_DONTROUTE;
+ break;
+ case 's':
+ /*
+ * set the ip source address of the outbound
+ * probe (e.g., on a multi-homed host).
+ */
+ source = optarg;
+ break;
+ case 't':
+ tos = atoi(optarg);
+ if (tos < 0 || tos > 255)
+ errx(1, "tos must be 0 to 255.");
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'w':
+ waittime = atoi(optarg);
+ if (waittime <= 1)
+ errx(1, "wait must be >1 sec.");
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ setlinebuf (stdout);
+
+ (void) memset(&to, 0, sizeof(struct sockaddr));
+ to.sin_family = AF_INET;
+ if (inet_aton(*argv, &to.sin_addr) != 0)
+ hostname = *argv;
+ else {
+ hp = gethostbyname(*argv);
+ if (hp == 0)
+ errx(1, "unknown host %s", *argv);
+ to.sin_family = hp->h_addrtype;
+ memcpy(&to.sin_addr, hp->h_addr, hp->h_length);
+ hostname = hp->h_name;
+ }
+ if (*++argv)
+ datalen = atoi(*argv);
+ if (datalen < 0 || datalen > IP_MAXPACKET - HEADERSIZE)
+ errx(1, "packet size must be 0 to %d.",
+ IP_MAXPACKET - HEADERSIZE);
+ datalen += HEADERSIZE;
+
+ outpacket = (u_char *)malloc(datalen);
+ if (outpacket == 0)
+ err(1, "malloc");
+ (void) memset(outpacket, 0, datalen);
+
+ ip = (struct ip *)outpacket;
+ if (lsrr != 0) {
+ u_char *p;
+ p = (u_char *)(ip + 1);
+ *p++ = IPOPT_NOP;
+ *p++ = IPOPT_LSRR;
+ *p++ = lsrrlen - 1;
+ *p++ = IPOPT_MINOFF;
+ gateway[lsrr] = to.sin_addr;
+ for (i = 1; i <= lsrr; i++)
+ *((struct in_addr *)p)++ = gateway[i];
+ ip->ip_dst = gateway[0];
+ } else
+ ip->ip_dst = to.sin_addr;
+ ip->ip_off = 0;
+ ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_v = IPVERSION;
+ ip->ip_tos = tos;
+
+ ident = (getpid() & 0xffff) | 0x8000;
+
+ if ((pe = getprotobyname("icmp")) == NULL) {
+ Fprintf(stderr, "icmp: unknown protocol\n");
+ exit(10);
+ }
+ if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
+ err(5, "icmp socket");
+ if (options & SO_DEBUG)
+ (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+
+ if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ err(5, "raw socket");
+
+#ifdef SO_SNDBUF
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
+ sizeof(datalen)) < 0)
+ err(6, "SO_SNDBUF");
+#endif SO_SNDBUF
+#ifdef IP_HDRINCL
+ if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+ sizeof(on)) < 0)
+ err(6, "IP_HDRINCL");
+#endif IP_HDRINCL
+ if (options & SO_DEBUG)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+
+ if (source) {
+ (void) memset(&from, 0, sizeof(struct sockaddr));
+ from.sin_family = AF_INET;
+ if (inet_aton(source, &from.sin_addr) != 0)
+ errx(1, "unknown host %s", source);
+ ip->ip_src = from.sin_addr;
+#ifndef IP_HDRINCL
+ if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
+ err(1, "bind");
+#endif IP_HDRINCL
+ }
+
+ Fprintf(stderr, "traceroute to %s (%s)", hostname,
+ inet_ntoa(to.sin_addr));
+ if (source)
+ Fprintf(stderr, " from %s", source);
+ Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
+ (void) fflush(stderr);
+
+ for (ttl = 1; ttl <= max_ttl; ++ttl) {
+ u_long lastaddr = 0;
+ int got_there = 0;
+ int unreachable = 0;
+
+ Printf("%2d ", ttl);
+ for (probe = 0; probe < nprobes; ++probe) {
+ int cc;
+ struct timeval t1, t2;
+ struct timezone tz;
+
+ (void) gettimeofday(&t1, &tz);
+ send_probe(++seq, ttl, &to);
+ while (cc = wait_for_reply(s, &from)) {
+ (void) gettimeofday(&t2, &tz);
+ if ((i = packet_ok(packet, cc, &from, seq))) {
+ if (from.sin_addr.s_addr != lastaddr) {
+ print(packet, cc, &from);
+ lastaddr = from.sin_addr.s_addr;
+ }
+ Printf(" %g ms", deltaT(&t1, &t2));
+ switch(i - 1) {
+ case ICMP_UNREACH_PORT:
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif ARCHAIC
+ ++got_there;
+ break;
+ case ICMP_UNREACH_NET:
+ ++unreachable;
+ Printf(" !N");
+ break;
+ case ICMP_UNREACH_HOST:
+ ++unreachable;
+ Printf(" !H");
+ break;
+ case ICMP_UNREACH_PROTOCOL:
+ ++got_there;
+ Printf(" !P");
+ break;
+ case ICMP_UNREACH_NEEDFRAG:
+ ++unreachable;
+ Printf(" !F");
+ break;
+ case ICMP_UNREACH_SRCFAIL:
+ ++unreachable;
+ Printf(" !S");
+ break;
+ }
+ break;
+ }
+ }
+ if (cc == 0)
+ Printf(" *");
+ (void) fflush(stdout);
+ }
+ putchar('\n');
+ if (got_there || unreachable >= nprobes)
+ exit(0);
+ }
+}
+
+int
+wait_for_reply(sock, from)
+ int sock;
+ struct sockaddr_in *from;
+{
+ fd_set fds;
+ struct timeval wait;
+ int cc = 0;
+ int fromlen = sizeof (*from);
+
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ wait.tv_sec = waittime; wait.tv_usec = 0;
+
+ if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
+ cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
+ (struct sockaddr *)from, &fromlen);
+
+ return(cc);
+}
+
+void
+dump_packet()
+{
+ u_char *p;
+ int i;
+
+ Fprintf(stderr, "packet data:");
+ for (p = outpacket, i = 0; i < datalen; i++) {
+ if ((i % 24) == 0)
+ Fprintf(stderr, "\n ");
+ Fprintf(stderr, " %02x", *p++);
+ }
+ Fprintf(stderr, "\n");
+}
+
+void
+send_probe(seq, ttl, to)
+ int seq, ttl;
+ struct sockaddr_in *to;
+{
+ struct ip *ip = (struct ip *)outpacket;
+ u_char *p = (u_char *)(ip + 1);
+ struct udphdr *up = (struct udphdr *)(p + lsrrlen);
+ struct packetdata *op = (struct packetdata *)(up + 1);
+ int i;
+
+ ip->ip_len = datalen;
+ ip->ip_ttl = ttl;
+ ip->ip_id = htons(ident+seq);
+
+ up->uh_sport = htons(ident);
+ up->uh_dport = htons(port+seq);
+ up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - lsrrlen));
+ up->uh_sum = 0;
+
+ op->seq = seq;
+ op->ttl = ttl;
+ (void) gettimeofday(&op->tv, &tz);
+
+ if (dump)
+ dump_packet();
+
+ i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
+ sizeof(struct sockaddr_in));
+ if (i < 0 || i != datalen) {
+ if (i<0)
+ perror("sendto");
+ Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
+ datalen, i);
+ (void) fflush(stdout);
+ }
+}
+
+
+double
+deltaT(t1p, t2p)
+ struct timeval *t1p, *t2p;
+{
+ register double dt;
+
+ dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+ (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ return (dt);
+}
+
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(t)
+ u_char t;
+{
+ static char *ttab[] = {
+ "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
+ "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
+ "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
+ "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
+ "Info Reply"
+ };
+
+ if(t > 16)
+ return("OUT-OF-RANGE");
+
+ return(ttab[t]);
+}
+
+
+int
+packet_ok(buf, cc, from, seq)
+ u_char *buf;
+ int cc;
+ struct sockaddr_in *from;
+ int seq;
+{
+ register struct icmp *icp;
+ u_char type, code;
+ int hlen;
+#ifndef ARCHAIC
+ struct ip *ip;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (verbose)
+ Printf("packet too short (%d bytes) from %s\n", cc,
+ inet_ntoa(from->sin_addr));
+ return (0);
+ }
+ cc -= hlen;
+ icp = (struct icmp *)(buf + hlen);
+#else
+ icp = (struct icmp *)buf;
+#endif ARCHAIC
+ type = icp->icmp_type; code = icp->icmp_code;
+ if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+ type == ICMP_UNREACH) {
+ struct ip *hip;
+ struct udphdr *up;
+
+ hip = &icp->icmp_ip;
+ hlen = hip->ip_hl << 2;
+ up = (struct udphdr *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
+ up->uh_sport == htons(ident) &&
+ up->uh_dport == htons(port+seq))
+ return (type == ICMP_TIMXCEED? -1 : code+1);
+ }
+#ifndef ARCHAIC
+ if (verbose) {
+ int i;
+ u_long *lp = (u_long *)&icp->icmp_ip;
+
+ Printf("\n%d bytes from %s to %s", cc,
+ inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
+ Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
+ icp->icmp_code);
+ for (i = 4; i < cc ; i += sizeof(long))
+ Printf("%2d: x%8.8lx\n", i, *lp++);
+ }
+#endif ARCHAIC
+ return(0);
+}
+
+
+void
+print(buf, cc, from)
+ u_char *buf;
+ int cc;
+ struct sockaddr_in *from;
+{
+ struct ip *ip;
+ int hlen;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ cc -= hlen;
+
+ if (nflag)
+ Printf(" %s", inet_ntoa(from->sin_addr));
+ else
+ Printf(" %s (%s)", inetname(from->sin_addr),
+ inet_ntoa(from->sin_addr));
+
+ if (verbose)
+ Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+}
+
+
+#ifdef notyet
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(addr, len)
+ u_short *addr;
+ int len;
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1)
+ sum += *(u_char *)w;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
+#endif notyet
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(in)
+ struct in_addr in;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && in.s_addr != INADDR_ANY) {
+ hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp)
+ (void) strcpy(line, cp);
+ else {
+ in.s_addr = ntohl(in.s_addr);
+#define C(x) ((x) & 0xff)
+ Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ return (line);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: traceroute [-dDnrv] [-g gateway_addr] ... [-m max_ttl] [-p port#]\n\t\
+[-q nqueries] [-s src_addr] [-t tos] [-w wait] host [data size]\n");
+ exit(1);
+}
diff --git a/usr.sbin/trpt/Makefile b/usr.sbin/trpt/Makefile
new file mode 100644
index 00000000000..491b840b7ae
--- /dev/null
+++ b/usr.sbin/trpt/Makefile
@@ -0,0 +1,9 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:29 deraadt Exp $
+
+PROG= trpt
+MAN= trpt.8
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/trpt/trpt.8 b/usr.sbin/trpt/trpt.8
new file mode 100644
index 00000000000..c292c0ab9e8
--- /dev/null
+++ b/usr.sbin/trpt/trpt.8
@@ -0,0 +1,155 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\" from: @(#)trpt.8 6.5 (Berkeley) 3/16/91
+.\" $Id: trpt.8,v 1.1.1.1 1995/10/18 08:48:29 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt TRPT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm trpt
+.Nd transliterate protocol trace
+.Sh SYNOPSIS
+.Nm trpt
+.Op Fl a
+.Op Fl f
+.Op Fl j
+.Op Fl p Ar hex-address
+.Op Fl s
+.Op Fl t
+.Oo
+.Ar system Op Ar core
+.Oc
+.Sh DESCRIPTION
+.Nm Trpt
+interrogates the buffer of
+.Tn TCP
+trace records created
+when a socket is marked for
+.Dq debugging
+(see
+.Xr setsockopt 2 ) ,
+and prints a readable description of these records.
+When no options are supplied,
+.Nm trpt
+prints all the trace records found in the system
+grouped according to
+.Tn TCP
+connection protocol control
+block
+.Pq Tn PCB .
+The following options may be used to
+alter this behavior.
+.Bl -tag -width Ds
+.It Fl a
+In addition to the normal output,
+print the values of the source and destination
+addresses for each packet recorded.
+.It Fl f
+Follow the trace as it occurs, waiting a short time for additional records
+each time the end of the log is reached.
+.It Fl j
+Just give a list of the protocol control block
+addresses for which there are trace records.
+.It Fl p
+Show only trace records associated with the protocol
+control block at the given address
+.Ar hex-address .
+.It Fl s
+In addition to the normal output,
+print a detailed description of the packet
+sequencing information.
+.It Fl t
+in addition to the normal output,
+print the values for all timers at each
+point in the trace.
+.El
+.Pp
+The recommended use of
+.Nm trpt
+is as follows.
+Isolate the problem and enable debugging on the
+socket(s) involved in the connection.
+Find the address of the protocol control blocks
+associated with the sockets using the
+.Fl A
+option to
+.Xr netstat 1 .
+Then run
+.Nm trpt
+with the
+.Fl p
+option, supplying the associated
+protocol control block addresses.
+The
+.Fl f
+option can be used to follow the trace log once the trace is located.
+If there are
+many sockets using the debugging option, the
+.Fl j
+option may be useful in checking to see if
+any trace records are present for the socket in
+question.
+The
+.Pp
+If debugging is being performed on a system or
+core file other than the default, the last two
+arguments may be used to supplant the defaults.
+.Sh FILES
+.Bl -tag -width /dev/kmem -compact
+.It Pa /dev/kmem
+default kernel memory
+.It Pa /netbsd
+default system namelist
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr setsockopt 2 ,
+.Xr trsp 8
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds
+.It Sy no namelist
+When the system image doesn't
+contain the proper symbols to find the trace buffer;
+others which should be self explanatory.
+.El
+.Sh BUGS
+Should also print the data for each input or output,
+but this is not saved in the race record.
+.Pp
+The output format is inscrutable and should be described
+here.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/trpt/trpt.c b/usr.sbin/trpt/trpt.c
new file mode 100644
index 00000000000..e9f62d8e8fc
--- /dev/null
+++ b/usr.sbin/trpt/trpt.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 1983, 1988 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
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)trpt.c 5.14 (Berkeley) 7/1/91";*/
+static char rcsid[] = "$Id: trpt.c,v 1.1.1.1 1995/10/18 08:48:29 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#if BSD >= 199103
+#define NEWVM
+#endif
+#ifndef NEWVM
+#include <machine/pte.h>
+#include <sys/vmmac.h>
+#endif
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#define PRUREQUESTS
+#include <sys/protosw.h>
+#include <sys/file.h>
+
+#include <net/route.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#define TCPTIMERS
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
+#define TANAMES
+#include <netinet/tcp_debug.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <nlist.h>
+#include <paths.h>
+
+struct nlist nl[] = {
+#define N_TCP_DEBUG 0
+ { "_tcp_debug" },
+#define N_TCP_DEBX 1
+ { "_tcp_debx" },
+#ifndef NEWVM
+#define N_SYSMAP 2
+ { "_Sysmap" },
+#define N_SYSSIZE 3
+ { "_Syssize" },
+#endif
+ { "" },
+};
+
+#ifndef NEWVM
+static struct pte *Sysmap;
+#endif
+static caddr_t tcp_pcbs[TCP_NDEBUG];
+static n_time ntime;
+static int aflag, kflag, memf, follow, sflag, tflag;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, i, jflag, npcbs, numeric();
+ char *system, *core, *malloc();
+ off_t lseek();
+
+ jflag = npcbs = 0;
+ while ((ch = getopt(argc, argv, "afjp:st")) != EOF)
+ switch (ch) {
+ case 'a':
+ ++aflag;
+ break;
+ case 'f':
+ ++follow;
+ setlinebuf(stdout);
+ break;
+ case 'j':
+ ++jflag;
+ break;
+ case 'p':
+ if (npcbs >= TCP_NDEBUG) {
+ fputs("trpt: too many pcb's specified\n",
+ stderr);
+ exit(1);
+ }
+ (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 't':
+ ++tflag;
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+"usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ core = _PATH_KMEM;
+ if (argc > 0) {
+ system = *argv;
+ argc--, argv++;
+ if (argc > 0) {
+ core = *argv;
+ argc--, argv++;
+ ++kflag;
+ }
+ }
+ else
+ system = _PATH_UNIX;
+
+ if (nlist(system, nl) < 0 || !nl[0].n_value) {
+ fprintf(stderr, "trpt: %s: no namelist\n", system);
+ exit(1);
+ }
+ if ((memf = open(core, O_RDONLY)) < 0) {
+ perror(core);
+ exit(2);
+ }
+ if (kflag) {
+#ifdef NEWVM
+ fputs("trpt: can't do core files yet\n", stderr);
+ exit(1);
+#else
+ off_t off;
+
+ Sysmap = (struct pte *)
+ malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
+ if (!Sysmap) {
+ fputs("trpt: can't get memory for Sysmap.\n", stderr);
+ exit(1);
+ }
+ off = nl[N_SYSMAP].n_value & ~KERNBASE;
+ (void)lseek(memf, off, L_SET);
+ (void)read(memf, (char *)Sysmap,
+ (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
+#endif
+ }
+ (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
+ if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
+ sizeof(tcp_debx)) {
+ perror("trpt: tcp_debx");
+ exit(3);
+ }
+ (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
+ if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
+ sizeof(tcp_debug)) {
+ perror("trpt: tcp_debug");
+ exit(3);
+ }
+ /*
+ * If no control blocks have been specified, figure
+ * out how many distinct one we have and summarize
+ * them in tcp_pcbs for sorting the trace records
+ * below.
+ */
+ if (!npcbs) {
+ for (i = 0; i < TCP_NDEBUG; i++) {
+ register struct tcp_debug *td = &tcp_debug[i];
+ register int j;
+
+ if (td->td_tcb == 0)
+ continue;
+ for (j = 0; j < npcbs; j++)
+ if (tcp_pcbs[j] == td->td_tcb)
+ break;
+ if (j >= npcbs)
+ tcp_pcbs[npcbs++] = td->td_tcb;
+ }
+ if (!npcbs)
+ exit(0);
+ }
+ qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
+ if (jflag) {
+ for (i = 0;;) {
+ printf("%lx", (long)tcp_pcbs[i]);
+ if (++i == npcbs)
+ break;
+ fputs(", ", stdout);
+ }
+ putchar('\n');
+ }
+ else for (i = 0; i < npcbs; i++) {
+ printf("\n%lx:\n", (long)tcp_pcbs[i]);
+ dotrace(tcp_pcbs[i]);
+ }
+ exit(0);
+}
+
+dotrace(tcpcb)
+ register caddr_t tcpcb;
+{
+ register struct tcp_debug *td;
+ register int i;
+ int prev_debx = tcp_debx;
+
+again: if (--tcp_debx < 0)
+ tcp_debx = TCP_NDEBUG - 1;
+ for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
+ td = &tcp_debug[i];
+ if (tcpcb && td->td_tcb != tcpcb)
+ continue;
+ ntime = ntohl(td->td_time);
+ tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
+ &td->td_ti, td->td_req);
+ if (i == tcp_debx)
+ goto done;
+ }
+ for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
+ td = &tcp_debug[i];
+ if (tcpcb && td->td_tcb != tcpcb)
+ continue;
+ ntime = ntohl(td->td_time);
+ tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
+ &td->td_ti, td->td_req);
+ }
+done: if (follow) {
+ prev_debx = tcp_debx + 1;
+ if (prev_debx >= TCP_NDEBUG)
+ prev_debx = 0;
+ do {
+ sleep(1);
+ (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
+ if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
+ sizeof(tcp_debx)) {
+ perror("trpt: tcp_debx");
+ exit(3);
+ }
+ } while (tcp_debx == prev_debx);
+ (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
+ if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
+ sizeof(tcp_debug)) {
+ perror("trpt: tcp_debug");
+ exit(3);
+ }
+ goto again;
+ }
+}
+
+/*
+ * Tcp debug routines
+ */
+/*ARGSUSED*/
+tcp_trace(act, ostate, atp, tp, ti, req)
+ short act, ostate;
+ struct tcpcb *atp, *tp;
+ struct tcpiphdr *ti;
+ int req;
+{
+ tcp_seq seq, ack;
+ int flags, len, win, timer;
+
+ printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
+ tanames[act]);
+ switch (act) {
+ case TA_INPUT:
+ case TA_OUTPUT:
+ case TA_DROP:
+ if (aflag) {
+ printf("(src=%s,%u, ",
+ inet_ntoa(ti->ti_src), ntohs(ti->ti_sport));
+ printf("dst=%s,%u)",
+ inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
+ }
+ seq = ti->ti_seq;
+ ack = ti->ti_ack;
+ len = ti->ti_len;
+ win = ti->ti_win;
+ if (act == TA_OUTPUT) {
+ seq = ntohl(seq);
+ ack = ntohl(ack);
+ len = ntohs(len);
+ win = ntohs(win);
+ }
+ if (act == TA_OUTPUT)
+ len -= sizeof(struct tcphdr);
+ if (len)
+ printf("[%lx..%lx)", seq, seq + len);
+ else
+ printf("%lx", seq);
+ printf("@%lx", ack);
+ if (win)
+ printf("(win=%x)", win);
+ flags = ti->ti_flags;
+ if (flags) {
+ register char *cp = "<";
+#define pf(flag, string) { \
+ if (ti->ti_flags&flag) { \
+ (void)printf("%s%s", cp, string); \
+ cp = ","; \
+ } \
+}
+ pf(TH_SYN, "SYN");
+ pf(TH_ACK, "ACK");
+ pf(TH_FIN, "FIN");
+ pf(TH_RST, "RST");
+ pf(TH_PUSH, "PUSH");
+ pf(TH_URG, "URG");
+ printf(">");
+ }
+ break;
+ case TA_USER:
+ timer = req >> 8;
+ req &= 0xff;
+ printf("%s", prurequests[req]);
+ if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
+ printf("<%s>", tcptimers[timer]);
+ break;
+ }
+ printf(" -> %s", tcpstates[tp->t_state]);
+ /* print out internal state of tp !?! */
+ printf("\n");
+ if (sflag) {
+ printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
+ tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
+ tp->snd_max);
+ printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
+ tp->snd_wl2, tp->snd_wnd);
+ }
+ /* print out timers? */
+ if (tflag) {
+ register char *cp = "\t";
+ register int i;
+
+ for (i = 0; i < TCPT_NTIMERS; i++) {
+ if (tp->t_timer[i] == 0)
+ continue;
+ printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
+ if (i == TCPT_REXMT)
+ printf(" (t_rxtshft=%d)", tp->t_rxtshift);
+ cp = ", ";
+ }
+ if (*cp != '\t')
+ putchar('\n');
+ }
+}
+
+numeric(c1, c2)
+ caddr_t *c1, *c2;
+{
+ return(*c1 - *c2);
+}
+
+klseek(fd, base, off)
+ int fd, off;
+ off_t base;
+{
+ off_t lseek();
+
+#ifndef NEWVM
+ if (kflag) { /* get kernel pte */
+ base &= ~KERNBASE;
+ base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
+ }
+#endif
+ (void)lseek(fd, base, off);
+}
diff --git a/usr.sbin/trsp/Makefile b/usr.sbin/trsp/Makefile
new file mode 100644
index 00000000000..0e7b4ad3a7f
--- /dev/null
+++ b/usr.sbin/trsp/Makefile
@@ -0,0 +1,10 @@
+# from: @(#)Makefile 5.3 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $
+
+PROG= trsp
+MAN= trsp.8
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/trsp/trsp.8 b/usr.sbin/trsp/trsp.8
new file mode 100644
index 00000000000..f9b8836728d
--- /dev/null
+++ b/usr.sbin/trsp/trsp.8
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1985, 1991 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.
+.\"
+.\" from: @(#)trsp.8 6.4 (Berkeley) 3/16/91
+.\" $Id: trsp.8,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $
+.\"
+.Dd March 16, 1991
+.Dt TRSP 8
+.Os BSD 4.2
+.Sh NAME
+.Nm trsp
+.Nd transliterate sequenced packet protocol trace
+.Sh SYNOPSIS
+.Nm trsp
+.Op Fl a
+.Op Fl s
+.Op Fl t
+.Op Fl j
+.Op Fl p Ar hex-address
+.Oo
+.Ar system Op Ar core
+.Oc
+.Sh DESCRIPTION
+.Xr Trpt
+interrogates the buffer of
+.Tn SPP
+trace records created
+when a socket is marked for
+.Dq debugging
+(see
+.Xr setsockopt 2 ) ,
+and prints a readable description of these records.
+When no options are supplied,
+.Nm trsp
+prints all the trace records found in the system
+grouped according to
+.Tn SPP
+connection protocol control
+block
+.Pq Tn PCB .
+The following options may be used to
+alter this behavior.
+.Bl -tag -width Ds
+.It Fl a
+In addition to the normal output,
+print the values of the source and destination
+addresses for each packet recorded.
+.It Fl j
+Just give a list of the protocol control block
+addresses for which there are trace records.
+.It Fl p
+Show only trace records associated with the protocol
+control block at the given address,
+.Ar hex-address .
+.It Fl s
+in addition to the normal output,
+print a detailed description of the packet
+sequencing information.
+.It Fl t
+in addition to the normal output,
+print the values for all timers at each
+point in the trace,
+.El
+.Pp
+The recommended use of
+.Nm trsp
+is as follows.
+Isolate the problem and enable debugging on the
+socket(s) involved in the connection.
+Find the address of the protocol control blocks
+associated with the sockets using the
+.Fl A
+option to
+.Xr netstat 1 .
+Then run
+.Nm trsp
+with the
+.Fl p
+option, supplying the associated
+protocol control block addresses. If there are
+many sockets using the debugging option, the
+.Fl j
+option may be useful in checking to see if
+any trace records are present for the socket in
+question.
+.Pp
+If debugging is being performed on a system or
+core file other than the default, the last two
+arguments may be used to supplant the defaults.
+.Sh FILES
+.Bl -tag -width /dev/kmem -compact
+.It Pa /dev/kmem
+default kernel memory
+.It Pa /netbsd
+default system namelist
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr setsockopt 2
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds
+.It Sy no namelist
+When the system image doesn't
+contain the proper symbols to find the trace buffer;
+others which should be self explanatory.
+.Sh BUGS
+Should also print the data for each input or output,
+but this is not saved in the race record.
+.Pp
+The output format is inscrutable and should be described
+here.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/trsp/trsp.c b/usr.sbin/trsp/trsp.c
new file mode 100644
index 00000000000..5212ee0eeaf
--- /dev/null
+++ b/usr.sbin/trsp/trsp.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 1985 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
+char copyright[] =
+"@(#) Copyright (c) 1985 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)trsp.c 6.8 (Berkeley) 3/2/91";*/
+static char rcsid[] = "$Id: trsp.c,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#define PRUREQUESTS
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <net/if.h>
+
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#define TCPTIMERS
+#include <netinet/tcp_timer.h>
+
+#include <netns/ns.h>
+#include <netns/sp.h>
+#include <netns/idp.h>
+#include <netns/spidp.h>
+#include <netns/spp_timer.h>
+#include <netns/spp_var.h>
+#include <netns/ns_pcb.h>
+#include <netns/idp_var.h>
+#define SANAMES
+#include <netns/spp_debug.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <nlist.h>
+#include <paths.h>
+
+unsigned long ntime;
+int sflag;
+int tflag;
+int jflag;
+int aflag;
+int zflag;
+int numeric();
+struct nlist nl[] = {
+ { "_spp_debug" },
+ { "_spp_debx" },
+ 0
+};
+struct spp_debug spp_debug[SPP_NDEBUG];
+caddr_t spp_pcbs[SPP_NDEBUG];
+int spp_debx;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i, mask = 0, npcbs = 0;
+ char *system, *core;
+
+ system = _PATH_UNIX;
+ core = _PATH_KMEM;
+
+ argc--, argv++;
+again:
+ if (argc > 0 && !strcmp(*argv, "-a")) {
+ aflag++, argc--, argv++;
+ goto again;
+ }
+ if (argc > 0 && !strcmp(*argv, "-z")) {
+ zflag++, argc--, argv++;
+ goto again;
+ }
+ if (argc > 0 && !strcmp(*argv, "-s")) {
+ sflag++, argc--, argv++;
+ goto again;
+ }
+ if (argc > 0 && !strcmp(*argv, "-t")) {
+ tflag++, argc--, argv++;
+ goto again;
+ }
+ if (argc > 0 && !strcmp(*argv, "-j")) {
+ jflag++, argc--, argv++;
+ goto again;
+ }
+ if (argc > 0 && !strcmp(*argv, "-p")) {
+ argc--, argv++;
+ if (argc < 1) {
+ fprintf(stderr, "-p: missing sppcb address\n");
+ exit(1);
+ }
+ if (npcbs >= SPP_NDEBUG) {
+ fprintf(stderr, "-p: too many pcb's specified\n");
+ exit(1);
+ }
+ sscanf(*argv, "%x", &spp_pcbs[npcbs++]);
+ argc--, argv++;
+ goto again;
+ }
+ if (argc > 0) {
+ system = *argv;
+ argc--, argv++;
+ mask++;
+ }
+ if (argc > 0) {
+ core = *argv;
+ argc--, argv++;
+ mask++;
+ }
+ (void) nlist(system, nl);
+ if (nl[0].n_value == 0) {
+ fprintf(stderr, "trsp: %s: no namelist\n", system);
+ exit(1);
+ }
+ (void) close(0);
+ if (open(core, 0) < 0) {
+ fprintf(stderr, "trsp: "); perror(core);
+ exit(2);
+ }
+ if (mask) {
+ nl[0].n_value &= 0x7fffffff;
+ nl[1].n_value &= 0x7fffffff;
+ }
+ (void) lseek(0, nl[1].n_value, 0);
+ if (read(0, &spp_debx, sizeof (spp_debx)) != sizeof (spp_debx)) {
+ fprintf(stderr, "trsp: "); perror("spp_debx");
+ exit(3);
+ }
+ printf("spp_debx=%d\n", spp_debx);
+ (void) lseek(0, nl[0].n_value, 0);
+ if (read(0, spp_debug, sizeof (spp_debug)) != sizeof (spp_debug)) {
+ fprintf(stderr, "trsp: "); perror("spp_debug");
+ exit(3);
+ }
+ /*
+ * Here, we just want to clear out the old trace data and start over.
+ */
+ if (zflag) {
+ char *cp = (char *) spp_debug,
+ *cplim = cp + sizeof(spp_debug);
+ (void) close(0);
+ if (open(core, 2) < 0) {
+ fprintf(stderr, "trsp: "); perror(core);
+ exit(2);
+ }
+ while(cp < cplim) *cp++ = 0;
+ (void) lseek(0, nl[0].n_value, 0);
+ if (write(0, spp_debug, sizeof (spp_debug)) != sizeof (spp_debug)) {
+ fprintf(stderr, "trsp: "); perror("spp_debug");
+ exit(3);
+ }
+ (void) lseek(0, nl[1].n_value, 0);
+ spp_debx = 0;
+ if (write(0, &spp_debx, sizeof (spp_debx)) != sizeof (spp_debx)) {
+ fprintf(stderr, "trsp: "); perror("spp_debx");
+ exit(3);
+ }
+ exit(0);
+ }
+ /*
+ * If no control blocks have been specified, figure
+ * out how many distinct one we have and summarize
+ * them in spp_pcbs for sorting the trace records
+ * below.
+ */
+ if (npcbs == 0) {
+ for (i = 0; i < SPP_NDEBUG; i++) {
+ register int j;
+ register struct spp_debug *sd = &spp_debug[i];
+
+ if (sd->sd_cb == 0)
+ continue;
+ for (j = 0; j < npcbs; j++)
+ if (spp_pcbs[j] == sd->sd_cb)
+ break;
+ if (j >= npcbs)
+ spp_pcbs[npcbs++] = sd->sd_cb;
+ }
+ }
+ qsort(spp_pcbs, npcbs, sizeof (caddr_t), numeric);
+ if (jflag) {
+ char *cp = "";
+
+ for (i = 0; i < npcbs; i++) {
+ printf("%s%x", cp, spp_pcbs[i]);
+ cp = ", ";
+ }
+ if (*cp)
+ putchar('\n');
+ exit(0);
+ }
+ for (i = 0; i < npcbs; i++) {
+ printf("\n%x:\n", spp_pcbs[i]);
+ dotrace(spp_pcbs[i]);
+ }
+ exit(0);
+}
+
+dotrace(sppcb)
+ register caddr_t sppcb;
+{
+ register int i;
+ register struct spp_debug *sd;
+
+ for (i = spp_debx % SPP_NDEBUG; i < SPP_NDEBUG; i++) {
+ sd = &spp_debug[i];
+ if (sppcb && sd->sd_cb != sppcb)
+ continue;
+ ntime = ntohl(sd->sd_time);
+ spp_trace(sd->sd_act, sd->sd_ostate, sd->sd_cb, &sd->sd_sp,
+ &sd->sd_si, sd->sd_req);
+ }
+ for (i = 0; i < spp_debx % SPP_NDEBUG; i++) {
+ sd = &spp_debug[i];
+ if (sppcb && sd->sd_cb != sppcb)
+ continue;
+ ntime = ntohl(sd->sd_time);
+ spp_trace(sd->sd_act, sd->sd_ostate, sd->sd_cb, &sd->sd_sp,
+ &sd->sd_si, sd->sd_req);
+ }
+}
+
+ptime(ms)
+ int ms;
+{
+
+ printf("%03d ", (ms/10) % 1000);
+}
+
+numeric(c1, c2)
+ caddr_t *c1, *c2;
+{
+
+ return (*c1 - *c2);
+}
+
+spp_trace(act, ostate, asp, sp, si, req)
+ short act, ostate;
+ struct sppcb *asp, *sp;
+ struct spidp *si;
+ int req;
+{
+ u_short seq, ack, len, alo;
+ int flags, timer;
+ char *cp;
+
+ if(ostate >= TCP_NSTATES) ostate = 0;
+ if(act > SA_DROP) act = SA_DROP;
+ printf("\n");
+ ptime(ntime);
+ printf("%s:%s", tcpstates[ostate], sanames[act]);
+
+ if (si != 0) {
+ seq = si->si_seq;
+ ack = si->si_ack;
+ alo = si->si_alo;
+ len = si->si_len;
+ switch (act) {
+ case SA_RESPOND:
+ case SA_OUTPUT:
+ seq = ntohs(seq);
+ ack = ntohs(ack);
+ alo = ntohs(alo);
+ len = ntohs(len);
+ case SA_INPUT:
+ case SA_DROP:
+ if (aflag) {
+ printf("\n\tsna=");
+ ns_printhost(&si->si_sna);
+ printf("\tdna=");
+ ns_printhost(&si->si_dna);
+ }
+ printf("\n\t");
+#define p1(name, f) { \
+ printf("%s = %x, ", name, f); \
+ }
+ p1("seq", seq);
+ p1("ack", ack);
+ p1("alo", alo);
+ p1("len", len);
+ flags = si->si_cc;
+ printf("flags=%x", flags);
+#define pf(name, f) { \
+ if (flags & f) { \
+ printf("%s%s", cp, name); \
+ cp = ","; \
+ } \
+}
+ if (flags) {
+ char *cp = "<";
+ pf("SP_SP", SP_SP);
+ pf("SP_SA", SP_SA);
+ pf("SP_OB", SP_OB);
+ pf("SP_EM", SP_EM);
+ printf(">");
+ }
+ printf(", ");
+#define p2(name, f) { \
+ printf("%s = %x, ", name, f); \
+}
+ p2("sid", si->si_sid);
+ p2("did", si->si_did);
+ p2("dt", si->si_dt);
+ printf("\n\tsna=");
+ ns_printhost(&si->si_sna);
+ printf("\tdna=");
+ ns_printhost(&si->si_dna);
+ }
+ }
+ if(act == SA_USER) {
+ printf("\treq=%s", prurequests[req&0xff]);
+ if ((req & 0xff) == PRU_SLOWTIMO)
+ printf("<%s>", tcptimers[req>>8]);
+ }
+ printf(" -> %s", tcpstates[sp->s_state]);
+
+ /* print out internal state of sp !?! */
+ printf("\n");
+ if (sp == 0)
+ return;
+#define p3(name, f) { \
+ printf("%s = %x, ", name, f); \
+}
+ if (sflag) {
+ printf("\t");
+ p3("rack", sp->s_rack);
+ p3("ralo", sp->s_ralo);
+ p3("smax", sp->s_smax);
+ p3("snxt", sp->s_snxt);
+ p3("flags", sp->s_flags);
+#undef pf
+#define pf(name, f) { \
+ if (flags & f) { \
+ printf("%s%s", cp, name); \
+ cp = ","; \
+ } \
+}
+ flags = sp->s_flags;
+ if (flags || sp->s_oobflags) {
+ char *cp = "<";
+ pf("ACKNOW", SF_ACKNOW);
+ pf("DELACK", SF_DELACK);
+ pf("HI", SF_HI);
+ pf("HO", SF_HO);
+ pf("PI", SF_PI);
+ pf("WIN", SF_WIN);
+ pf("RXT", SF_RXT);
+ pf("RVD", SF_RVD);
+ flags = sp->s_oobflags;
+ pf("SOOB", SF_SOOB);
+ pf("IOOB", SF_IOOB);
+ printf(">");
+ }
+ }
+ /* print out timers? */
+ if (tflag) {
+ char *cp = "\t";
+ register int i;
+
+ printf("\n\tTIMERS: ");
+ p3("idle", sp->s_idle);
+ p3("force", sp->s_force);
+ p3("rtseq", sp->s_rtseq);
+ for (i = 0; i < TCPT_NTIMERS; i++) {
+ if (sp->s_timer[i] == 0)
+ continue;
+ printf("%s%s=%d", cp, tcptimers[i], sp->s_timer[i]);
+ if (i == TCPT_REXMT)
+ printf(" (s_rxtshft=%d)", sp->s_rxtshift);
+ cp = ", ";
+ }
+ if (*cp != '\t')
+ putchar('\n');
+ }
+}
+
+ns_printhost(p)
+register struct ns_addr *p;
+{
+
+ printf("<net:%x%x,host:%4.4x%4.4x%4.4x,port:%x>",
+ p->x_net.s_net[0],
+ p->x_net.s_net[1],
+ p->x_host.s_host[0],
+ p->x_host.s_host[1],
+ p->x_host.s_host[2],
+ p->x_port);
+
+}
+
diff --git a/usr.sbin/update/Makefile b/usr.sbin/update/Makefile
new file mode 100644
index 00000000000..392a41c4c6f
--- /dev/null
+++ b/usr.sbin/update/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.5 (Berkeley) 6/29/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $
+
+PROG= update
+MAN= update.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/update/update.8 b/usr.sbin/update/update.8
new file mode 100644
index 00000000000..0201451b96f
--- /dev/null
+++ b/usr.sbin/update/update.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1991 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.
+.\"
+.\" from: @(#)update.8 6.5 (Berkeley) 8/5/91
+.\" $Id: update.8,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $
+.\"
+.Dd August 5, 1991
+.Dt UPDATE 8
+.Os
+.Sh NAME
+.Nm update
+.Nd flush internal filesystem caches to disk frequently
+.Sh SYNOPSIS
+.Nm update
+.Sh DESCRIPTION
+The
+.Nm update
+command helps protect the integrity of disk volumes
+by flushing
+volatile cached filesystem data
+to disk at thirty second intervals.
+.Nm Update
+uses the
+.Xr sync 2
+function call to do the task.
+.Pp
+.Nm Update
+is commonly invoked at startup time by
+.Xr rc 8
+when the system goes multi-user.
+.Sh SEE ALSO
+.Xr sync 2 ,
+.Xr fsck 8 ,
+.Xr init 8 ,
+.Xr rc 8 ,
+.Xr sync 8
+.Sh BUGS
+It is possible on some systems, that a
+.Xr sync
+occuring simultaneously with a crash may cause
+file system damage. See
+.Xr fsck 8 .
+.Sh HISTORY
+An
+.Nm update
+command appeared in
+.At v6 .
diff --git a/usr.sbin/update/update.c b/usr.sbin/update/update.c
new file mode 100644
index 00000000000..ca6b15ce204
--- /dev/null
+++ b/usr.sbin/update/update.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1987, 1990 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
+char copyright[] =
+"@(#) Copyright (c) 1987, 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)update.c 5.1 (Berkeley) 6/6/91";*/
+static char rcsid[] = "$Id: update.c,v 1.1.1.1 1995/10/18 08:48:30 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/time.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+main()
+{
+ struct itimerval value;
+ void mysync();
+
+ daemon(0, 0);
+
+ (void)signal(SIGALRM, mysync);
+
+ value.it_interval.tv_sec = 30;
+ value.it_interval.tv_usec = 0;
+ value.it_value = value.it_interval;
+ if (setitimer(ITIMER_REAL, &value, NULL)) {
+ perror("update: setitimer");
+ exit(1);
+ }
+ for (;;)
+ sigpause(sigblock(0L));
+ /* NOTREACHED */
+}
+
+void
+mysync()
+{
+ (void)sync();
+}
diff --git a/usr.sbin/videomode/Makefile b/usr.sbin/videomode/Makefile
new file mode 100644
index 00000000000..f56036ffa32
--- /dev/null
+++ b/usr.sbin/videomode/Makefile
@@ -0,0 +1,7 @@
+# $NetBSD: Makefile,v 1.1 1995/10/09 00:50:07 chopps Exp $
+
+PROG=videomode
+CFLAGS+=-I${.CURDIR}/../../sys/arch -D${MACHINE}
+NOMAN= noman
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/videomode/videomode.c b/usr.sbin/videomode/videomode.c
new file mode 100644
index 00000000000..ca4e4c2ed31
--- /dev/null
+++ b/usr.sbin/videomode/videomode.c
@@ -0,0 +1,167 @@
+/* $NetBSD: videomode.c,v 1.2 1995/10/09 13:52:49 chopps Exp $ */
+
+/*
+ * Copyright (c) 1995 Christian E. Hopps
+ * Copyright (c) 1994 Markus Wild
+ * 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 Markus Wild
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <amiga/dev/grfioctl.h>
+#include <amiga/dev/grfvar.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+
+void dump_mode __P((int));
+void dump_vm __P((struct grfvideo_mode *));
+int get_grf __P((void));
+void set_mode __P((int));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int m;
+ int c;
+
+ if (argc == 1) {
+ dump_mode(0);
+ return (0);
+ }
+ while ((c = getopt(argc, argv, "as:")) != EOF) {
+ switch (c) {
+ case 'a':
+ if (optind < argc)
+ usage();
+ dump_mode(-1);
+ return (0);
+ case 's':
+ m = atoi(optarg);
+ if (m == 0 || optind < argc)
+ usage();
+ set_mode(m);
+ return (0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 1)
+ usage();
+
+ dump_mode(atoi(*argv));
+ return (0);
+}
+
+
+int
+get_grf()
+{
+ struct stat stb;
+ char grfname[80];
+ int grffd;
+
+ /* find out on which ite/grf we are */
+ if (fstat(0, &stb) == -1)
+ err(1, "fstat 0");
+ if (((stb.st_mode & S_IFMT) != S_IFCHR) || !isatty(0))
+ errx(1, "stdin not a tty");
+ if (major(stb.st_rdev) != 13)
+ errx(1, "stdin not an ite device");
+ (void)sprintf(grfname, "/dev/grf%d", minor(stb.st_rdev) & 0x7);
+ if ((grffd = open(grfname, 2)) < 0)
+ err(1, "%s", grfname);
+ return (grffd);
+}
+
+void
+dump_mode(m)
+ int m;
+{
+ struct grfvideo_mode vm;
+ int num_vm;
+ int grffd;
+
+ grffd = get_grf();
+
+ if (ioctl(grffd, GRFGETNUMVM, &num_vm) < 0)
+ err(1, "GRFGETNUMVM");
+ if (m > 0 && m > num_vm)
+ errx(1, "no such mode");
+ if (m <= 0) {
+ (void)printf("Current mode:\n");
+ vm.mode_num = 0;
+ if (ioctl(grffd, GRFGETVMODE, &vm) == 0)
+ dump_vm(&vm);
+ (void)printf("\n");
+ }
+ if (m >= 0)
+ return;
+ for (m = 1; m <= num_vm; m++) {
+ vm.mode_num = m;
+ if (ioctl(grffd, GRFGETVMODE, &vm) == -1)
+ break;
+ dump_vm(&vm);
+ }
+}
+
+void
+set_mode(m)
+ int m;
+{
+ int grffd;
+
+ grffd = get_grf();
+ (void)ioctl(grffd, GRFSETVMODE, &m);
+}
+
+void
+dump_vm(vm)
+ struct grfvideo_mode *vm;
+{
+ (void)printf("%d: %s\n", vm->mode_num, vm->mode_descr);
+ (void)printf("pixel_clock = %u, width = %d, height = %d, depth = %d\n",
+ vm->pixel_clock, vm->disp_width, vm->disp_height, vm->depth);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: videomode [mode]\n");
+ (void)fprintf(stderr, "usage: videomode -a\n");
+ (void)fprintf(stderr, "usage: videomode -s mode\n");
+ exit(0);
+}
diff --git a/usr.sbin/vipw/Makefile b/usr.sbin/vipw/Makefile
new file mode 100644
index 00000000000..e89edcc054c
--- /dev/null
+++ b/usr.sbin/vipw/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.4 1995/01/20 19:19:53 mycroft Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= vipw
+SRCS= pw_util.c vipw.c
+MAN= vipw.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vipw/pw_util.c b/usr.sbin/vipw/pw_util.c
new file mode 100644
index 00000000000..ddafa60d57d
--- /dev/null
+++ b/usr.sbin/vipw/pw_util.c
@@ -0,0 +1,222 @@
+/* $NetBSD: pw_util.c,v 1.6 1995/01/20 19:45:39 mycroft Exp $ */
+
+/*-
+ * 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;
+static pid_t editpid = -1;
+static int lockfd;
+
+void
+pw_cont(sig)
+ int sig;
+{
+
+ if (editpid != -1)
+ kill(editpid, sig);
+}
+
+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(SIGCONT, pw_cont);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+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;
+ char *p, *editor;
+
+ if (!(editor = getenv("EDITOR")))
+ editor = _PATH_VI;
+ if (p = strrchr(editor, '/'))
+ ++p;
+ else
+ p = editor;
+
+ if (!(editpid = vfork())) {
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tempname, NULL);
+ _exit(1);
+ }
+ for (;;) {
+ editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
+ if (editpid == -1)
+ pw_error(editor, 1, 1);
+ else if (WIFSTOPPED(pstat))
+ raise(WSTOPSIG(pstat));
+ else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
+ break;
+ else
+ pw_error(editor, 1, 1);
+ }
+ editpid = -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/usr.sbin/vipw/pw_util.h b/usr.sbin/vipw/pw_util.h
new file mode 100644
index 00000000000..46f811eb672
--- /dev/null
+++ b/usr.sbin/vipw/pw_util.h
@@ -0,0 +1,44 @@
+/* $NetBSD: pw_util.h,v 1.2 1995/01/20 19:19:55 mycroft Exp $ */
+
+/*-
+ * 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_util.h 8.2 (Berkeley) 4/1/94
+ */
+
+void pw_edit __P((int));
+void pw_error __P((char *, int, int));
+void pw_init __P((void));
+int pw_lock __P((void));
+int pw_mkdb __P((void));
+void pw_prompt __P((void));
+int pw_tmp __P((void));
diff --git a/usr.sbin/vipw/vipw.8 b/usr.sbin/vipw/vipw.8
new file mode 100644
index 00000000000..ed3f084dd19
--- /dev/null
+++ b/usr.sbin/vipw/vipw.8
@@ -0,0 +1,95 @@
+.\" $NetBSD: vipw.8,v 1.4 1995/01/20 19:19:56 mycroft Exp $
+.\"
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)vipw.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt VIPW 8
+.Os BSD 4
+.Sh NAME
+.Nm vipw
+.Nd edit the password file
+.Sh SYNOPSIS
+.Nm vipw
+.Sh DESCRIPTION
+.Nm Vipw
+edits the password file after setting the appropriate locks,
+and does any necessary processing after the password file is unlocked.
+If the password file is already locked for editing by another user,
+.Nm vipw
+will ask you
+to try again later. The default editor for
+.Nm vipw
+is
+.Xr vi 1 .
+.Pp
+.Nm Vipw
+performs a number of consistency checks on the password entries,
+and will not allow a password file with a
+.Dq mangled
+entry to be
+installed.
+If
+.Nm vipw
+rejects the new password file, the user is prompted to re-enter
+the edit session.
+.Pp
+Once the information has been verified,
+.Nm vipw
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Sh ENVIRONMENT
+If the following environment variable exists it will be utilized by
+.Nm vipw :
+.Bl -tag -width EDITOR
+.It Ev EDITOR
+The editor specified by the string
+.Ev EDITOR
+will be invoked instead of the default editor
+.Xr vi 1 .
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr passwd 5 ,
+.Xr adduser 8 ,
+.Xr pwd_mkdb 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/vipw/vipw.c b/usr.sbin/vipw/vipw.c
new file mode 100644
index 00000000000..85fc0412eae
--- /dev/null
+++ b/usr.sbin/vipw/vipw.c
@@ -0,0 +1,129 @@
+/* $NetBSD: vipw.c,v 1.3 1995/01/20 19:19:57 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1987, 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 copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)vipw.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+char *tempname;
+
+void copyfile __P((int, int));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int pfd, tfd;
+ struct stat begin, end;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF) {
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ pw_init();
+ pfd = pw_lock();
+ tfd = pw_tmp();
+ copyfile(pfd, tfd);
+ (void)close(tfd);
+
+ for (;;) {
+ if (stat(tempname, &begin))
+ pw_error(tempname, 1, 1);
+ pw_edit(0);
+ if (stat(tempname, &end))
+ pw_error(tempname, 1, 1);
+ if (begin.st_mtime == end.st_mtime) {
+ warnx("no changes made");
+ pw_error((char *)NULL, 0, 0);
+ }
+ if (pw_mkdb())
+ break;
+ pw_prompt();
+ }
+ exit(0);
+}
+
+void
+copyfile(from, to)
+ int from, to;
+{
+ int nr, nw, off;
+ char buf[8*1024];
+
+ while ((nr = read(from, buf, sizeof(buf))) > 0)
+ for (off = 0; off < nr; nr -= nw, off += nw)
+ if ((nw = write(to, buf + off, nr)) < 0)
+ pw_error(tempname, 1, 1);
+ if (nr < 0)
+ pw_error(_PATH_MASTERPASSWD, 1, 1);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: vipw\n");
+ exit(1);
+}
diff --git a/usr.sbin/vnconfig/Makefile b/usr.sbin/vnconfig/Makefile
new file mode 100644
index 00000000000..d89245a48a2
--- /dev/null
+++ b/usr.sbin/vnconfig/Makefile
@@ -0,0 +1,6 @@
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:31 deraadt Exp $
+
+PROG= vnconfig
+MAN= vnconfig.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vnconfig/vnconfig.8 b/usr.sbin/vnconfig/vnconfig.8
new file mode 100644
index 00000000000..b01df7685a3
--- /dev/null
+++ b/usr.sbin/vnconfig/vnconfig.8
@@ -0,0 +1,105 @@
+.\" Copyright (c) 1993 University of Utah.
+.\" Copyright (c) 1980, 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Systems Programming Group of the University of Utah Computer
+.\" Science Department.
+.\"
+.\" 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.
+.\"
+.\" @(#)vnconfig.8 8.1 (Berkeley) 6/5/93
+.\"
+.Dd July 8, 1993
+.Dt VNCONFIG 8
+.Os BSD 4
+.Sh NAME
+.Nm vnconfig
+.Nd configure vnode disks
+.Sh SYNOPSIS
+.Nm vnconfig Fl c
+.Op Fl v
+.Ar special_file
+.Ar regular_file
+.Nm vnconfig Fl u
+.Op Fl v
+.Ar special_file
+.Sh DESCRIPTION
+The
+.Nm vnconfig
+command configures vnode pseudo disk devices.
+It will associate the special file
+.Ar special_file
+with the regular file
+.Ar regular_file
+allowing the latter to be accessed as though it were a disk.
+Hence a regular file within the filesystem can be used for swapping
+or can contain a filesystem that is mounted in the name space.
+.Pp
+Options indicate an action to be performed:
+.Bl -tag -width indent
+.It Fl c
+Configures the device.
+If successful, references to
+.Ar special_file
+will access the contents of
+.Ar regular_file .
+.It Fl u
+Unconfigures the device.
+.It Fl v
+Print messages to stdout describing actions taken.
+.El
+.Pp
+If no action option is given,
+.Fl c
+is assumed.
+.Sh FILES
+.Bl -tag -width /etc/rvnd?? -compact
+.It Pa /dev/rvnd??
+.It Pa /dev/vnd??
+.El
+.Sh EXAMPLES
+.Pp
+.Dl vnconfig /dev/vnd0c /tmp/diskimage
+.Pp
+Configures the vnode disk
+.Pa vnd0c .
+.Pp
+.Dl vnconfig -u /dev/vnd0c
+.Pp
+Unconfigures the
+.Pa vnd0c
+device.
+.Sh BUGS
+This command should really be named
+.Nm vndconfig .
+.Sh SEE ALSO
+.Xr swapon 8 ,
+.Xr mount 8 ,
+.Xr umount 8 .
diff --git a/usr.sbin/vnconfig/vnconfig.c b/usr.sbin/vnconfig/vnconfig.c
new file mode 100644
index 00000000000..3bfac4273b5
--- /dev/null
+++ b/usr.sbin/vnconfig/vnconfig.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1993 University of Utah.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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.
+ *
+ * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
+ *
+ * @(#)vnconfig.c 8.1 (Berkeley) 12/15/93
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <dev/vndioctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define VND_CONFIG 1
+#define VND_UNCONFIG 2
+
+int verbose = 0;
+
+char *rawdevice __P((char *));
+void usage __P((void));
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch, rv, action = VND_CONFIG;
+
+ while ((ch = getopt(argc, argv, "cuv")) != -1) {
+ switch (ch) {
+ case 'c':
+ action = VND_CONFIG;
+ break;
+ case 'u':
+ action = VND_UNCONFIG;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ case '?':
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (action == VND_CONFIG && argc == 2)
+ rv = config(argv[0], argv[1], action);
+ else if (action == VND_UNCONFIG && argc == 1)
+ rv = config(argv[0], NULL, action);
+ else
+ usage();
+ exit(rv);
+}
+
+config(dev, file, action)
+ char *dev;
+ char *file;
+ int action;
+{
+ struct vnd_ioctl vndio;
+ FILE *f;
+ char *rdev;
+ int rv;
+
+ rdev = rawdevice(dev);
+ f = fopen(rdev, "rw");
+ if (f == NULL) {
+ warn(rdev);
+ return (1);
+ }
+ vndio.vnd_file = file;
+
+ /*
+ * Clear (un-configure) the device
+ */
+ if (action == VND_UNCONFIG) {
+ rv = ioctl(fileno(f), VNDIOCCLR, &vndio);
+ if (rv)
+ warn("VNDIOCCLR");
+ else if (verbose)
+ printf("%s: cleared\n", dev);
+ }
+ /*
+ * Configure the device
+ */
+ if (action == VND_CONFIG) {
+ rv = ioctl(fileno(f), VNDIOCSET, &vndio);
+ if (rv)
+ warn("VNDIOCSET");
+ else if (verbose)
+ printf("%s: %d bytes on %s\n", dev, vndio.vnd_size,
+ file);
+ }
+done:
+ fclose(f);
+ fflush(stdout);
+ return (rv < 0);
+}
+
+char *
+rawdevice(dev)
+ char *dev;
+{
+ register char *rawbuf, *dp, *ep;
+ struct stat sb;
+ int len;
+
+ len = strlen(dev);
+ rawbuf = malloc(len + 2);
+ strcpy(rawbuf, dev);
+ if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
+ dp = rindex(rawbuf, '/');
+ if (dp) {
+ for (ep = &rawbuf[len]; ep > dp; --ep)
+ *(ep+1) = *ep;
+ *++ep = 'r';
+ }
+ }
+ return (rawbuf);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "%s%s",
+ "usage: vnconfig -c [-v] special-file regular-file\n",
+ " vnconfig -u [-v] special-file\n");
+ exit(1);
+}
diff --git a/usr.sbin/ypbind/Makefile b/usr.sbin/ypbind/Makefile
new file mode 100644
index 00000000000..8905d8d17b8
--- /dev/null
+++ b/usr.sbin/ypbind/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:31 deraadt Exp $
+
+PROG= ypbind
+MAN= ypbind.8
+CFLAGS+=-DDAEMON -DHEURISTIC
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypbind/ypbind.8 b/usr.sbin/ypbind/ypbind.8
new file mode 100644
index 00000000000..121cffdd33d
--- /dev/null
+++ b/usr.sbin/ypbind/ypbind.8
@@ -0,0 +1,104 @@
+.\"
+.\" Copyright (c) 1994 Jason R. Thorpe
+.\" 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 Jason Thorpe.
+.\" 4. Neither the name of the author 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 AUTHOR ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ypbind.8,v 1.1.1.1 1995/10/18 08:48:31 deraadt Exp $
+.\"
+.Dd October 25, 1994
+.Dt YPBIND 8
+.Os
+.Sh NAME
+.Nm ypbind
+.Nd create and maintain a binding to a YP server
+.Sh SYNOPSIS
+.Nm ypbind
+.Op Fl ypset
+.Nm ypbind
+.Op Fl ypsetme
+.Sh DESCRIPTION
+.Nm Ypbind
+finds the server for a particular YP domain and stores information about it
+in a
+.Pa binding file.
+This binding information includes the IP address of the server associated with
+that particular domain and which port the server is using. This information
+is stored in the directory
+.Pa /var/yp/binding
+in a file named with the convention
+.Pa domainname.version.
+(The YP system only supplies information on version 2.)
+.Pp
+When
+.Nm ypbind
+starts, it broadcasts looking for a process willing to serve maps for the
+client's domain. Once a binding is established,
+.Nm ypbind
+maintains this binding by periodically communicating with the server to which
+it is bound. If the binding is somehow lost, e.g by server reboot,
+.Nm ypbind
+marks the domain as unbound and attempts to re-establish the binding.
+When the binding is once again successful,
+.Nm ypbind
+marks the domain as bound and resumes its periodic check.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl ypset
+.Xr ypset 8
+may be used to change the server to which a domain is bound.
+.It Fl ypsetme
+.Xr ypset 8
+may be used only from this machine to change the server
+to which a domain is bound.
+.El
+.Pp
+The
+.Fl ypset
+and
+.Fl ypsetme
+options are dangerous and should be avoided.
+.Pp
+If the directory
+.Pa /var/yp
+exists, YP is started automatically at boot time by
+.Pa /etc/rc .
+.Sh FILES
+.Pa /var/yp/bindings/domainname.version
+- binding file for domainname
+.Sh SEE ALSO
+.Xr domainname 1 ,
+.Xr ypcat 1 ,
+.Xr ypmatch 1 ,
+.Xr yppoll 8 ,
+.Xr ypset 8 ,
+.Xr ypwhich 1 ,
+.Xr yp 8
+.Sh AUTHOR
+Theo De Raadt
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c
new file mode 100644
index 00000000000..d034b9c283b
--- /dev/null
+++ b/usr.sbin/ypbind/ypbind.c
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
+ * 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 Theo de Raadt.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: ypbind.c,v 1.1.1.1 1995/10/18 08:48:31 deraadt Exp $";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_rmt.h>
+#include <unistd.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#define BINDINGDIR "/var/yp/binding"
+#define YPBINDLOCK "/var/run/ypbind.lock"
+
+struct _dom_binding {
+ struct _dom_binding *dom_pnext;
+ char dom_domain[YPMAXDOMAIN + 1];
+ struct sockaddr_in dom_server_addr;
+ unsigned short int dom_server_port;
+ int dom_socket;
+ CLIENT *dom_client;
+ long int dom_vers;
+ time_t dom_check_t;
+ time_t dom_ask_t;
+ int dom_lockfd;
+ int dom_alive;
+};
+
+extern bool_t xdr_domainname(), xdr_ypbind_resp();
+extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
+extern bool_t xdr_ypbind_setdom();
+
+char *domainname;
+
+struct _dom_binding *ypbindlist;
+int check;
+
+#define YPSET_NO 0
+#define YPSET_LOCAL 1
+#define YPSET_ALL 2
+int ypsetmode = YPSET_NO;
+
+int rpcsock, pingsock;
+struct rmtcallargs rmtca;
+struct rmtcallres rmtcr;
+char rmtcr_outval;
+u_long rmtcr_port;
+SVCXPRT *udptransp, *tcptransp;
+
+void *
+ypbindproc_null_2(transp, argp, clnt)
+ SVCXPRT *transp;
+ void *argp;
+ CLIENT *clnt;
+{
+ static char res;
+
+ memset(&res, 0, sizeof(res));
+ return (void *)&res;
+}
+
+struct ypbind_resp *
+ypbindproc_domain_2(transp, argp, clnt)
+ SVCXPRT *transp;
+ char *argp;
+ CLIENT *clnt;
+{
+ static struct ypbind_resp res;
+ struct _dom_binding *ypdb;
+ char path[MAXPATHLEN];
+ time_t now;
+
+ memset(&res, 0, sizeof res);
+ res.ypbind_status = YPBIND_FAIL_VAL;
+
+ for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
+ if (!strcmp(ypdb->dom_domain, argp))
+ break;
+
+ if (ypdb == NULL) {
+ ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ memset(ypdb, 0, sizeof *ypdb);
+ strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain);
+ ypdb->dom_vers = YPVERS;
+ ypdb->dom_alive = 0;
+ ypdb->dom_lockfd = -1;
+ sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
+ unlink(path);
+ ypdb->dom_pnext = ypbindlist;
+ ypbindlist = ypdb;
+ check++;
+ return NULL;
+ }
+
+ if (ypdb->dom_alive == 0)
+ return NULL;
+
+#ifdef HEURISTIC
+ time(&now);
+ if (now < ypdb->dom_ask_t + 5) {
+ /*
+ * Hmm. More than 2 requests in 5 seconds have indicated
+ * that my binding is possibly incorrect.
+ * Ok, do an immediate poll of the server.
+ */
+ if (ypdb->dom_check_t >= now) {
+ /* don't flood it */
+ ypdb->dom_check_t = 0;
+ check++;
+ }
+ }
+ ypdb->dom_ask_t = now;
+#endif
+
+answer:
+ res.ypbind_status = YPBIND_SUCC_VAL;
+ res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
+ ypdb->dom_server_addr.sin_addr.s_addr;
+ res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
+ ypdb->dom_server_port;
+ /*printf("domain %s at %s/%d\n", ypdb->dom_domain,
+ inet_ntoa(ypdb->dom_server_addr.sin_addr),
+ ntohs(ypdb->dom_server_addr.sin_port));*/
+ return &res;
+}
+
+bool_t *
+ypbindproc_setdom_2(transp, argp, clnt)
+ SVCXPRT *transp;
+ struct ypbind_setdom *argp;
+ CLIENT *clnt;
+{
+ struct sockaddr_in *fromsin, bindsin;
+ static bool_t res;
+
+ memset(&res, 0, sizeof(res));
+ fromsin = svc_getcaller(transp);
+
+ switch (ypsetmode) {
+ case YPSET_LOCAL:
+ if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+ return (bool_t *)NULL;
+ break;
+ case YPSET_ALL:
+ break;
+ case YPSET_NO:
+ default:
+ return (bool_t *)NULL;
+ }
+
+ if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
+ return &res;
+
+ if (argp->ypsetdom_vers != YPVERS)
+ return &res;
+
+ memset(&bindsin, 0, sizeof bindsin);
+ bindsin.sin_family = AF_INET;
+ bindsin.sin_len = sizeof(bindsin);
+ bindsin.sin_addr = argp->ypsetdom_addr;
+ bindsin.sin_port = argp->ypsetdom_port;
+ rpc_received(argp->ypsetdom_domain, &bindsin, 1);
+
+ res = 1;
+ return &res;
+}
+
+static void
+ypbindprog_2(rqstp, transp)
+ struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ union {
+ char ypbindproc_domain_2_arg[MAXHOSTNAMELEN];
+ struct ypbind_setdom ypbindproc_setdom_2_arg;
+ } argument;
+ struct authunix_parms *creds;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case YPBINDPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) ypbindproc_null_2;
+ break;
+
+ case YPBINDPROC_DOMAIN:
+ xdr_argument = xdr_domainname;
+ xdr_result = xdr_ypbind_resp;
+ local = (char *(*)()) ypbindproc_domain_2;
+ break;
+
+ case YPBINDPROC_SETDOM:
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_UNIX:
+ creds = (struct authunix_parms *)rqstp->rq_clntcred;
+ if (creds->aup_uid != 0) {
+ svcerr_auth(transp, AUTH_BADCRED);
+ return;
+ }
+ break;
+ default:
+ svcerr_auth(transp, AUTH_TOOWEAK);
+ return;
+ }
+
+ xdr_argument = xdr_ypbind_setdom;
+ xdr_result = xdr_void;
+ local = (char *(*)()) ypbindproc_setdom_2;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ memset(&argument, 0, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local)(transp, &argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ return;
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char path[MAXPATHLEN];
+ struct timeval tv;
+ fd_set fdsr;
+ int width, lockfd;
+ int evil = 0, one;
+
+ yp_get_default_domain(&domainname);
+ if (domainname[0] == '\0') {
+ fprintf(stderr, "domainname not set. Aborting.\n");
+ exit(1);
+ }
+
+ while (--argc) {
+ ++argv;
+ if (!strcmp("-ypset", *argv))
+ ypsetmode = YPSET_ALL;
+ else if (!strcmp("-ypsetme", *argv))
+ ypsetmode = YPSET_LOCAL;
+ }
+
+ /* blow away everything in BINDINGDIR */
+
+#ifdef O_SHLOCK
+ if ((lockfd = open(YPBINDLOCK, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
+ fprintf(stderr, "ypbind: cannot create %s\n", YPBINDLOCK);
+ exit(1);
+ }
+#else
+ if ((lockfd = open(YPBINDLOCK, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
+ fprintf(stderr, "ypbind: cannot create %s\n", YPBINDLOCK);
+ exit(1);
+ }
+ flock(lockfd, LOCK_SH);
+#endif
+
+ (void)pmap_unset(YPBINDPROG, YPBINDVERS);
+
+ udptransp = svcudp_create(RPC_ANYSOCK);
+ if (udptransp == NULL) {
+ fprintf(stderr, "cannot create udp service.");
+ exit(1);
+ }
+ if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
+ IPPROTO_UDP)) {
+ fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).");
+ exit(1);
+ }
+
+ tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (tcptransp == NULL) {
+ fprintf(stderr, "cannot create tcp service.");
+ exit(1);
+ }
+ if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
+ IPPROTO_TCP)) {
+ fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).");
+ exit(1);
+ }
+
+ if ((rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket");
+ return -1;
+ }
+ if ((pingsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
+ fcntl(pingsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
+ one = 1;
+ setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
+ rmtca.prog = YPPROG;
+ rmtca.vers = YPVERS;
+ rmtca.proc = YPPROC_DOMAIN_NONACK;
+ rmtca.xdr_args = NULL; /* set at call time */
+ rmtca.args_ptr = NULL; /* set at call time */
+ rmtcr.port_ptr = &rmtcr_port;
+ rmtcr.xdr_results = xdr_bool;
+ rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
+
+ /* build initial domain binding, make it "unsuccessful" */
+ ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
+ memset(ypbindlist, 0, sizeof *ypbindlist);
+ strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain);
+ ypbindlist->dom_vers = YPVERS;
+ ypbindlist->dom_alive = 0;
+ ypbindlist->dom_lockfd = -1;
+ sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
+ ypbindlist->dom_vers);
+ (void)unlink(path);
+
+ checkwork();
+
+ while (1) {
+ width = svc_maxfd;
+ if (rpcsock > width)
+ width = rpcsock;
+ if (pingsock > width)
+ width = pingsock;
+ width++;
+
+ fdsr = svc_fdset;
+ FD_SET(rpcsock, &fdsr);
+ FD_SET(pingsock, &fdsr);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ switch (select(width, &fdsr, NULL, NULL, &tv)) {
+ case 0:
+ checkwork();
+ break;
+ case -1:
+ perror("select\n");
+ break;
+ default:
+ if (FD_ISSET(rpcsock, &fdsr))
+ handle_replies();
+ if (FD_ISSET(pingsock, &fdsr))
+ handle_ping();
+ svc_getreqset(&fdsr);
+ if (check)
+ checkwork();
+ break;
+ }
+
+ if (!evil && ypbindlist->dom_alive) {
+ evil = 1;
+ daemon(0, 0);
+ }
+ }
+}
+
+/*
+ * State transition is done like this:
+ *
+ * STATE EVENT ACTION NEWSTATE TIMEOUT
+ * no binding timeout broadcast no binding 5 sec
+ * no binding answer -- binding 60 sec
+ * binding timeout ping server checking 5 sec
+ * checking timeout ping server + broadcast checking 5 sec
+ * checking answer -- binding 60 sec
+ */
+checkwork()
+{
+ struct _dom_binding *ypdb;
+ time_t t;
+
+ check = 0;
+
+ time(&t);
+ for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) {
+ if (ypdb->dom_check_t < t) {
+ if (ypdb->dom_alive == 1)
+ ping(ypdb);
+ else
+ broadcast(ypdb);
+ time(&t);
+ ypdb->dom_check_t = t + 5;
+ }
+ }
+}
+
+ping(ypdb)
+ struct _dom_binding *ypdb;
+{
+ char *dom = ypdb->dom_domain;
+ struct rpc_msg msg;
+ char buf[1400];
+ enum clnt_stat st;
+ int outlen;
+ AUTH *rpcua;
+ XDR xdr;
+
+ memset(&xdr, 0, sizeof xdr);
+ memset(&msg, 0, sizeof msg);
+
+ rpcua = authunix_create_default();
+ if (rpcua == (AUTH *)NULL) {
+ /*printf("cannot get unix auth\n");*/
+ return RPC_SYSTEMERROR;
+ }
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg.rm_call.cb_prog = YPPROG;
+ msg.rm_call.cb_vers = YPVERS;
+ msg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK;
+ msg.rm_call.cb_cred = rpcua->ah_cred;
+ msg.rm_call.cb_verf = rpcua->ah_verf;
+
+ msg.rm_xid = (long)dom;
+ xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
+ if (!xdr_callmsg(&xdr, &msg)) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ if (!xdr_domainname(&xdr, dom)) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ outlen = (int)xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+ if (outlen < 1) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ AUTH_DESTROY(rpcua);
+
+ ypdb->dom_alive = 2;
+ if (sendto(pingsock, buf, outlen, 0,
+ (struct sockaddr *)&ypdb->dom_server_addr,
+ sizeof ypdb->dom_server_addr) < 0)
+ perror("sendto");
+ return 0;
+
+}
+
+broadcast(ypdb)
+ struct _dom_binding *ypdb;
+{
+ char *dom = ypdb->dom_domain;
+ struct rpc_msg msg;
+ char buf[1400], inbuf[8192];
+ char path[MAXPATHLEN];
+ enum clnt_stat st;
+ int outlen, i, sock, len;
+ struct sockaddr_in bindsin;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct in_addr in;
+ AUTH *rpcua;
+ XDR xdr;
+
+ rmtca.xdr_args = xdr_domainname;
+ rmtca.args_ptr = dom;
+
+ memset(&xdr, 0, sizeof xdr);
+ memset(&msg, 0, sizeof msg);
+
+ rpcua = authunix_create_default();
+ if (rpcua == (AUTH *)NULL) {
+ /*printf("cannot get unix auth\n");*/
+ return RPC_SYSTEMERROR;
+ }
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg.rm_call.cb_prog = PMAPPROG;
+ msg.rm_call.cb_vers = PMAPVERS;
+ msg.rm_call.cb_proc = PMAPPROC_CALLIT;
+ msg.rm_call.cb_cred = rpcua->ah_cred;
+ msg.rm_call.cb_verf = rpcua->ah_verf;
+
+ msg.rm_xid = (long)dom;
+ xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
+ if (!xdr_callmsg(&xdr, &msg)) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ if (!xdr_rmtcall_args(&xdr, &rmtca)) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ outlen = (int)xdr_getpos(&xdr);
+ xdr_destroy(&xdr);
+ if (outlen < 1) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ AUTH_DESTROY(rpcua);
+
+ if (ypdb->dom_lockfd != -1) {
+ close(ypdb->dom_lockfd);
+ ypdb->dom_lockfd = -1;
+ sprintf(path, "%s/%s.%d", BINDINGDIR,
+ ypdb->dom_domain, ypdb->dom_vers);
+ unlink(path);
+ }
+
+ memset(&bindsin, 0, sizeof bindsin);
+ bindsin.sin_family = AF_INET;
+ bindsin.sin_len = sizeof(bindsin);
+ bindsin.sin_port = htons(PMAPPORT);
+
+ if (ypdb->dom_alive == 2) {
+ /*
+ * This resolves the following situation:
+ * ypserver on other subnet was once bound,
+ * but rebooted and is now using a different port
+ */
+ bindsin.sin_addr = ypdb->dom_server_addr.sin_addr;
+ if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
+ sizeof bindsin) < 0)
+ perror("sendto");
+ }
+ /* find all networks and send the RPC packet out them all */
+ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof inbuf;
+ ifc.ifc_buf = inbuf;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ close(sock);
+ perror("ioctl(SIOCGIFCONF)");
+ return -1;
+ }
+ ifr = ifc.ifc_req;
+ ifreq.ifr_name[0] = '\0';
+ for (i = 0; i < ifc.ifc_len; i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+#if defined(BSD) && BSD >= 199103
+ len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len;
+#else
+ len = sizeof ifc.ifc_len / sizeof(struct ifreq);
+#endif
+ ifreq = *ifr;
+ if (ifreq.ifr_addr.sa_family != AF_INET)
+ continue;
+ if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) {
+ perror("ioctl(SIOCGIFFLAGS)");
+ continue;
+ }
+ if ((ifreq.ifr_flags & IFF_UP) == 0)
+ continue;
+
+ ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST);
+ if (ifreq.ifr_flags == IFF_BROADCAST) {
+ if (ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0) {
+ perror("ioctl(SIOCGIFBRDADDR)");
+ continue;
+ }
+ } else if (ifreq.ifr_flags == IFF_LOOPBACK) {
+ if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0) {
+ perror("ioctl(SIOCGIFADDR)");
+ continue;
+ }
+ } else
+ continue;
+
+ in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+ bindsin.sin_addr = in;
+ if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
+ sizeof bindsin) < 0)
+ perror("sendto");
+ }
+ close(sock);
+ return 0;
+}
+
+/*enum clnt_stat*/
+handle_replies()
+{
+ char buf[1400];
+ int fromlen, inlen;
+ struct sockaddr_in raddr;
+ struct rpc_msg msg;
+ XDR xdr;
+
+recv_again:
+ memset(&xdr, 0, sizeof(xdr));
+ memset(&msg, 0, sizeof(msg));
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr;
+ msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
+
+try_again:
+ fromlen = sizeof (struct sockaddr);
+ inlen = recvfrom(rpcsock, buf, sizeof buf, 0,
+ (struct sockaddr *)&raddr, &fromlen);
+ if (inlen < 0) {
+ if (errno == EINTR)
+ goto try_again;
+ return RPC_CANTRECV;
+ }
+ if (inlen < sizeof(u_int32_t))
+ goto recv_again;
+
+ /*
+ * see if reply transaction id matches sent id.
+ * If so, decode the results.
+ */
+ xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
+ if (xdr_replymsg(&xdr, &msg)) {
+ if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (msg.acpted_rply.ar_stat == SUCCESS)) {
+ raddr.sin_port = htons((u_short)rmtcr_port);
+ rpc_received(msg.rm_xid, &raddr, 0);
+ }
+ }
+ xdr.x_op = XDR_FREE;
+ msg.acpted_rply.ar_results.proc = xdr_void;
+ xdr_destroy(&xdr);
+
+ return RPC_SUCCESS;
+}
+
+/*enum clnt_stat*/
+handle_ping()
+{
+ char buf[1400];
+ int fromlen, inlen;
+ struct sockaddr_in raddr;
+ struct rpc_msg msg;
+ XDR xdr;
+ bool_t res;
+
+recv_again:
+ memset(&xdr, 0, sizeof(xdr));
+ memset(&msg, 0, sizeof(msg));
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where = (caddr_t)&res;
+ msg.acpted_rply.ar_results.proc = xdr_bool;
+
+try_again:
+ fromlen = sizeof (struct sockaddr);
+ inlen = recvfrom(pingsock, buf, sizeof buf, 0,
+ (struct sockaddr *)&raddr, &fromlen);
+ if (inlen < 0) {
+ if (errno == EINTR)
+ goto try_again;
+ return RPC_CANTRECV;
+ }
+ if (inlen < sizeof(u_int32_t))
+ goto recv_again;
+
+ /*
+ * see if reply transaction id matches sent id.
+ * If so, decode the results.
+ */
+ xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
+ if (xdr_replymsg(&xdr, &msg)) {
+ if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (msg.acpted_rply.ar_stat == SUCCESS)) {
+ rpc_received(msg.rm_xid, &raddr, 0);
+ }
+ }
+ xdr.x_op = XDR_FREE;
+ msg.acpted_rply.ar_results.proc = xdr_void;
+ xdr_destroy(&xdr);
+
+ return RPC_SUCCESS;
+}
+
+/*
+ * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
+ */
+rpc_received(dom, raddrp, force)
+char *dom;
+struct sockaddr_in *raddrp;
+int force;
+{
+ struct _dom_binding *ypdb;
+ struct iovec iov[2];
+ struct ypbind_resp ybr;
+ char path[MAXPATHLEN];
+ int fd;
+
+ /* XXX XXX USING POINTERS OVER THE NET LIKE THIS IS TOTALLY WRONG. */
+
+ /*printf("returned from %s about %s\n", inet_ntoa(raddrp->sin_addr), dom);*/
+
+#ifdef __alpha__ /* XXX XXX */
+ /* you _REALLY_ do not want to know... */ /* XXX XXX */
+ dom = (char *)((u_long)dom | (u_long)0x100000000); /* XXX XXX */
+#endif /* XXX XXX */
+
+ if (dom == NULL)
+ return;
+
+ for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
+ if (!strcmp(ypdb->dom_domain, dom))
+ break;
+
+ if (ypdb == NULL) {
+ if (force == 0)
+ return;
+ ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ memset(ypdb, 0, sizeof *ypdb);
+ strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
+ ypdb->dom_lockfd = -1;
+ ypdb->dom_pnext = ypbindlist;
+ ypbindlist = ypdb;
+ }
+
+ /* soft update, alive */
+ if (ypdb->dom_alive == 1 && force == 0) {
+ if (!memcmp(&ypdb->dom_server_addr, raddrp,
+ sizeof ypdb->dom_server_addr)) {
+ ypdb->dom_alive = 1;
+ ypdb->dom_check_t = time(NULL) + 60; /* recheck binding in 60 sec */
+ }
+ return;
+ }
+
+ memcpy(&ypdb->dom_server_addr, raddrp, sizeof ypdb->dom_server_addr);
+ ypdb->dom_check_t = time(NULL) + 60; /* recheck binding in 60 seconds */
+ ypdb->dom_vers = YPVERS;
+ ypdb->dom_alive = 1;
+
+ if (ypdb->dom_lockfd != -1)
+ close(ypdb->dom_lockfd);
+
+ sprintf(path, "%s/%s.%d", BINDINGDIR,
+ ypdb->dom_domain, ypdb->dom_vers);
+#ifdef O_SHLOCK
+ if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
+ (void)mkdir(BINDINGDIR, 0755);
+ if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
+ return;
+ }
+#else
+ if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
+ (void)mkdir(BINDINGDIR, 0755);
+ if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1)
+ return;
+ }
+ flock(fd, LOCK_SH);
+#endif
+
+ /*
+ * ok, if BINDINGDIR exists, and we can create the binding file,
+ * then write to it..
+ */
+ ypdb->dom_lockfd = fd;
+
+ iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
+ iov[0].iov_len = sizeof udptransp->xp_port;
+ iov[1].iov_base = (caddr_t)&ybr;
+ iov[1].iov_len = sizeof ybr;
+
+ memset(&ybr, 0, sizeof ybr);
+ ybr.ypbind_status = YPBIND_SUCC_VAL;
+ ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr;
+ ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
+
+ if (writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
+ perror("write");
+ close(ypdb->dom_lockfd);
+ unlink(path);
+ ypdb->dom_lockfd = -1;
+ return;
+ }
+}
diff --git a/usr.sbin/yppoll/Makefile b/usr.sbin/yppoll/Makefile
new file mode 100644
index 00000000000..c9a8789f3a2
--- /dev/null
+++ b/usr.sbin/yppoll/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:32 deraadt Exp $
+
+PROG= yppoll
+MAN= yppoll.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/yppoll/yppoll.8 b/usr.sbin/yppoll/yppoll.8
new file mode 100644
index 00000000000..bb61e1c3010
--- /dev/null
+++ b/usr.sbin/yppoll/yppoll.8
@@ -0,0 +1,77 @@
+.\"
+.\" Copyright (c) 1994 Jason R. Thorpe
+.\" 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 Jason Thorpe.
+.\" 4. Neither the name of the author 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 AUTHOR ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: yppoll.8,v 1.1.1.1 1995/10/18 08:48:32 deraadt Exp $
+.\"
+.Dd October 25, 1994
+.Dt YPPOLL 8
+.Os
+.Sh NAME
+.Nm yppoll
+.Nd ask version of YP map from YP server
+.Sh SYNOPSIS
+.Nm yppoll
+.Op Fl h Ar host
+.Op Fl d Ar domain
+.Ar mapname
+.Sh DESCRIPTION
+.Nm Yppoll
+asks a YP server process for the order number and which host is the master
+server for
+.Ar mapname .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl h Ar host
+Ask the YP server process running on
+.Ar host
+for information about
+.Ar mapname .
+If
+.Ar host
+is not specified, the server polled is the default server returned by
+.Xr ypwhich 1 .
+.It Fl d Ar domain
+Use the YP domain
+.Ar domain
+instead of the default domain as returned by
+.Xr domainname 1 .
+.El
+.Sh SEE ALSO
+.Xr domainname 1 ,
+.Xr ypbind 8 ,
+.Xr ypcat 1 ,
+.Xr ypmatch 1 ,
+.Xr ypset 8 ,
+.Xr ypwhich 1 ,
+.Xr yp 8
+.Sh AUTHORS
+Theo De Raadt and John Brezak
diff --git a/usr.sbin/yppoll/yppoll.c b/usr.sbin/yppoll/yppoll.c
new file mode 100644
index 00000000000..3311f4b86f3
--- /dev/null
+++ b/usr.sbin/yppoll/yppoll.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1992, 1993 John Brezak
+ * 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 Theo de Raadt and
+ * John Brezak.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: yppoll.c,v 1.1.1.1 1995/10/18 08:48:32 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+void
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typpoll [-h host] [-d domainname] mapname\n");
+ exit(1);
+}
+
+int
+get_remote_info(indomain, inmap, server, outorder, outname)
+ char *indomain;
+ char *inmap;
+ char *server;
+ int *outorder;
+ char **outname;
+{
+ struct ypresp_order ypro;
+ struct ypresp_master yprm;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+ struct sockaddr_in rsrv_sin;
+ int rsrv_sock;
+ CLIENT *client;
+ struct hostent *h;
+
+ bzero((char *)&rsrv_sin, sizeof rsrv_sin);
+ rsrv_sin.sin_len = sizeof rsrv_sin;
+ rsrv_sin.sin_family = AF_INET;
+ rsrv_sock = RPC_ANYSOCK;
+
+ h = gethostbyname(server);
+ if (h == NULL) {
+ if (inet_aton(server, &rsrv_sin.sin_addr) == 0) {
+ fprintf(stderr, "unknown host %s\n", server);
+ exit(1);
+ }
+ } else {
+ rsrv_sin.sin_addr.s_addr = *(u_long *)h->h_addr;
+ }
+
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ client = clntudp_create(&rsrv_sin, YPPROG, YPVERS, tv, &rsrv_sock);
+ if (client == NULL) {
+ fprintf(stderr, "clntudp_create: no contact with host %s.\n",
+ server);
+ exit(1);
+ }
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+
+ bzero((char *)(char *)&ypro, sizeof ypro);
+
+ r = clnt_call(client, YPPROC_ORDER, xdr_ypreq_nokey, &yprnk,
+ xdr_ypresp_order, &ypro, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_order: clnt_call");
+
+ *outorder = ypro.ordernum;
+ xdr_free(xdr_ypresp_order, (char *)&ypro);
+
+ r = ypprot_err(ypro.status);
+ if (r == RPC_SUCCESS) {
+ bzero((char *)&yprm, sizeof yprm);
+
+ r = clnt_call(client, YPPROC_MASTER, xdr_ypreq_nokey,
+ &yprnk, xdr_ypresp_master, &yprm, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_master: clnt_call");
+ r = ypprot_err(yprm.status);
+ if (r==0)
+ *outname = (char *)strdup(yprm.master);
+ xdr_free(xdr_ypresp_master, (char *)&yprm);
+ }
+ clnt_destroy(client);
+ return r;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *domainname;
+ char *hostname = NULL;
+ char *inmap, *master;
+ int order;
+ extern char *optarg;
+ extern int optind;
+ int c, r;
+
+ yp_get_default_domain(&domainname);
+
+ while ((c=getopt(argc, argv, "h:d:?")) != -1)
+ switch (c) {
+ case 'd':
+ domainname = optarg;
+ break;
+ case 'h':
+ hostname = optarg;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (optind + 1 != argc )
+ usage();
+ inmap = argv[optind];
+
+ if (hostname != NULL) {
+ r = get_remote_info(domainname, inmap, hostname,
+ &order, &master);
+ } else {
+ r = yp_order(domainname, inmap, &order);
+ if (r == 0)
+ r = yp_master(domainname, inmap, &master);
+ }
+
+ if (r != 0) {
+ fprintf(stderr, "No such map %s. Reason: %s\n",
+ inmap, yperr_string(r));
+ exit(1);
+ }
+
+ printf("Map %s has order number %d. %s", inmap, order,
+ ctime((time_t *)&order));
+ printf("The master server is %s.\n", master);
+ exit(0);
+}
diff --git a/usr.sbin/ypset/Makefile b/usr.sbin/ypset/Makefile
new file mode 100644
index 00000000000..4d3ccad920f
--- /dev/null
+++ b/usr.sbin/ypset/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.1.1.1 1995/10/18 08:48:32 deraadt Exp $
+
+PROG= ypset
+MAN= ypset.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypset/ypset.8 b/usr.sbin/ypset/ypset.8
new file mode 100644
index 00000000000..6448a69bffc
--- /dev/null
+++ b/usr.sbin/ypset/ypset.8
@@ -0,0 +1,87 @@
+.\"
+.\" Copyright (c) 1994 Jason R. Thorpe
+.\" 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 Jason Thorpe.
+.\" 4. Neither the name of the author 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 AUTHOR ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ypset.8,v 1.1.1.1 1995/10/18 08:48:32 deraadt Exp $
+.\"
+.Dd October 25, 1994
+.Dt YPSET 8
+.Os
+.Sh NAME
+.Nm ypset
+.Nd tell
+.Xr ypbind 8
+which YP server process to use
+.Sh SYNOPSIS
+.Nm ypset
+.Op Fl h Ar host
+.Op Fl d Ar domain
+.Ar server
+.Sh DESCRIPTION
+.Nm Ypset
+tells the
+.Xr ypbind 8
+process on the current machine which YP server process to communicate with.
+If
+.Ar server
+is down or is not running a YP server process, it is not discovered until
+a YP client process attempts to access a YP map, at which time
+.Xr ypbind 8
+tests the binding and takes appropriate action.
+.Pp
+.Nm Ypset
+is most useful for binding a YP client that is not on the same broadcast
+network as the closest YP server, but can also be used for debugging
+a local network's YP configuration, testing specific YP client
+programs, or binding to a specific server when there are many servers on
+the local network supplying YP maps.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl h Ar host
+Set the YP binding on
+.Ar host
+instead of the local machine.
+.It Fl d Ar domain
+Use the YP domain
+.Ar domain
+instead of the default domain as returned by
+.Xr domainname 1 .
+.El
+.Sh SEE ALSO
+.Xr domainname 1 ,
+.Xr ypbind 8 ,
+.Xr ypcat 1 ,
+.Xr ypmatch 1 ,
+.Xr yppoll 8 ,
+.Xr ypwhich 1 ,
+.Xr yp 8
+.Sh AUTHOR
+Theo De Raadt
diff --git a/usr.sbin/ypset/ypset.c b/usr.sbin/ypset/ypset.c
new file mode 100644
index 00000000000..0f13ec4d02d
--- /dev/null
+++ b/usr.sbin/ypset/ypset.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
+ * 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 Theo de Raadt.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LINT
+static char rcsid[] = "ypset.c,v 1.3 1993/06/12 00:02:37 deraadt Exp";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <arpa/inet.h>
+
+extern bool_t xdr_domainname();
+
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typset [-h host ] [-d domain] server\n");
+ exit(1);
+}
+
+bind_tohost(sin, dom, server)
+struct sockaddr_in *sin;
+char *dom, *server;
+{
+ struct ypbind_setdom ypsd;
+ struct timeval tv;
+ struct hostent *hp;
+ CLIENT *client;
+ int sock, port;
+ int r;
+
+ if( (port=htons(getrpcport(server, YPPROG, YPPROC_NULL, IPPROTO_UDP))) == 0) {
+ fprintf(stderr, "%s not running ypserv.\n", server);
+ exit(1);
+ }
+
+ bzero(&ypsd, sizeof ypsd);
+
+ if (inet_aton(server, &ypsd.ypsetdom_addr) == 0) {
+ hp = gethostbyname(server);
+ if (hp == NULL) {
+ fprintf(stderr, "ypset: can't find address for %s\n", server);
+ exit(1);
+ }
+ bcopy(hp->h_addr, &ypsd.ypsetdom_addr, sizeof(ypsd.ypsetdom_addr));
+ }
+
+ strncpy(ypsd.ypsetdom_domain, dom, sizeof ypsd.ypsetdom_domain);
+ ypsd.ypsetdom_port = port;
+ ypsd.ypsetdom_vers = YPVERS;
+
+ tv.tv_sec = 15;
+ tv.tv_usec = 0;
+ sock = RPC_ANYSOCK;
+ client = clntudp_create(sin, YPBINDPROG, YPBINDVERS, tv, &sock);
+ if (client==NULL) {
+ fprintf(stderr, "can't yp_bind: Reason: %s\n",
+ yperr_string(YPERR_YPBIND));
+ return YPERR_YPBIND;
+ }
+ client->cl_auth = authunix_create_default();
+
+ r = clnt_call(client, YPBINDPROC_SETDOM,
+ xdr_ypbind_setdom, &ypsd, xdr_void, NULL, tv);
+ if(r) {
+ fprintf(stderr, "Sorry, cannot ypset for domain %s on host.\n", dom);
+ clnt_destroy(client);
+ return YPERR_YPBIND;
+ }
+ clnt_destroy(client);
+ return 0;
+}
+
+int
+main(argc, argv)
+char **argv;
+{
+ struct sockaddr_in sin;
+ struct hostent *hent;
+ extern char *optarg;
+ extern int optind;
+ char *domainname;
+ int c;
+
+ yp_get_default_domain(&domainname);
+
+ bzero(&sin, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+
+ while( (c=getopt(argc, argv, "h:d:")) != -1)
+ switch(c) {
+ case 'd':
+ domainname = optarg;
+ break;
+ case 'h':
+ if (inet_aton(optarg, &sin.sin_addr) == 0) {
+ hent = gethostbyname(optarg);
+ if (hent == NULL) {
+ fprintf(stderr, "ypset: host %s unknown\n",
+ optarg);
+ exit(1);
+ }
+ bcopy(&hent->h_addr, &sin.sin_addr,
+ sizeof(sin.sin_addr));
+ }
+ break;
+ default:
+ usage();
+ }
+
+ if(optind + 1 != argc )
+ usage();
+
+ if (bind_tohost(&sin, domainname, argv[optind]))
+ exit(1);
+ exit(0);
+}
diff --git a/usr.sbin/zdump/Makefile b/usr.sbin/zdump/Makefile
new file mode 100644
index 00000000000..7e13befbd3c
--- /dev/null
+++ b/usr.sbin/zdump/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.2 1995/03/11 01:14:28 jtc Exp $
+
+PROG= zdump
+SRCS= zdump.c ialloc.c
+MAN= zdump.8
+
+.PATH: ${.CURDIR}/../../lib/libc/time
+.include <bsd.prog.mk>
diff --git a/usr.sbin/zic/Makefile b/usr.sbin/zic/Makefile
new file mode 100644
index 00000000000..35cf1981923
--- /dev/null
+++ b/usr.sbin/zic/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.2 1995/03/11 01:14:25 jtc Exp $
+
+PROG= zic
+SRCS= zic.c scheck.c ialloc.c
+MAN= zic.8
+
+.PATH: ${.CURDIR}/../../lib/libc/time
+.include <bsd.prog.mk>